diff --git a/.clang-format b/.clang-format index 5c76ce64..cee653f7 100644 --- a/.clang-format +++ b/.clang-format @@ -3,6 +3,7 @@ BasedOnStyle: Google Language: Cpp AccessModifierOffset: -4 AlignAfterOpenBracket: DontAlign +AlignArrayOfStructures: Right AlignOperands: DontAlign AlignTrailingComments: false AllowAllArgumentsOnNextLine: true @@ -31,6 +32,7 @@ IndentWidth: 4 LambdaBodyIndentation: Signature PackConstructorInitializers: Never PointerAlignment: Left +QualifierAlignment: Left ReferenceAlignment: Left ReflowComments: true SpacesBeforeTrailingComments: 2 diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..f93a7859 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,48 @@ +Checks: | + -*, + clang-analyzer-*, + clang-diagnostic-*, + misc-*, + -misc-const-correctness, + -misc-include-cleaner + -misc-non-private-member-variables-in-classes, + -misc-no-recursion, + -misc-unused-alias-decls, + -misc-unused-parameters, + -misc-use-anonymous-namespace, + modernize-*, + -modernize-use-trailing-return-type, + readability-identifier-naming, + +CheckOptions: + - key: readability-identifier-naming.ClassCase + value: CamelCase + - key: readability-identifier-naming.ClassIgnoredRegexp + value: "bf_cp|f_cp|uf_cp" + - key: readability-identifier-naming.EnumCase + value: CamelCase + - key: readability-identifier-naming.FunctionCase + value: lower_case + - key: readability-identifier-naming.FunctionIgnoredRegexp + value: ".*_|SetUp|MOCK_METHOD|TEST|TEST_F|TestBody\ + |DescribeNegationTo|DescribeTo|MatchAndExplain|ValuesEq\ + |addErrorListener|copyNodeAnnotation|expandNodeAnnotation|setNodeAnnotation|syntaxError\ + |visit.*" + - key: readability-identifier-naming.MemberCase + value: lower_case + - key: readability-identifier-naming.MemberIgnoredRegexp + value: ".*_" + - key: readability-identifier-naming.ParameterCase + value: lower_case + - key: readability-identifier-naming.ParameterIgnoredRegexp + value: ".*_|AnalysisResult|ParseResult" + - key: readability-identifier-naming.UnionCase + value: CamelCase + - key: readability-identifier-naming.VariableCase + value: lower_case + - key: readability-identifier-naming.IgnoreMainLikeFunctions + value: 1 + - key: readability-redundant-member-init.IgnoreBaseInCopyConstructors + value: 1 + - key: modernize-use-default-member-init.UseAssignment + value: 1 diff --git a/.github/workflows/assets.yaml b/.github/workflows/assets.yaml index 54379b48..9acb7190 100644 --- a/.github/workflows/assets.yaml +++ b/.github/workflows/assets.yaml @@ -14,55 +14,29 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - # macos-13 is an x64 runner, macos-14 is an arm64 runner - os: [ubuntu-latest, windows-latest, macos-13, macos-14] + os: [ + ubuntu-latest, # Linux/x64 + macos-13, # MacOS/x64 + windows-latest, # Windows/x64 + ubuntu-24.04-arm, # Linux/ARM64 + macos-14 # MacOS/ARM64 + ] steps: - name: Checkout uses: actions/checkout@v4 - uses: actions/setup-python@v5 - name: Install cibuildwheel - run: python -m pip install cibuildwheel==2.18.1 - - name: Build wheels - run: python -m cibuildwheel --output-dir wheelhouse - - uses: actions/upload-artifact@v4 - with: - name: cibw-wheels-${{ matrix.os }} - path: ./wheelhouse/*.whl - - cibw-wheels-linux-arm64: - name: Build wheels on linux-arm64 - runs-on: [self-hosted, ARM64, Linux] - container: - image: python:3.12-slim - volumes: - - /var/run/docker.sock:/var/run/docker.sock - steps: - - name: Checkout - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - - name: Install docker run: | - apt-get update - apt-get install -y ca-certificates curl - install -m 0755 -d /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc - chmod a+r /etc/apt/keyrings/docker.asc - - echo \ - "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \ - $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ - tee /etc/apt/sources.list.d/docker.list > /dev/null - apt-get update - apt-get install -y docker-ce-cli - - name: Install cibuildwheel and build wheels + python -m pip install cibuildwheel==2.18.1 + - name: Build wheels run: | - pip install cibuildwheel==2.18.1 - cibuildwheel --output-dir wheelhouse + python -m cibuildwheel --output-dir wheelhouse + if: ${{ matrix.os == 'ubuntu-24.04-arm' }} env: CIBW_BEFORE_ALL_LINUX: yum install -y java-11-openjdk - uses: actions/upload-artifact@v4 with: - name: cibw-wheels-linux-arm64 + name: cibw-wheels-${{ matrix.os }} path: ./wheelhouse/*.whl emscripten-wasm: @@ -108,7 +82,6 @@ jobs: name: Publish Python packages needs: - cibw-wheels - - cibw-wheels-linux-arm64 - emscripten-wasm runs-on: ubuntu-latest steps: diff --git a/.github/workflows/linters.yaml b/.github/workflows/linters.yaml index b7dc446d..2bb80eff 100644 --- a/.github/workflows/linters.yaml +++ b/.github/workflows/linters.yaml @@ -15,18 +15,28 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Build C++ tests (gcc-clang/Linux/x64) + uses: ./.github/actions/cpp-tests + with: + build_type: Release + conan_profile_host: conan/profiles/tests-release-gcc-linux-x64 + shell: bash - name: Run C++ linters uses: cpp-linter/cpp-linter-action@v2 id: linter env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: + database: '${{ github.workspace }}/build/Release' extensions: 'cpp,hpp' + ignore: 'emscripten/emscripten_wrapper.hpp' style: 'file' # use .clang-format config file - tidy-checks: '-*' # disable clang-tidy checks + tidy-checks: '' # use .clang-tidy config file version: 18 - name: Fail fast - if: steps.linter.outputs.clang-format-checks-failed > 0 + if: steps.linter.outputs.checks-failed > 0 run: | - echo "::notice::Try executing 'python3 ./scripts/run_cpp_linters.py .' to fix linter issues." + echo "::notice::Try running the following commands to fix and/or understand linter issues:" + echo "::notice:: conan build . -pr:a=conan/profiles/tests-release-gcc-linux-x64 -b missing" + echo "::notice:: python3 ./scripts/run_cpp_linters.py ." exit 1 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 6fdff61e..43e5b0a8 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -23,43 +23,41 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Install libc++ + run: | + sudo apt-get update + sudo apt-get install -y libc++-dev libc++abi-dev - uses: ./.github/actions/cpp-tests with: build_type: ${{ matrix.build_type }} conan_profile_host: conan/profiles/tests-${{ matrix.build_type }}-${{ matrix.compiler }}-linux-x64 + conan_profile_build: conan/profiles/tests-${{ matrix.build_type }}-${{ matrix.compiler }}-linux-x64 shell: bash cpp-linux-arm64: name: "C++ tests (gcc/Linux/ARM64)" - runs-on: [self-hosted, ARM64, Linux] - container: python:3.11 - # Run only when merging to develop - # (until we have a GitHub-hosted runner for Linux/ARM64) - if: github.ref == 'refs/heads/develop' + runs-on: ubuntu-24.04-arm strategy: fail-fast: false matrix: build_type: - Debug - Release + compiler: + - clang + - gcc steps: - name: Checkout uses: actions/checkout@v4 - # We are having problems when using zulu-opendjk Conan package on an armv8 architecture. - # zulu-openjdk provides the Java JRE required by the ANTLR generator. - # So, for the time being, we are installing Java manually for this platform - - name: Install dependencies + - name: Install libc++ run: | - apt-get update - apt-get install -y default-jre pipx - # Add Conan to path (even before it is installed) - - name: Add Conan to path - run: | - echo "${HOME}/.local/bin" >> $GITHUB_PATH + sudo apt-get update + sudo apt-get install -y libc++-dev libc++abi-dev - uses: ./.github/actions/cpp-tests with: build_type: ${{ matrix.build_type }} - conan_profile_host: conan/profiles/tests-${{ matrix.build_type }}-gcc-linux-arm64 + conan_profile_host: conan/profiles/tests-${{ matrix.build_type }}-${{ matrix.compiler }}-linux-arm64 + conan_profile_build: conan/profiles/tests-${{ matrix.build_type }}-${{ matrix.compiler }}-linux-arm64 shell: bash cpp-macos-x64: @@ -78,11 +76,12 @@ jobs: with: build_type: ${{ matrix.build_type }} conan_profile_host: conan/profiles/tests-${{ matrix.build_type }}-apple_clang-macos-x64 + conan_profile_build: conan/profiles/tests-${{ matrix.build_type }}-apple_clang-macos-x64 shell: bash cpp-macos-arm64: name: "C++ tests (clang/macos/ARM64)" - runs-on: macos-14 # arm64 + runs-on: macos-14 # ARM4 strategy: fail-fast: false matrix: @@ -96,6 +95,7 @@ jobs: with: build_type: ${{ matrix.build_type }} conan_profile_host: conan/profiles/tests-${{ matrix.build_type }}-apple_clang-macos-arm64 + conan_profile_build: conan/profiles/tests-${{ matrix.build_type }}-apple_clang-macos-arm64 shell: bash cpp-windows-x64: @@ -133,6 +133,7 @@ jobs: with: build_type: ${{ matrix.build_type }} conan_profile_host: conan/profiles/${{ matrix.build_type }}-gcc-linux-x64-shared + conan_profile_build: conan/profiles/${{ matrix.build_type }}-gcc-linux-x64-shared shell: bash ts-emscripten-wasm: @@ -190,9 +191,19 @@ jobs: run: | sudo apt-get install -y swig shell: bash - - name: Export LIBQASM_BUILD_TYPE + - uses: ./.github/actions/python-tests + with: + shell: bash + + python-linux-arm64: + name: "Python tests (Linux/arm64)" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install SWIG run: | - echo "LIBQASM_BUILD_TYPE=Debug" >> $GITHUB_ENV + sudo apt-get install -y swig shell: bash - uses: ./.github/actions/python-tests with: @@ -208,10 +219,6 @@ jobs: run: | brew install swig shell: bash - - name: Export LIBQASM_BUILD_TYPE - run: | - echo "LIBQASM_BUILD_TYPE=Debug" >> $GITHUB_ENV - shell: bash - uses: ./.github/actions/python-tests with: shell: bash @@ -222,14 +229,10 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: Install dependencies + - name: Install SWIG run: | brew install swig shell: bash - - name: Export LIBQASM_BUILD_TYPE - run: | - echo "LIBQASM_BUILD_TYPE=Debug" >> $GITHUB_ENV - shell: bash - uses: ./.github/actions/python-tests with: shell: bash @@ -240,10 +243,6 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: Export LIBQASM_BUILD_TYPE - run: | - echo "LIBQASM_BUILD_TYPE=Release" >> $env:GITHUB_ENV - shell: powershell - uses: ./.github/actions/python-tests with: shell: bash @@ -266,15 +265,17 @@ jobs: # see https://github.community/t/status-check-for-a-matrix-jobs/127354/7 name: Report status needs: - - cpp-shared - cpp-linux-x64 - - cpp-macos-x64 - - cpp-windows-x64 - cpp-linux-arm64 + - cpp-macos-x64 - cpp-macos-arm64 + - cpp-windows-x64 + - cpp-shared - ts-emscripten-wasm - python-linux-x64 + - python-linux-arm64 - python-macos-x64 + - python-macos-arm64 - python-windows-x64 - docker if: ${{ always() }} @@ -290,7 +291,6 @@ jobs: || ( github.ref != 'refs/heads/develop' && contains(needs.*.result, 'skipped') - && !contains(needs.cpp-linux-arm64.result, 'skipped') ) || ( diff --git a/CHANGELOG.md b/CHANGELOG.md index c3956b82..ef9d4dea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,28 @@ -# Change Log +# Changelog All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +### Types of changes: +- **Added** for new features. +- **Changed** for changes in existing functionality. +- **Fixed** for any bug fixes. +- **Removed** for now removed features. + + +## [ 1.0.0 ] - [ 2025-01-30 ] + +### Added +- `.clang-tidy`. +- Python Linux/ARM64 GitHub Actions job. + +### Changed +- Error when redeclaring a variable. +- Change Linux/ARM64 jobs to use GitHub-hosted runners. + +### Fixed +- clang/Linux/x64 GitHub Actions jobs (which use Ubuntu 24.04.1 since 2025). + ## [ 0.6.9 ] - [ 2024-11-13 ] @@ -10,8 +30,6 @@ This project adheres to [Semantic Versioning](http://semver.org/). - `SWAP` unitary instruction. - `init`, `barrier`, and `wait` non-unitary instructions. -### Changed - ### Removed - `reset` without qubit operands form. @@ -23,12 +41,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). - C++ linters GitHub Actions job (just running clang-format at the moment). ### Changed -- Fix bug: empty lists are written out to JSON as `"[]"` instead of `[]`. -- Fix bug: CRk and CZ parameter types were interchanged in the instruction set. - More descriptive and consistent (snake case) file names. - Minor fixes and tweaks to documentation. -### Removed +### Fixed +- Empty lists are written out to JSON as `"[]"` instead of `[]`. +- `CRk` and `CZ` parameter types were interchanged in the instruction set. ## [ 0.6.7 ] - [ 2024-05-30 ] @@ -37,10 +55,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). - `pyproject.toml`. - GitHub pages. -### Changed -- Fix building of tests in Conan profiles and `setup.py`. -- Fix Python MacOS/x64 (with Python > 3.11) packages. -- Fix deserialization of CBOR strings. +### Fixed +- Building of tests in Conan profiles and `setup.py`. +- Python MacOS/x64 (with Python > 3.11) packages. +- Deserialization of CBOR strings. ### Removed - Python 3.8 packages generation. @@ -50,39 +68,35 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Allow multiple qubit/bit (register) definitions and mid-circuit measurements. -- Python MacOS/arm64 jobs. +- Python MacOS/ARM64 jobs. - `python/test_libqasm.py` to test Python jobs. ### Changed -- Fix Python MacOS/arm64 packages. -- Fix `scripts/generate_antlr_parser.py`. -- MacOS/x64 jobs now run in macos-13, and MacOS/arm64 jobs in macos-14, both GitHub runners. +- MacOS/x64 jobs now run in macos-13, and MacOS/ARM64 jobs in macos-14, both GitHub runners. - Python module name from `libQasm` to `libqasm`. +## Fixed +- Python MacOS/ARM64 packages. +- `scripts/generate_antlr_parser.py`. + ### Removed - `python/module/libQasm` folder. ## [ 0.6.5 ] - [ 2024-04-23 ] -### Added - ### Changed - Update emscripten compilation flags. -- Change GitHub Actions `js-emscripten-wasm` job to work with `deno` instead of `node`. - -### Removed +- GitHub Actions `js-emscripten-wasm` job to work with `deno` instead of `node`. ## [ 0.6.4 ] - [ 2024-04-15 ] -### Added - ### Changed -- Fix CMake install. - `generate_antlr_parser.py` writes output include files in a given `include` folder. -### Removed +### Fixed +- CMake install. ## [ 0.6.3 ] - [ 2024-04-12 ] @@ -93,8 +107,6 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Changed - Allow multiple `measure` instructions at the end of a program. -### Removed - ## [ 0.6.2 ] - [ 2024-04-09 ] @@ -102,8 +114,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - `.clang-format`. - `emscripten-wasm` assets job. -### Changed -- Fix shared library build. +### Fixed +- Shared library build. ### Removed - `TREEN_GEN_BUILD_TESTS` option. @@ -111,12 +123,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [ 0.6.1 ] - [ 2024-04-08 ] -### Added - ### Changed -- Fix Python interface. - Update GitHub Actions versions. +### Fixed +- Python interface. + ### Removed - `m4` dependency. @@ -124,12 +136,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [ 0.6.0 ] - [ 2024-03-28 ] ### Added -- cQasm 3.0 parser. MVP (Minimum Viable Product) implemented. +- cQASM 3.0 parser. MVP (Minimum Viable Product) implemented. - Conan as package manager. ### Changed - Different upgrades: C++20, CMake 3.12, Python 3.8 to 3.12. ### Removed -- cQasm 1.x support. +- cQASM 1.x support. - Git submodules. diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c576472..5167e0e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,9 +20,11 @@ project(cqasm LANGUAGES C CXX) if(NOT TARGET cqasm) set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + # Library type option. Default is a static library. option(BUILD_SHARED_LIBS "whether the cqasm library should be built as a shared object or as a static library" diff --git a/README.md b/README.md index 89e6ac84..85852c51 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![CI](https://github.com/QuTech-Delft/libqasm/workflows/Test/badge.svg)](https://github.com/qutech-delft/libqasm/actions) [![Conan Center](https://img.shields.io/conan/v/libqasm)](https://conan.io/center/recipes/libqasm) +[![cpp-linter](https://github.com/cpp-linter/cpp-linter-action/actions/workflows/cpp-linter.yml/badge.svg)](https://github.com/cpp-linter/cpp-linter-action/actions/workflows/cpp-linter.yml) [![PyPI](https://badgen.net/pypi/v/libqasm)](https://pypi.org/project/libqasm/) ![OS](https://img.shields.io/badge/os-emscripten%20%7C%20linux%20%7C%20macos%20%7C%20windows-blue?style=flat-square) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) @@ -42,7 +43,7 @@ CNOT q[0], q[1] b = measure q ``` -We can parse or analyze this circuit, using libQASM through the following programming language: +We can parse or analyze this circuit using libQASM through the following programming language: ### C++ @@ -57,7 +58,6 @@ int main() { } ``` - ### Emscripten The emscripten API only allows to input a cQASM program as a string. diff --git a/conan/profiles/tests-debug-clang-linux-arm64 b/conan/profiles/tests-debug-clang-linux-arm64 index 76ef4bab..d57f514d 100644 --- a/conan/profiles/tests-debug-clang-linux-arm64 +++ b/conan/profiles/tests-debug-clang-linux-arm64 @@ -7,3 +7,8 @@ compiler.version=14 [conf] tools.build:cxxflags=["-stdlib=libc++"] tools.build:compiler_executables={ 'c' : 'clang', 'cpp' : 'clang++' } + +[options] +# Disable ASAN for Linux/x64 because we are having problems with gtest and address sanitizer +# Possible hints: libc++ ABI compatibility, small string optimization +libqasm/*:asan_enabled=False diff --git a/conan/profiles/tests-release-clang-linux-arm64 b/conan/profiles/tests-release-clang-linux-arm64 index 3f39a2ca..182edb7f 100644 --- a/conan/profiles/tests-release-clang-linux-arm64 +++ b/conan/profiles/tests-release-clang-linux-arm64 @@ -7,3 +7,8 @@ compiler.version=14 [conf] tools.build:cxxflags=["-stdlib=libc++"] tools.build:compiler_executables={ 'c' : 'clang', 'cpp' : 'clang++' } + +[options] +# Disable ASAN for Linux/x64 because we are having problems with gtest and address sanitizer +# Possible hints: libc++ ABI compatibility, small string optimization +libqasm/*:asan_enabled=False diff --git a/docs/about/license.md b/docs/about/license.md index 5ec3bba1..77af536e 100644 --- a/docs/about/license.md +++ b/docs/about/license.md @@ -1,3 +1,2 @@ -libQASM is licensed under the Apache License, Version 2.0. See -[LICENSE](https://github.com/QuTech-Delft/OpenSquirrel/blob/master/LICENSE.md) for the full -license text. +libQASM is licensed under the Apache License, Version 2.0. +See [LICENSE](https://github.com/QuTech-Delft/OpenSquirrel/blob/master/LICENSE.md) for the full license text. diff --git a/docs/api/cpp.md b/docs/api/cpp-api.md similarity index 100% rename from docs/api/cpp.md rename to docs/api/cpp-api.md diff --git a/docs/api/emscripten.md b/docs/api/emscripten-api.md similarity index 100% rename from docs/api/emscripten.md rename to docs/api/emscripten-api.md diff --git a/docs/api/python.md b/docs/api/python-api.md similarity index 100% rename from docs/api/python.md rename to docs/api/python-api.md diff --git a/docs/dev-guide/cpp.md b/docs/dev-guide/cpp-dev-guide.md similarity index 86% rename from docs/dev-guide/cpp.md rename to docs/dev-guide/cpp-dev-guide.md index 59702040..dbc99b4f 100644 --- a/docs/dev-guide/cpp.md +++ b/docs/dev-guide/cpp-dev-guide.md @@ -2,11 +2,12 @@ You can build the C++ binaries from the project's root directory. The following line will also build and cache the `libqasm` Conan package. !!! note + You may need to execute the `conan profile detect` command if this is the first time you run Conan. ```shell conan profile detect -conan create --version 0.6.9 . -pr:a=tests-debug -b missing +conan create --version 1.0.0 . -pr:a=tests-debug -b missing ``` You can test the C++ binaries: diff --git a/docs/dev-guide/dev-guide.md b/docs/dev-guide/dev-guide.md index 6a5c277e..abb54114 100644 --- a/docs/dev-guide/dev-guide.md +++ b/docs/dev-guide/dev-guide.md @@ -55,10 +55,10 @@ For the time being, we install Java manually for this platform. On a Linux machine, these linters can be installed with the following commands: ```shell - wget https://apt.llvm.org/llvm.sh -O llvm_install.sh - chmod +x llvm_install.sh - ./llvm_install.sh - apt-get install -y clang-format-18 clang-tidy-18 +wget https://apt.llvm.org/llvm.sh -O llvm_install.sh +chmod +x llvm_install.sh +./llvm_install.sh +apt-get install -y clang-format-18 clang-tidy-18 ``` ## Build @@ -77,7 +77,7 @@ conan build . -pr:a=conan/profiles/tests-debug -b missing !!! note - - the `conan profile` command only has to be run only once, and not before every build. + - the `conan profile` command has to be run only once, and not before every build. - the `conan build` command is building libQASM in Debug mode with tests using the `tests-debug` profile. - the `-b missing` parameter asks `conan` to build packages from sources in case it cannot find the binary packages for the current configuration (platform, OS, compiler, build type...). @@ -85,10 +85,9 @@ conan build . -pr:a=conan/profiles/tests-debug -b missing ### Profiles A group of predefined profiles is provided under the `conan/profiles` folder. -They follow the `[tests-|docs-](build_type)(-compiler)(-os)(-arch)[-shared]` naming convention: +They follow the `[tests-](build_type)(-compiler)(-os)(-arch)[-shared]` naming convention: - `tests`: if tests are being built. -- `docs`: if docs are being built. - `build_type`: can be `debug` or `release`. - `compiler`: `apple-clang`, `clang`, `gcc`, `msvc`. - `os`: `emscripten`, `linux`, `macos`, `windows`. @@ -109,7 +108,7 @@ conan build . -s:a compiler.cppstd=20 -s:a libqasm/*:build_type=Debug -o libqasm This is the list of options that could be specified either in a profile or in the command line: - `libqasm/*:asan_enabled={True,False}`: enables Address Sanitizer. -- `libqasm/*:build_type={Debug,Release}`: builds in debug or release mode. +- `libqasm/*:build_type={Debug,Release}`: builds in Debug or Release mode. - `libqasm/*:shared={True,False}`: builds a shared object library instead of a static library, if applicable. Tests are disabled by default. To enable them, use `-c tools.build:skip_test=False`. @@ -119,7 +118,7 @@ Tests are disabled by default. To enable them, use `-c tools.build:skip_test=Fal Build and serve on `http://127.0.0.1:8000/`. ```shell -export PTYHONPATH=./scripts/python +export PYTHONPATH=./scripts/python mkdocs serve ``` @@ -134,15 +133,21 @@ Continuous Integration will fail if the files do not adhere to a series of forma - Formatting checks are defined in `.clang-format`. - Code style checks are defined in `.clang-tidy`. -It is recommended to run these linters before pushing any change: +It is recommended to run these linters before pushing any changes: ```shell +conan build . -pr:a=conan/profiles/tests-release-gcc-linux-x64 -b missing python3 ./scripts/run_cpp_linters.py . ``` !!! note - The linters require `clang-format-18` and `clang-tidy-18` to be installed on the system. + - The linters require `clang-format-18` and `clang-tidy-18`. + - It is mandatory to have a build before running the linters. + - `clang-tidy` expects to find a `compile_commands.json` in a build folder. + - It is recommended to build with `gcc` in Release mode. + - We have observed `clang-tidy` fails to find some standard headers when compiling with `clang`. + - `run_cpp_linters.py` can receive a build folder as second argument, but defaults to `build/Release`. ## Docker diff --git a/docs/dev-guide/emscripten.md b/docs/dev-guide/emscripten-dev-guide.md similarity index 99% rename from docs/dev-guide/emscripten.md rename to docs/dev-guide/emscripten-dev-guide.md index 1b151b41..bd69aa9b 100644 --- a/docs/dev-guide/emscripten.md +++ b/docs/dev-guide/emscripten-dev-guide.md @@ -11,6 +11,7 @@ The output of this build lives in `build/Release/emscripten`: - `cqasm_emscripten.wasm`. !!! note + `cqasm_emscripten.js` is an ES6 module. Its extension has to be renamed to `.mjs` before using it from Typescript code. diff --git a/docs/dev-guide/python.md b/docs/dev-guide/python-dev-guide.md similarity index 100% rename from docs/dev-guide/python.md rename to docs/dev-guide/python-dev-guide.md diff --git a/docs/user-guide/cpp.md b/docs/user-guide/cpp-user-guide.md similarity index 86% rename from docs/user-guide/cpp.md rename to docs/user-guide/cpp-user-guide.md index 66a97a00..2c4daa2e 100644 --- a/docs/user-guide/cpp.md +++ b/docs/user-guide/cpp-user-guide.md @@ -1,10 +1,10 @@ -libQASM can be requested as a Conan package from a `conanfile.py`. +libQASM can be requested as a Conan package from a `conanfile.py`: ``` def build_requirements(self): - self.tool_requires("libqasm/0.6.9") + self.tool_requires("libqasm/1.0.0") def requirements(self): - self.requires("libqasm/0.6.9") + self.requires("libqasm/1.0.0") ``` And then linked against from a `CMakeLists.txt`: @@ -14,9 +14,10 @@ target_link_libraries( PUBLIC libqasm::libqasm) ``` !!! note + You will need to have `Java JRE` >= 11 installed in case Conan needs to build libQASM. -**Example**: +And used from a C++ program: ```cpp #include "libqasm/v3x/cqasm_python.hpp" diff --git a/docs/user-guide/emscripten.md b/docs/user-guide/emscripten-user-guide.md similarity index 98% rename from docs/user-guide/emscripten.md rename to docs/user-guide/emscripten-user-guide.md index 5f17642d..75987586 100644 --- a/docs/user-guide/emscripten.md +++ b/docs/user-guide/emscripten-user-guide.md @@ -3,8 +3,6 @@ libQASM can be used from a web environment via a Typescript frontend. Emscripten API only allows to input a cQASM program via a string and always returns a JSON string output. -**Example**: - ```typescript import { default as wrapper } from 'cqasm_emscripten.mjs'; diff --git a/docs/user-guide/python.md b/docs/user-guide/python-user-guide.md similarity index 71% rename from docs/user-guide/python.md rename to docs/user-guide/python-user-guide.md index 314195fd..22a94fc0 100644 --- a/docs/user-guide/python.md +++ b/docs/user-guide/python-user-guide.md @@ -1,6 +1,10 @@ -libQASM can be imported as a Python package. +libQASM can be installed as a Python package: -**Example**: +```shell +pip install libqasm +``` + +And then imported from a Python program: ```python from libqasm import Analyzer diff --git a/emscripten/emscripten_wrapper.hpp b/emscripten/emscripten_wrapper.hpp index c373a88a..575ff018 100644 --- a/emscripten/emscripten_wrapper.hpp +++ b/emscripten/emscripten_wrapper.hpp @@ -91,6 +91,7 @@ struct EmscriptenWrapper { std::string analyze_string_to_json(const std::string& data, const std::string& file_name); }; +// NOLINTNEXTLINE EMSCRIPTEN_BINDINGS(CqasmJS) { emscripten::class_("EmscriptenWrapper") .constructor() diff --git a/emscripten/test_libqasm.ts b/emscripten/test_libqasm.ts index d0539186..f141b451 100644 --- a/emscripten/test_libqasm.ts +++ b/emscripten/test_libqasm.ts @@ -8,7 +8,7 @@ wrapper().then(function(result: any) { try { let output = cqasm.get_version() - let expected_output = "0.6.9" + let expected_output = "1.0.0" console.log("\nThe version of libqasm compiled with emscripten is:", output); if (output !== expected_output) { console.log("\tExpected output:", expected_output) diff --git a/include/libqasm/error.hpp b/include/libqasm/error.hpp index 24dfe9b2..f7b575d1 100644 --- a/include/libqasm/error.hpp +++ b/include/libqasm/error.hpp @@ -75,7 +75,7 @@ class Error : public std::runtime_error { /** * Returns the message exception-style. */ - const char* what() const noexcept override; + [[nodiscard]] const char* what() const noexcept override; /** * Returns a string with a JSON representation of an Error. @@ -83,7 +83,7 @@ class Error : public std::runtime_error { * Every error is mapped to an LSP Diagnostic structure: * Severity is hardcoded to 1 at the moment (value corresponding to an Error level) */ - std::string to_json() const; + [[nodiscard]] std::string to_json() const; }; /** diff --git a/include/libqasm/overload.hpp b/include/libqasm/overload.hpp index 6f5d44a0..bb5319bf 100644 --- a/include/libqasm/overload.hpp +++ b/include/libqasm/overload.hpp @@ -6,7 +6,6 @@ #include // pair #include -#include "libqasm/overload.hpp" #include "libqasm/tree.hpp" /** diff --git a/include/libqasm/v3x/analysis_result.hpp b/include/libqasm/v3x/analysis_result.hpp index 9d42b3d3..2ba4518f 100644 --- a/include/libqasm/v3x/analysis_result.hpp +++ b/include/libqasm/v3x/analysis_result.hpp @@ -21,8 +21,10 @@ using Root = ast::One; */ class AnalysisFailed : public std::runtime_error { public: + // NOLINTBEGIN AnalysisFailed() : std::runtime_error{ "cQASM analysis failed" } {}; + // NOLINTEND }; /** diff --git a/include/libqasm/v3x/analyzer.hpp b/include/libqasm/v3x/analyzer.hpp index 62dd1c26..07cdc2b3 100644 --- a/include/libqasm/v3x/analyzer.hpp +++ b/include/libqasm/v3x/analyzer.hpp @@ -14,7 +14,6 @@ #include #include "analysis_result.hpp" -#include "analyzer.hpp" #include "libqasm/v3x/ast.hpp" #include "libqasm/v3x/core_function.hpp" #include "libqasm/v3x/parse_helper.hpp" diff --git a/include/libqasm/v3x/antlr_custom_error_listener.hpp b/include/libqasm/v3x/antlr_custom_error_listener.hpp index 39d172c2..95e87937 100644 --- a/include/libqasm/v3x/antlr_custom_error_listener.hpp +++ b/include/libqasm/v3x/antlr_custom_error_listener.hpp @@ -14,12 +14,12 @@ class AntlrCustomErrorListener : public antlr4::BaseErrorListener { */ std::optional file_name_; - void syntaxError(antlr4::Recognizer* recognizer, antlr4::Token* offendingSymbol, size_t line, - size_t charPositionInLine, const std::string& msg, std::exception_ptr e) override; + void syntaxError(antlr4::Recognizer* recognizer, antlr4::Token* offending_symbol, size_t line, + size_t char_position_in_line, const std::string& msg, std::exception_ptr e) override; public: explicit AntlrCustomErrorListener(const std::optional& file_name); - void syntaxError(size_t line, size_t charPositionInLine, const std::string& msg); + void syntaxError(size_t line, size_t char_position_in_line, const std::string& msg); }; } // namespace cqasm::v3x::parser diff --git a/include/libqasm/v3x/antlr_scanner.hpp b/include/libqasm/v3x/antlr_scanner.hpp index d3c6c14f..6b55d818 100644 --- a/include/libqasm/v3x/antlr_scanner.hpp +++ b/include/libqasm/v3x/antlr_scanner.hpp @@ -42,7 +42,7 @@ class FileAntlrScanner : public AntlrScanner { public: FileAntlrScanner(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up, const std::string& file_path); + std::unique_ptr error_listener_up, std::string file_path); ~FileAntlrScanner() override; @@ -54,7 +54,7 @@ class StringAntlrScanner : public AntlrScanner { public: StringAntlrScanner(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up, const std::string& data); + std::unique_ptr error_listener_up, std::string data); ~StringAntlrScanner() override; diff --git a/include/libqasm/v3x/core_function.hpp b/include/libqasm/v3x/core_function.hpp index e5030c38..52655d66 100644 --- a/include/libqasm/v3x/core_function.hpp +++ b/include/libqasm/v3x/core_function.hpp @@ -49,14 +49,8 @@ class CoreFunction : public tree::Base { * param_types is a shorthand type specification string as parsed by cqasm::types::from_spec(). * return_type is a shorthand type specification char as parsed by cqasm::types::from_spec(). */ - CoreFunction(std::string name, const std::string& param_types, const char return_type); - CoreFunction() = default; - ~CoreFunction() override = default; - CoreFunction(const CoreFunction& t) = default; - CoreFunction(CoreFunction&& t) noexcept = default; - CoreFunction& operator=(const CoreFunction& t) = default; - CoreFunction& operator=(CoreFunction&& t) noexcept = default; + CoreFunction(std::string name, const std::string& param_types, const char return_type); bool operator==(const CoreFunction& rhs) const; inline bool operator!=(const CoreFunction& rhs) const { return !(*this == rhs); } diff --git a/include/libqasm/v3x/cqasm_python.hpp b/include/libqasm/v3x/cqasm_python.hpp index a9093b91..9225c92e 100644 --- a/include/libqasm/v3x/cqasm_python.hpp +++ b/include/libqasm/v3x/cqasm_python.hpp @@ -146,24 +146,25 @@ class V3xAnalyzer { /** * Parses and analyzes a file containing a cQASM v3.0 program. */ - std::vector analyze_file(const std::string& file_name) const; + [[nodiscard]] std::vector analyze_file(const std::string& file_name) const; /** * Parses and analyzes a file containing a cQASM v3.0 program. */ - std::string analyze_file_to_json(const std::string& file_name) const; + [[nodiscard]] std::string analyze_file_to_json(const std::string& file_name) const; /** * Parses and analyzes a string containing a cQASM v3.0 program. * * `file_name` is optional. It is only used when reporting errors. */ - std::vector analyze_string(const std::string& data, const std::string& file_name = "") const; + [[nodiscard]] std::vector analyze_string( + const std::string& data, const std::string& file_name = "") const; /** * Parses and analyzes a string containing a cQASM v3.0 program. * * `file_name` is optional. It is only used when reporting errors. */ - std::string analyze_string_to_json(const std::string& data, const std::string& file_name = "") const; + [[nodiscard]] std::string analyze_string_to_json(const std::string& data, const std::string& file_name = "") const; }; diff --git a/include/libqasm/v3x/register_consteval_core_functions.hpp b/include/libqasm/v3x/register_consteval_core_functions.hpp index 74d7d11e..9845d22b 100644 --- a/include/libqasm/v3x/register_consteval_core_functions.hpp +++ b/include/libqasm/v3x/register_consteval_core_functions.hpp @@ -86,7 +86,7 @@ constexpr auto op_div_ff = bf_cp{}; constexpr auto op_mod_ii = bf_cp{}; -constexpr auto pow = [](auto base, auto exp) { return std::pow(base, exp); }; +inline constexpr auto pow = [](auto base, auto exp) { return std::pow(base, exp); }; constexpr auto op_pow_ff = bf_cp{}; constexpr auto op_eq_ff = bf_cp{}; @@ -115,53 +115,53 @@ constexpr auto op_band_ii = bf_cp{}; constexpr auto op_bor_ii = bf_cp{}; -constexpr auto shl = [](primitives::Int a, primitives::Int b) { return a << b; }; +inline constexpr auto shl = [](primitives::Int a, primitives::Int b) { return a << b; }; constexpr auto op_shl_ii = bf_cp{}; -constexpr auto shr = [](primitives::Int a, primitives::Int b) { return a >> b; }; +inline constexpr auto shr = [](primitives::Int a, primitives::Int b) { return a >> b; }; constexpr auto op_shr_ii = bf_cp{}; constexpr auto op_linv_b = uf_cp{}; constexpr auto op_land_bb = bf_cp{}; -constexpr auto lxor = [](primitives::Bool lhs, primitives::Bool rhs) { return !lhs ^ !rhs; }; +inline constexpr auto lxor = [](primitives::Bool lhs, primitives::Bool rhs) { return !lhs ^ !rhs; }; constexpr auto op_lxor_bb = bf_cp{}; constexpr auto op_lor_bb = bf_cp{}; -constexpr auto tcnd = [](bool condition, auto if_true, auto if_false) { return condition ? if_true : if_false; }; +inline constexpr auto tcnd = [](bool condition, auto if_true, auto if_false) { return condition ? if_true : if_false; }; constexpr auto op_tcnd_bff = tf_cp{}; constexpr auto op_tcnd_bii = tf_cp{}; constexpr auto op_tcnd_bbb = tf_cp{}; -constexpr auto sqrt = [](auto num) { return std::sqrt(num); }; +inline constexpr auto sqrt = [](auto num) { return std::sqrt(num); }; constexpr auto fn_sqrt_f = uf_cp{}; -constexpr auto exp = [](auto num) { return std::exp(num); }; +inline constexpr auto exp = [](auto num) { return std::exp(num); }; constexpr auto fn_exp_f = uf_cp{}; -constexpr auto log = [](auto num) { return std::log(num); }; +inline constexpr auto log = [](auto num) { return std::log(num); }; constexpr auto fn_log_f = uf_cp{}; -constexpr auto sin = [](auto num) { return std::sin(num); }; +inline constexpr auto sin = [](auto num) { return std::sin(num); }; constexpr auto fn_sin_f = uf_cp{}; -constexpr auto cos = [](auto num) { return std::cos(num); }; +inline constexpr auto cos = [](auto num) { return std::cos(num); }; constexpr auto fn_cos_f = uf_cp{}; -constexpr auto tan = [](auto num) { return std::tan(num); }; +inline constexpr auto tan = [](auto num) { return std::tan(num); }; constexpr auto fn_tan_f = uf_cp{}; -constexpr auto sinh = [](auto num) { return std::sinh(num); }; +inline constexpr auto sinh = [](auto num) { return std::sinh(num); }; constexpr auto fn_sinh_f = uf_cp{}; -constexpr auto cosh = [](auto num) { return std::cosh(num); }; +inline constexpr auto cosh = [](auto num) { return std::cosh(num); }; constexpr auto fn_cosh_f = uf_cp{}; -constexpr auto tanh = [](auto num) { return std::tanh(num); }; +inline constexpr auto tanh = [](auto num) { return std::tanh(num); }; constexpr auto fn_tanh_f = uf_cp{}; -constexpr auto asin = [](auto num) { return std::asin(num); }; +inline constexpr auto asin = [](auto num) { return std::asin(num); }; constexpr auto fn_asin_f = uf_cp{}; -constexpr auto acos = [](auto num) { return std::acos(num); }; +inline constexpr auto acos = [](auto num) { return std::acos(num); }; constexpr auto fn_acos_f = uf_cp{}; -constexpr auto atan = [](auto num) { return std::atan(num); }; +inline constexpr auto atan = [](auto num) { return std::atan(num); }; constexpr auto fn_atan_f = uf_cp{}; -constexpr auto asinh = [](auto num) { return std::asinh(num); }; +inline constexpr auto asinh = [](auto num) { return std::asinh(num); }; constexpr auto fn_asinh_f = uf_cp{}; -constexpr auto acosh = [](auto num) { return std::acosh(num); }; +inline constexpr auto acosh = [](auto num) { return std::acosh(num); }; constexpr auto fn_acosh_f = uf_cp{}; -constexpr auto atanh = [](auto num) { return std::atanh(num); }; +inline constexpr auto atanh = [](auto num) { return std::atanh(num); }; constexpr auto fn_atanh_f = uf_cp{}; -constexpr auto abs = [](auto num) { return std::abs(num); }; +inline constexpr auto abs = [](auto num) { return std::abs(num); }; constexpr auto fn_abs_f = uf_cp{}; constexpr auto fn_abs_i = uf_cp{}; diff --git a/include/libqasm/v3x/resolver.hpp b/include/libqasm/v3x/resolver.hpp index f70796a1..b5801ea0 100644 --- a/include/libqasm/v3x/resolver.hpp +++ b/include/libqasm/v3x/resolver.hpp @@ -36,6 +36,7 @@ using Values = values::Values; // Analysis errors // //-----------------// +// NOLINTBEGIN /** * Exception for failed name resolutions. */ @@ -50,6 +51,7 @@ CQASM_ANALYSIS_ERROR(OverloadResolutionFailure); * Exception for failed resolutions. */ CQASM_ANALYSIS_ERROR(ResolutionFailure); +// NOLINTEND //------------------------// // OverloadedNameResolver // diff --git a/include/libqasm/v3x/syntactic_analyzer.hpp b/include/libqasm/v3x/syntactic_analyzer.hpp index e582f926..bc5cbd5d 100644 --- a/include/libqasm/v3x/syntactic_analyzer.hpp +++ b/include/libqasm/v3x/syntactic_analyzer.hpp @@ -34,7 +34,7 @@ class SyntacticAnalyzer : public BaseSyntacticAnalyzer { std::int64_t get_int_value(antlr4::tree::TerminalNode* node) const; double get_float_value(antlr4::tree::TerminalNode* node) const; - tree::Maybe getArraySize(CqasmParser::ArraySizeDeclarationContext* context); + tree::Maybe get_array_size(CqasmParser::ArraySizeDeclarationContext* context); template tree::One visitVariable(Context* context) { @@ -107,7 +107,7 @@ class SyntacticAnalyzer : public BaseSyntacticAnalyzer { std::any visitFloatLiteral(CqasmParser::FloatLiteralContext* context) override; explicit SyntacticAnalyzer(const std::optional& file_name); - void addErrorListener(AntlrCustomErrorListener* errorListener) override; + void addErrorListener(AntlrCustomErrorListener* error_listener) override; void syntaxError(size_t line, size_t char_position_in_line, const std::string& text) const override; void setNodeAnnotation(const ast::One& node, antlr4::Token* token) const override; void expandNodeAnnotation(const ast::One& node, antlr4::Token* token) const override; diff --git a/include/libqasm/v3x/syntactic_analyzer_base.hpp b/include/libqasm/v3x/syntactic_analyzer_base.hpp index c0caf26a..fedb24eb 100644 --- a/include/libqasm/v3x/syntactic_analyzer_base.hpp +++ b/include/libqasm/v3x/syntactic_analyzer_base.hpp @@ -17,7 +17,7 @@ namespace cqasm::v3x::parser { class BaseSyntacticAnalyzer : public CqasmParserVisitor { public: - virtual void addErrorListener(AntlrCustomErrorListener* errorListener) = 0; + virtual void addErrorListener(AntlrCustomErrorListener* error_listener) = 0; virtual void syntaxError(size_t line, size_t char_position_in_line, const std::string& text) const = 0; virtual void setNodeAnnotation(const ast::One& node, antlr4::Token* token) const = 0; virtual void expandNodeAnnotation(const ast::One& node, antlr4::Token* token) const = 0; diff --git a/include/libqasm/versioning.hpp b/include/libqasm/versioning.hpp index 8b2c037e..f35c95b8 100644 --- a/include/libqasm/versioning.hpp +++ b/include/libqasm/versioning.hpp @@ -2,8 +2,8 @@ namespace cqasm { -static const char* version{ "0.6.9" }; -static const char* release_year{ "2024" }; +static const char* version{ "1.0.0" }; +static const char* release_year{ "2025" }; [[nodiscard]] [[maybe_unused]] static const char* get_version() { return version; diff --git a/mkdocs-base.yml b/mkdocs-base.yaml similarity index 79% rename from mkdocs-base.yml rename to mkdocs-base.yaml index 4d3129dd..8eea4ad6 100644 --- a/mkdocs-base.yml +++ b/mkdocs-base.yaml @@ -7,19 +7,19 @@ nav: - Home: index.md - User Guide: - User Guide: user-guide/user-guide.md - - C++: user-guide/cpp.md + - C++: user-guide/cpp-user-guide.md - Docker: user-guide/docker.md - - Emscripten: user-guide/emscripten.md - - Python: user-guide/python.md + - Emscripten: user-guide/emscripten-user-guide.md + - Python: user-guide/python-user-guide.md - Developer Guide: - Dev Guide: dev-guide/dev-guide.md - - C++: dev-guide/cpp.md - - Emscripten: dev-guide/emscripten.md - - Python: dev-guide/python.md + - C++: dev-guide/cpp-dev-guide.md + - Emscripten: dev-guide/emscripten-dev-guide.md + - Python: dev-guide/python-dev-guide.md - API: - - C++: api/cpp.md - - Emscripten: api/emscripten.md - - Python: api/python.md + - C++: api/cpp-api.md + - Emscripten: api/emscripten-api.md + - Python: api/python-api.md - About: - Release Notes: about/release-notes.md - Contributing: about/contributing.md @@ -72,4 +72,4 @@ plugins: default_handler: python watch: - - mkdocs-base.yml + - mkdocs-base.yaml diff --git a/mkdocs.yml b/mkdocs.yaml similarity index 57% rename from mkdocs.yml rename to mkdocs.yaml index fa558412..e0577a58 100644 --- a/mkdocs.yml +++ b/mkdocs.yaml @@ -1,4 +1,4 @@ -INHERIT: ./mkdocs-base.yml +INHERIT: ./mkdocs-base.yaml extra: version: diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 82fec437..6290815e 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -66,14 +66,6 @@ endif() message(STATUS "Found python3 include directory at ${PYTHON_INCLUDE_DIRS}") -# SWIG ------------------------------------------------------------------------ - -# Look for SWIG. -find_package(SWIG REQUIRED) - -include(${SWIG_USE_FILE}) - - #=============================================================================# # CMake configuration # #=============================================================================# @@ -89,14 +81,20 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +# SWIG ------------------------------------------------------------------------ + +# Look for SWIG. +find_package(SWIG REQUIRED) + +include(${SWIG_USE_FILE}) + + #=============================================================================# # Build the SWIG module # #=============================================================================# # Configure SWIG. -set(SWIG_FILE - "${CMAKE_CURRENT_SOURCE_DIR}/libqasm.i" -) +set(SWIG_FILE "${CMAKE_CURRENT_SOURCE_DIR}/libqasm.i") set_source_files_properties("${SWIG_FILE}" PROPERTIES CPLUSPLUS ON diff --git a/res/v3x/tests/integration/bit_array_definition/bit_array_of_17_b__bit_array_of_17_b/semantic.3.0.golden.txt b/res/v3x/tests/integration/bit_array_definition/bit_array_of_17_b__bit_array_of_17_b/semantic.3.0.golden.txt index aef0a6d4..e353874d 100644 --- a/res/v3x/tests/integration/bit_array_definition/bit_array_of_17_b__bit_array_of_17_b/semantic.3.0.golden.txt +++ b/res/v3x/tests/integration/bit_array_definition/bit_array_of_17_b__bit_array_of_17_b/semantic.3.0.golden.txt @@ -1,35 +1,2 @@ -SUCCESS -Program( - api_version: 3.0 - version: < - Version( - items: 3 - ) - > - block: < - Block( - statements: [] - ) - > - variables: [ - Variable( - name: b - typ: < - BitArray( - size: 17 - ) - > - annotations: [] - ) - Variable( - name: b - typ: < - BitArray( - size: 17 - ) - > - annotations: [] - ) - ] -) - +ERROR +Error at input.cq:4:9..10: trying to redeclare variable 'b' diff --git a/res/v3x/tests/integration/bit_definition/bit_b__bit_b/semantic.3.0.golden.txt b/res/v3x/tests/integration/bit_definition/bit_b__bit_b/semantic.3.0.golden.txt index 32f860fd..9dd503b3 100644 --- a/res/v3x/tests/integration/bit_definition/bit_b__bit_b/semantic.3.0.golden.txt +++ b/res/v3x/tests/integration/bit_definition/bit_b__bit_b/semantic.3.0.golden.txt @@ -1,35 +1,2 @@ -SUCCESS -Program( - api_version: 3.0 - version: < - Version( - items: 3 - ) - > - block: < - Block( - statements: [] - ) - > - variables: [ - Variable( - name: b - typ: < - Bit( - size: 1 - ) - > - annotations: [] - ) - Variable( - name: b - typ: < - Bit( - size: 1 - ) - > - annotations: [] - ) - ] -) - +ERROR +Error at input.cq:4:5..6: trying to redeclare variable 'b' diff --git a/res/v3x/tests/integration/qubit_array_definition/qubit_array_of_17_q__qubit_array_of_17_q/semantic.3.0.golden.txt b/res/v3x/tests/integration/qubit_array_definition/qubit_array_of_17_q__qubit_array_of_17_q/semantic.3.0.golden.txt index 66db44e5..11b2e258 100644 --- a/res/v3x/tests/integration/qubit_array_definition/qubit_array_of_17_q__qubit_array_of_17_q/semantic.3.0.golden.txt +++ b/res/v3x/tests/integration/qubit_array_definition/qubit_array_of_17_q__qubit_array_of_17_q/semantic.3.0.golden.txt @@ -1,35 +1,2 @@ -SUCCESS -Program( - api_version: 3.0 - version: < - Version( - items: 3 - ) - > - block: < - Block( - statements: [] - ) - > - variables: [ - Variable( - name: q - typ: < - QubitArray( - size: 17 - ) - > - annotations: [] - ) - Variable( - name: q - typ: < - QubitArray( - size: 17 - ) - > - annotations: [] - ) - ] -) - +ERROR +Error at input.cq:4:11..12: trying to redeclare variable 'q' diff --git a/res/v3x/tests/integration/qubit_definition/qubit_q__qubit_q/semantic.3.0.golden.txt b/res/v3x/tests/integration/qubit_definition/qubit_q__qubit_q/semantic.3.0.golden.txt index 6e5ea893..285bce82 100644 --- a/res/v3x/tests/integration/qubit_definition/qubit_q__qubit_q/semantic.3.0.golden.txt +++ b/res/v3x/tests/integration/qubit_definition/qubit_q__qubit_q/semantic.3.0.golden.txt @@ -1,35 +1,2 @@ -SUCCESS -Program( - api_version: 3.0 - version: < - Version( - items: 3 - ) - > - block: < - Block( - statements: [] - ) - > - variables: [ - Variable( - name: q - typ: < - Qubit( - size: 1 - ) - > - annotations: [] - ) - Variable( - name: q - typ: < - Qubit( - size: 1 - ) - > - annotations: [] - ) - ] -) - +ERROR +Error at input.cq:4:7..8: trying to redeclare variable 'q' diff --git a/scripts/run_cpp_linters.py b/scripts/run_cpp_linters.py index e19f883f..dd76f5d2 100644 --- a/scripts/run_cpp_linters.py +++ b/scripts/run_cpp_linters.py @@ -9,11 +9,12 @@ def print_usage(): usage_str = ''' Usage: - python3 run_cpp_linters.py + python3 run_cpp_linters.py [] Where: ROOT_FOLDER: folder containing the .clang-format, .clang-tidy, and C++ files. + BUILD_FOLDER: build folder (optional, defaulted to 'build/Release'). Example: - python3 run_cpp_linters.py . + python3 run_cpp_linters.py . build/Debug ''' logging.info(usage_str) @@ -21,7 +22,7 @@ def print_usage(): def get_list_of_cpp_files(root_folder: os.PathLike) -> list[str]: ret: list[str] = [] file_types = ['cpp', 'hpp'] - input_subfolders = ['emscripten', 'include', 'src', 'test'] + input_subfolders = ['include', 'src', 'test'] for input_subfolder in input_subfolders: input_folder = os.path.join(root_folder, input_subfolder) for root, dirs, files in os.walk(input_folder): @@ -32,35 +33,46 @@ def get_list_of_cpp_files(root_folder: os.PathLike) -> list[str]: return ret -def run_clang_format(root_folder: os.PathLike): +def run_clang_format(root_folder: os.PathLike, file_list_str: str) -> None: logging.info("Running clang-format") - file_list = get_list_of_cpp_files(root_folder) try: format_file_path = os.path.join(root_folder, ".clang-format") - file_list_str = " ".join(file_list) - command = f"clang-format-18 -i --style=file:{format_file_path} --verbose {file_list_str}" + options = f"-i --style=file:{format_file_path} --verbose" + command = f"clang-format-18 {options} {file_list_str}" subprocess.run(command, shell=True) except FileNotFoundError as err: print("Error running clang-format: {}".format(err.strerror)) exit(3) -def run_clang_tidy(root_folder: os.PathLike): - pass +def run_clang_tidy(root_folder: os.PathLike, build_folder: os.PathLike, file_list_str: str) -> None : + logging.info("Running clang-tidy") + try: + config_file_path = os.path.join(root_folder, ".clang-tidy") + options = f"--config-file={config_file_path} --fix --format-style=file -p {build_folder} --use-color" + command = f"clang-tidy-18 {options} {file_list_str}" + subprocess.run(command, shell=True) + except FileNotFoundError as err: + print("Error running clang-tidy: {}".format(err.strerror)) + exit(4) -def run_cpp_linters(root_folder: os.PathLike): +def run_cpp_linters(root_folder: os.PathLike, build_folder: os.PathLike): logging.info("Running C++ linters") - run_clang_format(root_folder) - run_clang_tidy(root_folder) + file_list = get_list_of_cpp_files(root_folder) + file_list_str = " ".join(file_list) + run_clang_format(root_folder, file_list_str) + run_clang_tidy(root_folder, build_folder, file_list_str) def main(argv): logging.basicConfig(level=logging.INFO, format='%(message)s') - if len(argv) != 2: + if len(argv) < 2 or len(argv) > 3: print_usage() exit(2) - run_cpp_linters(os.path.abspath(argv[1])) + root_folder = os.path.abspath(argv[1]) + build_folder = os.path.abspath(argv[2] if len(argv) == 3 else os.path.join("build", "Release")) + run_cpp_linters(root_folder, build_folder) if __name__ == '__main__': main(sys.argv) diff --git a/setup.py b/setup.py index 829753b5..ed9058fe 100755 --- a/setup.py +++ b/setup.py @@ -16,10 +16,10 @@ def get_version(verbose=False): """Extract version information from source code""" - inc_dir = os.path.join(root_dir, "include", "libqasm") # C++ include directory - matcher = re.compile('static const char\* version\{ "(.*)" \}') + inc_dir = os.path.join(root_dir, 'include', 'libqasm') # C++ include directory + matcher = re.compile('static const char\* version\{ "(.*)" }') version = None - with open(os.path.join(inc_dir, "versioning.hpp"), "r") as f: + with open(os.path.join(inc_dir, 'versioning.hpp'), 'r') as f: for ln in f: m = matcher.match(ln) if m: @@ -91,9 +91,8 @@ def run(self): # Configure and build using Conan with local.cwd(root_dir): - # Build type can be set using an environment variable - build_type = os.environ.get('LIBQASM_BUILD_TYPE', 'Release') - build_tests = os.environ.get("LIBQASM_BUILD_TESTS", "False") + build_type = os.environ.get('CMAKE_BUILD_TYPE', 'Release') + build_tests = os.environ.get('LIBQASM_BUILD_TESTS', 'False') cmd = local['conan']['profile']['detect']['--force'] cmd & FG @@ -117,9 +116,9 @@ def run(self): ['-b']['missing'] ['-tf'][''] ) - if build_tests == "True": + if build_tests == 'True': cmd = cmd['-c']['tools.build:skip_test=False'] - if platform.system() == "Darwin": + if platform.system() == 'Darwin': cmd = cmd['-c']['tools.build:defines=["_LIBCPP_DISABLE_AVAILABILITY"]'] cmd & FG diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2afc1b9a..2f28c5d6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -248,8 +248,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) -Wall -Wextra -Werror -Wfatal-errors -fPIC -Wno-error=deprecated-declarations - -Wno-error=maybe-uninitialized - -Wno-error=restrict + -Wno-error=uninitialized -Wno-error=sign-compare -Wno-error=unused-parameter ) diff --git a/src/v3x/antlr_custom_error_listener.cpp b/src/v3x/antlr_custom_error_listener.cpp index de54cdca..c3e6de71 100644 --- a/src/v3x/antlr_custom_error_listener.cpp +++ b/src/v3x/antlr_custom_error_listener.cpp @@ -15,28 +15,31 @@ AntlrCustomErrorListener::AntlrCustomErrorListener(const std::optional" text, so we avoid calculating the size of EOF from its text // Instead, we just return a zero size - size_t token_size = - (offendingSymbol && offendingSymbol->getType() != antlr4::Token::EOF) ? offendingSymbol->getText().size() : 0; + size_t token_size = (offending_symbol && offending_symbol->getType() != antlr4::Token::EOF) + ? offending_symbol->getText().size() + : 0; auto end_column = start_column + token_size; - throw error::ParseError{ msg, + throw error::ParseError{ + msg, file_name_, { { static_cast(line), static_cast(start_column) }, - { static_cast(line), static_cast(end_column) } } }; + { static_cast(line), static_cast(end_column) } } + }; } -void AntlrCustomErrorListener::syntaxError(size_t line, size_t charPositionInLine, const std::string& msg) { - syntaxError(nullptr, nullptr, line, charPositionInLine, msg, nullptr); +void AntlrCustomErrorListener::syntaxError(size_t line, size_t char_position_in_line, const std::string& msg) { + syntaxError(nullptr, nullptr, line, char_position_in_line, msg, nullptr); } } // namespace cqasm::v3x::parser diff --git a/src/v3x/antlr_scanner.cpp b/src/v3x/antlr_scanner.cpp index db8ca117..5e0a9f3b 100644 --- a/src/v3x/antlr_scanner.cpp +++ b/src/v3x/antlr_scanner.cpp @@ -45,9 +45,9 @@ cqasm::v3x::parser::ParseResult AntlrScanner::parse_(antlr4::ANTLRInputStream& i } FileAntlrScanner::FileAntlrScanner(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up, const std::string& file_path) + std::unique_ptr error_listener_up, std::string file_path) : AntlrScanner{ std::move(build_visitor_up), std::move(error_listener_up) } -, file_path_{ file_path } { +, file_path_{ std::move(file_path) } { if (!fs::exists(file_path_) || !fs::is_regular_file(file_path_)) { throw cqasm::error::ParseError{ fmt::format("FileAntlrScanner couldn't access file '{}'.", file_path_) }; } @@ -62,9 +62,9 @@ cqasm::v3x::parser::ParseResult FileAntlrScanner::parse() { } StringAntlrScanner::StringAntlrScanner(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up, const std::string& data) + std::unique_ptr error_listener_up, std::string data) : AntlrScanner{ std::move(build_visitor_up), std::move(error_listener_up) } -, data_{ data } {} +, data_{ std::move(data) } {} StringAntlrScanner::~StringAntlrScanner() = default; diff --git a/src/v3x/core_function.cpp b/src/v3x/core_function.cpp index c723fad0..7930f822 100644 --- a/src/v3x/core_function.cpp +++ b/src/v3x/core_function.cpp @@ -50,29 +50,32 @@ void serialize(const function::CoreFunctionRef& obj, ::tree::cbor::MapWriter& ma if (obj.empty()) { return; } - map.append_string("n", obj->name); - auto aw = map.append_array("pt"); + map.append_string("name", obj->name); + auto param_types_array = map.append_array("param_types"); for (const auto& t : obj->param_types) { - aw.append_binary(::tree::base::serialize(::tree::base::Maybe{ t.get_ptr() })); + param_types_array.append_binary(::tree::base::serialize(::tree::base::Maybe{ t.get_ptr() })); } - aw.close(); + param_types_array.close(); map.append_binary( - "rt", ::tree::base::serialize(::tree::base::Maybe{ obj->return_type.get_ptr() })); + "return_type", ::tree::base::serialize(::tree::base::Maybe{ obj->return_type.get_ptr() })); } template <> function::CoreFunctionRef deserialize(const ::tree::cbor::MapReader& map) { - if (!map.count("n")) { + // Remove what seems to be a false positive clang-analyzer-optin.cplusplus.VirtualCall + // NOLINTBEGIN + if (!map.count("name")) { return {}; } auto ret = tree::make(); - ret->name = map.at("n").as_string(); - auto ar = map.at("pt").as_array(); - for (const auto& element : ar) { + ret->name = map.at("name").as_string(); + auto param_types_array = map.at("param_types").as_array(); + for (const auto& element : param_types_array) { ret->param_types.add(::tree::base::deserialize(element.as_binary())); } - ret->return_type = ::tree::base::deserialize(map.at("rt").as_binary()); + ret->return_type = ::tree::base::deserialize(map.at("return_type").as_binary()); return ret; + // NOLINTEND } } // namespace cqasm::v3x::primitives diff --git a/src/v3x/instruction.cpp b/src/v3x/instruction.cpp index 39a7c00c..7b01a635 100644 --- a/src/v3x/instruction.cpp +++ b/src/v3x/instruction.cpp @@ -23,7 +23,7 @@ Instruction::Instruction(std::string name, const std::optional& ope * Equality operator. */ bool Instruction::operator==(const Instruction& rhs) const { - return name == rhs.name && operand_types == rhs.operand_types; + return name == rhs.name && operand_types.equals(rhs.operand_types); } /** @@ -59,6 +59,8 @@ void serialize(const instruction::InstructionRef& obj, ::tree::cbor::MapWriter& template <> instruction::InstructionRef deserialize(const ::tree::cbor::MapReader& map) { + // Remove what seems to be a false positive clang-analyzer-optin.cplusplus.VirtualCall + // NOLINTBEGIN if (!map.count("name")) { return {}; } @@ -69,6 +71,7 @@ instruction::InstructionRef deserialize(const ::tree::cbor::MapReader& map) { ret->operand_types.add(::tree::base::deserialize(element.as_binary())); } return ret; + // NOLINTEND } } // namespace cqasm::v3x::primitives diff --git a/src/v3x/instruction_set.cpp b/src/v3x/instruction_set.cpp index 79cb057f..2a0cc2a7 100644 --- a/src/v3x/instruction_set.cpp +++ b/src/v3x/instruction_set.cpp @@ -6,6 +6,7 @@ namespace cqasm::v3x::instruction { +// NOLINTBEGIN InstructionSet::InstructionSet() : named_gate_map{ { "CNOT", { std::nullopt, "QQ" } }, @@ -90,6 +91,7 @@ InstructionSet::InstructionSet() "measure", "reset", "init", "barrier", "wait" } {} +// NOLINTEND [[nodiscard]] /* static */ InstructionSet& InstructionSet::get_instance() { static InstructionSet instance; diff --git a/src/v3x/resolver.cpp b/src/v3x/resolver.cpp index 46da405e..ac6acc59 100644 --- a/src/v3x/resolver.cpp +++ b/src/v3x/resolver.cpp @@ -22,7 +22,9 @@ namespace cqasm::v3x::resolver { * Adds a variable. */ void VariableTable::add(const std::string& name, const Value& value) { - table.erase(name); + if (auto entry = table.find(name); entry != table.end()) { + throw NameResolutionFailure{ fmt::format("trying to redeclare variable '{}'", name) }; + } table.insert(std::make_pair(name, value)); } @@ -41,8 +43,10 @@ void VariableTable::add(const std::string& name, const Value& value) { // ConstEvalCoreFunctionTable // //----------------------------// +// NOLINTBEGIN ConstEvalCoreFunctionTable::ConstEvalCoreFunctionTable() -: resolver{ std::make_unique() } {} +: resolver{ std::make_unique() } {}; +// NOLINTEND ConstEvalCoreFunctionTable::~ConstEvalCoreFunctionTable() = default; ConstEvalCoreFunctionTable::ConstEvalCoreFunctionTable(const ConstEvalCoreFunctionTable& t) : resolver{ std::make_unique(*t.resolver) } {} @@ -93,8 +97,10 @@ Value ConstEvalCoreFunctionTable::resolve(const std::string& name, const Values& // InstructionTable // //------------------// +// NOLINTBEGIN InstructionTable::InstructionTable() : resolver{ std::make_unique() } {} +// NOLINTEND InstructionTable::~InstructionTable() = default; InstructionTable::InstructionTable(const InstructionTable& t) : resolver{ std::make_unique(*t.resolver) } {} diff --git a/src/v3x/syntactic_analyzer.cpp b/src/v3x/syntactic_analyzer.cpp index 13087cec..a10d50f9 100644 --- a/src/v3x/syntactic_analyzer.cpp +++ b/src/v3x/syntactic_analyzer.cpp @@ -28,8 +28,8 @@ SyntacticAnalyzer::SyntacticAnalyzer(const std::optional& file_name } } -void SyntacticAnalyzer::addErrorListener(AntlrCustomErrorListener* errorListener) { - error_listener_p_ = errorListener; +void SyntacticAnalyzer::addErrorListener(AntlrCustomErrorListener* error_listener) { + error_listener_p_ = error_listener; } void SyntacticAnalyzer::syntaxError(size_t line, size_t char_position_in_line, const std::string& text) const { @@ -43,11 +43,13 @@ void SyntacticAnalyzer::syntaxError(size_t line, size_t char_position_in_line, c */ void SyntacticAnalyzer::setNodeAnnotation(const ast::One& node, antlr4::Token* token) const { auto token_size = token->getStopIndex() - token->getStartIndex() + 1; - node->set_annotation(annotations::SourceLocation{ file_name_, + node->set_annotation(annotations::SourceLocation{ + file_name_, { { static_cast(token->getLine()), static_cast(token->getCharPositionInLine() + 1) }, - { static_cast(token->getLine()), - static_cast(token->getCharPositionInLine() + 1 + token_size) } } }); + { static_cast(token->getLine()), + static_cast(token->getCharPositionInLine() + 1 + token_size) } } + }); } void SyntacticAnalyzer::expandNodeAnnotation(const One& node, antlr4::Token* token) const { @@ -265,7 +267,7 @@ std::any SyntacticAnalyzer::visitType(CqasmParser::TypeContext* context) { std::any SyntacticAnalyzer::visitQubitType(CqasmParser::QubitTypeContext* context) { auto ret = - tree::make(tree::make(types::qubit_type_name), getArraySize(context->arraySizeDeclaration())); + tree::make(tree::make(types::qubit_type_name), get_array_size(context->arraySizeDeclaration())); setNodeAnnotation(ret, context->QUBIT_TYPE()->getSymbol()); if (context->arraySizeDeclaration()) { expandNodeAnnotation(ret, context->arraySizeDeclaration()->CLOSE_BRACKET()->getSymbol()); @@ -275,7 +277,7 @@ std::any SyntacticAnalyzer::visitQubitType(CqasmParser::QubitTypeContext* contex std::any SyntacticAnalyzer::visitBitType(CqasmParser::BitTypeContext* context) { auto ret = - tree::make(tree::make(types::bit_type_name), getArraySize(context->arraySizeDeclaration())); + tree::make(tree::make(types::bit_type_name), get_array_size(context->arraySizeDeclaration())); setNodeAnnotation(ret, context->BIT_TYPE()->getSymbol()); if (context->arraySizeDeclaration()) { expandNodeAnnotation(ret, context->arraySizeDeclaration()->CLOSE_BRACKET()->getSymbol()); @@ -283,7 +285,7 @@ std::any SyntacticAnalyzer::visitBitType(CqasmParser::BitTypeContext* context) { return ret; } -Maybe SyntacticAnalyzer::getArraySize(CqasmParser::ArraySizeDeclarationContext* context) { +Maybe SyntacticAnalyzer::get_array_size(CqasmParser::ArraySizeDeclarationContext* context) { return (context) ? Maybe{ std::any_cast>(context->accept(this)).get_ptr() } : Maybe{}; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0375debe..5acd4552 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -34,7 +34,6 @@ if(CMAKE_COMPILER_IS_GNUCXX) -Wall -Wextra -Werror -Wfatal-errors -fPIC -Wno-error=deprecated-declarations - -Wno-error=restrict -Wno-error=sign-compare ) elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") diff --git a/test/test_annotations.cpp b/test/test_annotations.cpp index 1358d0e2..04a4b462 100644 --- a/test/test_annotations.cpp +++ b/test/test_annotations.cpp @@ -17,26 +17,38 @@ TEST(source_location_constructor, no_file_name__no_line_numbers__no_column_numbe EXPECT_EQ(fmt::format("{}", location), ""); } TEST(source_location_constructor, null_file_name__yes_line_numbers__no_column_numbers) { - auto location = SourceLocation{ std::nullopt, { { 10, 0 }, { 10, 0 } } }; + auto location = SourceLocation{ + std::nullopt, { { 10, 0 }, { 10, 0 } } + }; EXPECT_EQ(fmt::format("{}", location), ":10"); } TEST(source_location_constructor, no_file_name__yes_line_numbers__no_column_numbers) { - auto location = SourceLocation{ "", { { 10, 0 }, { 10, 0 } } }; + auto location = SourceLocation{ + "", { { 10, 0 }, { 10, 0 } } + }; EXPECT_EQ(fmt::format("{}", location), ":10"); } TEST(source_location_constructor, null_file_name__yes_line_numbers__yes_column_numbers) { - auto location = SourceLocation{ std::nullopt, { { 10, 12 }, { 10, 15 } } }; + auto location = SourceLocation{ + std::nullopt, { { 10, 12 }, { 10, 15 } } + }; EXPECT_EQ(fmt::format("{}", location), ":10:12..15"); } TEST(source_location_constructor, no_file_name__yes_line_numbers__yes_column_numbers) { - auto location = SourceLocation{ "", { { 10, 12 }, { 10, 15 } } }; + auto location = SourceLocation{ + "", { { 10, 12 }, { 10, 15 } } + }; EXPECT_EQ(fmt::format("{}", location), ":10:12..15"); } TEST(source_location_constructor, yes_file_name__yes_line_numbers__yes_column_numbers) { - auto location = SourceLocation{ "input.cq", { { 10, 12 }, { 10, 15 } } }; + auto location = SourceLocation{ + "input.cq", { { 10, 12 }, { 10, 15 } } + }; EXPECT_EQ(fmt::format("{}", location), "input.cq:10:12..15"); } TEST(source_location_constructor, unknown_file_name__yes_line_numbers__yes_column_numbers) { - auto location = SourceLocation{ "", { { 10, 12 }, { 10, 15 } } }; + auto location = SourceLocation{ + "", { { 10, 12 }, { 10, 15 } } + }; EXPECT_EQ(fmt::format("{}", location), ":10:12..15"); } diff --git a/test/test_error.cpp b/test/test_error.cpp index 6bc2018a..f132926f 100644 --- a/test/test_error.cpp +++ b/test/test_error.cpp @@ -35,7 +35,9 @@ TEST(constructor_message_node, message_and_node_with_empty_location) { } TEST(constructor_message_node, message_and_node_with_location) { auto node = FakeNode{}; - node.set_annotation(SourceLocation{ "input.cq", { { 10, 12 }, { 10, 15 } } }); + node.set_annotation(SourceLocation{ + "input.cq", { { 10, 12 }, { 10, 15 } } + }); auto err = Error{ "syntax error", &node }; EXPECT_EQ(fmt::format("{}", err), "Error at input.cq:10:12..15: syntax error"); } @@ -48,11 +50,14 @@ TEST(constructor_message_location, message_and_empty_location) { auto err = Error{ "syntax error", std::make_shared() }; EXPECT_EQ(fmt::format("{}", err), "Error at : syntax error"); } +// clang-format off TEST(constructor_message_location, message_and_location) { - auto err = Error{ "syntax error", - std::make_shared("input.cq", SourceLocation::Range{ { 10, 12 }, { 10, 15 } }) }; + auto err = Error{ + "syntax error", std::make_shared("input.cq", SourceLocation::Range{ { 10, 12 }, { 10, 15 } }) + }; EXPECT_EQ(fmt::format("{}", err), "Error at input.cq:10:12..15: syntax error"); } +// clang-format on TEST(constructor_message_location_fields, empty_message) { auto err = Error{ "", std::nullopt, SourceLocation::Range{} }; @@ -63,16 +68,26 @@ TEST(constructor_message_location_fields, message_and_empty_location) { EXPECT_EQ(fmt::format("{}", err), "Error at : syntax error"); } TEST(constructor_message_location_fields, message_and_location) { - auto err = Error{ "syntax error", "input.cq", SourceLocation::Range{ { 10, 12 }, { 10, 15 } } }; + auto err = Error{ + "syntax error", "input.cq", SourceLocation::Range{ { 10, 12 }, { 10, 15 } } + }; EXPECT_EQ(fmt::format("{}", err), "Error at input.cq:10:12..15: syntax error"); } TEST(context, location) { auto node_1 = FakeNode{}; - node_1.set_annotation(SourceLocation("input.cq", SourceLocation::Range{ { 10, 12 }, { 10, 15 } })); + node_1.set_annotation(SourceLocation("input.cq", + SourceLocation::Range{ + { 10, 12 }, + { 10, 15 } + })); auto err = Error{ "syntax error", &node_1 }; auto node_2 = FakeNode{}; - node_2.set_annotation(SourceLocation("input.cq", SourceLocation::Range{ { 20, 22 }, { 20, 25 } })); + node_2.set_annotation(SourceLocation("input.cq", + SourceLocation::Range{ + { 20, 22 }, + { 20, 25 } + })); err.context(node_2); EXPECT_EQ(fmt::format("{}", err), "Error at input.cq:10:12..15: syntax error"); } @@ -85,7 +100,11 @@ TEST(context, no_location_and_node_does_not_have_source_location) { TEST(context, no_location_and_node_has_source_location) { auto err = Error{ "syntax error" }; auto node_2 = FakeNode{}; - node_2.set_annotation(SourceLocation("input.cq", SourceLocation::Range{ { 20, 22 }, { 20, 25 } })); + node_2.set_annotation(SourceLocation("input.cq", + SourceLocation::Range{ + { 20, 22 }, + { 20, 25 } + })); err.context(node_2); EXPECT_EQ(fmt::format("{}", err), "Error at input.cq:20:22..25: syntax error"); } @@ -103,11 +122,15 @@ TEST(what, message_and_empty_location) { EXPECT_EQ(std::string{ err.what() }, "Error at : syntax error"); } TEST(what, message_and_location_with_unknown_file_name) { - auto err = Error{ "syntax error", std::nullopt, SourceLocation::Range{ { 10, 12 }, { 10, 15 } } }; + auto err = Error{ + "syntax error", std::nullopt, SourceLocation::Range{ { 10, 12 }, { 10, 15 } } + }; EXPECT_EQ(std::string{ err.what() }, "Error at :10:12..15: syntax error"); } TEST(what, message_and_location_with_known_file_name) { - auto err = Error{ "syntax error", "input.cq", SourceLocation::Range{ { 10, 12 }, { 10, 15 } } }; + auto err = Error{ + "syntax error", "input.cq", SourceLocation::Range{ { 10, 12 }, { 10, 15 } } + }; EXPECT_EQ(std::string{ err.what() }, "Error at input.cq:10:12..15: syntax error"); } @@ -148,7 +171,9 @@ TEST(to_json, message_and_empty_location) { R"(})"); } TEST(to_json, message_and_location_with_unknown_file_name) { - auto err = Error{ "syntax error", std::nullopt, SourceLocation::Range{ { 10, 12 }, { 10, 15 } } }; + auto err = Error{ + "syntax error", std::nullopt, SourceLocation::Range{ { 10, 12 }, { 10, 15 } } + }; EXPECT_EQ(err.to_json(), R"({)" R"("range":{)" @@ -160,7 +185,9 @@ TEST(to_json, message_and_location_with_unknown_file_name) { R"(})"); } TEST(to_json, message_and_location_with_known_file_name) { - auto err = Error{ "syntax error", "input.cq", SourceLocation::Range{ { 10, 12 }, { 10, 15 } } }; + auto err = Error{ + "syntax error", "input.cq", SourceLocation::Range{ { 10, 12 }, { 10, 15 } } + }; EXPECT_EQ(err.to_json(), R"({)" R"("range":{)" diff --git a/test/v3x/cpp/integration_test.cpp b/test/v3x/cpp/integration_test.cpp index d3cf730a..1b7f247b 100644 --- a/test/v3x/cpp/integration_test.cpp +++ b/test/v3x/cpp/integration_test.cpp @@ -15,7 +15,6 @@ namespace cqasm::v3x::test { -namespace cq3x = cqasm::v3x; namespace fs = std::filesystem; /** @@ -33,8 +32,8 @@ class IntegrationTest : public ::testing::Test { // Parse the test input file std::string input{}; ASSERT_TRUE(cqasm::test::read_file(path_ / "input.cq", input)); - cq3x::parser::ParseResult parse_result{}; - parse_result = cq3x::parser::parse_string(input, "input.cq"); + parser::ParseResult parse_result{}; + parse_result = parser::parse_string(input, "input.cq"); // Check the debug dump of the parse result std::string ast_actual_file_contents = parse_result.errors.empty() @@ -68,7 +67,7 @@ class IntegrationTest : public ::testing::Test { // If there were no errors, try semantic analysis for (const auto& api_version : std::vector({ "3.0" })) { - auto analyzer = cq3x::analyzer::Analyzer{ api_version }; + auto analyzer = analyzer::Analyzer{ api_version }; analyzer.register_default_constants(); analyzer.register_default_functions(); @@ -111,8 +110,11 @@ class IntegrationTest : public ::testing::Test { }; void register_tests() { + // Remove a clang-analyzer.cplusplus.NewDeleteLeaks warning in gtest/gtest.h + // NOLINTBEGIN cqasm::test::register_tests(fs::path{ "res" } / "v3x" / "tests" / "integration", - [=](fs::path test_path) -> IntegrationTest* { return new IntegrationTest(std::move(test_path)); }); + [=](fs::path test_path) -> IntegrationTest* { return new IntegrationTest{ std::move(test_path) }; }); + // NOLINTEND } } // namespace cqasm::v3x::test diff --git a/test/v3x/cpp/matcher_values.cpp b/test/v3x/cpp/matcher_values.cpp index f0eab134..9d781fc1 100644 --- a/test/v3x/cpp/matcher_values.cpp +++ b/test/v3x/cpp/matcher_values.cpp @@ -8,11 +8,11 @@ namespace cqasm::v3x::values { -ValuesEqMatcher::ValuesEqMatcher(const Values& expectedValue) -: expectedValue_(expectedValue) {} +ValuesEqMatcher::ValuesEqMatcher(const Values& expected_value) +: expected_value_(expected_value) {} bool ValuesEqMatcher::MatchAndExplain(const Values& args, std::ostream* /* os */) const { - return args.equals(expectedValue_); + return args.equals(expected_value_); } void ValuesEqMatcher::DescribeTo(std::ostream* os) const { @@ -23,8 +23,8 @@ void ValuesEqMatcher::DescribeNegationTo(std::ostream* os) const { *os << "does not contain values equal to the expected"; } -::testing::Matcher ValuesEq(const Values& expectedValue) { - return ValuesEqMatcher(expectedValue); +::testing::Matcher ValuesEq(const values::Values& expected_value) { + return ValuesEqMatcher(expected_value); } } // namespace cqasm::v3x::values diff --git a/test/v3x/cpp/matcher_values.hpp b/test/v3x/cpp/matcher_values.hpp index 4e3fb690..1fa6707f 100644 --- a/test/v3x/cpp/matcher_values.hpp +++ b/test/v3x/cpp/matcher_values.hpp @@ -12,15 +12,15 @@ class ValuesEqMatcher { public: using is_gtest_matcher = void; - ValuesEqMatcher(const values::Values& expectedValue); + ValuesEqMatcher(const values::Values& expected_value); bool MatchAndExplain(const values::Values& args, std::ostream* os) const; void DescribeTo(std::ostream* os) const; void DescribeNegationTo(std::ostream* os) const; private: - const values::Values& expectedValue_; + const values::Values& expected_value_; }; -::testing::Matcher ValuesEq(const values::Values& expectedValue); +::testing::Matcher ValuesEq(const values::Values& expected_value); } // namespace cqasm::v3x::values diff --git a/test/v3x/cpp/test_analyzer.cpp b/test/v3x/cpp/test_analyzer.cpp index 0756f056..15a5017b 100644 --- a/test/v3x/cpp/test_analyzer.cpp +++ b/test/v3x/cpp/test_analyzer.cpp @@ -88,7 +88,9 @@ TEST_F(AnalyzerTest, add_statement_to_current_scope) { } TEST_F(AnalyzerTest, add_statement_with_source_location_information_to_current_scope) { MockAnalyzer analyzer{}; - const auto& statement_source_location = annotations::SourceLocation{ "input.cq", { { 10, 20 }, { 11, 10 } } }; + const auto& statement_source_location = annotations::SourceLocation{ + "input.cq", { { 10, 20 }, { 11, 10 } } + }; statement->set_annotation(statement_source_location); analyzer.add_statement_to_current_scope(statement); EXPECT_EQ(analyzer.current_block()->statements.size(), 1); @@ -102,12 +104,16 @@ TEST_F(AnalyzerTest, // 10 15 20 25 30 // 5 < // 8 > - const auto& block_initial_source_location = annotations::SourceLocation{ "input.cq", { { 5, 15 }, { 8, 30 } } }; + const auto& block_initial_source_location = annotations::SourceLocation{ + "input.cq", { { 5, 15 }, { 8, 30 } } + }; analyzer.current_block()->set_annotation(block_initial_source_location); // 10 15 20 25 30 // 10 < // 11 > - const auto& statement_source_location = annotations::SourceLocation{ "input.cq", { { 10, 10 }, { 11, 20 } } }; + const auto& statement_source_location = annotations::SourceLocation{ + "input.cq", { { 10, 10 }, { 11, 20 } } + }; statement->set_annotation(statement_source_location); analyzer.add_statement_to_current_scope(statement); EXPECT_EQ(analyzer.current_block()->statements.size(), 1); @@ -116,7 +122,11 @@ TEST_F(AnalyzerTest, // 11 > const auto& block_final_source_location = analyzer.current_block()->get_annotation(); EXPECT_EQ(block_final_source_location.file_name, "input.cq"); - EXPECT_EQ(block_final_source_location.range, (annotations::SourceLocation::Range{ { 5, 15 }, { 11, 20 } })); + EXPECT_EQ(block_final_source_location.range, + (annotations::SourceLocation::Range{ + { 5, 15 }, + { 11, 20 } + })); } } // namespace cqasm::v3x::analyzer diff --git a/test/v3x/cpp/test_functions.hpp b/test/v3x/cpp/test_functions.hpp index ece1b294..bdee9405 100644 --- a/test/v3x/cpp/test_functions.hpp +++ b/test/v3x/cpp/test_functions.hpp @@ -29,7 +29,9 @@ auto invoke_binary(ParamsType a, ParamsType b) { using FReturnValue = typename decltype(F)::return_value; using FParamValue = typename decltype(F)::param_value; - auto values = values::Values{ { cqasm::tree::make(a), cqasm::tree::make(b) } }; + auto values = values::Values{ + { cqasm::tree::make(a), cqasm::tree::make(b) } + }; auto ret = F(values); return dynamic_cast(*ret).value; } @@ -39,9 +41,11 @@ auto invoke_ternary(bool condition, ParamsType if_true, ParamsType if_false) { using FReturnValue = typename decltype(F)::return_value; using FParamValue = typename decltype(F)::param_value; - auto values = values::Values{ { cqasm::tree::make(condition), - cqasm::tree::make(if_true), - cqasm::tree::make(if_false) } }; + auto values = values::Values{ + { cqasm::tree::make(condition), + cqasm::tree::make(if_true), + cqasm::tree::make(if_false) } + }; auto ret = F(values); return dynamic_cast(*ret).value; } diff --git a/test/v3x/cpp/test_parse_helper.cpp b/test/v3x/cpp/test_parse_helper.cpp index 2da4a7fa..5c89aadf 100644 --- a/test/v3x/cpp/test_parse_helper.cpp +++ b/test/v3x/cpp/test_parse_helper.cpp @@ -23,19 +23,19 @@ namespace cqasm::v3x::parser { class ParseHelperParseTest : public ::testing::Test { protected: void SetUp() override { scanner_up = std::make_unique(); } - void ExpectScannerParseThrowsParseError() { + void expect_scanner_parse_throws_parse_error() { EXPECT_CALL(*scanner_up, parse()) .WillRepeatedly(::testing::Throw(ParseError{ parse_error_message, file_name, range })); } - void ExpectScannerParseThrowsRuntimeError() { + void expect_scanner_parse_throws_runtime_error() { EXPECT_CALL(*scanner_up, parse()) .WillRepeatedly(::testing::Throw(std::runtime_error{ runtime_error_message.c_str() })); } - void ExpectScannerParseReturnsIllFormedRoot() { + void expect_scanner_parse_returns_ill_formed_root() { auto parse_result = ParseResult{ tree::make(), error::ParseErrors{} }; EXPECT_CALL(*scanner_up, parse()).WillOnce(::testing::Return(parse_result)); } - void ExpectScannerParseReturnsWellFormedRoot() { + void expect_scanner_parse_returns_well_formed_root() { auto one_version = tree::make(version_3_0); auto one_global_block = tree::make(); auto one_program = tree::make(one_version, one_global_block); @@ -44,7 +44,10 @@ class ParseHelperParseTest : public ::testing::Test { } std::string file_name = "input.cq"; - annotations::SourceLocation::Range range{ { 10, 12 }, { 10, 15 } }; + annotations::SourceLocation::Range range{ + { 10, 12 }, + { 10, 15 } + }; std::string parse_error_message = "parse error"; std::string runtime_error_message = "runtime error"; @@ -56,7 +59,7 @@ class ParseHelperParseTest : public ::testing::Test { }; TEST_F(ParseHelperParseTest, scanner_parse_throws_parse_error) { - ExpectScannerParseThrowsParseError(); + expect_scanner_parse_throws_parse_error(); auto parse_helper = ParseHelper{ std::move(scanner_up), file_name }; auto parse_result = parse_helper.parse(); const auto& errors = parse_result.errors; @@ -70,7 +73,7 @@ TEST_F(ParseHelperParseTest, scanner_parse_throws_parse_error) { parse_error_message)); } TEST_F(ParseHelperParseTest, scanner_parse_throws_runtime_error) { - ExpectScannerParseThrowsRuntimeError(); + expect_scanner_parse_throws_runtime_error(); auto parse_helper = ParseHelper{ std::move(scanner_up), file_name }; auto parse_result = parse_helper.parse(); const auto& errors = parse_result.errors; @@ -78,13 +81,13 @@ TEST_F(ParseHelperParseTest, scanner_parse_throws_runtime_error) { EXPECT_EQ(fmt::format("{}", errors[0]), fmt::format("Error: {}", runtime_error_message)); } TEST_F(ParseHelperParseTest, parse_result_errors_is_empty_and_root_is_ill_formed) { - ExpectScannerParseReturnsIllFormedRoot(); + expect_scanner_parse_returns_ill_formed_root(); auto parse_helper = ParseHelper{ std::move(scanner_up), file_name }; EXPECT_THAT([&]() { parse_helper.parse(); }, ThrowsMessage(::testing::HasSubstr(ill_formed_root_message))); } TEST_F(ParseHelperParseTest, parse_result_errors_is_empty_and_root_is_well_formed) { - ExpectScannerParseReturnsWellFormedRoot(); + expect_scanner_parse_returns_well_formed_root(); auto parse_helper = ParseHelper{ std::move(scanner_up), file_name }; auto parse_result = parse_helper.parse(); auto program = parse_result.root->as_program(); diff --git a/test/v3x/cpp/test_semantic_analyzer.cpp b/test/v3x/cpp/test_semantic_analyzer.cpp index 7b12fff9..169c541e 100644 --- a/test/v3x/cpp/test_semantic_analyzer.cpp +++ b/test/v3x/cpp/test_semantic_analyzer.cpp @@ -7,7 +7,6 @@ #include "libqasm/v3x/values.hpp" #include "mock_analyzer.hpp" -namespace analyzer = cqasm::v3x::analyzer; namespace ast = cqasm::v3x::ast; namespace error = cqasm::error; namespace values = cqasm::v3x::values; @@ -17,16 +16,16 @@ namespace cqasm::v3x::analyzer { class VisitFunctionResolveTest : public ::testing::Test { protected: void SetUp() override {} - void ExpectAnalyzerResolveFunctionOK(const values::Value& function_return_value) { + void expect_analyzer_resolve_function_ok(const values::Value& function_return_value) { EXPECT_CALL(analyzer, resolve_function(::testing::_, ::testing::_)) .WillOnce(::testing::Return(function_return_value)); } - void ExpectAnalyzerResolveFunctionThrow(const std::string& error_message) { + void expect_analyzer_resolve_function_throw(const std::string& error_message) { EXPECT_CALL(analyzer, resolve_function(::testing::_, ::testing::_)) .WillRepeatedly(::testing::Throw(std::runtime_error{ error_message.c_str() })); } - analyzer::MockAnalyzer analyzer; - analyzer::SemanticAnalyzer visitor{ analyzer }; + MockAnalyzer analyzer; + SemanticAnalyzer visitor{ analyzer }; }; /** @@ -34,7 +33,7 @@ class VisitFunctionResolveTest : public ::testing::Test { */ TEST_F(VisitFunctionResolveTest, analyzer_resolve_function_returns_a_non_empty_value) { const auto& function_return_value = values::Value{ cqasm::tree::make(0) }; - ExpectAnalyzerResolveFunctionOK(function_return_value); + expect_analyzer_resolve_function_ok(function_return_value); auto name = cqasm::tree::make("function_that_returns_a_non_empty_value"); auto arguments = cqasm::tree::make(cqasm::tree::Any{}); @@ -45,7 +44,7 @@ TEST_F(VisitFunctionResolveTest, analyzer_resolve_function_returns_a_non_empty_v TEST_F(VisitFunctionResolveTest, analyzer_resolve_function_returns_an_empty_value) { const auto& function_return_value = values::Value{}; - ExpectAnalyzerResolveFunctionOK(function_return_value); + expect_analyzer_resolve_function_ok(function_return_value); auto name = cqasm::tree::make("function_that_returns_an_empty_value"); auto arguments = cqasm::tree::make(cqasm::tree::Any{}); @@ -57,7 +56,7 @@ TEST_F(VisitFunctionResolveTest, analyzer_resolve_function_returns_an_empty_valu TEST_F(VisitFunctionResolveTest, analyzer_resolve_function_throws) { const auto& function_name = std::string{ "function_that_is_not_registered" }; const auto& error_message = fmt::format("failed to resolve '{}'", function_name); - ExpectAnalyzerResolveFunctionThrow(error_message); + expect_analyzer_resolve_function_throw(error_message); auto name = cqasm::tree::make(function_name); auto arguments = cqasm::tree::make(cqasm::tree::Any{});