diff --git a/.clang-tidy b/.clang-tidy index 8a0df5c1..66117be9 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -12,3 +12,5 @@ CheckOptions: value: yy_sname # Generated by bison, so we don't care - key: modernize-deprecated-headers.CheckHeaderFile value: true + - key: cppcoreguidelines-macro-usage.AllowedRegexp + value: '^YY' # Generated by bison, so we don't care diff --git a/.github/workflows/darwin-appleclang.yml b/.github/workflows/darwin-appleclang.yml index ca3e9995..75a3c7b9 100644 --- a/.github/workflows/darwin-appleclang.yml +++ b/.github/workflows/darwin-appleclang.yml @@ -29,26 +29,24 @@ on: - 'examples/cmake/*.cmake' jobs: - build: - runs-on: macos-13 + darwin-appleclang: + runs-on: macos-15 # see https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md env: CCACHE_DIR: ${{ github.workspace }}/CCACHE - BUILD_DIR: build-darwin CTEST_OUTPUT_ON_FAILURE: 1 CMAKE_TOOLCHAIN_FILE: ${{ github.workspace }}/cmake/toolchain/darwin.cmake CMAKE_PREFIX_PATH: ${{ github.workspace }}/local/darwin CMAKE_INSTALL_PREFIX: ${{ github.workspace }}/local/darwin CMAKE_GENERATOR: Ninja CMAKE_BUILD_TYPE: Debug - CFLAGS: "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -fstrict-flex-arrays=2 -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -fstack-protector-strong" - CXXFLAGS: "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -fstrict-flex-arrays=2 -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -fstack-protector-strong" - LDFLAGS: "-fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -fstack-protector-strong" + CC: cc + CXX: c++ steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '14.3.1' + xcode-version: '16.4.0' - name: Get Home Brew dependencies run: | brew install -q cmake ninja ccache flex bison wget curl coreutils automake autoconf libtool gnu-sed gawk @@ -56,25 +54,25 @@ jobs: BISON_PATH=$(brew --prefix bison)/bin FLEX_PATH=$(brew --prefix flex)/bin export PATH="${NINJA_PATH}:${BISON_PATH}:${FLEX_PATH}:${PATH}" - command -v ninja + command -v ninja command -v bison command -v flex echo "$PATH" >> $GITHUB_PATH - name: Compute CCache keys - id: darwin-keys + id: ccache-keys run: | - key2=ccache-darwin- + key2=ccache-darwin-appleclang- key1="${key2}$(date +%W)" echo "key1=${key1}" >> $GITHUB_OUTPUT echo "key2=${key2}" >> $GITHUB_OUTPUT - name: Restore CCache id: ccache-restore - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ env.CCACHE_DIR }} - key: ${{ steps.darwin-keys.outputs.key1 }} - restore-keys: ${{ steps.darwin-keys.outputs.key2 }} + key: ${{ steps.ccache-keys.outputs.key1 }} + restore-keys: ${{ steps.ccache-keys.outputs.key2 }} - name: CCache Limits and Stats run: | ccache -M120M @@ -82,11 +80,11 @@ jobs: - name: Restore Libs id: restore-libs - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: local/darwin - key: libs-darwin-${{ hashFiles('getlibs.sh') }} - restore-keys: libs-darwin + key: libs-darwin-appleclang-${{ hashFiles('getlibs.sh') }} + restore-keys: libs-darwin-appleclang - name: Get library dependencies if: steps.restore-libs.outputs.cache-hit != 'true' run: ./getlibs.sh darwin @@ -98,13 +96,15 @@ jobs: path: local/darwin key: ${{ steps.restore-libs.outputs.cache-primary-key }} - name: Configure UTAP - run: cmake -B "$BUILD_DIR" -DUTAP_CLANG_TIDY=OFF + run: cmake -DUTAP_CLANG_TIDY=OFF --preset debug-san - name: Build UTAP - run: cmake --build "$BUILD_DIR" --config $CMAKE_BUILD_TYPE + run: cmake --build --preset debug-san - name: Test UTAP - run: ctest --test-dir "$BUILD_DIR" -C $CMAKE_BUILD_TYPE + run: ctest --preset debug-san + - name: Quick UTAP Release + run: cmake --workflow --preset release-quick - name: Install UTAP - run: cmake --install "$BUILD_DIR" --config $CMAKE_BUILD_TYPE --prefix="$CMAKE_INSTALL_PREFIX" + run: cmake --install build-quick --config Release --prefix="$CMAKE_INSTALL_PREFIX" - name: CCache Statistics run: ccache --show-stats - name: Configure Examples diff --git a/.github/workflows/darwin-brew-gcc15.yml b/.github/workflows/darwin-brew-gcc15.yml index 0ba017fd..2d1f04f0 100644 --- a/.github/workflows/darwin-brew-gcc15.yml +++ b/.github/workflows/darwin-brew-gcc15.yml @@ -29,26 +29,24 @@ on: - 'examples/cmake/*.cmake' jobs: - build: - runs-on: macos-13 + darwin-gcc15: + runs-on: macos-15 # see https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md env: CCACHE_DIR: ${{ github.workspace }}/CCACHE - BUILD_DIR: build-darwin-brew-gcc15 CTEST_OUTPUT_ON_FAILURE: 1 CMAKE_TOOLCHAIN_FILE: ${{ github.workspace }}/cmake/toolchain/darwin-brew-gcc15.cmake CMAKE_PREFIX_PATH: ${{ github.workspace }}/local/darwin-brew-gcc15 CMAKE_INSTALL_PREFIX: ${{ github.workspace }}/local/darwin-brew-gcc15 CMAKE_GENERATOR: Ninja CMAKE_BUILD_TYPE: Debug - CFLAGS: "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -fstrict-flex-arrays=2 -fno-omit-frame-pointer -fsanitize=leak -fstack-protector-strong" - CXXFLAGS: "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -fstrict-flex-arrays=2 -fno-omit-frame-pointer -fsanitize=leak -fstack-protector-strong" - LDFLAGS: "-fno-omit-frame-pointer -fsanitize=leak -fstack-protector-strong" + CC: gcc-15 + CXX: g++-15 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '14.3.1' + xcode-version: '16.4.0' - name: Get Home Brew dependencies run: | brew install -q cmake ninja ccache gcc@15 flex bison wget curl coreutils automake autoconf libtool gnu-sed gawk @@ -62,7 +60,7 @@ jobs: echo "$PATH" >> $GITHUB_PATH - name: Compute CCache keys - id: darwin-keys + id: ccache-keys run: | key2=ccache-darwin-brew-gcc15- key1="${key2}$(date +%W)" @@ -70,11 +68,11 @@ jobs: echo "key2=${key2}" >> $GITHUB_OUTPUT - name: Restore CCache id: ccache-restore - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ env.CCACHE_DIR }} - key: ${{ steps.darwin-keys.outputs.key1 }} - restore-keys: ${{ steps.darwin-keys.outputs.key2 }} + key: ${{ steps.ccache-keys.outputs.key1 }} + restore-keys: ${{ steps.ccache-keys.outputs.key2 }} - name: CCache Limits and Stats run: | ccache -M120M @@ -82,7 +80,7 @@ jobs: - name: Restore Libs id: restore-libs - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: local/darwin-brew-gcc15 key: libs-darwin-brew-gcc15-${{ hashFiles('getlibs.sh') }} @@ -98,13 +96,15 @@ jobs: path: local/darwin-brew-gcc15 key: ${{ steps.restore-libs.outputs.cache-primary-key }} - name: Configure UTAP - run: cmake -B "$BUILD_DIR" -DUTAP_CLANG_TIDY=OFF + run: cmake -DUTAP_CLANG_TIDY=OFF --preset debug - name: Build UTAP - run: cmake --build "$BUILD_DIR" --config $CMAKE_BUILD_TYPE + run: cmake --build --preset debug - name: Test UTAP - run: ctest --test-dir "$BUILD_DIR" -C $CMAKE_BUILD_TYPE + run: ctest --preset debug + - name: Quick UTAP Release + run: cmake --workflow --preset release-quick - name: Install UTAP - run: cmake --install "$BUILD_DIR" --config $CMAKE_BUILD_TYPE --prefix="$CMAKE_INSTALL_PREFIX" + run: cmake --install build-quick --config Release --prefix="$CMAKE_INSTALL_PREFIX" - name: CCache Statistics run: ccache --show-stats - name: Configure Examples @@ -112,4 +112,4 @@ jobs: - name: Build Examples run: cmake --build examples/build - name: Test Examples - run: ctest --test-dir examples/build --output-on-failure + run: ctest --test-dir examples/build diff --git a/.github/workflows/ubuntu-clang20.yml b/.github/workflows/ubuntu-clang20.yml index 633187f9..bf597de4 100644 --- a/.github/workflows/ubuntu-clang20.yml +++ b/.github/workflows/ubuntu-clang20.yml @@ -29,22 +29,19 @@ on: - 'examples/cmake/*.cmake' jobs: - build: + ubuntu-clang20: runs-on: ubuntu-latest env: CCACHE_DIR: ${{ github.workspace }}/CCACHE - BUILD_DIR: build-x86_64-linux64-clang20 CTEST_OUTPUT_ON_FAILURE: 1 - CMAKE_TOOLCHAIN_FILE: ${{ github.workspace }}/cmake/toolchain/x86_64-linux-clang20.cmake CMAKE_PREFIX_PATH: ${{ github.workspace }}/local/x86_64-linux-clang20 CMAKE_INSTALL_PREFIX: ${{ github.workspace }}/local/x86_64-linux-clang20 - CMAKE_GENERATOR: Ninja + CMAKE_TOOLCHAIN_FILE: ${{ github.workspace }}/cmake/toolchain/x86_64-linux-clang20.cmake CMAKE_BUILD_TYPE: Debug - CFLAGS: "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -fstrict-flex-arrays=2 -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -fsanitize=leak -fstack-protector-strong" - CXXFLAGS: "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -fstrict-flex-arrays=2 -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -fsanitize=leak -fstack-protector-strong" - LDFLAGS: "-fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -fsanitize=leak -fstack-protector-strong" + CC: clang-20 + CXX: clang++-20 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Get Ubuntu dependencies run: | sudo apt-get -qq update @@ -65,7 +62,7 @@ jobs: - name: Restore CCache id: ccache-restore - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ env.CCACHE_DIR }} key: ${{ steps.x86_64-linux-clang20-keys.outputs.key1 }} @@ -77,7 +74,7 @@ jobs: - name: Restore Libs id: restore-libs - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: local/x86_64-linux-clang20 key: libs-x86_64-linux-clang20-${{ hashFiles('getlibs.sh') }} @@ -88,23 +85,25 @@ jobs: - name: Save Libs if: steps.restore-libs.outputs.cache-hit != 'true' id: save-libs - uses: actions/cache/save@v4 + uses: actions/cache/save@v5 with: path: local/x86_64-linux-clang20 key: ${{ steps.restore-libs.outputs.cache-primary-key }} - name: Configure UTAP - run: cmake -B "$BUILD_DIR" -DUTAP_CLANG_TIDY=OFF + run: cmake -DUTAP_CLANG_TIDY=OFF --preset debug-san - name: Build UTAP - run: cmake --build "$BUILD_DIR" --config $CMAKE_BUILD_TYPE + run: cmake --build --preset debug-san - name: Test UTAP - run: ctest --test-dir "$BUILD_DIR" -C $CMAKE_BUILD_TYPE + run: ctest --preset debug-san + - name: Quick UTAP Release + run: cmake --workflow --preset release-quick - name: Install UTAP - run: cmake --install "$BUILD_DIR" --config $CMAKE_BUILD_TYPE --prefix "$CMAKE_INSTALL_PREFIX" + run: cmake --install build-quick --config Release --prefix "$CMAKE_INSTALL_PREFIX" - name: CCache Statistics run: ccache --show-stats - name: Configure Examples - run: cmake -B examples/build -S examples + run: cmake -B "examples/${BUILD_DIR}" -S examples - name: Build Examples - run: cmake --build examples/build + run: cmake --build "examples/${BUILD_DIR}" --config "$CMAKE_BUILD_TYPE" - name: Test Examples - run: ctest --test-dir examples/build + run: ctest --test-dir "examples/${BUILD_DIR}" diff --git a/.github/workflows/ubuntu-gcc.yml b/.github/workflows/ubuntu-gcc.yml index 2c1fc855..3026c3d6 100644 --- a/.github/workflows/ubuntu-gcc.yml +++ b/.github/workflows/ubuntu-gcc.yml @@ -29,22 +29,19 @@ on: - 'examples/cmake/*.cmake' jobs: - build: + ubuntu-gcc14: runs-on: ubuntu-latest env: CCACHE_DIR: ${{ github.workspace }}/CCACHE - BUILD_DIR: build-x86_64-linux64-gcc14 CTEST_OUTPUT_ON_FAILURE: 1 CMAKE_TOOLCHAIN_FILE: ${{ github.workspace }}/cmake/toolchain/x86_64-linux-gcc14.cmake CMAKE_PREFIX_PATH: ${{ github.workspace }}/local/x86_64-linux-gcc14 CMAKE_INSTALL_PREFIX: ${{ github.workspace }}/local/x86_64-linux-gcc14 - CMAKE_GENERATOR: Ninja CMAKE_BUILD_TYPE: Debug - CFLAGS: "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -fstrict-flex-arrays=2 -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -fsanitize=leak -fstack-protector-strong" - CXXFLAGS: "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -fstrict-flex-arrays=2 -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -fsanitize=leak -fstack-protector-strong" - LDFLAGS: "-fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -fsanitize=leak -fstack-protector-strong" + CC: gcc-14 + CXX: g++-14 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Get Ubuntu dependencies run: | sudo apt-get -qq update @@ -65,7 +62,7 @@ jobs: - name: Restore CCache id: ccache-restore - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ env.CCACHE_DIR }} key: ${{ steps.x86_64-linux-gcc14-keys.outputs.key1 }} @@ -77,7 +74,7 @@ jobs: - name: Restore Libs id: restore-libs - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: local/x86_64-linux-gcc14 key: libs-x86_64-linux-gcc14-${{ hashFiles('getlibs.sh') }} @@ -88,23 +85,25 @@ jobs: - name: Save Libs if: steps.restore-libs.outputs.cache-hit != 'true' id: save-libs - uses: actions/cache/save@v4 + uses: actions/cache/save@v5 with: path: local/x86_64-linux-gcc14 key: ${{ steps.restore-libs.outputs.cache-primary-key }} - name: Configure UTAP - run: cmake -B "$BUILD_DIR" -DUTAP_CLANG_TIDY=OFF + run: cmake -DUTAP_CLANG_TIDY=OFF --preset debug-san - name: Build UTAP - run: cmake --build "$BUILD_DIR" --config $CMAKE_BUILD_TYPE + run: cmake --build --preset debug-san - name: Test UTAP - run: ctest --test-dir "$BUILD_DIR" -C $CMAKE_BUILD_TYPE + run: ctest --preset debug-san + - name: Quick UTAP Release + run: cmake --workflow --preset release-quick - name: Install UTAP - run: cmake --install "$BUILD_DIR" --config $CMAKE_BUILD_TYPE --prefix "$CMAKE_INSTALL_PREFIX" + run: cmake --install build-quick --config Release --prefix "$CMAKE_INSTALL_PREFIX" - name: CCache Statistics run: ccache --show-stats - name: Configure Examples - run: cmake -B examples/build -S examples + run: cmake -B "examples/${BUILD_DIR}" -S examples - name: Build Examples - run: cmake --build examples/build + run: cmake --build "examples/${BUILD_DIR}" --config "$CMAKE_BUILD_TYPE" - name: Test Examples - run: ctest --test-dir examples/build + run: ctest --test-dir "examples/${BUILD_DIR}" diff --git a/.github/workflows/ubuntu-mingw.yml b/.github/workflows/ubuntu-mingw.yml index 9910a7c2..a091e03f 100644 --- a/.github/workflows/ubuntu-mingw.yml +++ b/.github/workflows/ubuntu-mingw.yml @@ -29,27 +29,27 @@ on: - 'examples/cmake/*.cmake' jobs: - build: + ubuntu-mingw: runs-on: ubuntu-latest env: CCACHE_DIR: ${{ github.workspace }}/CCACHE - BUILD_DIR: build-x86_64-w64-mingw32 CTEST_OUTPUT_ON_FAILURE: 1 #CROSSCOMPILING_EMULATOR: wine CMAKE_TOOLCHAIN_FILE: ${{ github.workspace }}/cmake/toolchain/x86_64-w64-mingw32.cmake CMAKE_PREFIX_PATH: ${{ github.workspace }}/local/x86_64-w64-mingw32 CMAKE_INSTALL_PREFIX: ${{ github.workspace }}/local/x86_64-w64-mingw32 - CMAKE_GENERATOR: Ninja CMAKE_BUILD_TYPE: Debug + CC: x86_64-w64-mingw32-gcc + CXX: x86_64-w64-mingw32-g++ WINEPREFIX: ${{ github.workspace }}/.wine64 WINEARCH: win64 WINEDEBUG: fixme-all,-all steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Get Ubuntu dependencies run: | sudo apt-get -qq update - sudo apt-get -qq install curl wget unzip xz-utils bison flex cmake ninja-build ccache g++-mingw-w64-x86-64-posix wine wine-binfmt binfmt-support xvfb + sudo apt-get -qq install curl wget unzip xz-utils bison flex cmake ninja-build ccache g++-mingw-w64-x86-64-posix wine wine-binfmt binfmt-support xvfb sudo update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix - name: Setup Wine @@ -57,7 +57,7 @@ jobs: sudo update-binfmts --disable cli # disable mono attempts to execute windows binaries sudo update-binfmts --import /usr/share/binfmts/wine # enable wine to execute windows binaries rm -Rf "$WINEPREFIX" - xvfb-run wineboot --init # must init WINEPREFIX before WINEPATH is set!! + xvfb-run wineboot --init # must init WINEPREFIX before WINEPATH is set!! export WINEPATH=$($PWD/winepath-for x86_64-w64-mingw32) echo "WINEPATH=$WINEPATH" >> $GITHUB_ENV @@ -71,7 +71,7 @@ jobs: - name: Restore CCache id: ccache-restore - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ env.CCACHE_DIR }} key: ${{ steps.x86_64-w64-mingw32-keys.outputs.key1 }} @@ -83,7 +83,7 @@ jobs: - name: Restore Libs id: restore-libs - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: local/x86_64-w64-mingw32 key: libs-x86_64-w64-mingw32-${{ hashFiles('getlibs.sh') }} @@ -97,18 +97,20 @@ jobs: - name: Save Libs if: steps.restore-libs.outputs.cache-hit != 'true' id: save-libs - uses: actions/cache/save@v4 + uses: actions/cache/save@v5 with: path: local/x86_64-w64-mingw32 key: ${{ steps.restore-libs.outputs.cache-primary-key }} - name: Configure UTAP - run: cmake -B "$BUILD_DIR" -DUTAP_CLANG_TIDY=OFF + run: cmake -DUTAP_CLANG_TIDY=OFF --preset debug - name: Build UTAP - run: cmake --build "$BUILD_DIR" --config $CMAKE_BUILD_TYPE + run: cmake --build --preset debug - name: Test UTAP - run: ctest --test-dir "$BUILD_DIR" -C $CMAKE_BUILD_TYPE - - name: Build UTAP - run: cmake --install "$BUILD_DIR" --config $CMAKE_BUILD_TYPE --prefix "$CMAKE_INSTALL_PREFIX" + run: ctest --preset debug + - name: Quick UTAP Release + run: cmake --workflow --preset release-quick + - name: Install UTAP + run: cmake --install build-quick --config Release --prefix "$CMAKE_INSTALL_PREFIX" - name: CCache Statistics run: ccache --show-stats - name: Configure Examples diff --git a/.github/workflows/windows-clang.yml b/.github/workflows/windows-clang.yml new file mode 100644 index 00000000..f7f68885 --- /dev/null +++ b/.github/workflows/windows-clang.yml @@ -0,0 +1,110 @@ +--- +name: Windows Clang +on: + workflow_dispatch: + push: + branches: [main] + paths: + - src/** + - test/** + - benchmark/** + - cmake/** + - CMakeLists.txt + - CMakePresets.json + - .github/workflows/build-windows-clang.yml + pull_request: + branches: [main] + types: [synchronize, opened, reopened, ready_for_review] + paths: + - src/** + - test/** + - benchmark/** + - cmake/** + - CMakeLists.txt + - CMakePresets.json + - github/workflows/build-windows-clang.yml + +jobs: + windows-clang: + runs-on: windows-latest + defaults: + run: + shell: msys2 {0} + env: + CCACHE_DIR: ${{ github.workspace }}/CCACHE + CTEST_OUTPUT_ON_FAILURE: 1 + CMAKE_PREFIX_PATH: ${{ github.workspace }}/local/x86_64-windows-clang + CMAKE_INSTALL_PREFIX: ${{ github.workspace }}/local/x86_64-windows-clang + CMAKE_TOOLCHAIN_FILE: ${{ github.workspace }}/cmake/toolchain/x86_64-windows-clang.cmake + CMAKE_BUILD_TYPE: Debug + CC: clang + CXX: clang++ + steps: + - uses: msys2/setup-msys2@v2 + with: + msystem: UCRT64 + update: true + install: bison flex mingw-w64-ucrt-x86_64-git mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-ninja mingw-w64-ucrt-x86_64-clang mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-ccache + - name: Setup Runner Environment + run: | + uname -a + CORES=$(nproc) + echo "CMAKE_BUILD_PARALLEL_LEVEL=$CORES" >> $GITHUB_ENV + echo "CTEST_TEST_PARALLEL_LEVEL=$CORES" >> $GITHUB_ENV + echo "CTEST_TEST_LOAD=$CORES" >> $GITHUB_ENV + - uses: actions/checkout@v6 + - name: Compute CCache keys + id: x86_64-windows-clang-keys + run: | + key2=ccache-x86_64-windows-clang- + key1="${key2}$(date +%W)" + echo "key1=${key1}" >> $GITHUB_OUTPUT + echo "key2=${key2}" >> $GITHUB_OUTPUT + + - name: Restore CCache + id: ccache-restore + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ${{ steps.x86_64-windows-clang-keys.outputs.key1 }} + restore-keys: ${{ steps.x86_64-windows-clang-keys.outputs.key2 }} + - name: CCache limits and stats + run: | + ccache -M120M + ccache --show-stats + + - name: Restore Libs + id: restore-libs + uses: actions/cache/restore@v5 + with: + path: local/x86_64-windows-clang + key: libs-x86_64-windows-clang-${{ hashFiles('getlibs.sh') }} + restore-keys: libs-x86_64-windows-clang- + - name: Get library dependencies + if: steps.restore-libs.outputs.cache-hit != 'true' + run: ./getlibs.sh x86_64-windows-clang + - name: Save Libs + if: steps.restore-libs.outputs.cache-hit != 'true' + id: save-libs + uses: actions/cache/save@v5 + with: + path: local/x86_64-windows-clang + key: ${{ steps.restore-libs.outputs.cache-primary-key }} + - name: Configure UTAP + run: cmake -DUTAP_CLANG_TIDY=OFF --preset debug + - name: Build UTAP + run: cmake --build --preset debug + - name: Test UTAP + run: ctest --preset debug + - name: Quick UTAP Release + run: cmake --workflow --preset release-quick + - name: Install UTAP + run: cmake --install build-quick --config Release --prefix "$CMAKE_INSTALL_PREFIX" + - name: CCache Statistics + run: ccache --show-stats + - name: Configure Examples + run: cmake -B "examples/${BUILD_DIR}" -S examples + - name: Build Examples + run: cmake --build "examples/${BUILD_DIR}" --config "$CMAKE_BUILD_TYPE" + - name: Test Examples + run: ctest --test-dir "examples/${BUILD_DIR}" diff --git a/.github/workflows/windows-gcc.yml b/.github/workflows/windows-gcc.yml new file mode 100644 index 00000000..81df483a --- /dev/null +++ b/.github/workflows/windows-gcc.yml @@ -0,0 +1,110 @@ +--- +name: Windows GCC +on: + workflow_dispatch: + push: + branches: [main] + paths: + - src/** + - test/** + - benchmark/** + - cmake/** + - CMakeLists.txt + - CMakePresets.json + - .github/workflows/build-windows-gcc.yml + pull_request: + branches: [main] + types: [synchronize, opened, reopened, ready_for_review] + paths: + - src/** + - test/** + - benchmark/** + - cmake/** + - CMakeLists.txt + - CMakePresets.json + - .github/workflows/build-windows-gcc.yml + +jobs: + windows-gcc: + runs-on: windows-latest + defaults: + run: + shell: msys2 {0} + env: + CCACHE_DIR: ${{ github.workspace }}/CCACHE + CTEST_OUTPUT_ON_FAILURE: 1 + CMAKE_PREFIX_PATH: ${{ github.workspace }}/local/x86_64-windows-gcc + CMAKE_INSTALL_PREFIX: ${{ github.workspace }}/local/x86_64-windows-gcc + CMAKE_TOOLCHAIN_FILE: ${{ github.workspace }}/cmake/toolchain/x86_64-windows-gcc.cmake + CMAKE_BUILD_TYPE: Debug + CC: gcc + CXX: g++ + steps: + - uses: msys2/setup-msys2@v2 + with: + msystem: UCRT64 + update: true + install: bison flex mingw-w64-ucrt-x86_64-git mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-ninja mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-ccache + - name: Setup Runner Environment + run: | + uname -a + CORES=$(nproc) + echo "CMAKE_BUILD_PARALLEL_LEVEL=$CORES" >> $GITHUB_ENV + echo "CTEST_TEST_PARALLEL_LEVEL=$CORES" >> $GITHUB_ENV + echo "CTEST_TEST_LOAD=$CORES" >> $GITHUB_ENV + - uses: actions/checkout@v6 + - name: Compute CCache keys + id: x86_64-windows-gcc-keys + run: | + key2=ccache-x86_64-windows-gcc- + key1="${key2}$(date +%W)" + echo "key1=${key1}" >> $GITHUB_OUTPUT + echo "key2=${key2}" >> $GITHUB_OUTPUT + + - name: Restore CCache + id: ccache-restore + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ${{ steps.x86_64-windows-gcc-keys.outputs.key1 }} + restore-keys: ${{ steps.x86_64-windows-gcc-keys.outputs.key2 }} + - name: CCache limits and stats + run: | + ccache -M120M + ccache --show-stats + + - name: Restore Libs + id: restore-libs + uses: actions/cache/restore@v5 + with: + path: local/x86_64-windows-gcc + key: libs-x86_64-windows-gcc-${{ hashFiles('getlibs.sh') }} + restore-keys: libs-x86_64-windows-gcc- + - name: Get library dependencies + if: steps.restore-libs.outputs.cache-hit != 'true' + run: ./getlibs.sh x86_64-windows-gcc + - name: Save Libs + if: steps.restore-libs.outputs.cache-hit != 'true' + id: save-libs + uses: actions/cache/save@v5 + with: + path: local/x86_64-windows-gcc + key: ${{ steps.restore-libs.outputs.cache-primary-key }} + - name: Configure UTAP + run: cmake -DUTAP_CLANG_TIDY=OFF --preset debug + - name: Build UTAP + run: cmake --build --preset debug + - name: Test UTAP + run: ctest --preset debug + - name: Quick UTAP Release + run: cmake --workflow --preset release-quick + - name: Install UTAP + run: cmake --install build-quick --config Release --prefix "$CMAKE_INSTALL_PREFIX" + - name: CCache Statistics + run: ccache --show-stats + - name: Configure Examples + run: cmake -B "examples/${BUILD_DIR}" -S examples + - name: Build Examples + run: cmake --build "examples/${BUILD_DIR}" --config "$CMAKE_BUILD_TYPE" + - name: Test Examples + run: ctest --test-dir "examples/${BUILD_DIR}" diff --git a/.gitignore b/.gitignore index 42c30551..b80cf36d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ /build -/cmake-build-* /build-* +/cmake-build-* /local /examples/build /examples/build-* @@ -10,3 +10,4 @@ /doc/api/html .idea .vscode +.claude diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..62a01d83 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,136 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +`libutap` (UTAP) is the Uppaal Timed Automata Parser — a C++17 library that parses and type-checks +Uppaal model files (`.xml`, `.xta`, `.ta` formats) into an in-memory AST (`Document`). It is a +dependency of the Uppaal model checker toolchain, licensed under LGPL. + +## Build + +Requires GCC 10+ (or compatible clang), Ninja or GNU make, CMake 3.16+ (presets need 3.28+), +`flex` >= 2.6.4, `bison` >= 3.6.0, and `libxml2` >= 2.6.10. + +```shell +sudo apt-get install g++ ninja-build cmake flex bison libxml2-dev doctest-dev +``` + +Preferred workflow uses CMake presets (`CMakePresets.json` + `cmake/CommonPresets.json`): + +```shell +cmake --workflow --preset default # configure + build + test, Debug, single-config +cmake --workflow --preset debug # multi-config Ninja, Debug +cmake --workflow --preset debug-san # Debug with ASan/UBSan/SSP +cmake --workflow --preset quick # build only, no tests, no clang-tidy (fastest iteration) +``` + +Manual configure/build/test (no presets): + +```shell +cmake . -B build -DCMAKE_INSTALL_PREFIX=$MYPATH -G Ninja +cmake --build build +ctest --test-dir build --output-on-failure +cmake --install build +``` + +Cross-compiling / full dependency bootstrap (fetches libxml2 etc. into `local/`, then +configures, builds, tests, and installs): + +```shell +./compile.sh x86_64-linux # see cmake/toolchain/*.cmake for supported target names +``` + +Key CMake options (`CMakeLists.txt`): `UTAP_TESTS` (default ON), `UTAP_STATIC`, `UTAP_CLANG_TIDY` +(default ON — runs clang-tidy during the build), `UTAP_CCACHE` (default ON). + +## Running tests + +Tests use doctest and are registered individually with ctest (see `test/CMakeLists.txt`), so a +single test binary or case can be targeted directly: + +```shell +ctest --test-dir build-multi --output-on-failure # all tests +ctest --test-dir build-multi -R typechecker_test # one test binary by ctest name +build-multi/Debug/typechecker_test --test-case="*scalar*" # one doctest case, run binary directly +``` + +Test binaries: `expression_test`, `statement_test`, `parser_test`, `featurechecker_test`, +`range_test`, `typechecker_test`, `prettyprint_test`, `example_test`. Several depend on +`MODELS_DIR` (compiled in, points at `test/models/`) and `parser_test` additionally depends on the +`external_fn` shared library (built from `test/external_fn.cpp`) to exercise dynamically-loaded +functions. + +## Coverage + +`coverage-gcovr.sh` and `coverage-lcov.sh` configure/build/test the `coverage` preset (gcov) and +open an HTML report. `coverage-llvm.sh` does the same for the LLVM/clang coverage preset. All +regenerate their build dir (`build-coverage-gcov*`) from scratch via the preset. + +## Code style + +- `.clang-format` enforces formatting (Google-based, 4-space indent, 120 col) — run `clang-format` + before committing. +- `.clang-tidy` enables a specific curated check set (readability/modernize/performance subset); + `UTAP_CLANG_TIDY` runs it as part of the normal build. +- C++17, no compiler-specific extensions (`CMAKE_CXX_EXTENSIONS OFF`). + +## Architecture + +Information flow (see README.md section 5 for the original diagram): + +``` +.xml --> libxml2 (SAX) --> xmlreader.cpp --\ + >--> bison parser (parser.y / lexer.l) --> ParserBuilder +.ta/.xta -----------------------------------/ +``` + +- **Grammar**: `src/parser.y` (bison) and `src/lexer.l` (flex) implement the BNF for both old + (3.x) and new (4.x) syntax, and are used both for direct `.ta`/`.xta` parsing and, reused + block-by-block, for text embedded inside `.xml` documents. Generated parser/lexer land in the + build directory (see `src/CMakeLists.txt` custom commands), not in source. +- **`ParserBuilder`** (`include/utap/builder.hpp`) is the abstract callback interface the grammar + drives — one method per grammar production (types, declarations, statements, expressions, + processes/templates, properties, LSC/SMC/priority extensions). The parser has no knowledge of + how the model is stored; it only calls into whatever `ParserBuilder` implementation it's given. +- **Builder inheritance chain** turns those callbacks into an AST: + `AbstractBuilder` (`ParserBuilder` + shared bookkeeping, e.g. type/name stacks) + → `ExpressionBuilder` (expression trees) + → `StatementBuilder` (statements) + → `DocumentBuilder` (full `Document`: templates, processes, declarations). + `PropertyBuilder`/`TigaPropertyBuilder` (`property.hpp`) similarly subclass `StatementBuilder` + for query/property parsing. `PrettyPrinter` subclasses `AbstractBuilder` directly to regenerate + source text from the same callback stream (used by the `pretty` tool and round-trip tests). +- **`Document`** (`include/utap/document.hpp`) is the resulting AST: templates, `Variable`, + `Location`, `Edge`, `Branchpoint`, processes, and the system declaration. Symbols are `Symbol` + objects (name + `Type`) grouped into `Frame`s representing scopes (`include/utap/symbols.hpp`). + All expressions are `Expression` trees (`include/utap/expression.hpp`); all statements are + `Statement` subclasses with a visitor hierarchy (`StatementVisitor` / + `AbstractStatementVisitor` in `include/utap/statement.hpp`). +- **Post-parse passes** walk the built `Document` via `DocumentVisitor`/`AbstractStatementVisitor`: + `TypeChecker` (`TypeChecker.cpp`, by far the largest source file) does the semantic type checking + and rewriting after the whole document is built; `FeatureChecker` inspects which model features + are in use (e.g. to pick symbolic/stochastic/concrete analysis support, see `SupportedMethods`). +- **`xmlreader.cpp`** bridges libxml2 SAX events to the bison parser for embedded expression/ + statement text inside XML elements; `xmlwriter.cpp` does the reverse (serializing a `Document` + back to Uppaal XML). +- Public headers live under `include/utap/`; the top-level umbrella header is + `include/utap/utap.hpp` (parse entry points operating on `Document&`, e.g. `parse_XML_file`, + `parse_XTA`), while `include/utap/builder.hpp` exposes the lower-level entry points that operate + directly on a `ParserBuilder&` instead of a `Document`. +- Command-line utilities built alongside the library (`src/CMakeLists.txt`): `pretty` (pretty- + printer), `syntaxcheck`, `featurecheck` — thin executables over the corresponding builder/checker + classes, useful for manually exercising a code path end-to-end against a real model file. + +## Repo layout notes + +- `examples/` is a self-contained consumer of the installed/built library, with its own CMake + project and two build paths (`compile-with-getlibs.sh` vendors deps into `examples/local/`, + `compile-with-cmake.sh` fetches deps via CMake) — useful as a template for exercising the public + API in isolation from the main build. +- `cmake/toolchain/` holds CMake toolchain files for cross-compilation targets (Linux/macOS/mingw, + multiple GCC/clang versions); `getlibs.sh` fetches and builds dependencies for a given target + into `local/`. +- CI matrix is defined across `.github/workflows/*.yml` (ubuntu-gcc, ubuntu-clang20, ubuntu-mingw, + darwin-appleclang, darwin-brew-gcc15, nix). diff --git a/CMakeLists.txt b/CMakeLists.txt index e2cc6157..174ec168 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,9 +9,6 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - add_compile_options(-Wpedantic -Wall -Wextra -Werror=vla -Wno-unused-parameter) - endif() else() message(STATUS "UTAP is NOT the top-level project") endif() @@ -23,14 +20,15 @@ else(WIN32) set(UTAP_STATIC_DEFAULT OFF) endif(WIN32) -option(UTAP_WARNINGS "UTAP Compiler Warnings" ON) +include(cmake/warnings.cmake) +include(cmake/sanitizers.cmake) option(UTAP_TESTS "UTAP Unit Tests" ON) +include(cmake/coverage.cmake) option(UTAP_STATIC "UTAP Static Linking" ${UTAP_STATIC_DEFAULT}) option(UTAP_CLANG_TIDY "Enable clang-tidy linting" ON) option(UTAP_CCACHE "Enables ccache for intermediate object file caching" ON) cmake_policy(SET CMP0048 NEW) # project() command manages VERSION variables -include(cmake/sanitizers.cmake) if (UTAP_CLANG_TIDY) include(cmake/clang-tidy.cmake) endif (UTAP_CLANG_TIDY) @@ -51,8 +49,8 @@ add_subdirectory(src) if (UTAP_TESTS) include(cmake/doctest.cmake) enable_testing() + add_subdirectory(test) endif(UTAP_TESTS) -add_subdirectory(test) write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/UTAPConfigVersion.cmake VERSION ${PACKAGE_VERSION} COMPATIBILITY SameMajorVersion) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 00000000..15888453 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,230 @@ +{ + "version": 8, + "cmakeMinimumRequired": { + "major": 3, + "minor": 28, + "patch": 0 + }, + "include": ["cmake/CommonPresets.json"], + "configurePresets": [ + { + "name": "quick", + "inherits": "multi", + "binaryDir": "${sourceDir}/build-quick", + "cacheVariables": { + "UTAP_TESTS": { "type": "BOOL", "value": "OFF" }, + "UTAP_CLANG_TIDY": { "type": "BOOL", "value": "OFF" } + }, + "displayName": "Configure quick build (no testing) for Debug and Release" + }, + { + "name": "quick-san", + "inherits": "multi-san", + "binaryDir": "${sourceDir}/build-quick-san", + "cacheVariables": { + "UTAP_TESTS": { "type": "bool", "value": "OFF" }, + "UTAP_CLANG_TIDY": { "type": "bool", "value": "OFF" } + }, + "displayName": "Configure quick build (no testing) with Sanitizers for Debug and Release" + }, + { + "name": "coverage", + "inherits": "debug", + "binaryDir": "${sourceDir}/build-coverage-gcov", + "cacheVariables": { "UTAP_COVERAGE": "ON" }, + "displayName": "Configure gcov coverage build" + }, + { + "name": "coverage-llvm", + "inherits": "debug", + "binaryDir": "${sourceDir}/build-coverage-llvm", + "cacheVariables": { + "UTAP_COVERAGE": "ON", + "UTAP_COVERAGE_TYPE": "llvm" + }, + "displayName": "Configure llvm coverage build" + } + ], + "buildPresets": [ + { + "name": "release-quick", + "inherits": "release", + "configurePreset": "quick", + "displayName": "Build quick (no testing) for Release" + }, + { + "name": "debug-quick", + "inherits": "debug", + "configurePreset": "quick", + "displayName": "Build quick (no testing) for Debug" + }, + { + "name": "release-quick-san", + "inherits": "release-san", + "configurePreset": "quick-san", + "displayName": "Build quick (no testing) with Sanitizers and Release" + }, + { + "name": "debug-quick-san", + "inherits": "debug-san", + "configurePreset": "quick-san", + "displayName": "Build quick (no testing) with Sanitizers and Debug" + }, + { + "name": "coverage", + "inherits": "debug", + "configurePreset": "coverage", + "displayName": "Build with gcov coverage" + }, + { + "name": "coverage-llvm", + "inherits": "debug", + "configurePreset": "coverage-llvm", + "displayName": "Build with llvm coverage" + } + ], + "testPresets": [ + { + "name": "coverage", + "inherits": "debug", + "configurePreset": "coverage", + "displayName": "Test the Debug with gcov coverage" + }, + { + "name": "coverage-llvm", + "inherits": "debug", + "configurePreset": "coverage-llvm", + "displayName": "Test the Debug with llvm coverage" + } + ], + "workflowPresets": [ + { + "name": "quick", + "displayName": "Configure and Build quick (no testing) for Debug and Release", + "steps": [ + { + "type": "configure", + "name": "quick" + }, + { + "type": "build", + "name": "release-quick" + }, + { + "type": "build", + "name": "debug-quick" + } + ] + }, + { + "name": "release-quick", + "displayName": "Configure and Build quick (no testing) for Release", + "steps": [ + { + "type": "configure", + "name": "quick" + }, + { + "type": "build", + "name": "release-quick" + } + ] + }, + { + "name": "debug-quick", + "displayName": "Configure and Build quick (no testing) for Debug", + "steps": [ + { + "type": "configure", + "name": "quick" + }, + { + "type": "build", + "name": "debug-quick" + } + ] + }, + { + "name": "quick-san", + "displayName": "Configure and Build quick (no testing) with Sanitizers for Debug and Release", + "steps": [ + { + "type": "configure", + "name": "quick-san" + }, + { + "type": "build", + "name": "release-quick-san" + }, + { + "type": "build", + "name": "debug-quick-san" + } + ] + }, + { + "name": "release-quick-san", + "displayName": "Configure and Build quick (no testing) with Sanitizers for Release", + "steps": [ + { + "type": "configure", + "name": "quick-san" + }, + { + "type": "build", + "name": "release-quick-san" + } + ] + }, + { + "name": "debug-quick-san", + "displayName": "Configure and Build quick (no testing) with Sanitizers for Debug", + "steps": [ + { + "type": "configure", + "name": "quick-san" + }, + { + "type": "build", + "name": "debug-quick-san" + } + ] + }, + { + "name": "coverage", + "displayName": "Configure, Build and Test with gcov Coverage", + "steps": [ + { + "type": "configure", + "name": "coverage" + }, + { + "type": "build", + "name": "coverage" + }, + { + "type": "test", + "name": "coverage" + } + ] + }, + { + "name": "coverage-llvm", + "displayName": "Configure, Build and Test with llvm Coverage", + "steps": [ + { + "type": "configure", + "name": "coverage-llvm" + }, + { + "type": "build", + "name": "coverage-llvm" + }, + { + "type": "test", + "name": "coverage-llvm" + } + ] + } + ] +} \ No newline at end of file diff --git a/cmake/CommonPresets.json b/cmake/CommonPresets.json new file mode 100644 index 00000000..3f918e32 --- /dev/null +++ b/cmake/CommonPresets.json @@ -0,0 +1,294 @@ +{ + "version": 8, + "cmakeMinimumRequired": { + "major": 3, + "minor": 28, + "patch": 0 + }, + "configurePresets": [ + { + "name": "default", + "binaryDir": "${sourceDir}/build", + "displayName": "Configure with Defaults (Debug)" + }, + { + "name": "multi", + "inherits": "default", + "binaryDir": "${sourceDir}/build-multi", + "generator": "Ninja Multi-Config", + "displayName": "Configure for Ninja Debug/Release" + }, + { + "name": "multi-san", + "inherits": "multi", + "binaryDir": "${sourceDir}/build-multi-san", + "cacheVariables": { + "UBSAN" : { "type": "BOOL", "value": "ON"}, + "ASAN" : { "type": "BOOL", "value": "ON"}, + "SSP" : { "type": "BOOL", "value": "ON"} + }, + "displayName": "Configure for Ninja Debug/Release with Sanitizers" + }, + { + "name": "debug", + "inherits": "multi", + "displayName": "Configure for Ninja Debug/Release (alias of multi)" + }, + { + "name": "release", + "inherits": "multi", + "displayName": "Configure for Ninja Debug/Release (alias of multi)" + }, + { + "name": "debug-san", + "inherits": "multi-san", + "displayName": "Configure for Ninja Debug/Release with Sanitizers (alias of multi-san)" + }, + { + "name": "release-san", + "inherits": "multi-san", + "displayName": "Configure for Ninja Debug/Release with Sanitizers (alias of multi-san)" + } + ], + "buildPresets": [ + { + "name": "default", + "configurePreset": "default", + "displayName": "Build for default configuration" + }, + { + "name": "debug", + "configurePreset": "multi", + "configuration": "Debug", + "displayName": "Build for Debug" + }, + { + "name": "debug-san", + "inherits": "debug", + "configurePreset": "multi-san", + "displayName": "Build for Debug with Sanitizers" + }, + { + "name": "release", + "configurePreset": "multi", + "configuration": "Release", + "displayName": "Build for Release" + }, + { + "name": "release-debug", + "configurePreset": "multi", + "configuration": "RelWithDebInfo", + "displayName": "Build for Release with Debug Info" + }, + { + "name": "release-san", + "inherits": "release-debug", + "configurePreset": "multi-san", + "displayName": "Build for Release with Sanitizers and Debug Info" + } + ], + "testPresets": [ + { + "name": "default", + "configurePreset": "default", + "output": { "outputOnFailure": true, "verbosity": "verbose" }, + "execution": { "noTestsAction": "error", "stopOnFailure": true }, + "displayName": "Test with default options" + }, + { + "name": "debug", + "inherits": "default", + "configurePreset": "multi", + "configuration": "Debug", + "displayName": "Test the Debug" + }, + { + "name": "debug-san", + "inherits": "debug", + "configurePreset": "multi-san", + "displayName": "Test the Debug with Sanitizers" + }, + { + "name": "release", + "inherits": "default", + "configurePreset": "multi", + "configuration": "Release", + "displayName": "Test the Release" + }, + { + "name": "release-debug", + "inherits": "default", + "configurePreset": "multi", + "configuration": "RelWithDebInfo", + "displayName": "Test the Release with Debug Info" + }, + { + "name": "release-san", + "inherits": "release-debug", + "configurePreset": "multi-san", + "displayName": "Test the Release with Sanitizers and Debug Info" + } + ], + "workflowPresets": [ + { + "name": "default", + "displayName": "Configure, Build and Test with Defaults (Debug)", + "steps": [ + { + "type": "configure", + "name": "default" + }, + { + "type": "build", + "name": "default" + }, + { + "type": "test", + "name": "default" + } + ] + }, + { + "name": "debug", + "displayName": "Configure, Build and Test with Debug", + "steps": [ + { + "type": "configure", + "name": "multi" + }, + { + "type": "build", + "name": "debug" + }, + { + "type": "test", + "name": "debug" + } + ] + }, + { + "name": "release", + "displayName": "Configure, Build and Test with Release", + "steps": [ + { + "type": "configure", + "name": "multi" + }, + { + "type": "build", + "name": "release" + }, + { + "type": "test", + "name": "release" + } + ] + }, + { + "name": "release-debug", + "displayName": "Configure, Build and Test Release with Debug Info", + "steps": [ + { + "type": "configure", + "name": "multi" + }, + { + "type": "build", + "name": "release-debug" + }, + { + "type": "test", + "name": "release-debug" + } + ] + }, + { + "name": "debug-san", + "displayName": "Configure, Build and Test with Debug and Sanitizers", + "steps": [ + { + "type": "configure", + "name": "multi-san" + }, + { + "type": "build", + "name": "debug-san" + }, + { + "type": "test", + "name": "debug-san" + } + ] + }, + { + "name": "release-san", + "displayName": "Configure, Build and Test with Release and Sanitizers", + "steps": [ + { + "type": "configure", + "name": "multi-san" + }, + { + "type": "build", + "name": "release-san" + }, + { + "type": "test", + "name": "release-san" + } + ] + }, + { + "name": "multi", + "displayName": "Configure, Build and Test with Debug and Release", + "steps": [ + { + "type": "configure", + "name": "multi" + }, + { + "type": "build", + "name": "debug" + }, + { + "type": "test", + "name": "debug" + }, + { + "type": "build", + "name": "release-debug" + }, + { + "type": "test", + "name": "release-debug" + } + ] + }, + { + "name": "multi-san", + "displayName": "Configure, Build and Test with Debug and Release and Sanitizers", + "steps": [ + { + "type": "configure", + "name": "multi-san" + }, + { + "type": "build", + "name": "debug-san" + }, + { + "type": "test", + "name": "debug-san" + }, + { + "type": "build", + "name": "release-san" + }, + { + "type": "test", + "name": "release-san" + } + ] + } + ] +} diff --git a/cmake/coverage.cmake b/cmake/coverage.cmake new file mode 100644 index 00000000..f1ddafca --- /dev/null +++ b/cmake/coverage.cmake @@ -0,0 +1,29 @@ +# Adds code coverage instrumentation to inspect the quality of tests +option(UTAP_COVERAGE "Enable UTAP Code Coverage" OFF) +set(UTAP_COVERAGE_TYPE "gcov" CACHE STRING "Coverage backend: gcov or llvm") +set_property(CACHE UTAP_COVERAGE_TYPE PROPERTY STRINGS gcov llvm) + +add_library(coverage_config INTERFACE) + +if(UTAP_COVERAGE) + if (NOT UTAP_TESTS) + message(WARNING "Code coverage is enabled while UTAP_TESTS is disabled") + endif () + if(UTAP_COVERAGE_TYPE STREQUAL "llvm" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") + target_compile_options(coverage_config INTERFACE -fcoverage-mcdc -fprofile-instr-generate -fcoverage-mapping -O0 -g) + target_link_options(coverage_config INTERFACE -fcoverage-mcdc -fprofile-instr-generate -fcoverage-mapping) + message(STATUS "Enabled Code Coverage using llvm") + else() + target_compile_options(coverage_config INTERFACE --coverage -O0 -g) + target_link_options(coverage_config INTERFACE --coverage) + message(STATUS "Enabled Code Coverage using gcov") + endif() +else () + message(STATUS "Disabled Code Coverage") +endif() + +function(target_coverage target) + if(UTAP_COVERAGE) + target_link_libraries(${target} PRIVATE coverage_config) + endif() +endfunction() diff --git a/cmake/doctest.cmake b/cmake/doctest.cmake index 605b3b4a..48933b48 100644 --- a/cmake/doctest.cmake +++ b/cmake/doctest.cmake @@ -1,13 +1,15 @@ -# Ensures that doctest unit testing framework is installed +# Downloads and compiles DocTest unit testing framework include(FetchContent) +#set(FETCHCONTENT_QUIET ON) +#set(FETCHCONTENT_UPDATES_DISCONNECTED ON) FetchContent_Declare(doctest - GIT_REPOSITORY https://github.com/doctest/doctest.git - GIT_TAG v2.4.12 # "main" for latest - GIT_SHALLOW TRUE # download specific revision only (git clone --depth 1) - GIT_PROGRESS TRUE # show download progress in Ninja - EXCLUDE_FROM_ALL ON # don't build if not used - FIND_PACKAGE_ARGS 2.4.12) + GIT_REPOSITORY https://github.com/doctest/doctest.git + GIT_TAG v2.5.3 # "main" for latest + GIT_SHALLOW TRUE # download specific revision only (git clone --depth 1) + GIT_PROGRESS TRUE # show download progress in Ninja + EXCLUDE_FROM_ALL ON # don't build if not used + FIND_PACKAGE_ARGS 2.5.3) set(DOCTEST_WITH_TESTS OFF CACHE BOOL "Build tests/examples") set(DOCTEST_WITH_MAIN_IN_STATIC_LIB ON CACHE BOOL "Build a static lib for doctest::doctest_with_main") @@ -17,21 +19,29 @@ set(DOCTEST_USE_STD_HEADERS OFF CACHE BOOL "Use std headers") FetchContent_MakeAvailable(doctest) if(doctest_FOUND) # find_package - message(STATUS "Found doctest: ${doctest_DIR}") + message(STATUS "Found doctest: ${doctest_DIR}") else(doctest_FOUND) # FetchContent - message(STATUS "Fetched doctest: ${doctest_SOURCE_DIR}") + message(STATUS "Fetched doctest: ${doctest_SOURCE_DIR}") endif(doctest_FOUND) if (TARGET doctest::doctest) - message(STATUS " Available target: doctest::doctest") + message(STATUS " Available target: doctest::doctest") +else() + message(FATAL_ERROR " Target not found: doctest::doctest") endif () if (TARGET doctest::doctest_with_main) message(STATUS " Available target: doctest::doctest_with_main") -else () + if (TARGET doctest_with_main) + message(STATUS " Available target: doctest_with_main") + else () + add_library(doctest_with_main INTERFACE) + target_link_libraries(doctest_with_main INTERFACE doctest::doctest_with_main) + message(STATUS " Created target: doctest_with_main") + endif() +else() add_library(doctest_with_main INTERFACE) target_compile_definitions(doctest_with_main INTERFACE DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) target_link_libraries(doctest_with_main INTERFACE doctest::doctest) - add_library(doctest::doctest_with_main ALIAS doctest_with_main) - message(STATUS " Added target: doctest::doctest_with_main") + message(STATUS " Created target: doctest_with_main") endif () diff --git a/cmake/libxml2.cmake b/cmake/libxml2.cmake index 413b67b4..0c321578 100644 --- a/cmake/libxml2.cmake +++ b/cmake/libxml2.cmake @@ -10,7 +10,7 @@ FetchContent_Declare(LibXml2 GIT_SHALLOW ON GIT_PROGRESS ON EXCLUDE_FROM_ALL ON # don't build if not used - FIND_PACKAGE_ARGS 2.9.14) + FIND_PACKAGE_ARGS 2.13.9) set(LIBXML2_SHARED_LIBS OFF CACHE BOOL "LibXml2 shared libraries") set(LIBXML2_WITH_FTP OFF CACHE BOOL "LibXml2 FTP support") diff --git a/cmake/sanitizers.cmake b/cmake/sanitizers.cmake index 8a4d41f1..b4eef6f0 100644 --- a/cmake/sanitizers.cmake +++ b/cmake/sanitizers.cmake @@ -1,43 +1,187 @@ # Various sanitizers (runtime checks) for debugging -# Available with GCC and Clang on Linux and macOS (not on Windows yet) - -option(SSP "Stack Smashing Protector" OFF) # Available on Windows too -option(UBSAN "Undefined Behavior Sanitizer" OFF) -option(ASAN "Address Sanitizer" OFF) -option(LSAN "Leak Sanitizer" OFF) -option(TSAN "Thread Sanitizer" OFF) - -if (SSP) - add_compile_options(-fstack-protector) - add_link_options(-fstack-protector) - message(STATUS "Enable Stack Smashing Protector") +# Use options (e.g. -DASAN=ON) for your *entire* project +# AddressSanitizer also checks for stack abuse and leaks, but StackProtector and LeakSanitizer have less overhead. +# Mutually compatible sanitizers: SSP, UBSAN, LSAN, ASAN +# TSAN is incompatible with UBSAN, LSAN, ASAN +option(CXXWARN "Compiler warnings" OFF) +option(HARDENED "Enable flags which improve security without affecting ABI" OFF) +option(SSP "Stack Smashing Protector (GCC/Clang/AppleClang/MSVC)" OFF) +option(UBSAN "Undefined Behavior Sanitizer (GCC/Clang/AppleClang on Unix)" OFF) +option(LSAN "Leak Sanitizer (GCC/Clang/AppleClang on Unix)" OFF) +option(ASAN "Address Sanitizer (GCC/Clang/AppleClang on Unix, MSVC on Windows)" OFF) +option(MSAN "Memory (initialization) Sanitizer (Clang/AppleClang on Unix)" OFF) +option(TSAN "Thread Sanitizer (GCC/Clang/AppleClang on Unix)" OFF) +option(RTC_C "Runtime Checks for Conversions (MSVC on Windows)" OFF) +option(RTC_S "Runtime Checks for Stack (MSVC on Windows)" OFF) +option(RTC_U "Runtime Checks for Uninitialized (MSVC on Windows)" OFF) + +if (CXXWARN) + if (CMAKE_CXX_COMPILER_ID MATCHES GNU) + add_compile_options(-Wpedantic -Wall -Wextra) + message(STATUS "Enabled compiler warnings") + elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang) + add_compile_options(-Wpedantic -Wall -Wextra) + # consider: -Wunsafe-buffer-usage + message(STATUS "Enabled compiler warnings") + elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC) + add_compile_options(/Wall) + message(STATUS "Enabled compiler warnings") + else() + message(STATUS "Failed to turn on compiler warnings for ${CMAKE_CXX_COMPILER_ID}") + endif () +endif (CXXWARN) + +if(SSP) + add_compile_options(-Wstack-protector -fstack-protector-strong) + add_link_options(-fstack-protector-strong) + if(CMAKE_CXX_COMPILER_ID MATCHES GNU) + add_compile_options(-fstack-clash-protection) + add_link_options(-fstack-clash-protection) + endif() + message(STATUS "Enabled Stack Smashing Protector") +else(SSP) + message(STATUS "Disabled Stack Smashing Protector") endif(SSP) -if (ASAN OR UBSAN OR LSAN OR TSAN) - add_compile_options(-fno-omit-frame-pointer) - add_link_options(-fno-omit-frame-pointer) -endif() +if (HARDENED) + if(CMAKE_CXX_COMPILER_ID MATCHES GNU) + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14) + # See `g++ --help=hardened` + add_compile_options(-Whardened -fhardened) + add_link_options(-Whardened -fhardened) + else () + add_compile_definitions(_FORTIFY_SOURCE=3 _GLIBCXX_ASSERTIONS) + add_compile_options(-fvisibility=hidden -ftrivial-auto-var-init=zero -fstack-protector-strong -fstack-clash-protection -fcf-protection=full) + add_link_options(-ftrivial-auto-var-init=zero -fstack-protector-strong -fstack-clash-protection -fcf-protection=full -Wl,-z,relro,-z,now) + endif () + message(STATUS "Enabled Hardened Security") + elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang) + # See https://clang.llvm.org/docs/SafeStack.html + # Also https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening-Guide-for-C-and-C++.html + # -fsanitize=cfi depends on libclang-rt-19-dev being installed + add_compile_definitions(_FORTIFY_SOURCE=3 _GLIBCXX_ASSERTIONS) + add_compile_options(-fvisibility=hidden -fstack-protector-strong -fcf-protection=full -fstack-clash-protection -fsanitize=safe-stack) + add_link_options(-fstack-protector-strong -fstack-clash-protection -fcf-protection=full -fsanitize=safe-stack -Wl,-z,relro,-z,now) + # -flto -fsanitize=cfi # breaks in several weird ways + # See https://libcxx.llvm.org/Hardening.html + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + add_compile_definitions(_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG _LIBCPP_ABI_BOUNDED_ITERATORS) + else () + add_compile_definitions(_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST) + endif () + message(STATUS "Enabled Hardened Security") + elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC) + add_compile_definitions(_MSVC_STL_HARDENING _STL_VERIFY _MSVC_STL_DESTRUCTOR_TOMBSTONES) + add_compile_options(/analyze /sdl /GS /guard:cf) + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + add_compile_definitions(_ALLOW_RTCc_IN_STL) + add_compile_options(/RTCs /RTCu) # incompatible with /O2, loops: /RTCc + endif () + message(STATUS "Enabled Hardened Security") + else () + message(WARNING "Failed to Harden Security for ${CMAKE_CXX_COMPILER_ID}") + endif () +else (HARDENED) + message(STATUS "Disabled Hardened Security") +endif (HARDENED) -if (UBSAN) +if(UBSAN) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + add_compile_options(/fsanitize=undefined) + message(STATUS "See MSVC sanitizers: https://learn.microsoft.com/en-us/cpp/sanitizers") + message(STATUS "Consider RTC_C, RTC_S, RTS_U instead") + else() add_compile_options(-fsanitize=undefined) add_link_options(-fsanitize=undefined) - message(STATUS "Enabled Undefined Behavior Sanitizer") + endif() + message(STATUS "Enabled Undefined Behavior Sanitizer") +else(UBSAN) + message(STATUS "Disabled Undefined Behavior Sanitizer") endif(UBSAN) -if (ASAN) +if(LSAN) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + add_compile_options(/fsanitize=leak) + message(STATUS "See MSVC sanitizers: https://learn.microsoft.com/en-us/cpp/sanitizers") + message(STATUS "Consider ASAN instead") + else() + add_compile_options(-fsanitize=leak) + add_link_options(-fsanitize=leak) + endif() + message(STATUS "Enabled Leak Sanitizer") +else(LSAN) + message(STATUS "Disabled Leak Sanitizer") +endif(LSAN) + +if(ASAN) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + add_compile_options(/fsanitize=address) + else() add_compile_options(-fsanitize=address) add_link_options(-fsanitize=address) - message(STATUS "Enabled Address Sanitizer") + endif() + message(STATUS "Enabled Address Sanitizer") +else(ASAN) + message(STATUS "Disabled Address Sanitizer") endif(ASAN) -if (LSAN) - add_compile_options(-fsanitize=leak) - add_link_options(-fsanitize=leak) - message(STATUS "Enabled Leak Sanitizer") -endif(LSAN) +if(MSAN) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + add_compile_options(/fsanitize=memory) + else() + add_compile_options(-fsanitize=memory) + add_link_options(-fsanitize=memory) + endif() + message(STATUS "Enabled Memory Sanitizer") +else(MSAN) + message(STATUS "Disabled Memory Sanitizer") +endif(MSAN) -if (TSAN) +if(TSAN) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + add_compile_options(/fsanitize=thread) + message(STATUS "See MSVC sanitizers: https://learn.microsoft.com/en-us/cpp/sanitizers") + else() add_compile_options(-fsanitize=thread) add_link_options(-fsanitize=thread) - message(STATUS "Enabled Thread Sanitizer") + endif() + message(STATUS "Enabled Thread Sanitizer") +else(TSAN) + message(STATUS "Disabled Thread Sanitizer") endif(TSAN) + +if(UBSAN OR LSAN OR ASAN OR MSAN OR TSAN) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + else() + add_compile_options(-fno-omit-frame-pointer) + add_link_options(-fno-omit-frame-pointer) + endif() +endif() + +if(RTC_C) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + add_compile_options(/RTCc) + add_compile_definitions(_ALLOW_RTCc_IN_STL) + message(STATUS "Enabled Runtime Check Conversions") + else() + message(WARNING "Runtime Check Conversions are not enabled for ${CMAKE_CXX_COMPILER_ID}") + endif() +endif(RTC_C) + +if(RTC_S) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + add_compile_options(/RTCs) + message(STATUS "Enabled Runtime Check Stack") + else() + message(WARNING "Runtime Check Stack is not enabled for ${CMAKE_CXX_COMPILER_ID}") + endif() +endif(RTC_S) + +if(RTC_U) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + add_compile_options(/RTCu) + message(STATUS "Enabled Runtime Check Uninitialized") + else() + message(WARNING "Runtime Check Uninitialized is not enabled for ${CMAKE_CXX_COMPILER_ID}") + endif() +endif(RTC_U) diff --git a/cmake/toolchain/x86_64-linux-gcc16.cmake b/cmake/toolchain/x86_64-linux-gcc16.cmake new file mode 100644 index 00000000..167574ef --- /dev/null +++ b/cmake/toolchain/x86_64-linux-gcc16.cmake @@ -0,0 +1,19 @@ +# the name of the target operating system +set(CMAKE_SYSTEM_NAME Linux) + +# which compilers to use for C and C++ +set(CMAKE_C_COMPILER gcc-16) +set(CMAKE_CXX_COMPILER g++-16) +set(CMAKE_C_FLAGS -m64) +set(CMAKE_CXX_FLAGS -m64) + +# where is the target environment located +set(CMAKE_FIND_ROOT_PATH "${CMAKE_PREFIX_PATH}") + +# adjust the default behavior of the FIND_XXX() commands: +# search programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) + +# search headers and libraries in the target environment +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/cmake/toolchain/x86_64-windows-clang.cmake b/cmake/toolchain/x86_64-windows-clang.cmake new file mode 100644 index 00000000..03f6e847 --- /dev/null +++ b/cmake/toolchain/x86_64-windows-clang.cmake @@ -0,0 +1,22 @@ +# the name of the target operating system +set(CMAKE_SYSTEM_NAME Windows) + +# which compilers to use for C and C++ +set(CMAKE_C_COMPILER clang) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_C_FLAGS -m64) +set(CMAKE_CXX_FLAGS -m64) + +# where is the target environment located +set(CMAKE_FIND_ROOT_PATH "${CMAKE_PREFIX_PATH}") + +# adjust the default behavior of the FIND_XXX() commands: +# search programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) + +# search headers and libraries in the target environment +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +# Workaround for "libxml2.a(dict.c.obj):dict.c:(.text+0x1226): undefined reference to `BCryptGenRandom'" +set(LIBXML_WINLIBS bcrypt) diff --git a/cmake/toolchain/x86_64-windows-gcc.cmake b/cmake/toolchain/x86_64-windows-gcc.cmake new file mode 100644 index 00000000..b366f93a --- /dev/null +++ b/cmake/toolchain/x86_64-windows-gcc.cmake @@ -0,0 +1,22 @@ +# the name of the target operating system +set(CMAKE_SYSTEM_NAME Windows) + +# which compilers to use for C and C++ +set(CMAKE_C_COMPILER gcc) +set(CMAKE_CXX_COMPILER g++) +set(CMAKE_C_FLAGS -m64) +set(CMAKE_CXX_FLAGS -m64) + +# where is the target environment located +set(CMAKE_FIND_ROOT_PATH "${CMAKE_PREFIX_PATH}") + +# adjust the default behavior of the FIND_XXX() commands: +# search programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) + +# search headers and libraries in the target environment +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +# Workaround for "libxml2.a(dict.c.obj):dict.c:(.text+0x1226): undefined reference to `BCryptGenRandom'" +set(LIBXML_WINLIBS bcrypt) diff --git a/cmake/warnings.cmake b/cmake/warnings.cmake new file mode 100644 index 00000000..c554b798 --- /dev/null +++ b/cmake/warnings.cmake @@ -0,0 +1,17 @@ +# Enables compiler warnings + +option(UTAP_WARNINGS "UTAP Compiler Warnings" ON) +if (UTAP_WARNINGS) + set(UTAP_COMMON_WARN -Wpedantic -Wall -Wextra -Wimplicit-fallthrough -Werror=vla) + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(UTAP_WARN ${UTAP_COMMON_WARN} -Wconversion -Wno-sign-conversion) + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(UTAP_WARN ${UTAP_COMMON_WARN} -Wconversion -Wno-sign-conversion) + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + set(UTAP_WARN ${UTAP_COMMON_WARN}) + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(UTAP_WARN /W4) + else () + message(WARNING "Failed to enable warnings for ${CMAKE_CXX_COMPILER_ID}") + endif () +endif () diff --git a/coverage-gcovr.sh b/coverage-gcovr.sh new file mode 100755 index 00000000..bcc7148c --- /dev/null +++ b/coverage-gcovr.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -e + +BUILD_DIR=build-coverage-gcov +COVERAGE_DIR="${BUILD_DIR}/coverage_report" + +mkdir -p "$COVERAGE_DIR" + +cmake --preset coverage +cmake --build --preset coverage +ctest --preset coverage +gcovr --root . "$BUILD_DIR" --html --html-details -o "$COVERAGE_DIR/index.html" +xdg-open "$COVERAGE_DIR/index.html" diff --git a/coverage-lcov.sh b/coverage-lcov.sh new file mode 100755 index 00000000..47548301 --- /dev/null +++ b/coverage-lcov.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -e + +BUILD_DIR=build-coverage-gcov +COVERAGE_INFO="${BUILD_DIR}/coverage.info" +COVERAGE_DIR="${BUILD_DIR}/coverage_report" + +cmake --preset coverage +cmake --build --preset coverage +lcov --zerocounters --directory "$BUILD_DIR" +ctest --preset coverage +lcov --capture --directory "$BUILD_DIR" --output-file "$COVERAGE_INFO" +lcov --remove "$COVERAGE_INFO" '/usr/*' --output-file "$COVERAGE_INFO" +genhtml "$COVERAGE_INFO" --output-directory "$COVERAGE_DIR" +xdg-open "$COVERAGE_DIR/index.html" diff --git a/coverage-llvm.sh b/coverage-llvm.sh new file mode 100755 index 00000000..b179443a --- /dev/null +++ b/coverage-llvm.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -e + +BUILD_DIR=build-coverage-llvm +COVERAGE_DIR="${BUILD_DIR}/coverage_report" +PROFDATA="${BUILD_DIR}/coverage.profdata" + +mkdir -p "$COVERAGE_DIR" + +cmake -DCMAKE_TOOLCHAIN_FILE=$PWD/cmake/toolchain/x86_64-linux-clang.cmake --preset coverage-llvm +cmake --build --preset coverage-llvm + +# each test binary gets its own raw profile (keyed by pid), otherwise they clobber +# one another since they'd all default to writing "default.profraw" +rm -f "$BUILD_DIR"/test/coverage-*.profraw +LLVM_PROFILE_FILE="$PWD/$BUILD_DIR/test/coverage-%p.profraw" ctest --preset coverage-llvm + +llvm-profdata merge -sparse "$BUILD_DIR"/test/coverage-*.profraw -o "$PROFDATA" + +# only target_coverage()-linked binaries (e.g. libUTAP.so) carry the __llvm_covmap +# section; the test executables themselves are not instrumented, so discover the +# actual instrumented binaries instead of assuming which ones they are +mapfile -t OBJECTS < <( + find "$BUILD_DIR" -path "$BUILD_DIR/_deps" -prune -o \ + -type f \( -executable -o -name "*.so*" \) -print | + while read -r f; do + readelf -S "$f" 2>/dev/null | grep -q __llvm_covmap && echo "$f" + done +) +OBJECT_ARGS=() +for obj in "${OBJECTS[@]:1}"; do + OBJECT_ARGS+=(-object "$obj") +done + +llvm-cov show "${OBJECTS[0]}" "${OBJECT_ARGS[@]}" \ + -instr-profile="$PROFDATA" \ + -format=html -output-dir="$COVERAGE_DIR" \ + -show-mcdc -show-branches=count \ + -ignore-filename-regex='(_deps|/test/)/' +xdg-open "$COVERAGE_DIR/index.html" diff --git a/examples/compile-with-getlibs.sh b/examples/compile-with-getlibs.sh index 67c9f294..44097a39 100755 --- a/examples/compile-with-getlibs.sh +++ b/examples/compile-with-getlibs.sh @@ -11,7 +11,7 @@ function show_vars() { # Absolute path to the example directory: EXAMPLE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Path to UTAP library source directory: -[ -n "$UTAP_SRC" ] || UTAP_SRC=${EXAMPLE_DIR%/*} +[ -n "$UTAP_SRC" ] || UTAP_SRC=$(dirname "$EXAMPLE_DIR") # Figure out the native host target (architecture and kernel); if [ -z "$TARGET" ] ; then diff --git a/getlibs.sh b/getlibs.sh index 1fe48ffd..3e2c3220 100755 --- a/getlibs.sh +++ b/getlibs.sh @@ -13,11 +13,10 @@ LIBXML2_Z="${LIBXML2}.tar.xz" LIBXML2_URL="https://people.cs.aau.dk/~marius/mirrors/libxml2/${LIBXML2_Z}" LIBXML2_SHA256=a2c9ae7b770da34860050c309f903221c67830c86e4a7e760692b803df95143a - -DOCTEST=doctest-2.4.12 +DOCTEST=doctest-2.5.3 DOCTEST_Z="${DOCTEST}.tar.gz" DOCTEST_URL="https://github.com/doctest/doctest/archive/refs/tags/v${DOCTEST#doctest-}.tar.gz" -DOCTEST_SHA256=73381c7aa4dee704bd935609668cf41880ea7f19fa0504a200e13b74999c2d70 +DOCTEST_SHA256=174ebc4e769928959614789c5b4e9c3d0a0f81a62bb608756b127bfebfb21331 BISON=bison-3.8.2 BISON_Z="${BISON}.tar.xz" @@ -121,7 +120,6 @@ for target in "$@" ; do echo -e "${BW}${target}: Configuring ${DOCTEST}${NC}" cmake -S "$SOURCE/$DOCTEST" -B "$BUILD" -DCMAKE_TOOLCHAIN_FILE="$PROJECT_DIR/cmake/toolchain/${target}.cmake" \ -DCMAKE_PREFIX_PATH="$LIBS" -DCMAKE_INSTALL_PREFIX="$LIBS" -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ -DDOCTEST_WITH_TESTS=OFF -DDOCTEST_WITH_MAIN_IN_STATIC_LIB=ON -DDOCTEST_USE_STD_HEADERS=OFF echo -e "${BW}${target}: Building ${DOCTEST}${NC}" cmake --build "$BUILD" diff --git a/include/utap/AbstractBuilder.hpp b/include/utap/AbstractBuilder.hpp index 1bea1818..5c9acf16 100644 --- a/include/utap/AbstractBuilder.hpp +++ b/include/utap/AbstractBuilder.hpp @@ -121,7 +121,7 @@ class AbstractBuilder : public ParserBuilder // 1 epxr,1sync,1expr void proc_select(std::string_view id) override; void proc_guard() override; - void proc_sync(Constants::Synchronisation type) override; // 1 expr + void proc_sync(Sync type) override; // 1 expr void proc_update() override; void proc_prob() override; /************************************************************ @@ -132,7 +132,7 @@ class AbstractBuilder : public ParserBuilder void instance_name_begin(std::string_view name) override; void instance_name_end(std::string_view name, uint32_t arguments) override; void proc_message(std::string_view from, std::string_view to, const int loc, const bool pch) override; - void proc_message(Constants::Synchronisation type) override; // 1 expr + void proc_message(Sync type) override; // 1 expr void proc_condition(const std::vector& anchors, const int loc, const bool pch, const bool hot) override; void proc_condition() override; // Label @@ -187,12 +187,12 @@ class AbstractBuilder : public ParserBuilder void expr_pre_increment() override; // 1 expr void expr_post_decrement() override; // 1 expr void expr_pre_decrement() override; // 1 expr - void expr_assignment(Constants::Kind op) override; // 2 expr - void expr_unary(Constants::Kind unaryop) override; // 1 expr - void expr_binary(Constants::Kind binaryop) override; // 2 expr - void expr_nary(Constants::Kind, uint32_t num) override; + void expr_assignment(Kind op) override; // 2 expr + void expr_unary(Kind unaryop) override; // 1 expr + void expr_binary(Kind binaryop) override; // 2 expr + void expr_nary(Kind, uint32_t num) override; void expr_scenario(std::string_view name) override; - void expr_ternary(Constants::Kind ternaryop, bool firstMissing) override; // 3 expr + void expr_ternary(Kind ternaryop, bool firstMissing) override; // 3 expr void expr_inline_if() override; // 3 expr void expr_comma() override; // 2 expr void expr_dot(std::string_view) override; // 1 expr @@ -204,15 +204,15 @@ class AbstractBuilder : public ParserBuilder void expr_sum_begin(std::string_view name) override; void expr_sum_end(std::string_view name) override; - void expr_proba_qualitative(Constants::Kind, Constants::Kind, double) override; - void expr_proba_quantitative(Constants::Kind) override; - void expr_proba_compare(Constants::Kind, Constants::Kind) override; + void expr_proba_qualitative(Kind, Kind, double) override; + void expr_proba_quantitative(Kind) override; + void expr_proba_compare(Kind, Kind) override; void expr_proba_expected(std::string_view identifier) override; void expr_simulate(int no_of_exprs, bool = false, int = 0) override; - void expr_builtin_function1(Constants::Kind) override; - void expr_builtin_function2(Constants::Kind) override; - void expr_builtin_function3(Constants::Kind) override; - void expr_optimize_exp(Constants::Kind, PRICETYPE, Constants::Kind) override; + void expr_builtin_function1(Kind) override; + void expr_builtin_function2(Kind) override; + void expr_builtin_function3(Kind) override; + void expr_optimize_exp(Kind, PriceType, Kind) override; void expr_load_strategy() override; void expr_save_strategy(std::string_view strategy_name) override; @@ -224,6 +224,8 @@ class AbstractBuilder : public ParserBuilder void expr_MITL_conj() override; void expr_MITL_next() override; void expr_MITL_atom() override; + void expr_MITL_diamond(int, int) override; + void expr_MITL_box(int, int) override; void expr_optimize(int, int, int, int) override; /************************************************************ diff --git a/include/utap/DocumentBuilder.hpp b/include/utap/DocumentBuilder.hpp index 1df120cb..9debdb48 100644 --- a/include/utap/DocumentBuilder.hpp +++ b/include/utap/DocumentBuilder.hpp @@ -94,8 +94,8 @@ class DocumentBuilder : public StatementBuilder Declarations* getCurrentDeclarationBlock(); - Variable* addVariable(Type type, std::string_view name, Expression init, position_t pos) override; - bool addFunction(Type type, std::string_view name, position_t pos) override; + Variable* add_variable(Type type, std::string_view name, Expression init, position_t pos) override; + bool add_function(Type type, std::string_view name, position_t pos) override; void addSelectSymbolToFrame(std::string_view name, Frame&, position_t pos); @@ -122,7 +122,7 @@ class DocumentBuilder : public StatementBuilder void proc_edge_end(std::string_view from = {}, std::string_view to = {}) override; void proc_select(std::string_view id) override; void proc_guard() override; - void proc_sync(Constants::Synchronisation type) override; + void proc_sync(Sync type) override; void proc_update() override; void proc_prob() override; void instantiation_begin(std::string_view, uint32_t, std::string_view) override; @@ -142,7 +142,7 @@ class DocumentBuilder : public StatementBuilder void instance_name_begin(std::string_view name) override; void instance_name_end(std::string_view name, uint32_t arguments) override; void proc_message(std::string_view from, std::string_view to, const int loc, const bool pch) override; - void proc_message(Constants::Synchronisation type) override; + void proc_message(Sync type) override; void proc_condition(const std::vector& anchors, const int loc, const bool pch, const bool hot) override; void proc_condition() override; // Label diff --git a/include/utap/ExpressionBuilder.hpp b/include/utap/ExpressionBuilder.hpp index 6b7a460a..3dc37a53 100644 --- a/include/utap/ExpressionBuilder.hpp +++ b/include/utap/ExpressionBuilder.hpp @@ -199,13 +199,13 @@ class ExpressionBuilder : public AbstractBuilder void expr_pre_increment() override; void expr_post_decrement() override; void expr_pre_decrement() override; - void expr_assignment(Constants::Kind op) override; - void expr_unary(Constants::Kind unaryop) override; - void expr_binary(Constants::Kind binaryop) override; - void expr_nary(Constants::Kind op, uint32_t num) override; + void expr_assignment(Kind op) override; + void expr_unary(Kind unaryop) override; + void expr_binary(Kind binaryop) override; + void expr_nary(Kind op, uint32_t num) override; void expr_scenario(std::string_view name) override; Expression exprScenario(); - void expr_ternary(Constants::Kind ternaryop, bool firstMissing) override; + void expr_ternary(Kind ternaryop, bool firstMissing) override; void expr_inline_if() override; void expr_comma() override; void expr_dot(std::string_view) override; @@ -217,14 +217,14 @@ class ExpressionBuilder : public AbstractBuilder void expr_sum_begin(std::string_view name) override; void expr_sum_end(std::string_view name) override; - void expr_proba_qualitative(Constants::Kind, Constants::Kind, double) override; - void expr_proba_quantitative(Constants::Kind) override; - void expr_proba_compare(Constants::Kind, Constants::Kind) override; + void expr_proba_qualitative(Kind, Kind, double) override; + void expr_proba_quantitative(Kind) override; + void expr_proba_compare(Kind, Kind) override; void expr_proba_expected(std::string_view) override; - void expr_builtin_function1(Constants::Kind) override; - void expr_builtin_function2(Constants::Kind) override; - void expr_builtin_function3(Constants::Kind) override; - void expr_optimize_exp(Constants::Kind, PRICETYPE, Constants::Kind) override; + void expr_builtin_function1(Kind) override; + void expr_builtin_function2(Kind) override; + void expr_builtin_function3(Kind) override; + void expr_optimize_exp(Kind, PriceType, Kind) override; void expr_save_strategy(std::string_view strategy_name) override; void expr_load_strategy() override; diff --git a/include/utap/PrettyPrinter.hpp b/include/utap/PrettyPrinter.hpp index fc5b2f71..21492e5f 100644 --- a/include/utap/PrettyPrinter.hpp +++ b/include/utap/PrettyPrinter.hpp @@ -50,7 +50,7 @@ class PrettyPrinter : public AbstractBuilder uint32_t level{}; void indent(); - void indent(std::string& s); + void indent(std::string& s) const; public: PrettyPrinter(std::ostream& stream); @@ -114,7 +114,7 @@ class PrettyPrinter : public AbstractBuilder void proc_location_init(std::string_view id) override; void proc_select(std::string_view id) override; void proc_guard() override; - void proc_sync(Constants::Synchronisation type) override; + void proc_sync(Sync type) override; void proc_update() override; void proc_edge_begin(std::string_view source, std::string_view target, const bool control); void proc_edge_begin(std::string_view source, std::string_view target, const bool control, @@ -135,12 +135,12 @@ class PrettyPrinter : public AbstractBuilder void expr_pre_increment() override; void expr_post_decrement() override; void expr_pre_decrement() override; - void expr_assignment(Constants::Kind op) override; - void expr_unary(Constants::Kind op) override; - void expr_binary(Constants::Kind op) override; - void expr_nary(Constants::Kind op, uint32_t num) override; + void expr_assignment(Kind op) override; + void expr_unary(Kind op) override; + void expr_binary(Kind op) override; + void expr_nary(Kind op, uint32_t num) override; void expr_scenario(std::string_view name) override; - void expr_ternary(Constants::Kind op, bool firstMissing) override; + void expr_ternary(Kind op, bool firstMissing) override; void expr_inline_if() override; void expr_comma() override; void expr_dot(std::string_view) override; @@ -151,13 +151,13 @@ class PrettyPrinter : public AbstractBuilder void expr_exists_end(std::string_view name) override; void expr_sum_begin(std::string_view name) override; void expr_sum_end(std::string_view name) override; - void expr_proba_quantitative(Constants::Kind) override; + void expr_proba_quantitative(Kind) override; void expr_MITL_diamond(int, int) override; void expr_MITL_box(int, int) override; void expr_simulate(int no_of_expr, bool filter_prop, int max_accept_runs) override; - void expr_builtin_function1(Constants::Kind kind) override; - void expr_builtin_function2(Constants::Kind kind) override; - void expr_builtin_function3(Constants::Kind kind) override; + void expr_builtin_function1(Kind kind) override; + void expr_builtin_function2(Kind kind) override; + void expr_builtin_function3(Kind kind) override; void before_update() override; void after_update() override; void instantiation_begin(std::string_view, uint32_t, std::string_view) override; diff --git a/include/utap/StatementBuilder.hpp b/include/utap/StatementBuilder.hpp index 5d6abec8..b0de8790 100644 --- a/include/utap/StatementBuilder.hpp +++ b/include/utap/StatementBuilder.hpp @@ -58,11 +58,11 @@ class StatementBuilder : public ExpressionBuilder /** path to libraries*/ std::vector libpaths; - virtual Variable* addVariable(Type type, std::string_view name, Expression init, position_t pos) = 0; - virtual bool addFunction(Type type, std::string_view name, position_t pos) = 0; + virtual Variable* add_variable(Type type, std::string_view name, Expression init, position_t pos) = 0; + virtual bool add_function(Type type, std::string_view name, position_t pos) = 0; - static void collectDependencies(std::set&, const Expression&); - static void collectDependencies(std::set&, const Type&); + static void collect_dependencies(std::set&, const Expression&); + static void collect_dependencies(std::set&, const Type&); public: explicit StatementBuilder(Document&, std::vector libpaths = {}); @@ -95,9 +95,9 @@ class StatementBuilder : public ExpressionBuilder void while_end() override; void do_while_begin() override; void do_while_end() override; - void if_begin() override {}; - void if_condition() override {}; - void if_then() override {}; + void if_begin() override; + void if_condition() override; + void if_then() override; void if_end(bool) override; void expr_statement() override; void return_statement(bool) override; diff --git a/include/utap/TypeChecker.hpp b/include/utap/TypeChecker.hpp index 889853e4..7b3728f4 100644 --- a/include/utap/TypeChecker.hpp +++ b/include/utap/TypeChecker.hpp @@ -144,7 +144,7 @@ class TypeChecker : public DocumentVisitor, public AbstractStatementVisitor bool checkBound(const Expression& expr); bool checkPredicate(const Expression& expr); bool checkProbBound(const Expression& expr); - bool checkUntilCond(Constants::Kind kind, const Expression& expr); + bool checkUntilCond(Kind kind, const Expression& expr); bool checkMonitoredExpr(const Expression& expr); bool checkPathQuant(const Expression& expr); bool checkAggregationOp(const Expression& expr); diff --git a/include/utap/builder.hpp b/include/utap/builder.hpp index c79b6916..e123377c 100644 --- a/include/utap/builder.hpp +++ b/include/utap/builder.hpp @@ -79,19 +79,6 @@ class TypeException : public std::logic_error class ParserBuilder { public: - /********************************************************************* - * Type prefix which can be applied in front of some type. - */ - enum class TypePrefix : uint8_t { - NONE = 0, - CONST = 1, - URGENT = 2, - BROADCAST = 4, - URGENT_BROADCAST = 6, - SYSTEM_META = 8, - HYBRID = 16 - }; - std::vector lscTemplateNames; virtual ~ParserBuilder() noexcept = default; @@ -253,7 +240,7 @@ class ParserBuilder virtual void proc_edge_end(std::string_view from, std::string_view to) = 0; virtual void proc_select(std::string_view id) = 0; // 1 expr virtual void proc_guard() = 0; // 1 expr - virtual void proc_sync(Constants::Synchronisation type) = 0; // 1 expr + virtual void proc_sync(Sync type) = 0; // 1 expr virtual void proc_update() = 0; // 1 expr virtual void proc_prob() = 0; virtual void proc_branchpoint(std::string_view name) = 0; @@ -265,7 +252,7 @@ class ParserBuilder virtual void instance_name_begin(std::string_view name) = 0; virtual void instance_name_end(std::string_view name, uint32_t arguments) = 0; virtual void proc_message(std::string_view from, std::string_view to, const int loc, const bool pch) = 0; - virtual void proc_message(Constants::Synchronisation type) = 0; + virtual void proc_message(Sync type) = 0; virtual void proc_condition(const std::vector& anchors, const int loc, const bool pch, const bool hot) = 0; virtual void proc_condition() = 0; // 1 expr @@ -330,13 +317,12 @@ class ParserBuilder virtual void expr_pre_increment() = 0; // 1 expr virtual void expr_post_decrement() = 0; // 1 expr virtual void expr_pre_decrement() = 0; // 1 expr - virtual void expr_assignment(Constants::Kind op) = 0; // 2 expr - virtual void expr_unary(Constants::Kind unaryop) = 0; // 1 expr - virtual void expr_binary(Constants::Kind binaryop) = 0; // 2 expr - virtual void expr_nary(Constants::Kind, uint32_t num) = 0; // n expr + virtual void expr_assignment(Kind op) = 0; // 2 expr + virtual void expr_unary(Kind unaryop) = 0; // 1 expr + virtual void expr_binary(Kind binaryop) = 0; // 2 expr + virtual void expr_nary(Kind, uint32_t num) = 0; // n expr virtual void expr_scenario(std::string_view name) = 0; // LSC - virtual void expr_ternary(Constants::Kind ternaryop, - bool firstMissing = false) = 0; // 3 expr + virtual void expr_ternary(Kind ternaryop, bool firstMissing = false) = 0; // 3 expr virtual void expr_inline_if() = 0; // 3 expr virtual void expr_comma() = 0; // 2 expr virtual void expr_dot(std::string_view) = 0; // 1 expr @@ -349,19 +335,17 @@ class ParserBuilder virtual void expr_sum_end(std::string_view name) = 0; // Extensions for SMC: - virtual void expr_proba_qualitative(Constants::Kind, Constants::Kind, double) = 0; ///< estimate Pr - virtual void expr_proba_quantitative(Constants::Kind) = 0; ///< evaluate if Pr >= value - virtual void expr_proba_compare(Constants::Kind, Constants::Kind) = 0; ///< compare two Prs + virtual void expr_proba_qualitative(Kind, Kind, double) = 0; ///< estimate Pr + virtual void expr_proba_quantitative(Kind) = 0; ///< evaluate if Pr >= value + virtual void expr_proba_compare(Kind, Kind) = 0; ///< compare two Prs virtual void expr_proba_expected(std::string_view identifier) = 0; ///< estimate mean value virtual void expr_simulate(int nb_of_exprs, bool filter_prop = false, int max_accepting_runs = 0) = 0; - virtual void expr_builtin_function1(Constants::Kind) = 0; - virtual void expr_builtin_function2(Constants::Kind) = 0; - virtual void expr_builtin_function3(Constants::Kind) = 0; + virtual void expr_builtin_function1(Kind) = 0; + virtual void expr_builtin_function2(Kind) = 0; + virtual void expr_builtin_function3(Kind) = 0; // Extensions for learning: - enum PRICETYPE { TIMEPRICE, EXPRPRICE, PROBAPRICE }; - virtual void expr_optimize_exp(Constants::Kind, PRICETYPE, - Constants::Kind) = 0; ///< minimize/maximize expected value query + virtual void expr_optimize_exp(Kind, PriceType, Kind) = 0; ///< minimize/maximize expected value query virtual void expr_load_strategy() = 0; virtual void expr_save_strategy(std::string_view strategy_name) = 0; @@ -461,8 +445,6 @@ TypeException strategy_not_declared_error(std::string_view name); TypeException unknown_dynamic_template_error(std::string_view name); TypeException shadows_a_variable_warning(std::string_view name); -} // namespace UTAP - /** * Parse a file in the XTA format, reporting the document to the given * implementation of the the ParserBuilder interface and reporting @@ -470,9 +452,9 @@ TypeException shadows_a_variable_warning(std::string_view name); * is used; otherwise the 3.x syntax is used. On success, this * function returns with a positive value. */ -int32_t parse_XTA(FILE*, UTAP::ParserBuilder&, bool newxta); +int32_t parse_XTA(FILE*, ParserBuilder&, bool newxta); -int32_t parse_XTA(const char*, UTAP::ParserBuilder&, bool newxta); +int32_t parse_XTA(const char*, ParserBuilder&, bool newxta); /** * Parse a buffer in the XTA format, reporting the document to the given @@ -481,7 +463,7 @@ int32_t parse_XTA(const char*, UTAP::ParserBuilder&, bool newxta); * is used; otherwise the 3.x syntax is used. On success, this * function returns with a positive value. */ -int32_t parse_XTA(const char*, UTAP::ParserBuilder&, bool newxta, UTAP::XTAPart part, std::string_view xpath); +int32_t parse_XTA(const char*, ParserBuilder&, bool newxta, XTAPart part, std::string_view xpath); /** * Parse a buffer in the XML format, reporting the document to the given @@ -490,7 +472,7 @@ int32_t parse_XTA(const char*, UTAP::ParserBuilder&, bool newxta, UTAP::XTAPart * is used; otherwise the 3.x syntax is used. On success, this * function returns with a positive value. */ -int32_t parse_XML_buffer(const char* buffer, UTAP::ParserBuilder&, bool newxta); +int32_t parse_XML_buffer(const char* buffer, ParserBuilder&, bool newxta); /** * Parse the file with the given name assuming it is in the XML @@ -500,21 +482,22 @@ int32_t parse_XML_buffer(const char* buffer, UTAP::ParserBuilder&, bool newxta); * otherwise the 3.x syntax is used. On success, this function returns * with a positive value. */ -int32_t parse_XML_file(const std::filesystem::path& path, UTAP::ParserBuilder&, bool newxta); +int32_t parse_XML_file(const std::filesystem::path& path, ParserBuilder&, bool newxta); -int32_t parse_XML_fd(int fd, UTAP::ParserBuilder& pb, bool newxta); +int32_t parse_XML_fd(int fd, ParserBuilder& pb, bool newxta); /** * Parse properties from a buffer. The properties are reported using * the given ParserBuilder and errors are reported using the * ErrorHandler. */ -int32_t parse_property(const char* buffer, UTAP::ParserBuilder& aParserBuilder, const std::string& xpath = {}); +int32_t parse_property(const char* buffer, ParserBuilder& aParserBuilder, const std::string& xpath = {}); /** * Parse properties from a file. The properties are reported using the * given ParserBuilder and errors are reported using the ErrorHandler. */ -int32_t parse_property(FILE*, UTAP::ParserBuilder& aParserBuilder); +int32_t parse_property(FILE*, ParserBuilder& aParserBuilder); +} // namespace UTAP #endif /* UTAP_BUILDER_HH */ diff --git a/include/utap/common.hpp b/include/utap/common.hpp index 41eb2b0c..bb210743 100644 --- a/include/utap/common.hpp +++ b/include/utap/common.hpp @@ -1,7 +1,7 @@ // -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- /* libutap - Uppaal Timed Automata Parser. - Copyright (C) 2020 Aalborg University. + Copyright (C) 2020-2026 Aalborg University. Copyright (C) 2002-2006 Uppsala University and Aalborg University. This library is free software; you can redistribute it and/or @@ -24,7 +24,9 @@ #define UTAP_COMMON_HH namespace UTAP { -namespace Constants { + +//TODO: upgrade to `using enum` from C++20 +namespace KindNames { enum Kind { PLUS, MINUS, @@ -289,39 +291,62 @@ enum Kind { DYNAMIC_EVAL, PROCESS_VAR, DOUBLE_INV_GUARD, - }; +} // namespace KindNames +using KindNames::Kind; /********************************************************** * Synchronisations: */ -enum Synchronisation { SYNC_QUE, SYNC_BANG, SYNC_CSP }; -} // namespace Constants +namespace SyncNames { enum Sync { QUE, BANG, CSP }; } +using SyncNames::Sync; /** Type for specifying which XTA part to parse (syntax switch) */ +namespace XTAPartNames { enum XTAPart { - S_XTA, // entire document - S_DECLARATION, - S_LOCAL_DECL, - S_INST, - S_SYSTEM, - S_PARAMETERS, - S_INVARIANT, - S_EXPONENTIAL_RATE, - S_SELECT, - S_GUARD, - S_SYNC, - S_ASSIGN, - S_EXPRESSION, - S_EXPRESSION_LIST, - S_PROPERTY, - S_XTA_PROCESS, - S_PROBABILITY, - /*LSC*/ S_INSTANCE_LINE, - S_MESSAGE, - S_UPDATE, - S_CONDITION + XTA, // entire document + DECLARATION, + LOCAL_DECL, + INST, + SYSTEM, + PARAMETERS, + INVARIANT, + EXPONENTIAL_RATE, + SELECT, + GUARD, + SYNC, + ASSIGN, + EXPRESSION, + EXPRESSION_LIST, + PROPERTY, + XTA_PROCESS, + PROBABILITY, + /*LSC*/ INSTANCE_LINE, + MESSAGE, + UPDATE, + CONDITION +}; +} // namespace XTAPartNS +using XTAPartNames::XTAPart; + +/********************************************************************* + * Type prefix which can be applied in front of some type. + */ +namespace TypePrefixNames { +enum TypePrefix { + NONE = 0, + CONST = 1, + URGENT = 2, + BROADCAST = 4, + URGENT_BROADCAST = 6, + SYSTEM_META = 8, + HYBRID = 16 }; +} // namespace TypePrefixNames +using TypePrefixNames::TypePrefix; + +namespace PriceTypeNames { enum PriceType { TIME, EXPR, PROBA }; } +using PriceTypeNames::PriceType; } // namespace UTAP diff --git a/include/utap/document.hpp b/include/utap/document.hpp index 90174656..13183163 100644 --- a/include/utap/document.hpp +++ b/include/utap/document.hpp @@ -460,7 +460,7 @@ struct Resource std::string value; std::optional unit; Resource(std::string name, std::string value, std::optional unit): - name{std::move(name)}, value{std::move(name)}, unit{std::move(unit)} + name{std::move(name)}, value{std::move(value)}, unit{std::move(unit)} {} }; diff --git a/include/utap/expression.hpp b/include/utap/expression.hpp index 9431f313..8d2d23d1 100644 --- a/include/utap/expression.hpp +++ b/include/utap/expression.hpp @@ -69,10 +69,9 @@ namespace UTAP { class Expression { -private: - struct expression_data; - std::shared_ptr data = nullptr; // PIMPL pattern with cheap/shallow copying - Expression(Constants::Kind, const position_t&); + struct Data; + std::shared_ptr data = nullptr; // PIMPL pattern with cheap/shallow copying + Expression(Kind, const position_t&); public: /// Default constructor creates an empty expression. @@ -98,7 +97,7 @@ class Expression Expression clone_deeper(const Frame& frame, const Frame& select = {}) const; /// Returns the kind of the expression. - Constants::Kind get_kind() const; + Kind get_kind() const; /// Returns the number of subexpression. uint32_t get_size() const; @@ -134,7 +133,7 @@ class Expression bool empty() const; /// Returns the synchronisation type of SYNC operations. - Constants::Synchronisation get_sync() const; + Sync get_sync() const; /// Outputs a textual representation of the expression. std::ostream& print(std::ostream& os, bool old = false) const; @@ -214,7 +213,7 @@ class Expression Expression subst(const Symbol&, Expression) const; /// Precedence of expression type, higher precedence goes before low precedence - static int get_precedence(Constants::Kind); + static int get_precedence(Kind); /// Create a CONSTANT expression. static Expression create_constant(int32_t, position_t = {}); @@ -228,22 +227,22 @@ class Expression static Expression create_identifier(const Symbol&, position_t = {}); /// Create a unary expression - static Expression create_unary(Constants::Kind, Expression, position_t = {}, Type = {}); + static Expression create_unary(Kind, Expression, position_t = {}, Type = {}); /** Create a binary expression */ - static Expression create_binary(Constants::Kind, Expression, Expression, position_t = {}, Type = {}); + static Expression create_binary(Kind, Expression, Expression, position_t = {}, Type = {}); /** Create a ternary expression */ - static Expression create_ternary(Constants::Kind, Expression, Expression, Expression, position_t = {}, Type = {}); + static Expression create_ternary(Kind, Expression, Expression, Expression, position_t = {}, Type = {}); /** Create an n-ary expression */ - static Expression create_nary(Constants::Kind, std::vector sub, position_t = {}, Type = {}); + static Expression create_nary(Kind, std::vector sub, position_t = {}, Type = {}); /** Create a DOT expression */ static Expression create_dot(Expression, int32_t index, position_t = {}, Type = {}); /** Create a SYNC expression */ - static Expression create_sync(Expression, Constants::Synchronisation, position_t = {}); + static Expression create_sync(Expression, Sync, position_t = {}); /** Create a DEADLOCK expression */ static Expression create_deadlock(position_t = {}); diff --git a/include/utap/property.hpp b/include/utap/property.hpp index 06ab0369..e0484d65 100644 --- a/include/utap/property.hpp +++ b/include/utap/property.hpp @@ -208,9 +208,9 @@ class PropertyBuilder : public UTAP::StatementBuilder, public std::enable_shared protected: std::list properties{}; // TigaPropertyBuilder assumes stable list and stores pointers. - UTAP::Variable* addVariable(UTAP::Type type, std::string_view name, UTAP::Expression init, + UTAP::Variable* add_variable(UTAP::Type type, std::string_view name, UTAP::Expression init, UTAP::position_t pos) override; - bool addFunction(UTAP::Type type, std::string_view name, UTAP::position_t pos) override; + bool add_function(UTAP::Type type, std::string_view name, UTAP::position_t pos) override; void typeCheck(UTAP::Expression& expr); bool allowProcessReferences() override; diff --git a/include/utap/statement.hpp b/include/utap/statement.hpp index 0af80e31..8403e97a 100644 --- a/include/utap/statement.hpp +++ b/include/utap/statement.hpp @@ -39,7 +39,7 @@ class StatementVisitor; class Statement { public: - virtual ~Statement() noexcept = default; + virtual ~Statement() noexcept; virtual int32_t accept(StatementVisitor&) = 0; virtual bool returns() const = 0; virtual std::ostream& print(std::ostream&, const std::string& indent = {}) const = 0; @@ -55,7 +55,7 @@ class EmptyStatement final : public Statement public: EmptyStatement() = default; int32_t accept(StatementVisitor&) override; - bool returns() const override { return false; } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -65,7 +65,7 @@ class ExprStatement final : public Statement Expression expr; explicit ExprStatement(Expression expr): expr{std::move(expr)} {} int32_t accept(StatementVisitor&) override; - bool returns() const override { return false; } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -75,7 +75,7 @@ class AssertStatement final : public Statement Expression expr; explicit AssertStatement(Expression expr): expr{std::move(expr)} {} int32_t accept(StatementVisitor&) override; - bool returns() const override { return false; } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -87,7 +87,7 @@ class IfStatement final : public Statement std::unique_ptr falseCase; IfStatement(Expression cond, std::unique_ptr trueCase, std::unique_ptr falseCase = nullptr); int32_t accept(StatementVisitor&) override; - bool returns() const override { return trueCase->returns() && falseCase != nullptr && falseCase->returns(); } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -100,7 +100,7 @@ class ForStatement final : public Statement std::unique_ptr stat; ForStatement(Expression init, Expression cond, Expression step, std::unique_ptr statement); int32_t accept(StatementVisitor&) override; - bool returns() const override { return false; } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -118,7 +118,7 @@ class RangeStatement final : public Statement {} const Frame& get_frame() const { return frame; } int32_t accept(StatementVisitor&) override; - bool returns() const override { return false; } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -129,7 +129,7 @@ class WhileStatement final : public Statement std::unique_ptr stat; WhileStatement(Expression condition, std::unique_ptr statement); int32_t accept(StatementVisitor&) override; - bool returns() const override { return false; } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -140,7 +140,7 @@ class DoWhileStatement final : public Statement Expression cond; DoWhileStatement(std::unique_ptr, Expression); int32_t accept(StatementVisitor&) override; - bool returns() const override { return stat->returns(); } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -152,7 +152,7 @@ class CompositeStatement : public Statement using iterator = std::vector>::iterator; CompositeStatement() = default; std::ostream& print(std::ostream&, const std::string& indent) const override; - bool returns() const override { return empty() || back().returns(); } + bool returns() const override; /// pushes the statement to the end of statement list void push(std::unique_ptr stat); /// pops the last statement from the list @@ -163,7 +163,7 @@ class CompositeStatement : public Statement Statement& back(); const_iterator begin() const { return stats.begin(); } const_iterator end() const { return stats.end(); } - bool empty() const { return stats.empty(); } + bool empty() const; iterator begin() { return stats.begin(); } iterator end() { return stats.end(); } @@ -204,7 +204,7 @@ class SwitchStatement : public CompositeStatement Expression cond; SwitchStatement(Expression expr): CompositeStatement{}, cond{std::move(expr)} {} int32_t accept(StatementVisitor& v) override; - bool returns() const override { return false; } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -215,7 +215,7 @@ class CaseStatement final : public Statement std::unique_ptr stat; CaseStatement(Expression value): cond{std::move(value)} {} int32_t accept(StatementVisitor&) override; - bool returns() const override { return false; } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -225,7 +225,7 @@ class DefaultStatement final : public Statement std::unique_ptr stat; DefaultStatement() = default; int32_t accept(StatementVisitor&) override; - bool returns() const override { return false; } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -234,7 +234,7 @@ class BreakStatement final : public Statement public: BreakStatement() = default; int32_t accept(StatementVisitor&) override; - bool returns() const override { return false; } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -243,7 +243,7 @@ class ContinueStatement final : public Statement public: ContinueStatement() = default; int32_t accept(StatementVisitor&) override; - bool returns() const override { return false; } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -251,10 +251,10 @@ class ReturnStatement final : public Statement { public: Expression value; - ReturnStatement() = default; + ReturnStatement(); explicit ReturnStatement(Expression expr): value{std::move(expr)} {} int32_t accept(StatementVisitor& visitor) override; - bool returns() const override { return true; } + bool returns() const override; std::ostream& print(std::ostream&, const std::string& indent) const override; }; @@ -279,22 +279,6 @@ class StatementVisitor virtual int32_t visit_return_statement(ReturnStatement& stat) = 0; }; -inline int32_t EmptyStatement::accept(StatementVisitor& v) { return v.visit_empty_statement(*this); } -inline int32_t ExprStatement::accept(StatementVisitor& v) { return v.visit_expr_statement(*this); } -inline int32_t AssertStatement::accept(StatementVisitor& v) { return v.visit_assert_statement(*this); } -inline int32_t ForStatement::accept(StatementVisitor& v) { return v.visit_for_statement(*this); } -inline int32_t RangeStatement::accept(StatementVisitor& v) { return v.visit_iteration_statement(*this); } -inline int32_t WhileStatement::accept(StatementVisitor& v) { return v.visit_while_statement(*this); } -inline int32_t DoWhileStatement::accept(StatementVisitor& v) { return v.visit_do_while_statement(*this); } -inline int32_t BlockStatement::accept(StatementVisitor& v) { return v.visit_block_statement(*this); } -inline int32_t SwitchStatement::accept(StatementVisitor& v) { return v.visit_switch_statement(*this); } -inline int32_t CaseStatement::accept(StatementVisitor& v) { return v.visit_case_statement(*this); } -inline int32_t DefaultStatement::accept(StatementVisitor& v) { return v.visit_default_statement(*this); } -inline int32_t IfStatement::accept(StatementVisitor& v) { return v.visit_if_statement(*this); } -inline int32_t BreakStatement::accept(StatementVisitor& v) { return v.visit_break_statement(*this); } -inline int32_t ContinueStatement::accept(StatementVisitor& v) { return v.visit_continue_statement(*this); } -inline int32_t ReturnStatement::accept(StatementVisitor& v) { return v.visit_return_statement(*this); } - /// Calls visit_statement on every statement class AbstractStatementVisitor : public StatementVisitor { diff --git a/include/utap/symbols.hpp b/include/utap/symbols.hpp index 0abc848c..03255443 100644 --- a/include/utap/symbols.hpp +++ b/include/utap/symbols.hpp @@ -33,7 +33,6 @@ namespace UTAP { class Frame; -class expression_t; class NoParentException : public std::exception {}; @@ -59,7 +58,6 @@ class NoParentException : public std::exception */ class Symbol { -private: struct Data; std::shared_ptr data{nullptr}; // pImpl pattern @@ -70,22 +68,15 @@ class Symbol public: /// Default constructor Symbol() = default; - Symbol(const Symbol&) = default; + ~Symbol() noexcept; ///< hidden dtor due to pImpl + Symbol(const Symbol&) = default; ///< light/shallow copy + Symbol& operator=(const Symbol&) = default; ///< light/shallow copy Symbol(Symbol&&) = default; - Symbol& operator=(const Symbol&) = default; Symbol& operator=(Symbol&&) = default; - /// Destructor - ~Symbol() noexcept; - - /// Equality operator - bool operator==(const Symbol&) const; - - /// Inequality operator - bool operator!=(const Symbol&) const; - - /// Less-than operator - bool operator<(const Symbol&) const; + bool operator==(const Symbol& other) const { return data == other.data; } + bool operator!=(const Symbol& other) const { return !(*this == other); } + bool operator<(const Symbol& other) const { return data < other.data; } /// Get frame this symbol belongs to Frame get_frame() const; // TODO: consider removing this method (mostly unused) @@ -110,6 +101,7 @@ class Symbol /// Alters the name of this symbol void set_name(std::string); + friend std::ostream& operator<<(std::ostream&, const Symbol&); }; /** @@ -159,10 +151,10 @@ class Frame Frame make_sub(); /// Equality operator - bool operator==(const Frame&) const; + bool operator==(const Frame& other) const { return data == other.data; } /// Inequality operator - bool operator!=(const Frame&) const; + bool operator!=(const Frame& other) const { return !(*this == other); } /// Returns the number of symbols in this frame uint32_t get_size() const; @@ -221,10 +213,9 @@ class Frame /// Creates and returns a new root-frame. static Frame make(); + friend std::ostream& operator<<(std::ostream&, const Frame&); }; -} // namespace UTAP -std::ostream& operator<<(std::ostream& o, const UTAP::Symbol& t); -std::ostream& operator<<(std::ostream& o, const UTAP::Frame& t); +} // namespace UTAP #endif /* UTAP_SYMBOLS_HH */ diff --git a/include/utap/type.hpp b/include/utap/type.hpp index bb84614e..ce66ab2f 100644 --- a/include/utap/type.hpp +++ b/include/utap/type.hpp @@ -93,23 +93,22 @@ class Symbol; */ class Type { -private: struct type_data; std::shared_ptr data; public: - explicit Type(Constants::Kind kind, const position_t& pos, size_t size); + explicit Type(Kind kind, const position_t& pos, size_t size); /// Default constructor creates a null-type. Type() = default; /// Checks if types are equal - bool operator==(const Type&) const; + bool operator==(const Type& other) const { return data == other.data; } /// Checks if types are not equal - bool operator!=(const Type&) const; + bool operator!=(const Type& other) const { return !(*this == other); } /// Returns the kind of type object. - Constants::Kind get_kind() const; + Kind get_kind() const; /** * Returns the position of the type in the input file. This @@ -121,7 +120,7 @@ class Type uint32_t size() const; /// Less-than operator. - bool operator<(const Type&) const; + bool operator<(const Type& other) const { return data < other.data; } /// Returns the \a i'th child. const Type& operator[](uint32_t) const; @@ -176,72 +175,72 @@ class Type std::string declaration() const; /// Shortcut for is(RANGE). - bool is_range() const { return is(Constants::RANGE); } + bool is_range() const { return is(Kind::RANGE); } /// Shortcut for is(INT). - bool is_integer() const { return is(Constants::INT); } + bool is_integer() const { return is(Kind::INT); } /// Shortcut for is(BOOL). - bool is_boolean() const { return is(Constants::BOOL); } + bool is_boolean() const { return is(Kind::BOOL); } /// Shortcut for is(FUNCTION). - bool is_function() const { return is(Constants::FUNCTION); } + bool is_function() const { return is(Kind::FUNCTION); } /// Shortcut for is(FUNCTION_EXTERNAL). - bool is_function_external() const { return is(Constants::FUNCTION_EXTERNAL); } + bool is_function_external() const { return is(Kind::FUNCTION_EXTERNAL); } /// Shortcut for is(PROCESS). - bool is_process() const { return is(Constants::PROCESS); } + bool is_process() const { return is(Kind::PROCESS); } /// Shortcut for is(PROCESS_SET). - bool is_process_set() const { return is(Constants::PROCESS_SET); } + bool is_process_set() const { return is(Kind::PROCESS_SET); } /// Shortcut for is(LOCATION). - bool is_location() const { return is(Constants::LOCATION); } + bool is_location() const { return is(Kind::LOCATION); } /// Shortcut for is(LOCATION_EXPR). - bool is_location_expr() const { return is(Constants::LOCATION_EXPR); } + bool is_location_expr() const { return is(Kind::LOCATION_EXPR); } /// Shortcut for is(INSTANCELINE). - bool is_instance_line() const { return is(Constants::INSTANCE_LINE); } + bool is_instance_line() const { return is(Kind::INSTANCE_LINE); } /// Shortcut for is(BRANCHPOINT). - bool is_branchpoint() const { return is(Constants::BRANCHPOINT); } + bool is_branchpoint() const { return is(Kind::BRANCHPOINT); } /// Shortcut for is(CHANNEL). - bool is_channel() const { return is(Constants::CHANNEL); } + bool is_channel() const { return is(Kind::CHANNEL); } /// Shortcut for is(ARRAY). - bool is_array() const { return is(Constants::ARRAY); } + bool is_array() const { return is(Kind::ARRAY); } /// Shortcut for is(SCALAR). - bool is_scalar() const { return is(Constants::SCALAR); } + bool is_scalar() const { return is(Kind::SCALAR); } /// Shortcut for is(CLOCK). - bool is_clock() const { return is(Constants::CLOCK); } + bool is_clock() const { return is(Kind::CLOCK); } /// Shortcut for is(RECORD). - bool is_record() const { return is(Constants::RECORD); } + bool is_record() const { return is(Kind::RECORD); } /// Shortcut for is(DIFF). - bool is_diff() const { return is(Constants::DIFF); } + bool is_diff() const { return is(Kind::DIFF); } /// Shortcut for is(VOID_TYPE). - bool is_void() const { return is(Constants::VOID_TYPE); } + bool is_void() const { return is(Kind::VOID_TYPE); } /// Shortcut for is(COST). - bool is_cost() const { return is(Constants::COST); } + bool is_cost() const { return is(Kind::COST); } /// Shortcut for is(DOUBLE). - bool is_double() const { return is(Constants::DOUBLE); } + bool is_double() const { return is(Kind::DOUBLE); } /// Shortcut for is(STRING). - bool is_string() const { return is(Constants::STRING); } + bool is_string() const { return is(Kind::STRING); } /// True if the type is a boolean, integer, or location bool is_integral() const { - using namespace Constants; + using namespace KindNames; return is(INT) || is(BOOL) || is(PROCESS_VAR) || is(LOCATION) || is(LOCATION_EXPR); } @@ -249,33 +248,33 @@ class Type * Returns true if this is an invariant, boolean or * integer. Shortcut for isIntegral() || is(INVARIANT). */ - bool is_invariant() const { return is(Constants::INVARIANT) || is_integral(); } + bool is_invariant() const { return is(Kind::INVARIANT) || is_integral(); } /** * Returns true if this is a guard, invariant, boolean or * integer. Shortcut for is(GUARD) || is_invariant(). */ - bool is_guard() const { return is(Constants::GUARD) || is_invariant(); } + bool is_guard() const { return is(Kind::GUARD) || is_invariant(); } /** * Returns true if this is a probability or integer. Shortcut * for is(PROBABILITY) || isInteger(). */ - bool is_probability() const { return is(Constants::PROBABILITY) || is_integer() || is_double() || is_clock(); } + bool is_probability() const { return is(Kind::PROBABILITY) || is_integer() || is_double() || is_clock(); } /** * Returns true if this is a constraint, guard, invariant, * boolean or integer. Shortcut for is(CONSTRAINT) || * is_guard(). */ - bool is_constraint() const { return is(Constants::CONSTRAINT) || is_guard(); } + bool is_constraint() const { return is(Kind::CONSTRAINT) || is_guard(); } /** * Returns true if this is a formula, constraint, guard, * invariant, boolean or integer. Shortcut for is(FORMULA) || * is_constraint(). */ - bool is_formula() const { return is(Constants::FORMULA) || is_constraint(); } + bool is_formula() const { return is(Kind::FORMULA) || is_constraint(); } /** * Removes any leading prefixes, RANGE, REF and LABEL types @@ -305,7 +304,7 @@ class Type /** Returns true if the type has kind \a kind or if type is a * prefix, RANGE or REF type and the getChild().is(kind) * returns true. */ - bool is(Constants::Kind kind) const; + bool is(Kind kind) const; /** Returns true if two types are compatible for equality operator. * Types are compatible if they are structurally @@ -364,7 +363,7 @@ class Type * could be anything and it is the responsibility of the * caller to make sure that the given kind is a valid prefix. */ - Type create_prefix(Constants::Kind kind, position_t = position_t()) const; + Type create_prefix(Kind kind, position_t = position_t()) const; /// Creates a LABEL. Type create_label(std::string_view, position_t = position_t()) const; @@ -373,7 +372,7 @@ class Type static Type create_range(Type primitive, Expression from, Expression till, position_t = position_t()); /// Creates a primitive type - static Type create_primitive(Constants::Kind, position_t = position_t()); + static Type create_primitive(Kind, position_t = position_t()); /// Creates an array type. static Type create_array(Type sub, Type size, position_t = position_t()); @@ -401,9 +400,8 @@ class Type static Type create_instance(const Frame&, position_t = position_t()); /// Creates a new LSC instance type static Type create_LSC_instance(const Frame&, position_t = position_t()); + friend std::ostream& operator<<(std::ostream&, const Type&); }; } // namespace UTAP -std::ostream& operator<<(std::ostream& o, const UTAP::Type& t); - #endif // UTAP_TYPE_HH diff --git a/include/utap/utap.hpp b/include/utap/utap.hpp index 0c0a3810..022abcad 100644 --- a/include/utap/utap.hpp +++ b/include/utap/utap.hpp @@ -32,17 +32,21 @@ #include #include -bool parse_XTA(FILE*, UTAP::Document&, bool newxta); -bool parse_XTA(const char* buffer, UTAP::Document&, bool newxta); -int32_t parse_XML_buffer(const char* buffer, UTAP::Document&, bool newxta, +namespace UTAP { + +bool parse_XTA(FILE*, Document&, bool newxta); +bool parse_XTA(const char* buffer, Document&, bool newxta); +int32_t parse_XML_buffer(const char* buffer, Document&, bool newxta, const std::vector& libpaths = {}); -int32_t parse_XML_file(const std::filesystem::path&, UTAP::Document&, bool newxta, +int32_t parse_XML_file(const std::filesystem::path&, Document&, bool newxta, const std::vector& libpaths = {}); -int32_t parse_XML_fd(int fd, UTAP::Document&, bool newxta, const std::vector& libpaths = {}); -UTAP::expression_t parse_expression(const char* buffer, UTAP::Document&, bool); -int32_t write_XML_file(const char* filename, UTAP::Document& doc); +int32_t parse_XML_fd(int fd, Document&, bool newxta, const std::vector& libpaths = {}); +Expression parse_expression(const char* buffer, Document&, bool); +int32_t write_XML_file(const char* filename, Document& doc); /** returns a string representation of built-in types and constants (see parser.y) */ const char* utap_builtin_declarations(); +} + #endif /* UTAP_HH */ diff --git a/src/AbstractBuilder.cpp b/src/AbstractBuilder.cpp index fbb76c7a..d548627f 100644 --- a/src/AbstractBuilder.cpp +++ b/src/AbstractBuilder.cpp @@ -26,8 +26,7 @@ #include #include -using namespace UTAP; - +namespace UTAP { /* void ParserBuilder::handleWarning(const char* msg, ...) { @@ -73,75 +72,74 @@ void AbstractBuilder::type_channel(TypePrefix) { UNSUPPORTED; } void AbstractBuilder::type_clock(TypePrefix) { UNSUPPORTED; } void AbstractBuilder::type_void() { UNSUPPORTED; } void AbstractBuilder::type_scalar(TypePrefix) { UNSUPPORTED; } -void AbstractBuilder::type_name(TypePrefix, std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::type_struct(TypePrefix, uint32_t fields) { UNSUPPORTED; } +void AbstractBuilder::type_name(TypePrefix, std::string_view) { UNSUPPORTED; } +void AbstractBuilder::type_struct(TypePrefix, uint32_t) { UNSUPPORTED; } void AbstractBuilder::type_array_of_size(uint32_t) { UNSUPPORTED; } void AbstractBuilder::type_array_of_type(uint32_t) { UNSUPPORTED; } -void AbstractBuilder::struct_field(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::struct_field(std::string_view) { UNSUPPORTED; } -void AbstractBuilder::decl_typedef(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::decl_var(std::string_view name, bool init) { UNSUPPORTED; } -void AbstractBuilder::decl_init_list(uint32_t num) { UNSUPPORTED; } -void AbstractBuilder::decl_field_init(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::decl_typedef(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::decl_var(std::string_view, bool) { UNSUPPORTED; } +void AbstractBuilder::decl_init_list(uint32_t) { UNSUPPORTED; } +void AbstractBuilder::decl_field_init(std::string_view) { UNSUPPORTED; } -void AbstractBuilder::gantt_decl_begin(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::gantt_decl_select(std::string_view id) { UNSUPPORTED; } +void AbstractBuilder::gantt_decl_begin(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::gantt_decl_select(std::string_view) { UNSUPPORTED; } void AbstractBuilder::gantt_decl_end() { UNSUPPORTED; } void AbstractBuilder::gantt_entry_begin() { UNSUPPORTED; } -void AbstractBuilder::gantt_entry_select(std::string_view id) { UNSUPPORTED; } +void AbstractBuilder::gantt_entry_select(std::string_view) { UNSUPPORTED; } void AbstractBuilder::gantt_entry_end() { UNSUPPORTED; } void AbstractBuilder::decl_progress(bool) { UNSUPPORTED; } -void AbstractBuilder::decl_parameter(std::string_view name, bool) { UNSUPPORTED; } -void AbstractBuilder::decl_func_begin(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::decl_parameter(std::string_view, bool) { UNSUPPORTED; } +void AbstractBuilder::decl_func_begin(std::string_view) { UNSUPPORTED; } void AbstractBuilder::decl_func_end() { UNSUPPORTED; } -void AbstractBuilder::dynamic_load_lib(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::decl_external_func(std::string_view name, std::string_view alias) { UNSUPPORTED; } +void AbstractBuilder::dynamic_load_lib(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::decl_external_func(std::string_view, std::string_view) { UNSUPPORTED; } -void AbstractBuilder::proc_begin(std::string_view name, const bool isTA, std::string_view type, std::string_view mode) +void AbstractBuilder::proc_begin(std::string_view, const bool, std::string_view, std::string_view) { UNSUPPORTED; } void AbstractBuilder::proc_end() { UNSUPPORTED; } -void AbstractBuilder::proc_location(std::string_view name, bool hasInvariant, bool hasER) { UNSUPPORTED; } -void AbstractBuilder::proc_location_commit(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::proc_location_urgent(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::proc_location_init(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::proc_branchpoint(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::proc_edge_begin(std::string_view from, std::string_view to, const bool control, - std::string_view actname) +void AbstractBuilder::proc_location(std::string_view, bool, bool) { UNSUPPORTED; } +void AbstractBuilder::proc_location_commit(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::proc_location_urgent(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::proc_location_init(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::proc_branchpoint(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::proc_edge_begin(std::string_view, std::string_view, const bool, std::string_view) { UNSUPPORTED; } -void AbstractBuilder::proc_edge_end(std::string_view from, std::string_view to) { UNSUPPORTED; } -void AbstractBuilder::proc_select(std::string_view id) { UNSUPPORTED; } +void AbstractBuilder::proc_edge_end(std::string_view, std::string_view) { UNSUPPORTED; } +void AbstractBuilder::proc_select(std::string_view) { UNSUPPORTED; } void AbstractBuilder::proc_guard() { UNSUPPORTED; } -void AbstractBuilder::proc_sync(Constants::Synchronisation type) { UNSUPPORTED; } +void AbstractBuilder::proc_sync(Sync) { UNSUPPORTED; } void AbstractBuilder::proc_update() { UNSUPPORTED; } void AbstractBuilder::proc_prob() { UNSUPPORTED; } // LSC -void AbstractBuilder::proc_message(Constants::Synchronisation type) { UNSUPPORTED; } +void AbstractBuilder::proc_message(Sync) { UNSUPPORTED; } void AbstractBuilder::proc_instance_line() { UNSUPPORTED; } -void AbstractBuilder::instance_name_begin(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::instance_name_end(std::string_view name, uint32_t arguments) { UNSUPPORTED; } -void AbstractBuilder::instance_name(std::string_view name, bool templ) { UNSUPPORTED; } +void AbstractBuilder::instance_name_begin(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::instance_name_end(std::string_view, uint32_t) { UNSUPPORTED; } +void AbstractBuilder::instance_name(std::string_view, bool) { UNSUPPORTED; } -void AbstractBuilder::proc_message(std::string_view from, std::string_view to, const int loc, const bool pch) +void AbstractBuilder::proc_message(std::string_view, std::string_view, const int, const bool) { UNSUPPORTED; } -void AbstractBuilder::proc_condition(const std::vector& anchors, const int loc, const bool pch, - const bool hot) +void AbstractBuilder::proc_condition(const std::vector&, const int, const bool, + const bool) { UNSUPPORTED; } void AbstractBuilder::proc_condition() { UNSUPPORTED; } -void AbstractBuilder::proc_LSC_update(std::string_view anchor, const int loc, const bool pch) { UNSUPPORTED; } +void AbstractBuilder::proc_LSC_update(std::string_view, const int, const bool) { UNSUPPORTED; } void AbstractBuilder::proc_LSC_update() { UNSUPPORTED; } -void AbstractBuilder::prechart_set(const bool pch) { UNSUPPORTED; } +void AbstractBuilder::prechart_set(const bool) { UNSUPPORTED; } // end LSC void AbstractBuilder::block_begin() { UNSUPPORTED; } @@ -149,8 +147,8 @@ void AbstractBuilder::block_end() { UNSUPPORTED; } void AbstractBuilder::empty_statement() { UNSUPPORTED; } void AbstractBuilder::for_begin() { UNSUPPORTED; } void AbstractBuilder::for_end() { UNSUPPORTED; } -void AbstractBuilder::iteration_begin(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::iteration_end(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::iteration_begin(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::iteration_end(std::string_view) { UNSUPPORTED; } void AbstractBuilder::while_begin() { UNSUPPORTED; } void AbstractBuilder::while_end() { UNSUPPORTED; } @@ -179,45 +177,45 @@ void AbstractBuilder::assert_statement() { UNSUPPORTED; } void AbstractBuilder::expr_true() { UNSUPPORTED; } void AbstractBuilder::expr_false() { UNSUPPORTED; } void AbstractBuilder::expr_double(double) { UNSUPPORTED; } -void AbstractBuilder::expr_string(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::expr_identifier(std::string_view varName) { UNSUPPORTED; } +void AbstractBuilder::expr_string(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::expr_identifier(std::string_view) { UNSUPPORTED; } void AbstractBuilder::expr_nat(int32_t) { UNSUPPORTED; } void AbstractBuilder::expr_call_begin() { UNSUPPORTED; } -void AbstractBuilder::expr_call_end(uint32_t n) { UNSUPPORTED; } +void AbstractBuilder::expr_call_end(uint32_t) { UNSUPPORTED; } void AbstractBuilder::expr_array() { UNSUPPORTED; } void AbstractBuilder::expr_post_increment() { UNSUPPORTED; } void AbstractBuilder::expr_pre_increment() { UNSUPPORTED; } void AbstractBuilder::expr_post_decrement() { UNSUPPORTED; } void AbstractBuilder::expr_pre_decrement() { UNSUPPORTED; } -void AbstractBuilder::expr_assignment(Constants::Kind op) { UNSUPPORTED; } -void AbstractBuilder::expr_unary(Constants::Kind unaryop) { UNSUPPORTED; } -void AbstractBuilder::expr_binary(Constants::Kind binaryop) { UNSUPPORTED; } -void AbstractBuilder::expr_nary(Constants::Kind kind, uint32_t num) { UNSUPPORTED; } +void AbstractBuilder::expr_assignment(Kind) { UNSUPPORTED; } +void AbstractBuilder::expr_unary(Kind) { UNSUPPORTED; } +void AbstractBuilder::expr_binary(Kind) { UNSUPPORTED; } +void AbstractBuilder::expr_nary(Kind, uint32_t) { UNSUPPORTED; } // LSC -void AbstractBuilder::expr_scenario(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::expr_scenario(std::string_view) { UNSUPPORTED; } // end LSC -void AbstractBuilder::expr_ternary(Constants::Kind ternaryop, bool firstMissing) { UNSUPPORTED; } +void AbstractBuilder::expr_ternary(Kind, bool) { UNSUPPORTED; } void AbstractBuilder::expr_inline_if() { UNSUPPORTED; } void AbstractBuilder::expr_comma() { UNSUPPORTED; } void AbstractBuilder::expr_location() { UNSUPPORTED; } void AbstractBuilder::expr_dot(std::string_view) { UNSUPPORTED; } void AbstractBuilder::expr_deadlock() { UNSUPPORTED; } -void AbstractBuilder::expr_forall_begin(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::expr_forall_end(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::expr_sum_begin(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::expr_sum_end(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::expr_forall_begin(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::expr_forall_end(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::expr_sum_begin(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::expr_sum_end(std::string_view) { UNSUPPORTED; } -void AbstractBuilder::expr_builtin_function1(Constants::Kind) { UNSUPPORTED; } -void AbstractBuilder::expr_builtin_function2(Constants::Kind) { UNSUPPORTED; } -void AbstractBuilder::expr_builtin_function3(Constants::Kind) { UNSUPPORTED; } +void AbstractBuilder::expr_builtin_function1(Kind) { UNSUPPORTED; } +void AbstractBuilder::expr_builtin_function2(Kind) { UNSUPPORTED; } +void AbstractBuilder::expr_builtin_function3(Kind) { UNSUPPORTED; } -void AbstractBuilder::expr_simulate(int no_of_exprs, bool, int) { UNSUPPORTED; } -void AbstractBuilder::expr_optimize_exp(Constants::Kind, PRICETYPE, Constants::Kind) { UNSUPPORTED; } +void AbstractBuilder::expr_simulate(int, bool, int) { UNSUPPORTED; } +void AbstractBuilder::expr_optimize_exp(Kind, PriceType, Kind) { UNSUPPORTED; } void AbstractBuilder::expr_load_strategy() { UNSUPPORTED; } -void AbstractBuilder::expr_save_strategy(std::string_view strategy_name) { UNSUPPORTED; } +void AbstractBuilder::expr_save_strategy(std::string_view) { UNSUPPORTED; } void AbstractBuilder::expr_MITL_formula() { UNSUPPORTED; } void AbstractBuilder::expr_MITL_until(int, int) { UNSUPPORTED; } void AbstractBuilder::expr_MITL_release(int, int) { UNSUPPORTED; } @@ -225,14 +223,16 @@ void AbstractBuilder::expr_MITL_disj() { UNSUPPORTED; } void AbstractBuilder::expr_MITL_conj() { UNSUPPORTED; } void AbstractBuilder::expr_MITL_next() { UNSUPPORTED; } void AbstractBuilder::expr_MITL_atom() { UNSUPPORTED; } +void AbstractBuilder::expr_MITL_diamond(int, int) { UNSUPPORTED; } +void AbstractBuilder::expr_MITL_box(int, int) { UNSUPPORTED; } void AbstractBuilder::expr_optimize(int, int, int, int) { UNSUPPORTED; } -void AbstractBuilder::expr_proba_qualitative(Constants::Kind, Constants::Kind, double) { UNSUPPORTED; } -void AbstractBuilder::expr_proba_quantitative(Constants::Kind) { UNSUPPORTED; } -void AbstractBuilder::expr_proba_compare(Constants::Kind, Constants::Kind) { UNSUPPORTED; } +void AbstractBuilder::expr_proba_qualitative(Kind, Kind, double) { UNSUPPORTED; } +void AbstractBuilder::expr_proba_quantitative(Kind) { UNSUPPORTED; } +void AbstractBuilder::expr_proba_compare(Kind, Kind) { UNSUPPORTED; } void AbstractBuilder::expr_proba_expected(std::string_view) { UNSUPPORTED; } -void AbstractBuilder::expr_exists_begin(std::string_view name) { UNSUPPORTED; } -void AbstractBuilder::expr_exists_end(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::expr_exists_begin(std::string_view) { UNSUPPORTED; } +void AbstractBuilder::expr_exists_end(std::string_view) { UNSUPPORTED; } void AbstractBuilder::instantiation_begin(std::string_view, uint32_t, std::string_view) { UNSUPPORTED; } void AbstractBuilder::instantiation_end(std::string_view, uint32_t, std::string_view, uint32_t) { UNSUPPORTED; } @@ -246,7 +246,7 @@ void AbstractBuilder::parse(const char*) { UNSUPPORTED; } // end LSC void AbstractBuilder::done() {} -void AbstractBuilder::handle_expect(std::string_view text) {} +void AbstractBuilder::handle_expect(std::string_view) {} void AbstractBuilder::property() { UNSUPPORTED; } void AbstractBuilder::strategy_declaration(std::string_view) { UNSUPPORTED; } @@ -256,29 +256,29 @@ void AbstractBuilder::imitation(std::string_view) { UNSUPPORTED; } void AbstractBuilder::before_update() { UNSUPPORTED; } void AbstractBuilder::after_update() { UNSUPPORTED; } void AbstractBuilder::chan_priority_begin() { UNSUPPORTED; } -void AbstractBuilder::chan_priority_add(char separator) { UNSUPPORTED; } +void AbstractBuilder::chan_priority_add(char) { UNSUPPORTED; } void AbstractBuilder::chan_priority_default() { UNSUPPORTED; } void AbstractBuilder::proc_priority_inc() { UNSUPPORTED; } void AbstractBuilder::proc_priority(std::string_view) { UNSUPPORTED; } -void AbstractBuilder::decl_dynamic_template(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::decl_dynamic_template(std::string_view) { UNSUPPORTED; } void AbstractBuilder::expr_spawn(int) { UNSUPPORTED; } void AbstractBuilder::expr_exit() { UNSUPPORTED; } void AbstractBuilder::expr_numof() { UNSUPPORTED; } void AbstractBuilder::expr_forall_dynamic_begin(std::string_view, std::string_view) { UNSUPPORTED; } -void AbstractBuilder::expr_forall_dynamic_end(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::expr_forall_dynamic_end(std::string_view ) { UNSUPPORTED; } void AbstractBuilder::expr_exists_dynamic_begin(std::string_view, std::string_view) { UNSUPPORTED; } -void AbstractBuilder::expr_exists_dynamic_end(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::expr_exists_dynamic_end(std::string_view ) { UNSUPPORTED; } void AbstractBuilder::expr_sum_dynamic_begin(std::string_view, std::string_view) { UNSUPPORTED; } -void AbstractBuilder::expr_sum_dynamic_end(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::expr_sum_dynamic_end(std::string_view ) { UNSUPPORTED; } void AbstractBuilder::expr_foreach_dynamic_begin(std::string_view, std::string_view) { UNSUPPORTED; } -void AbstractBuilder::expr_foreach_dynamic_end(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::expr_foreach_dynamic_end(std::string_view) { UNSUPPORTED; } void AbstractBuilder::expr_dynamic_process_expr(std::string_view) { UNSUPPORTED; } void AbstractBuilder::expr_MITL_forall_dynamic_begin(std::string_view, std::string_view) { UNSUPPORTED; } -void AbstractBuilder::expr_MITL_forall_dynamic_end(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::expr_MITL_forall_dynamic_end(std::string_view) { UNSUPPORTED; } void AbstractBuilder::expr_MITL_exists_dynamic_begin(std::string_view, std::string_view) { UNSUPPORTED; } -void AbstractBuilder::expr_MITL_exists_dynamic_end(std::string_view name) { UNSUPPORTED; } +void AbstractBuilder::expr_MITL_exists_dynamic_end(std::string_view) { UNSUPPORTED; } void AbstractBuilder::query_begin() { UNSUPPORTED; } void AbstractBuilder::query_end() { UNSUPPORTED; } @@ -287,7 +287,7 @@ void AbstractBuilder::query_comment(std::string_view) { UNSUPPORTED; } void AbstractBuilder::query_options(std::string_view, std::string_view) { UNSUPPORTED; } void AbstractBuilder::expectation_begin() { UNSUPPORTED; } void AbstractBuilder::expectation_end() { UNSUPPORTED; } -void AbstractBuilder::expectation_value(std::string_view type, std::string_view res, std::string_view value) +void AbstractBuilder::expectation_value(std::string_view, std::string_view, std::string_view) { UNSUPPORTED; } @@ -295,3 +295,5 @@ void AbstractBuilder::expect_resource(std::string_view, std::string_view, std::s void AbstractBuilder::query_results_begin() { UNSUPPORTED; } void AbstractBuilder::query_results_end() { UNSUPPORTED; } void AbstractBuilder::model_option(std::string_view, std::string_view) { UNSUPPORTED; } + +} // namenamespace UTAP \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9e8dda9c..ec2d98c3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,6 +19,12 @@ add_custom_command( DEPENDS lexer_generate parser.y) add_custom_target(parser_generate DEPENDS "${parser_source}") +# Bison's stack-growth cleanup trips a GCC false positive: it can't prove +# yyss is heap-allocated before YYSTACK_FREE conditionally frees it. +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set_source_files_properties("${parser_source}" PROPERTIES COMPILE_OPTIONS "-Wno-free-nonheap-object") +endif () + add_library(UTAP AbstractBuilder.cpp DocumentBuilder.cpp @@ -47,23 +53,12 @@ if (UTAP_STATIC) target_link_options(UTAP PUBLIC -static) message(STATUS "Enabled LIBXML_STATIC -static") endif (UTAP_STATIC) +target_coverage(UTAP) set_target_properties(UTAP PROPERTIES CXX_STANDARD_REQUIRED ON CXX_STANDARD_EXTENSIONS OFF POSITION_INDEPENDENT_CODE ON) -if (UTAP_WARNINGS) - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(UTAP PUBLIC -Wpedantic -Wall -Wextra -Wconversion -Wno-sign-conversion -Wimplicit-fallthrough) - elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - target_compile_options(UTAP PUBLIC -Wpedantic -Wall -Wextra -Wconversion -Wno-sign-conversion -Wimplicit-fallthrough) - elseif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - target_compile_options(UTAP PUBLIC -Wpedantic -Wall -Wextra -Wimplicit-fallthrough) - elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - target_compile_options(UTAP PUBLIC /Wall) - else () - message(WARNING "Failed to enable warnings for ${CMAKE_CXX_COMPILER_ID}") - endif () -endif () +target_compile_options(UTAP PUBLIC ${UTAP_WARN}) target_include_directories(UTAP PRIVATE # where the library itself will look for its internal headers @@ -75,6 +70,22 @@ target_include_directories(UTAP # where external projects will look for the library's public headers $ ) -target_link_libraries(UTAP PRIVATE LibXml2::LibXml2 ${CMAKE_DL_LIBS} - ${LIBXML_WINLIBS}) +target_link_libraries(UTAP PRIVATE LibXml2::LibXml2 ${CMAKE_DL_LIBS} ${LIBXML_WINLIBS}) add_library(UTAP::UTAP ALIAS UTAP) # in case the library is not exported-imported + +add_executable(pretty pretty.cpp) +target_link_libraries(pretty PRIVATE UTAP) + +add_executable(syntaxcheck syntaxcheck.cpp) +target_link_libraries(syntaxcheck PRIVATE UTAP) + +add_executable(featurecheck featurecheck.cpp) +target_link_libraries(featurecheck PRIVATE UTAP) + +if (UTAP_STATIC) + target_link_options(pretty PRIVATE -static) + target_link_options(syntaxcheck PRIVATE -static) + target_link_options(featurecheck PRIVATE -static) +endif (UTAP_STATIC) + +install(TARGETS pretty syntaxcheck featurecheck) diff --git a/src/DocumentBuilder.cpp b/src/DocumentBuilder.cpp index 7bea49f6..a0f4e126 100644 --- a/src/DocumentBuilder.cpp +++ b/src/DocumentBuilder.cpp @@ -28,8 +28,8 @@ #include #include -using namespace UTAP; -using namespace Constants; +namespace UTAP { + using namespace std::string_view_literals; DocumentBuilder::DocumentBuilder(Document& doc, std::vector paths): @@ -39,7 +39,7 @@ DocumentBuilder::DocumentBuilder(Document& doc, std::vectoradd_function(type, name, pos, currentFun); } @@ -61,12 +61,12 @@ Declarations* DocumentBuilder::getCurrentDeclarationBlock() void DocumentBuilder::addSelectSymbolToFrame(std::string_view id, Frame& frame, position_t pos) { auto type = typeFragments.pop(); - if (!type.is(CONSTANT)) { - type = type.create_prefix(CONSTANT); + if (!type.is(Kind::CONSTANT)) { + type = type.create_prefix(Kind::CONSTANT); } if (!type.is_scalar() && !type.is_integer()) { handle_error(TypeException{"$Scalar_set_or_integer_expected"}); - } else if (!type.is(RANGE)) { + } else if (!type.is(Kind::RANGE)) { handle_error(TypeException{"$Range_expected"}); } else { if (auto uid = Symbol{}; resolve(id, uid)) @@ -178,10 +178,10 @@ void DocumentBuilder::proc_location_commit(std::string_view name) { if (auto uid = Symbol{}; !resolve(name, uid) || !uid.get_type().is_location()) { handle_error(TypeException{"$Location_expected"}); - } else if (uid.get_type().is(URGENT)) { + } else if (uid.get_type().is(Kind::URGENT)) { handle_error(TypeException{"$States_cannot_be_committed_and_urgent_at_the_same_time"}); } else { - uid.set_type(uid.get_type().create_prefix(COMMITTED, position)); + uid.set_type(uid.get_type().create_prefix(Kind::COMMITTED, position)); } } @@ -189,10 +189,10 @@ void DocumentBuilder::proc_location_urgent(std::string_view name) { if (auto uid = Symbol{}; !resolve(name, uid) || !uid.get_type().is_location()) { handle_error(TypeException{"$Location_expected"}); - } else if (uid.get_type().is(COMMITTED)) { + } else if (uid.get_type().is(Kind::COMMITTED)) { handle_error(TypeException{"$States_cannot_be_committed_and_urgent_at_the_same_time"}); } else { - uid.set_type(uid.get_type().create_prefix(URGENT, position)); + uid.set_type(uid.get_type().create_prefix(Kind::URGENT, position)); } } @@ -214,21 +214,21 @@ void DocumentBuilder::proc_edge_begin(std::string_view from, std::string_view to !resolve(from, fid) || (!fid.get_type().is_location() && !fid.get_type().is_branchpoint())) { handle_error(TypeException{"$No_such_location_or_branchpoint_(source)"}); push_frame(frames.top().make_sub()); // dummy frame for upcoming popFrame - } else if (auto tid = Symbol{}; - !resolve(to, tid) || (!tid.get_type().is_location() && !tid.get_type().is_branchpoint())) { - handle_error(TypeException{"$No_such_location_or_branchpoint_(destination)"}); - push_frame(frames.top().make_sub()); // dummy frame for upcoming popFrame - } else { - currentEdge = ¤tTemplate->add_edge(fid, tid, control, actname); - currentEdge->guard = make_constant(1); - currentEdge->assign = make_constant(1); - // default "probability" weight is 1. - currentEdge->prob = make_constant(1); - push_frame(currentEdge->select = frames.top().make_sub()); - } -} - -void DocumentBuilder::proc_edge_end(std::string_view from, std::string_view to) { frames.pop(); } + } else if (auto tid = Symbol{}; + !resolve(to, tid) || (!tid.get_type().is_location() && !tid.get_type().is_branchpoint())) { + handle_error(TypeException{"$No_such_location_or_branchpoint_(destination)"}); + push_frame(frames.top().make_sub()); // dummy frame for upcoming popFrame + } else { + currentEdge = ¤tTemplate->add_edge(fid, tid, control, actname); + currentEdge->guard = make_constant(1); + currentEdge->assign = make_constant(1); + // default "probability" weight is 1. + currentEdge->prob = make_constant(1); + push_frame(currentEdge->select = frames.top().make_sub()); + } +} + +void DocumentBuilder::proc_edge_end(std::string_view, std::string_view) { frames.pop(); } void DocumentBuilder::proc_select(std::string_view id) { addSelectSymbolToFrame(id, currentEdge->select, position); } @@ -241,7 +241,7 @@ void DocumentBuilder::proc_guard() currentEdge->guard = fragments.pop(); } -void DocumentBuilder::proc_sync(Synchronisation type) +void DocumentBuilder::proc_sync(Sync type) { if (currentEdge == nullptr) { handle_error(TypeException("Must be declared inside of an edge")); @@ -272,7 +272,7 @@ void DocumentBuilder::proc_prob() * System declaration */ -void DocumentBuilder::instantiation_begin(std::string_view name, uint32_t parameters, std::string_view templ_name) +void DocumentBuilder::instantiation_begin(std::string_view name, uint32_t, std::string_view templ_name) { // Make sure this identifier is new. if (frames.top().contains(name)) @@ -281,9 +281,9 @@ void DocumentBuilder::instantiation_begin(std::string_view name, uint32_t parame // Lookup symbol. auto id = Symbol{}; if (!resolve(templ_name, id) || - (id.get_type().get_kind() != INSTANCE && id.get_type().get_kind() != LSC_INSTANCE)) { + (id.get_type().get_kind() != Kind::INSTANCE && id.get_type().get_kind() != Kind::LSC_INSTANCE)) { handle_error(TypeException{"$Not_a_template"}); - } + } // Push parameters to frame stack. auto frame = frames.top().make_sub(); @@ -303,7 +303,7 @@ void DocumentBuilder::instantiation_end(std::string_view name, uint32_t paramete * reported the problem. */ auto id = Symbol{}; - if (resolve(templ_name, id) && (id.get_type().get_kind() == INSTANCE || id.get_type().get_kind() == LSC_INSTANCE)) { + if (resolve(templ_name, id) && (id.get_type().get_kind() == Kind::INSTANCE || id.get_type().get_kind() == Kind::LSC_INSTANCE)) { auto* old_instance = static_cast(id.get_data()); // Check number of arguments. If too many arguments, pop the rest. auto expected = id.get_type().size(); @@ -318,7 +318,7 @@ void DocumentBuilder::instantiation_end(std::string_view name, uint32_t paramete exprs[arguments] = fragments.pop(); arguments = 0; // Create template composition. - Instance& new_instance = (id.get_type().get_kind() == INSTANCE) + Instance& new_instance = (id.get_type().get_kind() == Kind::INSTANCE) ? document.add_instance(name, *old_instance, params, exprs, position) : document.add_LSC_instance(name, *old_instance, params, exprs, position); @@ -331,7 +331,7 @@ void DocumentBuilder::instantiation_end(std::string_view name, uint32_t paramete std::set& restricted = old_instance->restricted; for (uint32_t i = 0; i < expected; i++) { if (restricted.find(old_instance->parameters[i]) != restricted.end()) { - collectDependencies(new_instance.restricted, exprs[i]); + collect_dependencies(new_instance.restricted, exprs[i]); } } } @@ -348,7 +348,7 @@ void DocumentBuilder::process(std::string_view name) throw no_such_process_error(name); auto type = symbol.get_type(); - if (type.get_kind() != INSTANCE) + if (type.get_kind() != Kind::INSTANCE) throw not_a_template_error(symbol.get_name()); if (type.size() > 0) { // FIXME: Check type of unbound parameters @@ -408,10 +408,10 @@ void DocumentBuilder::instance_name(std::string_view name, bool templ) if (templ) { auto instName = std::string{name}; auto templName = instName.substr(0, instName.find('(')); - if (!resolve(templName, uid) || (uid.get_type().get_kind() != INSTANCE)) + if (!resolve(templName, uid) || (uid.get_type().get_kind() != Kind::INSTANCE)) handle_error(not_a_template_error(templName)); } else { - if (resolve(name, uid) && (uid.get_type().get_kind() == INSTANCE)) { + if (resolve(name, uid) && (uid.get_type().get_kind() == Kind::INSTANCE)) { const auto* t = static_cast(uid.get_data()); if (t->parameters.get_size() > 0) { handle_error(TypeException{"$Wrong_number_of_arguments_in_instance_line_name"}); @@ -419,10 +419,10 @@ void DocumentBuilder::instance_name(std::string_view name, bool templ) } } currentInstanceLine->uid = - currentTemplate->frame.add_symbol(name, Type::create_primitive(INSTANCE_LINE), position, currentInstanceLine); + currentTemplate->frame.add_symbol(name, Type::create_primitive(Kind::INSTANCE_LINE), position, currentInstanceLine); } -void DocumentBuilder::instance_name_begin(std::string_view name) +void DocumentBuilder::instance_name_begin(std::string_view) { // Push parameters to frame stack. auto frame = frames.top().make_sub(); @@ -440,7 +440,7 @@ void DocumentBuilder::instance_name_end(std::string_view name, uint32_t argument // assert(parameters == params.get_size()); // Lookup symbol. In case of failure, instance_name_begin already reported the problem. - if (auto id = Symbol{}; resolve(name, id) && id.get_type().get_kind() == INSTANCE) { + if (auto id = Symbol{}; resolve(name, id) && id.get_type().get_kind() == Kind::INSTANCE) { auto* old_instance = static_cast(id.get_data()); /* Check number of arguments. If too many arguments, pop the @@ -471,7 +471,7 @@ void DocumentBuilder::instance_name_end(std::string_view name, uint32_t argument std::set& restricted = old_instance->restricted; for (uint32_t i = 0; i < expected; i++) { if (restricted.find(old_instance->parameters[i]) != restricted.end()) { - collectDependencies(currentInstanceLine->restricted, exprs[i]); + collect_dependencies(currentInstanceLine->restricted, exprs[i]); } } } @@ -495,7 +495,7 @@ void DocumentBuilder::proc_message(std::string_view from, std::string_view to, c } } -void DocumentBuilder::proc_message(Synchronisation type) // Label +void DocumentBuilder::proc_message(Sync type) // Label { if (currentMessage != nullptr) currentMessage->label = Expression::create_sync(fragments[0], type, position); @@ -572,7 +572,7 @@ void DocumentBuilder::decl_dynamic_template(std::string_view name) for (uint32_t i = 0; i < params.get_size(); i++) { if (!params[i].get_type().is_integer() && !params[i].get_type().is_boolean() && - !(params[i].get_type().is(REF) && params[i].get_type()[0].is(BROADCAST))) + !(params[i].get_type().is(Kind::REF) && params[i].get_type()[0].is(Kind::BROADCAST))) handle_error(TypeException{"Dynamic template parameters can either be boolean or integer and " "cannot be references"}); } @@ -664,3 +664,5 @@ void DocumentBuilder::model_option(std::string_view key, std::string_view value) handle_error(TypeException{"options tag found without attribute 'key'"}); document.get_options().emplace_back(std::string{key}, std::string{value}); } + +} // namespace UTAP \ No newline at end of file diff --git a/src/ExpressionBuilder.cpp b/src/ExpressionBuilder.cpp index bf1b13ac..7d7d5c32 100644 --- a/src/ExpressionBuilder.cpp +++ b/src/ExpressionBuilder.cpp @@ -23,20 +23,20 @@ #include "utap/TypeChecker.hpp" -#include #include #include -#include #include #include #include -using namespace UTAP; -using namespace Constants; +#include + +namespace UTAP { -inline static bool isMITL(const Expression& e) +static bool isMITL(const Expression& e) { switch (e.get_kind()) { + using namespace KindNames; case MITL_FORMULA: case MITL_RELEASE: case MITL_UNTIL: @@ -50,7 +50,7 @@ inline static bool isMITL(const Expression& e) } } -inline static Expression toMITLAtom(const Expression& e) { return Expression::create_unary(MITL_ATOM, e); } +static Expression toMITLAtom(const Expression& e) { return Expression::create_unary(Kind::MITL_ATOM, e); } ExpressionBuilder::ExpressionBuilder(Document& doc): document{doc}, scalar_count{0} { @@ -83,7 +83,7 @@ bool ExpressionBuilder::is_type(std::string_view name) if (!resolve(name, uid)) { return false; } - return uid.get_type().get_kind() == TYPEDEF; + return uid.get_type().get_kind() == Kind::TYPEDEF; } Expression ExpressionBuilder::make_constant(int value) const { return Expression::create_constant(value, position); } @@ -102,15 +102,15 @@ Expression ExpressionBuilder::make_constant(std::string_view value) const Type ExpressionBuilder::apply_prefix(TypePrefix prefix, Type type) { switch (prefix) { - case TypePrefix::CONST: return type.create_prefix(CONSTANT, position); + case TypePrefix::CONST: return type.create_prefix(Kind::CONSTANT, position); case TypePrefix::SYSTEM_META: // Meta in the syntax corresponds to a static variable internally. // Internal "meta" variables correspond to state meta variables. - return type.create_prefix(SYSTEM_META, position); - case TypePrefix::URGENT: return type.create_prefix(URGENT, position); - case TypePrefix::BROADCAST: return type.create_prefix(BROADCAST, position); - case TypePrefix::URGENT_BROADCAST: return type.create_prefix(URGENT, position).create_prefix(BROADCAST, position); - case TypePrefix::HYBRID: return type.create_prefix(HYBRID, position); + return type.create_prefix(Kind::SYSTEM_META, position); + case TypePrefix::URGENT: return type.create_prefix(Kind::URGENT, position); + case TypePrefix::BROADCAST: return type.create_prefix(Kind::BROADCAST, position); + case TypePrefix::URGENT_BROADCAST: return type.create_prefix(Kind::URGENT, position).create_prefix(Kind::BROADCAST, position); + case TypePrefix::HYBRID: return type.create_prefix(Kind::HYBRID, position); default: return type; } } @@ -121,13 +121,13 @@ void ExpressionBuilder::type_pop() { typeFragments.pop(); } void ExpressionBuilder::type_bool(TypePrefix prefix) { - Type type = Type::create_primitive(Constants::BOOL, position); + Type type = Type::create_primitive(Kind::BOOL, position); typeFragments.push(apply_prefix(prefix, type)); } void ExpressionBuilder::type_int(TypePrefix prefix) { - Type type = Type::create_primitive(Constants::INT, position); + Type type = Type::create_primitive(Kind::INT, position); if (prefix != TypePrefix::CONST) { type = Type::create_range(type, make_constant(defaultIntMin), make_constant(defaultIntMax), position); } @@ -137,22 +137,22 @@ void ExpressionBuilder::type_int(TypePrefix prefix) void ExpressionBuilder::type_string(TypePrefix prefix) { if (prefix != TypePrefix::CONST) { - typeFragments.push(Type::create_primitive(VOID_TYPE)); + typeFragments.push(Type::create_primitive(Kind::VOID_TYPE)); throw TypeException("$Strings_should_always_be_const"); } - Type type = Type::create_primitive(Constants::STRING, position); + Type type = Type::create_primitive(Kind::STRING, position); typeFragments.push(apply_prefix(prefix, type)); } void ExpressionBuilder::type_double(TypePrefix prefix) { - Type type = Type::create_primitive(Constants::DOUBLE, position); + Type type = Type::create_primitive(Kind::DOUBLE, position); typeFragments.push(apply_prefix(prefix, type)); } void ExpressionBuilder::type_bounded_int(TypePrefix prefix) { - Type type = Type::create_primitive(Constants::INT, position); + Type type = Type::create_primitive(Kind::INT, position); type = Type::create_range(type, fragments[1], fragments[0], position); fragments.pop(2); typeFragments.push(apply_prefix(prefix, type)); @@ -162,23 +162,23 @@ void ExpressionBuilder::type_channel(TypePrefix prefix) { bool is_broadcast = prefix == TypePrefix::BROADCAST || prefix == TypePrefix::URGENT_BROADCAST; document.add_channel(is_broadcast); - Type type = Type::create_primitive(CHANNEL, position); + Type type = Type::create_primitive(Kind::CHANNEL, position); typeFragments.push(apply_prefix(prefix, type)); } void ExpressionBuilder::type_clock(TypePrefix prefix) { - Type type = Type::create_primitive(CLOCK, position); + Type type = Type::create_primitive(Kind::CLOCK, position); typeFragments.push(apply_prefix(prefix, type)); } void ExpressionBuilder::type_void() { - Type type = Type::create_primitive(VOID_TYPE, position); + Type type = Type::create_primitive(Kind::VOID_TYPE, position); typeFragments.push(type); } -static void collectDependencies(std::set& dependencies, const Expression& expr) +static void collect_dependencies(std::set& dependencies, const Expression& expr) { std::set symbols; expr.collect_possible_reads(symbols); @@ -200,12 +200,12 @@ void ExpressionBuilder::type_scalar(TypePrefix prefix) Expression lower, upper; expr_nat(1); - expr_binary(MINUS); + expr_binary(Kind::MINUS); upper = fragments[0]; lower = make_constant(0); fragments.pop(); - auto type = Type::create_primitive(SCALAR, position); + auto type = Type::create_primitive(Kind::SCALAR, position); type = Type::create_range(type, lower, upper, position); type = apply_prefix(prefix, type); @@ -227,7 +227,7 @@ void ExpressionBuilder::type_scalar(TypePrefix prefix) * Therefore mark all symbols in upper and those that they * depend on as restricted. */ - collectDependencies(currentTemplate->restricted, upper); + collect_dependencies(currentTemplate->restricted, upper); } typeFragments.push(type); } @@ -237,8 +237,8 @@ void ExpressionBuilder::type_name(TypePrefix prefix, std::string_view name) Symbol uid; assert(resolve(name, uid)); - if (!resolve(name, uid) || uid.get_type().get_kind() != TYPEDEF) { - typeFragments.push(Type::create_primitive(VOID_TYPE)); + if (!resolve(name, uid) || uid.get_type().get_kind() != Kind::TYPEDEF) { + typeFragments.push(Type::create_primitive(Kind::VOID_TYPE)); throw TypeException("$Identifier_is_undeclared_or_not_a_type_name"); } @@ -256,21 +256,21 @@ void ExpressionBuilder::type_name(TypePrefix prefix, std::string_view name) void ExpressionBuilder::expr_true() { Expression expr = make_constant(1); - expr.set_type(Type::create_primitive(Constants::BOOL)); + expr.set_type(Type::create_primitive(Kind::BOOL)); fragments.push(expr); } void ExpressionBuilder::expr_false() { Expression expr = make_constant(0); - expr.set_type(Type::create_primitive(Constants::BOOL)); + expr.set_type(Type::create_primitive(Kind::BOOL)); fragments.push(expr); } void ExpressionBuilder::expr_double(double d) { Expression expr = Expression::create_double(d, position); - expr.set_type(Type::create_primitive(Constants::DOUBLE)); + expr.set_type(Type::create_primitive(Kind::DOUBLE)); fragments.push(expr); } @@ -317,15 +317,15 @@ void ExpressionBuilder::expr_call_end(uint32_t n) * function or a processset. */ switch (id.get_type().get_kind()) { - case FUNCTION_EXTERNAL: - case FUNCTION: + case Kind::FUNCTION_EXTERNAL: + case Kind::FUNCTION: if (expr.size() != id.get_type().size()) handle_error(TypeException{"$Wrong_number_of_arguments"}); - e = Expression::create_nary(id.get_type().get_kind() == FUNCTION ? FUN_CALL : FUN_CALL_EXT, expr, position, + e = Expression::create_nary(id.get_type().get_kind() == Kind::FUNCTION ? Kind::FUN_CALL : Kind::FUN_CALL_EXT, expr, position, id.get_type()[0]); break; - case PROCESS_SET: + case Kind::PROCESS_SET: if (expr.size() - 1 != id.get_type().size()) handle_error(TypeException{"$Wrong_number_of_arguments"}); instance = static_cast(id.get_symbol().get_data()); @@ -346,7 +346,7 @@ void ExpressionBuilder::expr_call_end(uint32_t n) e.set_type(type); for (size_t i = 1; i < expr.size(); ++i) { type = type.get_sub(); - e = Expression::create_binary(ARRAY, e, expr[i], position, type); + e = Expression::create_binary(Kind::ARRAY, e, expr[i], position, type); } break; @@ -375,28 +375,28 @@ void ExpressionBuilder::expr_array() element = Type(); } - fragments.push(Expression::create_binary(ARRAY, var, index, position, element)); + fragments.push(Expression::create_binary(Kind::ARRAY, var, index, position, element)); } // 1 expr void ExpressionBuilder::expr_post_increment() { - fragments[0] = Expression::create_unary(POST_INCREMENT, fragments[0], position); + fragments[0] = Expression::create_unary(Kind::POST_INCREMENT, fragments[0], position); } void ExpressionBuilder::expr_pre_increment() { - fragments[0] = Expression::create_unary(PRE_INCREMENT, fragments[0], position, fragments[0].get_type()); + fragments[0] = Expression::create_unary(Kind::PRE_INCREMENT, fragments[0], position, fragments[0].get_type()); } void ExpressionBuilder::expr_post_decrement() // 1 expr { - fragments[0] = Expression::create_unary(POST_DECREMENT, fragments[0], position); + fragments[0] = Expression::create_unary(Kind::POST_DECREMENT, fragments[0], position); } void ExpressionBuilder::expr_pre_decrement() { - fragments[0] = Expression::create_unary(PRE_DECREMENT, fragments[0], position, fragments[0].get_type()); + fragments[0] = Expression::create_unary(Kind::PRE_DECREMENT, fragments[0], position, fragments[0].get_type()); } void ExpressionBuilder::expr_builtin_function1(Kind kind) @@ -432,11 +432,11 @@ void ExpressionBuilder::expr_assignment(Kind op) // 2 expr void ExpressionBuilder::expr_unary(Kind unaryop) // 1 expr { switch (unaryop) { - case PLUS: + case Kind::PLUS: /* Unary plus can be ignored */ break; - case MINUS: - unaryop = UNARY_MINUS; + case Kind::MINUS: + unaryop = Kind::UNARY_MINUS; [[fallthrough]]; default: fragments[0] = Expression::create_unary(unaryop, fragments[0], position, fragments[0].get_type()); } @@ -444,7 +444,7 @@ void ExpressionBuilder::expr_unary(Kind unaryop) // 1 expr void ExpressionBuilder::expr_binary(Kind binaryop) // 2 expr { - Kind mitlop = (binaryop == AND ? MITL_CONJ : MITL_DISJ); + Kind mitlop = (binaryop == Kind::AND ? Kind::MITL_CONJ : Kind::MITL_DISJ); Kind op = binaryop; Expression left = fragments[1]; Expression right = fragments[0]; @@ -482,8 +482,8 @@ void ExpressionBuilder::expr_scenario(std::string_view name) auto check [[maybe_unused]] = resolve(name, uid); assert(check); auto scen = Expression::create_identifier(uid); - auto expr = Expression::create_unary(SCENARIO, scen, position); - fragments.push(Expression::create_unary(SCENARIO, scen, position)); + auto expr = Expression::create_unary(Kind::SCENARIO, scen, position); + fragments.push(Expression::create_unary(Kind::SCENARIO, scen, position)); } Expression ExpressionBuilder::exprScenario() @@ -495,14 +495,14 @@ Expression ExpressionBuilder::exprScenario() auto i = obs.get_type().find_index_of("lmin"); Expression left = Expression::create_dot(obs, i.value_or(-1), position, - Type::create_primitive(Constants::BOOL)); // std::cout << left << std::endl; + Type::create_primitive(Kind::BOOL)); // std::cout << left << std::endl; obs = Expression::create_identifier(uid); i = obs.get_type().find_index_of("lmax"); Expression right = Expression::create_dot(obs, i.value_or(-1), position, - Type::create_primitive(Constants::BOOL)); // std::cout << right << std::endl; - return Expression::create_binary(SCENARIO2, left, right, position); + Type::create_primitive(Kind::BOOL)); // std::cout << right << std::endl; + return Expression::create_binary(Kind::SCENARIO2, left, right, position); } void ExpressionBuilder::expr_ternary(Kind ternaryop, bool firstMissing) // 3 expr @@ -521,7 +521,7 @@ void ExpressionBuilder::expr_inline_if() Expression e = fragments[0]; fragments.pop(3); - fragments.push(Expression::create_ternary(INLINE_IF, c, t, e, position)); + fragments.push(Expression::create_ternary(Kind::INLINE_IF, c, t, e, position)); } void ExpressionBuilder::expr_comma() @@ -529,7 +529,7 @@ void ExpressionBuilder::expr_comma() Expression e1 = fragments[1]; Expression e2 = fragments[0]; fragments.pop(2); - fragments.push(Expression::create_binary(COMMA, e1, e2, position, e2.get_type())); + fragments.push(Expression::create_binary(Kind::COMMA, e1, e2, position, e2.get_type())); } void ExpressionBuilder::expr_location() @@ -540,7 +540,7 @@ void ExpressionBuilder::expr_location() // TODO: create a separate type for location expressions and get rid of magical constants // we use special max-value to denote this special "meta-variable" expr = Expression::create_dot(expr, std::numeric_limits::max(), position, - Type::create_primitive(Constants::LOCATION_EXPR)); + Type::create_primitive(Kind::LOCATION_EXPR)); } else { handle_error(not_a_process_error(expr.str(true))); } @@ -565,14 +565,14 @@ void ExpressionBuilder::expr_dot(std::string_view id) if (!i) { handle_error(has_no_such_member_error(id)); } else if (type.get_sub(*i).is_location()) { - expr = Expression::create_dot(expr, *i, position, Type::create_primitive(Constants::BOOL)); + expr = Expression::create_dot(expr, *i, position, Type::create_primitive(Kind::BOOL)); } else { type = type.get_sub(*i).rename(process->templ->uid.get_name() + "::", name.get_name() + "::"); for (const auto& [s, e] : process->mapping) type = type.subst(s, e); expr = Expression::create_dot(expr, *i, position, type); } - } else if (type.is(PROCESS_VAR)) { + } else if (type.is(Kind::PROCESS_VAR)) { Symbol uid; // temporarily set the frame to that of its associated template if (dynamicFrames.find(expr.get_symbol().get_name()) == dynamicFrames.end()) { @@ -588,10 +588,10 @@ void ExpressionBuilder::expr_dot(std::string_view id) Expression identifier = Expression::create_identifier(uid, position); expr = (Expression::create_nary( - DYNAMIC_EVAL, {identifier, expr}, position, + Kind::DYNAMIC_EVAL, {identifier, expr}, position, identifier.get_type().is_location() - ? Type::create_primitive(Constants::BOOL, position) - : identifier.get_type())); // Type::createPrimitive (Constants::BOOL,position))); + ? Type::create_primitive(Kind::BOOL, position) + : identifier.get_type())); // Type::createPrimitive (Kind::BOOL,position))); } else { handle_error(is_not_a_struct_error(expr.str(true))); } @@ -603,8 +603,8 @@ void ExpressionBuilder::expr_forall_begin(std::string_view name) Type type = typeFragments[0]; typeFragments.pop(); - if (!type.is(CONSTANT)) { - type = type.create_prefix(CONSTANT); + if (!type.is(Kind::CONSTANT)) { + type = type.create_prefix(Kind::CONSTANT); } push_frame(frames.top().make_sub()); @@ -615,67 +615,67 @@ void ExpressionBuilder::expr_forall_begin(std::string_view name) } } -void ExpressionBuilder::expr_forall_end(std::string_view name) +void ExpressionBuilder::expr_forall_end(std::string_view) { /* Create the forall expression. The symbol is added as an identifier * expression as the first child. Notice that the frame is discarded * but the identifier expression will maintain a reference to the * symbol so it will not be deallocated. */ - fragments[0] = Expression::create_binary(FORALL, Expression::create_identifier(frames.top()[0], position), + fragments[0] = Expression::create_binary(Kind::FORALL, Expression::create_identifier(frames.top()[0], position), fragments[0], position); pop_frame(); } void ExpressionBuilder::expr_exists_begin(std::string_view name) { expr_forall_begin(name); } -void ExpressionBuilder::expr_exists_end(std::string_view name) +void ExpressionBuilder::expr_exists_end(std::string_view) { /* Create the exists expression. The symbol is added as an identifier * expression as the first child. Notice that the frame is discarded * but the identifier expression will maintain a reference to the * symbol so it will not be deallocated. */ - fragments[0] = Expression::create_binary(EXISTS, Expression::create_identifier(frames.top()[0], position), + fragments[0] = Expression::create_binary(Kind::EXISTS, Expression::create_identifier(frames.top()[0], position), fragments[0], position); pop_frame(); } void ExpressionBuilder::expr_sum_begin(std::string_view name) { expr_forall_begin(name); } -void ExpressionBuilder::expr_sum_end(std::string_view name) +void ExpressionBuilder::expr_sum_end(std::string_view) { /* Create the sum expression. The symbol is added as an identifier * expression as the first child. Notice that the frame is discarded * but the identifier expression will maintain a reference to the * symbol so it will not be deallocated. */ - fragments[0] = Expression::create_binary(SUM, Expression::create_identifier(frames.top()[0], position), + fragments[0] = Expression::create_binary(Kind::SUM, Expression::create_identifier(frames.top()[0], position), fragments[0], position); pop_frame(); } -void ExpressionBuilder::expr_proba_qualitative(Constants::Kind pathType, Constants::Kind comp, double probBound) +void ExpressionBuilder::expr_proba_qualitative(Kind pathType, Kind comp, double probBound) { - auto invert = (comp == LE); + auto invert = (comp == Kind::LE); auto& boundTypeOrBoundedExpr = fragments[3]; auto& bound = fragments[2]; auto& runs = fragments[1]; auto& predicate = fragments[0]; auto args = std::vector{runs, boundTypeOrBoundedExpr, bound, - invert ? Expression::create_unary(NOT, predicate, position) : predicate, + invert ? Expression::create_unary(Kind::NOT, predicate, position) : predicate, Expression::create_double(invert ? 1.0 - probBound : probBound, position)}; fragments.pop(4); - fragments.push(Expression::create_nary(invert ? (pathType == BOX ? PROBA_MIN_DIAMOND : PROBA_MIN_BOX) - : (pathType == BOX ? PROBA_MIN_BOX : PROBA_MIN_DIAMOND), + fragments.push(Expression::create_nary(invert ? (pathType == Kind::BOX ? Kind::PROBA_MIN_DIAMOND : Kind::PROBA_MIN_BOX) + : (pathType == Kind::BOX ? Kind::PROBA_MIN_BOX : Kind::PROBA_MIN_DIAMOND), std::move(args), position)); } -void ExpressionBuilder::expr_optimize_exp(Constants::Kind kind, PRICETYPE ptype, Constants::Kind goal_type) +void ExpressionBuilder::expr_optimize_exp(Kind kind, PriceType ptype, Kind goal_type) { - if (goal_type != Constants::DIAMOND) + if (goal_type != Kind::DIAMOND) handle_error(TypeException{"$Wrong_path_quantifier"}); auto boundVar = fragments[4]; @@ -685,21 +685,21 @@ void ExpressionBuilder::expr_optimize_exp(Constants::Kind kind, PRICETYPE ptype, auto goal = fragments[0]; if (!discrete.is_true() && !cont.is_true()) { - discrete.set_type(Type::create_primitive(LIST, position)); - cont.set_type(Type::create_primitive(LIST, position)); + discrete.set_type(Type::create_primitive(Kind::LIST, position)); + cont.set_type(Type::create_primitive(Kind::LIST, position)); } Expression price; Expression level = make_constant(0); size_t nb = 4; switch (ptype) { - case TIMEPRICE: // use time + case PriceType::TIME: // use time price = make_constant(1); break; - case EXPRPRICE: // user-provided expression + case PriceType::EXPR: // user-provided expression price = fragments[5]; ++nb; break; - case PROBAPRICE: price = goal; break; + case PriceType::PROBA: price = goal; break; default: handle_error(TypeException{"$Unknown_price_type"}); } @@ -716,20 +716,20 @@ void ExpressionBuilder::expr_load_strategy() Expression cont = fragments[1]; Expression strat = fragments[0]; if (!discrete.is_true() && !cont.is_true()) { - discrete.set_type(Type::create_primitive(LIST, position)); - cont.set_type(Type::create_primitive(LIST, position)); + discrete.set_type(Type::create_primitive(Kind::LIST, position)); + cont.set_type(Type::create_primitive(Kind::LIST, position)); } fragments.pop(3); - fragments.push(Expression::create_ternary(LOAD_STRAT, strat, discrete, cont, position)); + fragments.push(Expression::create_ternary(Kind::LOAD_STRAT, strat, discrete, cont, position)); } void ExpressionBuilder::expr_save_strategy(std::string_view strategy_name) { assert(fragments.size() == 1); - fragments[0] = Expression::create_binary(SAVE_STRAT, fragments[0], make_constant(strategy_name), position); + fragments[0] = Expression::create_binary(Kind::SAVE_STRAT, fragments[0], make_constant(strategy_name), position); } -void ExpressionBuilder::expr_proba_quantitative(Constants::Kind pathType) +void ExpressionBuilder::expr_proba_quantitative(Kind pathType) { auto& boundTypeOrBoundedExpr = fragments[4]; auto& bound = fragments[3]; @@ -739,10 +739,10 @@ void ExpressionBuilder::expr_proba_quantitative(Constants::Kind pathType) auto args = std::vector{runs, boundTypeOrBoundedExpr, bound, predicate, untilCond}; fragments.pop(5); - fragments.push(Expression::create_nary((pathType == BOX ? PROBA_BOX : PROBA_DIAMOND), std::move(args), position)); + fragments.push(Expression::create_nary((pathType == Kind::BOX ? Kind::PROBA_BOX : Kind::PROBA_DIAMOND), std::move(args), position)); } -void ExpressionBuilder::expr_proba_compare(Constants::Kind pathType1, Constants::Kind pathType2) +void ExpressionBuilder::expr_proba_compare(Kind pathType1, Kind pathType2) { auto& boundTypeOrBoundedExpr1 = fragments[7]; auto& bound1 = fragments[6]; @@ -761,7 +761,7 @@ void ExpressionBuilder::expr_proba_compare(Constants::Kind pathType1, Constants: boundTypeOrBoundedExpr2, bound2, make_constant(pathType2), predicate2}; fragments.pop(8); - fragments.push(Expression::create_nary(PROBA_CMP, std::move(args), position)); + fragments.push(Expression::create_nary(Kind::PROBA_CMP, std::move(args), position)); } void ExpressionBuilder::expr_proba_expected(std::string_view aggregatingOp) @@ -782,7 +782,7 @@ void ExpressionBuilder::expr_proba_expected(std::string_view aggregatingOp) auto args = std::vector{runs, boundTypeOrBoundedExpr, bound, make_constant(aggOpId), expression}; fragments.pop(4); - fragments.push(Expression::create_nary(PROBA_EXP, std::move(args), position)); + fragments.push(Expression::create_nary(Kind::PROBA_EXP, std::move(args), position)); } void ExpressionBuilder::expr_simulate(int nbExpr, bool hasReach, int numberOfAcceptingRuns) @@ -797,7 +797,7 @@ void ExpressionBuilder::expr_simulate(int nbExpr, bool hasReach, int numberOfAcc auto& bound = fragments[1 + offset]; auto runs = fragments[0 + offset]; - if (runs.get_kind() == CONSTANT && runs.get_type().is_integer() && runs.get_value() < 0) + if (runs.get_kind() == Kind::CONSTANT && runs.get_type().is_integer() && runs.get_value() < 0) runs = make_constant(1); auto args = std::vector{}; @@ -816,9 +816,9 @@ void ExpressionBuilder::expr_simulate(int nbExpr, bool hasReach, int numberOfAcc fragments.pop(offset + 3); if (hasReach) - fragments.push(Expression::create_nary(SIMULATEREACH, std::move(args), position)); + fragments.push(Expression::create_nary(Kind::SIMULATEREACH, std::move(args), position)); else - fragments.push(Expression::create_nary(SIMULATE, std::move(args), position)); + fragments.push(Expression::create_nary(Kind::SIMULATE, std::move(args), position)); } void ExpressionBuilder::expr_MITL_formula() @@ -826,7 +826,7 @@ void ExpressionBuilder::expr_MITL_formula() Expression mitl = fragments[0]; if (!isMITL(mitl)) mitl = toMITLAtom(mitl); - Expression form = Expression::create_unary(MITL_FORMULA, mitl, position); + Expression form = Expression::create_unary(Kind::MITL_FORMULA, mitl, position); fragments.pop(); fragments.push(form); } @@ -842,7 +842,7 @@ void ExpressionBuilder::expr_MITL_until(int low, int high) auto lowd = make_constant(low); auto highd = make_constant(high); auto args = std::vector{left, lowd, highd, right}; - Expression form = Expression::create_nary(MITL_UNTIL, std::move(args), position); + Expression form = Expression::create_nary(Kind::MITL_UNTIL, std::move(args), position); fragments.pop(2); fragments.push(form); } @@ -859,20 +859,20 @@ void ExpressionBuilder::expr_MITL_release(int low, int high) auto highd = make_constant(high); auto args = std::vector{left, lowd, highd, right}; fragments.pop(2); - fragments.push(Expression::create_nary(MITL_RELEASE, std::move(args), position)); + fragments.push(Expression::create_nary(Kind::MITL_RELEASE, std::move(args), position)); } /*transform the diamond <>[low,high]phi into a (true U[low,high] phi) structure */ void ExpressionBuilder::expr_MITL_diamond(int low, int high) { - auto left = Expression::create_unary(MITL_ATOM, make_constant(1)); + auto left = Expression::create_unary(Kind::MITL_ATOM, make_constant(1)); auto right = fragments[0]; if (!isMITL(right)) right = toMITLAtom(right); auto lowd = make_constant(low); auto highd = make_constant(high); auto args = std::vector{left, lowd, highd, right}; - Expression form = Expression::create_nary(MITL_UNTIL, std::move(args), position); + Expression form = Expression::create_nary(Kind::MITL_UNTIL, std::move(args), position); fragments.pop(1); fragments.push(form); } @@ -880,14 +880,14 @@ void ExpressionBuilder::expr_MITL_diamond(int low, int high) /*transform the diamond [][low,high]phi into a (false R[low,high] phi) structure */ void ExpressionBuilder::expr_MITL_box(int low, int high) { - auto left = Expression::create_unary(MITL_ATOM, make_constant(0)); + auto left = Expression::create_unary(Kind::MITL_ATOM, make_constant(0)); auto right = fragments[0]; if (!isMITL(right)) right = toMITLAtom(right); auto lowd = make_constant(low); auto highd = make_constant(high); auto args = std::vector{left, lowd, highd, right}; - Expression form = Expression::create_nary(MITL_RELEASE, std::move(args), position); + Expression form = Expression::create_nary(Kind::MITL_RELEASE, std::move(args), position); fragments.pop(1); fragments.push(form); } @@ -896,7 +896,7 @@ void ExpressionBuilder::expr_MITL_disj() { auto& left = fragments[1]; auto& right = fragments[0]; - Expression form = Expression::create_binary(MITL_DISJ, left, right, position); + Expression form = Expression::create_binary(Kind::MITL_DISJ, left, right, position); fragments.pop(2); fragments.push(form); } @@ -906,7 +906,7 @@ void ExpressionBuilder::expr_MITL_conj() auto left = fragments[1]; auto right = fragments[0]; fragments.pop(2); - fragments.push(Expression::create_binary(MITL_CONJ, left, right, position)); + fragments.push(Expression::create_binary(Kind::MITL_CONJ, left, right, position)); } void ExpressionBuilder::expr_MITL_next() @@ -915,7 +915,7 @@ void ExpressionBuilder::expr_MITL_next() if (!isMITL(next)) next = toMITLAtom(next); fragments.pop(); - fragments.push(Expression::create_unary(MITL_NEXT, next, position)); + fragments.push(Expression::create_unary(Kind::MITL_NEXT, next, position)); } void ExpressionBuilder::expr_MITL_atom() @@ -923,7 +923,7 @@ void ExpressionBuilder::expr_MITL_atom() Expression atom = fragments[0]; if (!isMITL(atom)) { fragments.pop(); - fragments.push(Expression::create_unary(MITL_ATOM, atom, position)); + fragments.push(Expression::create_unary(Kind::MITL_ATOM, atom, position)); } } @@ -934,7 +934,7 @@ void ExpressionBuilder::expr_spawn(int n) for (auto i = 0; i <= n; ++i) exprs[i] = fragments[n - i]; fragments.pop(n + 1); - fragments.push(Expression::create_nary(SPAWN, std::move(exprs), position, id.get_type())); + fragments.push(Expression::create_nary(Kind::SPAWN, std::move(exprs), position, id.get_type())); } void ExpressionBuilder::expr_exit() { fragments.push(Expression::create_exit(position)); } @@ -942,15 +942,15 @@ void ExpressionBuilder::expr_exit() { fragments.push(Expression::create_exit(pos void ExpressionBuilder::expr_numof() { Expression id = fragments[0]; - Type t = Type::create_primitive(Constants::INT, position); + Type t = Type::create_primitive(Kind::INT, position); fragments.pop(); - fragments.push(Expression::create_unary(NUMOF, id, position, t)); + fragments.push(Expression::create_unary(Kind::NUMOF, id, position, t)); } void ExpressionBuilder::expr_forall_dynamic_begin(std::string_view name, std::string_view temp) { push_frame(frames.top().make_sub()); - frames.top().add_symbol(name, Type::create_primitive(PROCESS_VAR, position), position); + frames.top().add_symbol(name, Type::create_primitive(Kind::PROCESS_VAR, position), position); Template* templ = document.find_dynamic_template(temp); if (templ == nullptr) throw unknown_dynamic_template_error(temp); @@ -967,7 +967,7 @@ void ExpressionBuilder::expr_forall_dynamic_end(std::string_view name) auto identifier = Expression::create_identifier(frames.top()[0], position); bool mitl = isMITL(expr); if (mitl) { - if (expr.get_kind() == MITL_ATOM) { + if (expr.get_kind() == Kind::MITL_ATOM) { expr = expr.get(0).clone(); mitl = false; } @@ -975,15 +975,15 @@ void ExpressionBuilder::expr_forall_dynamic_end(std::string_view name) auto exprs = std::vector{identifier, process, expr}; fragments.pop(2); - fragments.push(Expression::create_nary((mitl ? MITL_FORALL : FORALL_DYNAMIC), std::move(exprs), position, - Type::create_primitive(Constants::BOOL, position))); + fragments.push(Expression::create_nary((mitl ? Kind::MITL_FORALL : Kind::FORALL_DYNAMIC), std::move(exprs), position, + Type::create_primitive(Kind::BOOL, position))); pop_frame(); pop_dynamic_frame_of(name); } void ExpressionBuilder::expr_exists_dynamic_begin(std::string_view name, std::string_view temp) { push_frame(frames.top().make_sub()); - frames.top().add_symbol(name, Type::create_primitive(Constants::PROCESS_VAR, position), position); + frames.top().add_symbol(name, Type::create_primitive(Kind::PROCESS_VAR, position), position); if (Template* templ = document.find_dynamic_template(temp); templ == nullptr) throw unknown_dynamic_template_error(temp); else { @@ -999,15 +999,15 @@ void ExpressionBuilder::expr_exists_dynamic_end(std::string_view name) Expression identifier = Expression::create_identifier(frames.top()[0], position); bool mitl = isMITL(expr); if (mitl) { - if (expr.get_kind() == MITL_ATOM) { + if (expr.get_kind() == Kind::MITL_ATOM) { expr = expr.get(0).clone(); mitl = false; } } auto exprs = std::vector{identifier, process, expr}; fragments.pop(2); - fragments.push(Expression::create_nary((mitl ? MITL_EXISTS : EXISTS_DYNAMIC), std::move(exprs), position, - Type::create_primitive(Constants::BOOL, position))); + fragments.push(Expression::create_nary((mitl ? Kind::MITL_EXISTS : Kind::EXISTS_DYNAMIC), std::move(exprs), position, + Type::create_primitive(Kind::BOOL, position))); pop_frame(); pop_dynamic_frame_of(name); } @@ -1015,7 +1015,7 @@ void ExpressionBuilder::expr_exists_dynamic_end(std::string_view name) void ExpressionBuilder::expr_sum_dynamic_begin(std::string_view name, std::string_view temp) { push_frame(frames.top().make_sub()); - frames.top().add_symbol(name, Type::create_primitive(Constants::PROCESS_VAR, position), position); + frames.top().add_symbol(name, Type::create_primitive(Kind::PROCESS_VAR, position), position); Template* templ = document.find_dynamic_template(temp); if (templ == nullptr) throw unknown_dynamic_template_error(temp); @@ -1029,8 +1029,9 @@ void ExpressionBuilder::expr_sum_dynamic_end(std::string_view name) Expression& process = fragments[1]; Expression identifier = Expression::create_identifier(frames.top()[0], position); auto exprs = std::vector{identifier, process, expr}; + auto type = expr.get_type(); // save before pop() invalidates the reference fragments.pop(2); - fragments.push(Expression::create_nary(SUM_DYNAMIC, std::move(exprs), position, expr.get_type())); + fragments.push(Expression::create_nary(Kind::SUM_DYNAMIC, std::move(exprs), position, std::move(type))); pop_frame(); pop_dynamic_frame_of(name); } @@ -1038,7 +1039,7 @@ void ExpressionBuilder::expr_sum_dynamic_end(std::string_view name) void ExpressionBuilder::expr_foreach_dynamic_begin(std::string_view name, std::string_view temp) { push_frame(frames.top().make_sub()); - frames.top().add_symbol(name, Type::create_primitive(Constants::PROCESS_VAR, position), position); + frames.top().add_symbol(name, Type::create_primitive(Kind::PROCESS_VAR, position), position); if (auto* t = document.find_dynamic_template(temp); t != nullptr) { // dynamicFrames [name]=document->find_dynamic_template(temp)->frame; push_dynamic_frame_of(document.find_dynamic_template(temp), name); @@ -1053,8 +1054,8 @@ void ExpressionBuilder::expr_foreach_dynamic_end(std::string_view name) auto identifier = Expression::create_identifier(frames.top()[0], position); auto exprs = std::vector{identifier, process, expr}; fragments.pop(2); - fragments.push(Expression::create_nary(FOREACH_DYNAMIC, std::move(exprs), position, - Type::create_primitive(Constants::INT, position))); + fragments.push(Expression::create_nary(Kind::FOREACH_DYNAMIC, std::move(exprs), position, + Type::create_primitive(Kind::INT, position))); pop_frame(); pop_dynamic_frame_of(name); } @@ -1071,3 +1072,5 @@ void ExpressionBuilder::pop_dynamic_frame_of(std::string_view name) if (auto it = dynamicFrames.find(name); it != dynamicFrames.end()) dynamicFrames.erase(it); } + +} // namespace UTAP \ No newline at end of file diff --git a/src/FeatureChecker.cpp b/src/FeatureChecker.cpp index b9cf7f83..41ef120f 100644 --- a/src/FeatureChecker.cpp +++ b/src/FeatureChecker.cpp @@ -27,7 +27,7 @@ #include -using namespace UTAP; +namespace UTAP { FeatureChecker::FeatureChecker(Document& document) { @@ -62,14 +62,15 @@ void FeatureChecker::visit_edge(Edge& edge) void FeatureChecker::visit_guard(Expression& guard) { switch (guard.get_kind()) { - case Constants::LT: - case Constants::LE: - case Constants::EQ: + using namespace KindNames; + case LT: + case LE: + case EQ: for (auto i = 0u; i < guard.get_size(); ++i) { if (guard.get(i).uses_fp()) supported_methods.symbolic = false; } - [[fallthrough]]; + [[fallthrough]]; default: break; } } @@ -77,11 +78,11 @@ void FeatureChecker::visit_guard(Expression& guard) void FeatureChecker::visit_assignment(Expression& ass) { switch (ass.get_kind()) { - case Constants::ASSIGN: + case Kind::ASSIGN: if (ass.uses_fp() && !ass.uses_hybrid()) supported_methods.symbolic = false; break; - case Constants::COMMA: + case Kind::COMMA: for (auto i = 0u; i < ass.get_size(); ++i) visit_assignment(ass.get(i)); break; @@ -104,16 +105,16 @@ void FeatureChecker::visit_location(Location& location) */ bool FeatureChecker::is_rate_disallowed_in_symbolic(const Expression& e) { - if (e.get_kind() == Constants::EQ) { + if (e.get_kind() == Kind::EQ) { assert(e.get_size() >= 2); Expression rate; Expression clock; - if (e.get(0).get_kind() == Constants::RATE) { + if (e.get(0).get_kind() == Kind::RATE) { clock = e.get(0); rate = e.get(1); - } else if (e.get(1).get_kind() == Constants::RATE) { + } else if (e.get(1).get_kind() == Kind::RATE) { clock = e.get(1); rate = e.get(0); } else { @@ -121,10 +122,10 @@ bool FeatureChecker::is_rate_disallowed_in_symbolic(const Expression& e) } // rates over hybrid clocks are allowed, because they are ignored/abstracted in symbolic analysis - if (clock.get(0).get_symbol().get_type().is(Constants::HYBRID)) + if (clock.get(0).get_symbol().get_type().is(Kind::HYBRID)) return false; - if (rate.get_kind() != Constants::CONSTANT) + if (rate.get_kind() != Kind::CONSTANT) return false; if (rate.get_value() != 0 && rate.get_value() != 1) return true; // NOLINT(readability-simplify-boolean-expr) @@ -132,7 +133,7 @@ bool FeatureChecker::is_rate_disallowed_in_symbolic(const Expression& e) return false; } - if (e.get_kind() == Constants::AND) { + if (e.get_kind() == Kind::AND) { for (uint32_t i = 0; i < e.get_size(); ++i) { if (is_rate_disallowed_in_symbolic(e.get(i))) return true; @@ -146,7 +147,9 @@ void FeatureChecker::visit_frame(const Frame& frame) { for (uint32_t i = 0; i < frame.get_size(); ++i) { Type t = frame.get_symbol(i).get_type(); - if (t.is_channel() && !t.is(Constants::BROADCAST)) + if (t.is_channel() && !t.is(Kind::BROADCAST)) supported_methods.stochastic = false; } } + +} // namespace UTAP \ No newline at end of file diff --git a/src/PrettyPrinter.cpp b/src/PrettyPrinter.cpp index f68f8154..c6ccfcdd 100644 --- a/src/PrettyPrinter.cpp +++ b/src/PrettyPrinter.cpp @@ -31,26 +31,26 @@ #include #include -using namespace UTAP; -using namespace UTAP::Constants; +namespace UTAP { + using namespace std::string_literals; using namespace std::string_view_literals; -static inline const std::string& label(AbstractBuilder::TypePrefix prefix) +static const std::string& label(TypePrefix prefix) { static const std::string labels[] = {"", "const ", "urgent ", "", "broadcast ", "", "urgent broadcast ", "", "meta "}; - return labels[(uint8_t)prefix]; + return labels[static_cast(prefix)]; } -static inline std::string pop_back(std::vector& vs) +static std::string pop_back(std::vector& vs) { auto res = std::move(vs.back()); vs.pop_back(); return res; } -static inline std::string pop_top(std::stack& ss) +static std::string pop_top(std::stack& ss) { auto res = std::move(ss.top()); ss.pop(); @@ -59,16 +59,15 @@ static inline std::string pop_top(std::stack& ss) void PrettyPrinter::indent() { - for (uint32_t i = 0; i < level; i++) { + for (uint32_t i = 0; i < level; i++) *o.top() << '\t'; - } } -void PrettyPrinter::indent(std::string& s) +void PrettyPrinter::indent(std::string& s) const { - for (uint32_t i = 0; i < level; i++) { + s.reserve(s.size() + level); + for (uint32_t i = 0; i < level; i++) s += '\t'; - } } PrettyPrinter::PrettyPrinter(std::ostream& stream) @@ -80,7 +79,7 @@ PrettyPrinter::PrettyPrinter(std::ostream& stream) select = guard = sync = update = probability = -1; } -void PrettyPrinter::add_position(uint32_t position, uint32_t offset, uint32_t line, std::shared_ptr path) +void PrettyPrinter::add_position(uint32_t, uint32_t, uint32_t, std::shared_ptr) {} void PrettyPrinter::handle_error(const TypeException& msg) { throw msg; } @@ -126,9 +125,9 @@ void PrettyPrinter::type_name(TypePrefix prefix, std::string_view name) type.push(label(prefix) + std::string{name}); } -void PrettyPrinter::type_array_of_size(uint32_t n) { array.push(pop_back(st)); } +void PrettyPrinter::type_array_of_size(uint32_t) { array.push(pop_back(st)); } -void PrettyPrinter::type_array_of_type(uint32_t n) +void PrettyPrinter::type_array_of_type(uint32_t) { array.push(type.top()); type.pop(); @@ -205,7 +204,7 @@ void PrettyPrinter::expr_nary(Kind kind, uint32_t num) { auto opString = std::string{}; switch (kind) { - case LIST: opString = ", "; break; + case Kind::LIST: opString = ", "; break; default: throw TypeException{"Invalid operator"}; } @@ -250,9 +249,13 @@ void PrettyPrinter::decl_func_end() *o.top() << "}\n"; } -void PrettyPrinter::dynamic_load_lib(std::string_view name) {} +void PrettyPrinter::dynamic_load_lib(std::string_view) {} -void PrettyPrinter::decl_external_func(std::string_view name, std::string_view alias) {} +void PrettyPrinter::decl_external_func(std::string_view, std::string_view) +{ + pop_top(type); // discard the return type pushed for this declaration + param.clear(); // discard the parameters accumulated by decl_parameter() +} void PrettyPrinter::block_begin() { @@ -284,7 +287,7 @@ void PrettyPrinter::iteration_begin(std::string_view id) type.pop(); } -void PrettyPrinter::iteration_end(std::string_view id) +void PrettyPrinter::iteration_end(std::string_view) { *o.top() << '\n'; level--; @@ -329,9 +332,25 @@ void PrettyPrinter::while_end() // 1 expr, 1 stat delete s; } -void PrettyPrinter::do_while_begin() {} +void PrettyPrinter::do_while_begin() +{ + level++; + o.push(new std::ostringstream{}); +} + +void PrettyPrinter::do_while_end() +{ + auto expr = pop_back(st); + auto* s = dynamic_cast(o.top()); + o.pop(); -void PrettyPrinter::do_while_end() {} + level--; + indent(); + *o.top() << "do\n" << s->str() << '\n'; + indent(); + *o.top() << "while (" << expr << ");\n"; + delete s; +} void PrettyPrinter::if_begin() { @@ -394,7 +413,7 @@ void PrettyPrinter::return_statement(bool hasValue) } } -void PrettyPrinter::proc_begin(std::string_view id, const bool isTA, std::string_view type, std::string_view mode) +void PrettyPrinter::proc_begin(std::string_view id, const bool, std::string_view, std::string_view) { *o.top() << "process " << id << templateset << '(' << param << ")\n{\n"; param.clear(); @@ -492,12 +511,12 @@ void PrettyPrinter::proc_select(std::string_view id) void PrettyPrinter::proc_guard() { guard = static_cast(st.size()); } -void PrettyPrinter::proc_sync(Synchronisation type) +void PrettyPrinter::proc_sync(Sync type) { switch (type) { - case SYNC_QUE: st.back() += '?'; break; - case SYNC_BANG: st.back() += '!'; break; - case SYNC_CSP: + case Sync::QUE: st.back() += '?'; break; + case Sync::BANG: st.back() += '!'; break; + case Sync::CSP: // no append break; } @@ -539,7 +558,7 @@ void PrettyPrinter::proc_edge_begin(std::string_view source, std::string_view ta } } -void PrettyPrinter::proc_edge_end(std::string_view source, std::string_view target) +void PrettyPrinter::proc_edge_end(std::string_view, std::string_view) { level++; @@ -722,10 +741,10 @@ static std::string_view get_builtin_fun_name(Kind kind) "random_poisson", "random_tri", "random_weibull"}; - static_assert(RANDOM_WEIBULL_F - ABS_F + 1 == sizeof(funNames) / sizeof(funNames[0]), + static_assert(Kind::RANDOM_WEIBULL_F - Kind::ABS_F + 1 == sizeof(funNames) / sizeof(funNames[0]), "Builtin function name list is wrong"); - assert(ABS_F <= kind && kind <= RANDOM_WEIBULL_F); - return funNames[kind - ABS_F]; + assert(Kind::ABS_F <= kind && kind <= Kind::RANDOM_WEIBULL_F); + return funNames[kind - Kind::ABS_F]; } void PrettyPrinter::expr_builtin_function1(Kind kind) @@ -752,6 +771,7 @@ void PrettyPrinter::expr_assignment(Kind op) auto lhs = pop_back(st); st.emplace_back(); switch (op) { + using namespace KindNames; case ASSIGN: st.back() = '(' + lhs + " = " + rhs + ')'; break; case ASS_PLUS: st.back() = '(' + lhs + " += " + rhs + ')'; break; case ASS_MINUS: st.back() = '(' + lhs + " -= " + rhs + ')'; break; @@ -772,6 +792,7 @@ void PrettyPrinter::expr_unary(Kind op) auto exp = pop_back(st); st.emplace_back(); switch (op) { + using namespace KindNames; case MINUS: st.back() = '-' + exp; break; case NOT: st.back() = '!' + exp; break; case PLUS: st.back() = '+' + exp; break; @@ -789,6 +810,7 @@ void PrettyPrinter::expr_binary(Kind op) auto exp1 = pop_back(st); st.emplace_back(); switch (op) { + using namespace KindNames; case PO_CONTROL: st.back() = exp1 + " control: " + exp2; break; case CONTROL_TOPT_DEF1: st.back() = "control_t*(" + exp1 + "): " + exp2; break; case PLUS: st.back() = '(' + exp1 + " + " + exp2 + ')'; break; @@ -824,8 +846,8 @@ void PrettyPrinter::expr_ternary(Kind op, bool firstMissing) auto exp1 = (firstMissing) ? "1"s : pop_back(st); st.emplace_back(); switch (op) { - case CONTROL_TOPT: st.back() = "control_t*(" + exp1 + "," + exp2 + "): " + exp3; break; - case SMC_CONTROL: st.back() = "control[" + exp1 + "<=" + exp2 + "]: " + exp3; break; + case Kind::CONTROL_TOPT: st.back() = "control_t*(" + exp1 + "," + exp2 + "): " + exp3; break; + case Kind::SMC_CONTROL: st.back() = "control[" + exp1 + "<=" + exp2 + "]: " + exp3; break; default: throw TypeException{"Invalid operator"}; } } @@ -858,7 +880,7 @@ void PrettyPrinter::expr_forall_begin(std::string_view name) st.push_back("forall (" + std::string{name} + ":" + pop_top(type) + ") "); } -void PrettyPrinter::expr_forall_end(std::string_view name) +void PrettyPrinter::expr_forall_end(std::string_view) { auto expr = pop_back(st); st.back() += expr; @@ -869,7 +891,7 @@ void PrettyPrinter::expr_exists_begin(std::string_view name) st.push_back("exists (" + std::string{name} + ":" + pop_top(type) + ") "); } -void PrettyPrinter::expr_exists_end(std::string_view name) +void PrettyPrinter::expr_exists_end(std::string_view) { auto expr = pop_back(st); st.back() += expr; @@ -880,7 +902,7 @@ void PrettyPrinter::expr_sum_begin(std::string_view name) st.push_back("sum (" + std::string{name} + ":" + pop_top(type) + ") "); } -void PrettyPrinter::expr_sum_end(std::string_view name) +void PrettyPrinter::expr_sum_end(std::string_view) { auto expr = pop_back(st); st.back() += expr; @@ -906,12 +928,12 @@ void PrettyPrinter::after_update() *o.top() << "}\n"; } -void PrettyPrinter::instantiation_begin(std::string_view id, uint32_t, std::string_view templ) +void PrettyPrinter::instantiation_begin(std::string_view, uint32_t, std::string_view) { // Ignore } -void PrettyPrinter::instantiation_end(std::string_view id, uint32_t parameters, std::string_view templ, +void PrettyPrinter::instantiation_end(std::string_view id, uint32_t, std::string_view templ, uint32_t arguments) { auto s = std::stack{}; @@ -964,7 +986,7 @@ void PrettyPrinter::exprProba2(bool isTimedBound, int type) st.push_back(ss.str()); } */ -void PrettyPrinter::expr_proba_quantitative(Constants::Kind type) +void PrettyPrinter::expr_proba_quantitative(Kind) { const auto pred2 = pop_back(st); const auto pred1 = pop_back(st); @@ -1034,7 +1056,7 @@ void PrettyPrinter::expr_simulate(int nbExpr, bool hasReach, int nbOfAcceptingRu /** Built-in verification queries if any */ void PrettyPrinter::query_begin() { *o.top() << "\n/** Query begin: */\n"; } -void PrettyPrinter::query_formula(std::string_view formula, std::string_view location) +void PrettyPrinter::query_formula(std::string_view formula, std::string_view) { if (not formula.empty()) *o.top() << "/* Formula: " << formula << " */\n"; @@ -1045,3 +1067,5 @@ void PrettyPrinter::query_comment(std::string_view comment) *o.top() << "/* Comment: " << comment << " */\n"; } void PrettyPrinter::query_end() { *o.top() << "/** Query end. */\n"; } + +} // namespace UTAP \ No newline at end of file diff --git a/src/StatementBuilder.cpp b/src/StatementBuilder.cpp index 3596aecd..4484b5a8 100644 --- a/src/StatementBuilder.cpp +++ b/src/StatementBuilder.cpp @@ -34,8 +34,7 @@ #include #endif -using namespace UTAP; -using namespace Constants; +namespace UTAP { StatementBuilder::StatementBuilder(Document& doc, std::vector libpaths): ExpressionBuilder{doc}, libpaths{std::move(libpaths)} @@ -44,7 +43,7 @@ StatementBuilder::StatementBuilder(Document& doc, std::vectorlibpaths.emplace(this->libpaths.begin(), ""); } -void StatementBuilder::collectDependencies(std::set& dependencies, const Expression& expr) +void StatementBuilder::collect_dependencies(std::set& dependencies, const Expression& expr) { auto symbols = std::set{}; expr.collect_possible_reads(symbols); @@ -66,16 +65,16 @@ void StatementBuilder::collectDependencies(std::set& dependencies, const } } -void StatementBuilder::collectDependencies(std::set& dependencies, const Type& type) +void StatementBuilder::collect_dependencies(std::set& dependencies, const Type& type) { - if (type.get_kind() == RANGE) { + if (type.get_kind() == Kind::RANGE) { auto [lower, upper] = type.get_range(); - collectDependencies(dependencies, lower); - collectDependencies(dependencies, upper); - collectDependencies(dependencies, type[0]); + collect_dependencies(dependencies, lower); + collect_dependencies(dependencies, upper); + collect_dependencies(dependencies, type[0]); } else { for (uint32_t i = 0; i < type.size(); ++i) - collectDependencies(dependencies, type[i]); + collect_dependencies(dependencies, type[i]); } } @@ -88,7 +87,7 @@ void StatementBuilder::type_array_of_size(uint32_t n) expr_nat(0); fragments.push(expr); expr_nat(1); - expr_binary(MINUS); + expr_binary(Kind::MINUS); type_bounded_int(TypePrefix::NONE); type_array_of_type(n + 1); } @@ -104,10 +103,10 @@ void StatementBuilder::type_array_of_type(uint32_t n) * processes. */ if (currentTemplate != nullptr) { - collectDependencies(currentTemplate->restricted, size); + collect_dependencies(currentTemplate->restricted, size); } - if ((!size.is_integer() && !size.is_scalar()) || !size.is(RANGE)) { + if ((!size.is_integer() && !size.is_scalar()) || !size.is(Kind::RANGE)) { handle_error(TypeException{"$Array_must_be_defined_over_an_integer_range_or_a_scalar_set"}); } } @@ -135,7 +134,7 @@ void StatementBuilder::struct_field(std::string_view name) auto type = typeFragments.pop(); // Constant fields are not allowed - if (type.is(CONSTANT)) + if (type.is(Kind::CONSTANT)) handle_error(TypeException{"$Constant_fields_not_allowed_in_struct"}); fields.push_back(type); @@ -171,7 +170,7 @@ static bool initialisable(Type type) { type = type.strip(); switch (type.get_kind()) { - case RECORD: + case Kind::RECORD: for (auto i = 0u; i < type.size(); i++) { if (!initialisable(type[i])) { return false; @@ -179,12 +178,12 @@ static bool initialisable(Type type) } return true; - case ARRAY: + case Kind::ARRAY: if (type.get_array_size().is_scalar()) { return false; } return initialisable(type.get_sub()); - case STRING: return true; + case Kind::STRING: return true; default: return type.is_integral() || type.is_clock() || type.is_double(); } } @@ -192,15 +191,15 @@ static bool initialisable(Type type) static bool mustInitialise(const Type& type) { const auto k = type.get_kind(); - assert(k != FUNCTION); - assert(k != FUNCTION_EXTERNAL); - assert(k != PROCESS); - assert(k != INSTANCE); - assert(k != LSC_INSTANCE); + assert(k != Kind::FUNCTION); + assert(k != Kind::FUNCTION_EXTERNAL); + assert(k != Kind::PROCESS); + assert(k != Kind::INSTANCE); + assert(k != Kind::LSC_INSTANCE); switch (k) { - case CONSTANT: return true; - case RECORD: + case Kind::CONSTANT: return true; + case Kind::RECORD: for (auto i = 0u; i < type.size(); i++) { if (mustInitialise(type[i])) { return true; @@ -243,7 +242,7 @@ void StatementBuilder::decl_var(std::string_view name, bool hasInit) } // Add variable to document - addVariable(type, name, init, position_t()); + add_variable(type, name, init, position_t()); } // Array and struct initialisers are represented as expressions having @@ -284,13 +283,13 @@ Expression StatementBuilder::make_initialiser(const Type& type, const Expression { if (type.is_assignment_compatible(init.get_type(), true)) { return init; - } else if (type.is_array() && init.get_kind() == LIST) { + } else if (type.is_array() && init.get_kind() == Kind::LIST) { auto subtype = type.get_sub(); auto result = std::vector(init.get_size()); for (uint32_t i = 0; i < init.get_type().size(); i++) result[i] = make_initialiser(subtype, init[i]); - return Expression::create_nary(LIST, result, init.get_position(), type); - } else if (type.is_record() && init.get_kind() == LIST) { + return Expression::create_nary(Kind::LIST, result, init.get_position(), type); + } else if (type.is_record() && init.get_kind() == Kind::LIST) { /* In order to access the record labels we have to strip any * prefixes and labels from the record type. */ @@ -317,7 +316,7 @@ Expression StatementBuilder::make_initialiser(const Type& type, const Expression } result[current] = make_initialiser(type.get_sub(current), init[i]); } - return Expression::create_nary(LIST, result, init.get_position(), type); + return Expression::create_nary(Kind::LIST, result, init.get_position(), type); } document.add_error(init.get_position(), "$Invalid_initialiser", type.str()); return init; @@ -343,7 +342,7 @@ void StatementBuilder::decl_init_list(uint32_t num) fields[i].set_type(type[0]); } // Create list expression - fragments.push(Expression::create_nary(LIST, fields, position, Type::create_record(types, labels, position))); + fragments.push(Expression::create_nary(Kind::LIST, fields, position, Type::create_record(types, labels, position))); } /******************************************************************** @@ -353,7 +352,7 @@ void StatementBuilder::decl_parameter(std::string_view name, bool ref) { Type type = typeFragments.pop(); if (ref) - type = type.create_prefix(REF); + type = type.create_prefix(Kind::REF); params.add_symbol(name, type, position); } @@ -383,7 +382,7 @@ void StatementBuilder::decl_func_begin(std::string_view name) labels.push_back(param.get_name()); } auto type = Type::create_function(return_type, types, labels, position); - if (!addFunction(type, name, {})) + if (!add_function(type, name, {})) handle_error(duplicate_definition_error(name)); /* We maintain a stack of frames. As the function has a local @@ -473,7 +472,7 @@ void StatementBuilder::decl_external_func(std::string_view name, std::string_vie } auto type = Type::create_external_function(return_type, types, labels, position); - if (!addFunction(type, alias, position_t())) + if (!add_function(type, alias, position_t())) handle_error(duplicate_definition_error(alias)); push_frame(frames.top().make_sub()); params.move_to(frames.top()); // params is emptied here @@ -520,15 +519,15 @@ void StatementBuilder::iteration_begin(std::string_view name) { Type type = typeFragments.pop(); // The iterator cannot be modified. - if (!type.is(CONSTANT)) { - type = type.create_prefix(CONSTANT); + if (!type.is(Kind::CONSTANT)) { + type = type.create_prefix(Kind::CONSTANT); } // The iteration statement has a local scope for the iterator. push_frame(frames.top().make_sub()); // Add variable. - Variable* variable = addVariable(type, name, Expression(), position_t()); + Variable* variable = add_variable(type, name, Expression(), position_t()); /* Create a new statement for the loop. We need to already create * this here as the statement is the only thing that can keep the @@ -537,7 +536,7 @@ void StatementBuilder::iteration_begin(std::string_view name) get_block().push(std::make_unique(variable->uid, frames.top(), nullptr)); } -void StatementBuilder::iteration_end(std::string_view name) +void StatementBuilder::iteration_end(std::string_view) { // Retrieve the statement that we iterate over. auto statement = get_block().pop(); @@ -566,6 +565,12 @@ void StatementBuilder::do_while_end() get_block().push(std::make_unique(std::move(substat), fragments.pop())); } +void StatementBuilder::if_begin() {} + +void StatementBuilder::if_condition() {} + +void StatementBuilder::if_then() {} + void StatementBuilder::if_end(bool elsePart) { // 1 expr, 1 or 2 statements std::unique_ptr falseCase; @@ -621,3 +626,5 @@ void StatementBuilder::expr_call_begin() handle_error(TypeException{"$Recursion_is_not_allowed"}); } } + +} // namespace UTAP \ No newline at end of file diff --git a/src/TypeChecker.cpp b/src/TypeChecker.cpp index 5d116336..6307ef0d 100644 --- a/src/TypeChecker.cpp +++ b/src/TypeChecker.cpp @@ -38,19 +38,19 @@ #include #include #include + #include // size_t #include // uint32_t #include -using namespace UTAP; -using namespace Constants; +namespace UTAP { using namespace std::string_literals; namespace { // anonymous namespace is preferred over `static` (C++ standard) /// The following are simple helper functions for testing the type of expressions. -bool is_cost(const Expression& expr) { return expr.get_type().is(COST); } +bool is_cost(const Expression& expr) { return expr.get_type().is(Kind::COST); } bool is_void(const Expression& expr) { return expr.get_type().is_void(); } @@ -69,7 +69,7 @@ bool is_string(Expression expr) bool is_integer(const Expression& expr) { return expr.get_type().is_integer(); } -bool is_const_integer(const Expression& expr) { return expr.get_kind() == CONSTANT && is_integer(expr); } +bool is_const_integer(const Expression& expr) { return expr.get_kind() == Kind::CONSTANT && is_integer(expr); } bool is_default_int(const Type& type) { @@ -93,7 +93,7 @@ bool is_double_value(const Expression& expr) { return is_double(expr) || is_cloc bool is_number(const Expression& expr) { return is_double_value(expr) || is_integral(expr); } -bool is_const_double(const Expression& expr) { return expr.get_kind() == CONSTANT && is_double(expr); } +bool is_const_double(const Expression& expr) { return expr.get_kind() == Kind::CONSTANT && is_double(expr); } bool is_invariant(const Expression& expr) { return expr.get_type().is_invariant(); } @@ -107,7 +107,7 @@ bool is_formula(const Expression& expr) { return expr.get_type().is_formula(); } bool is_formula_list(const Expression& expr) { - if (expr.get_kind() != LIST) { + if (expr.get_kind() != Kind::LIST) { return false; } @@ -129,12 +129,12 @@ bool hasStrictLowerBound(const Expression& expr) } switch (expr.get_kind()) { - case LT: // int < clock + case Kind::LT: // int < clock if (is_integral(expr[0]) && is_clock(expr[1])) { return true; } break; - case GT: // clock > int + case Kind::GT: // clock > int if (is_clock(expr[0]) && is_integral(expr[1])) { return true; } @@ -155,12 +155,12 @@ bool hasStrictUpperBound(const Expression& expr) } switch (expr.get_kind()) { - case GT: // int > clock + case Kind::GT: // int > clock if (is_integral(expr[0]) && is_clock(expr[1])) { return true; } break; - case LT: // clock < int + case Kind::LT: // clock < int if (is_clock(expr[0]) && is_integral(expr[1])) { return true; } @@ -176,7 +176,7 @@ bool hasStrictUpperBound(const Expression& expr) * Returns true iff type is a valid invariant. A valid invariant is * either an invariant expression or an integer expression. */ -bool is_invariant_wr(const Expression& expr) { return is_invariant(expr) || (expr.get_type().is(INVARIANT_WR)); } +bool is_invariant_wr(const Expression& expr) { return is_invariant(expr) || (expr.get_type().is(Kind::INVARIANT_WR)); } /** * Returns true if values of this type can be assigned. This is the @@ -186,13 +186,14 @@ bool is_invariant_wr(const Expression& expr) { return is_invariant(expr) || (exp bool is_assignable(const Type& type) { switch (type.get_kind()) { - case Constants::INT: - case Constants::BOOL: - case Constants::DOUBLE: - case Constants::STRING: - case Constants::CLOCK: - case Constants::COST: - case Constants::SCALAR: return true; + using namespace KindNames; + case INT: + case BOOL: + case DOUBLE: + case STRING: + case CLOCK: + case COST: + case SCALAR: return true; case ARRAY: return is_assignable(type[0]); @@ -490,6 +491,7 @@ Error clock_difference_is_not_supported(const Expression& expr) bool is_game_property(const Expression& expr) { switch (expr.get_kind()) { + using namespace KindNames; case CONTROL: case SMC_CONTROL: case EF_CONTROL: @@ -503,7 +505,7 @@ bool is_game_property(const Expression& expr) bool has_MITL_in_quantified_sub(const Expression& expr) { - bool hasIt = (expr.get_kind() == MITL_FORALL || expr.get_kind() == MITL_EXISTS); + bool hasIt = (expr.get_kind() == Kind::MITL_FORALL || expr.get_kind() == Kind::MITL_EXISTS); if (!hasIt) { for (uint32_t i = 0; i < expr.get_size(); i++) { hasIt |= has_MITL_in_quantified_sub(expr.get(i)); @@ -514,7 +516,7 @@ bool has_MITL_in_quantified_sub(const Expression& expr) bool has_spawn_or_exit(const Expression& expr) { - bool hasIt = (expr.get_kind() == SPAWN || expr.get_kind() == EXIT); + bool hasIt = (expr.get_kind() == Kind::SPAWN || expr.get_kind() == Kind::EXIT); if (!hasIt) { for (uint32_t i = 0; i < expr.get_size(); i++) { hasIt |= has_spawn_or_exit(expr.get(i)); @@ -526,7 +528,8 @@ bool has_spawn_or_exit(const Expression& expr) bool valid_return_type(const Type& type) { switch (type.get_kind()) { - case Constants::RECORD: + using namespace KindNames; + case RECORD: for (uint32_t i = 0; i < type.size(); i++) { if (!valid_return_type(type[i])) { return false; @@ -534,13 +537,13 @@ bool valid_return_type(const Type& type) } return true; - case Constants::RANGE: - case Constants::LABEL: return valid_return_type(type[0]); + case RANGE: + case LABEL: return valid_return_type(type[0]); - case Constants::INT: - case Constants::BOOL: - case Constants::SCALAR: - case Constants::DOUBLE: return true; + case INT: + case BOOL: + case SCALAR: + case DOUBLE: return true; default: return false; } @@ -570,7 +573,7 @@ void CompileTimeComputableValues::visit_instance(Instance& temp) { for (const auto& param : temp.parameters) { const Type& type = param.get_type(); - if (!type.is(REF) && type.is_constant() && !type.is_double()) { + if (!type.is(Kind::REF) && type.is_constant() && !type.is_double()) { variables.insert(param); } } @@ -602,24 +605,24 @@ void RateDecomposer::decompose(const Expression& expr, bool inforall) assert(is_invariant_wr(expr)); if (is_invariant(expr)) { - if (expr.get_kind() == Constants::LT) { + if (expr.get_kind() == Kind::LT) { hasStrictInvariant = true; // Strict upper bounds only. } if (!inforall) { invariant = invariant.empty() ? expr - : invariant = Expression::create_binary(AND, invariant, expr, expr.get_position(), - Type::create_primitive(INVARIANT)); + : invariant = Expression::create_binary(Kind::AND, invariant, expr, expr.get_position(), + Type::create_primitive(Kind::INVARIANT)); } - } else if (expr.get_kind() == AND) { + } else if (expr.get_kind() == Kind::AND) { decompose(expr[0], inforall); decompose(expr[1], inforall); - } else if (expr.get_kind() == EQ) { + } else if (expr.get_kind() == Kind::EQ) { Expression left; Expression right; - assert((expr[0].get_type().get_kind() == RATE) ^ (expr[1].get_type().get_kind() == RATE)); + assert((expr[0].get_type().get_kind() == Kind::RATE) ^ (expr[1].get_type().get_kind() == Kind::RATE)); - if (expr[0].get_type().get_kind() == RATE) { + if (expr[0].get_type().get_kind() == Kind::RATE) { left = expr[0][0]; right = expr[1]; } else { @@ -634,19 +637,19 @@ void RateDecomposer::decompose(const Expression& expr, bool inforall) hasClockRates = true; if (!inforall) { invariant = invariant.empty() ? expr - : Expression::create_binary(AND, invariant, expr, expr.get_position(), - Type::create_primitive(INVARIANT_WR)); + : Expression::create_binary(Kind::AND, invariant, expr, expr.get_position(), + Type::create_primitive(Kind::INVARIANT_WR)); } } } else { - assert(expr.get_type().is(INVARIANT_WR)); - assert(expr.get_kind() == FORALL); + assert(expr.get_type().is(Kind::INVARIANT_WR)); + assert(expr.get_kind() == Kind::FORALL); // Enter the forall to look for clock rates but don't // record them, rather the forall expression. decompose(expr[1], true); invariant = invariant.empty() ? expr - : invariant = Expression::create_binary(AND, invariant, expr, expr.get_position(), - Type::create_primitive(INVARIANT_WR)); + : invariant = Expression::create_binary(Kind::AND, invariant, expr, expr.get_position(), + Type::create_primitive(Kind::INVARIANT_WR)); } } @@ -682,9 +685,9 @@ void TypeChecker::handleError(TypeError error) */ void TypeChecker::checkIgnoredValue(const Expression& expr) { - if (!expr.changes_any_variable() && expr.get_kind() != FUN_CALL_EXT) { + if (!expr.changes_any_variable() && expr.get_kind() != Kind::FUN_CALL_EXT) { handleWarning(expression_has_no_effect(expr)); - } else if (expr.get_kind() == COMMA && !expr[1].changes_any_variable() && expr[1].get_kind() != FUN_CALL_EXT) { + } else if (expr.get_kind() == Kind::COMMA && !expr[1].changes_any_variable() && expr[1].get_kind() != Kind::FUN_CALL_EXT) { handleWarning(expression_has_no_effect(expr[1])); } } @@ -728,6 +731,7 @@ void TypeChecker::checkType(const Type& type, bool initialisable, bool inStruct) Type size; switch (type.get_kind()) { + using namespace KindNames; case LABEL: checkType(type[0], initialisable, inStruct); break; case URGENT: @@ -806,14 +810,14 @@ void TypeChecker::checkType(const Type& type, bool initialisable, bool inStruct) checkType(type.get_sub(i), true, true); } break; - case Constants::STRING: + case STRING: if (inStruct) handleError(cannot_be_inside_struct(type)); - break; - case Constants::CLOCK: break; - case Constants::DOUBLE: break; - case Constants::INT: break; - case Constants::BOOL: break; + break; + case CLOCK: break; + case DOUBLE: break; + case INT: break; + case BOOL: break; default: if (initialisable) @@ -838,7 +842,7 @@ void TypeChecker::visit_doc_after(Document& doc) } // Check index expressions - while (expr.get_kind() == ARRAY) { + while (expr.get_kind() == Kind::ARRAY) { if (!isCompileTimeComputable(expr[1])) handleError(must_be_computable_at_compile_time(expr[1])); else if (i.head.changes_any_variable()) @@ -860,7 +864,7 @@ void TypeChecker::visit_doc_after(Document& doc) handleError(channel_expected(expr)); // Check index expressions - while (expr.get_kind() == ARRAY) { + while (expr.get_kind() == Kind::ARRAY) { if (!isCompileTimeComputable(expr[1])) handleError(must_be_computable_at_compile_time(expr[1])); else if (j.second.changes_any_variable()) @@ -913,8 +917,16 @@ void TypeChecker::visit_io_decl(IODecl& iodecl) syncUsed = -1; } } - if (syncUsed == -1) - handleError(csp_and_io_cannot_be_mixed(iodecl.csp.front())); + if (syncUsed == -1) { + // The mismatch may have been triggered by this iodecl's csp field + // (if it followed an IO-style one) or by its inputs/outputs (if it + // followed a CSP-style one) -- whichever of the three is actually + // populated here, since only one of them is guaranteed non-empty. + const Expression& offender = !iodecl.csp.empty() ? iodecl.csp.front() + : !iodecl.inputs.empty() ? iodecl.inputs.front() + : iodecl.outputs.front(); + handleError(csp_and_io_cannot_be_mixed(offender)); + } document.set_sync_used(syncUsed); @@ -929,7 +941,7 @@ void TypeChecker::visit_io_decl(IODecl& iodecl) handleError(channel_expected(expr)); // Check index expressions - while (expr.get_kind() == ARRAY) { + while (expr.get_kind() == Kind::ARRAY) { if (!isCompileTimeComputable(expr[1])) handleError(must_be_computable_at_compile_time(expr[1])); else if (expr.changes_any_variable()) @@ -950,7 +962,7 @@ void TypeChecker::visit_io_decl(IODecl& iodecl) handleError(channel_expected(expr)); // Check index expressions - while (expr.get_kind() == ARRAY) { + while (expr.get_kind() == Kind::ARRAY) { if (!isCompileTimeComputable(expr[1])) handleError(must_be_computable_at_compile_time(expr[1])); else if (expr.changes_any_variable()) @@ -967,7 +979,7 @@ void TypeChecker::visit_process(Instance& process) // Unbound parameters of processes must be either scalars or bounded integers. const Symbol& parameter = process.parameters[i]; const Type& type = parameter.get_type(); - if (!(type.is_scalar() || type.is_range()) || type.is(REF) || is_default_int(type)) + if (!(type.is_scalar() || type.is_range()) || type.is(Kind::REF) || is_default_int(type)) handleError(free_param_must_be_int_or_scalar(parameter)); /* Unbound parameters must not be used either directly or indirectly in any array size declarations. * I.e. they must not be restricted. */ @@ -1024,7 +1036,7 @@ void TypeChecker::visit_location(Location& loc) } if (!loc.exp_rate.empty()) { if (auto& expr = loc.exp_rate; checkExpression(expr)) { - if (!is_integral(expr) && expr.get_kind() != FRACTION && !expr.get_type().is_double()) { + if (!is_integral(expr) && expr.get_kind() != Kind::FRACTION && !expr.get_type().is_double()) { handleError(number_expected(expr)); } } @@ -1071,8 +1083,8 @@ void TypeChecker::visit_edge(Edge& edge) handleError(must_be_side_effect_free(edge.sync)); else { const bool hasClockGuard = !edge.guard.empty() && !is_integral(edge.guard); - const bool isUrgent = channel.is(URGENT); - const bool receivesBroadcast = channel.is(BROADCAST) && edge.sync.get_sync() == SYNC_QUE; + const bool isUrgent = channel.is(Kind::URGENT); + const bool receivesBroadcast = channel.is(Kind::BROADCAST) && edge.sync.get_sync() == Sync::QUE; if (isUrgent && hasClockGuard) { document.set_urgent_transition(); @@ -1111,25 +1123,25 @@ void TypeChecker::visit_edge(Edge& edge) switch (syncUsed) { case 0: switch (edge.sync.get_sync()) { - case SYNC_BANG: - case SYNC_QUE: syncUsed = 1; break; - case SYNC_CSP: syncUsed = 2; break; + case Sync::BANG: + case Sync::QUE: syncUsed = 1; break; + case Sync::CSP: syncUsed = 2; break; } break; case 1: switch (edge.sync.get_sync()) { - case SYNC_BANG: - case SYNC_QUE: + case Sync::BANG: + case Sync::QUE: // ok break; - case SYNC_CSP: syncUsed = -1; break; + case Sync::CSP: syncUsed = -1; break; } break; case 2: switch (edge.sync.get_sync()) { - case SYNC_BANG: - case SYNC_QUE: syncUsed = -1; break; - case SYNC_CSP: + case Sync::BANG: + case Sync::QUE: syncUsed = -1; break; + case Sync::CSP: // ok break; } @@ -1143,11 +1155,11 @@ void TypeChecker::visit_edge(Edge& edge) if (refinementWarnings) { switch (edge.sync.get_sync()) { - case SYNC_BANG: + case Sync::BANG: if (edge.control) handleWarning(outputs_should_be_uncontrollable(edge.sync)); break; - case SYNC_QUE: + case Sync::QUE: if (!edge.control) handleWarning(inputs_should_be_controllable(edge.sync)); break; @@ -1262,7 +1274,7 @@ void TypeChecker::visit_instance(Instance& instance) // - Constant reference with computable argument // - Reference parameter with unique lhs argument // If none of the cases are true, then we generate an error - const bool ref = parameter.get_type().is(REF); + const bool ref = parameter.get_type().is(Kind::REF); const bool constant = parameter.get_type().is_constant(); const bool computable = isCompileTimeComputable(argument); @@ -1270,7 +1282,7 @@ void TypeChecker::visit_instance(Instance& instance) (ref && constant && !computable)) { handleError(incompatible_argument(argument)); continue; - } + } checkParameterCompatible(parameter.get_type(), argument); } @@ -1282,7 +1294,7 @@ void TypeChecker::visitProperty(Expression& expr) if (expr.changes_any_variable()) { handleError(must_be_side_effect_free(expr)); } - if (expr.get_kind() == LOAD_STRAT || expr.get_kind() == SAVE_STRAT) { + if (expr.get_kind() == Kind::LOAD_STRAT || expr.get_kind() == Kind::SAVE_STRAT) { if (!expr.get(0).get_type().is_string()) handleError(loadStrategy_and_saveStrategy_expect_string(expr)); return; @@ -1305,12 +1317,12 @@ void TypeChecker::visitProperty(Expression& expr) } } */ - } else if (auto k = expr.get_kind(); k != SUP_VAR && k != INF_VAR && k != BOUNDS_VAR && k != SCENARIO && - k != PROBA_MIN_BOX && k != PROBA_MIN_DIAMOND && k != PROBA_BOX && - k != PROBA_DIAMOND && k != PROBA_EXP && k != PROBA_CMP && k != SIMULATE && - k != SIMULATEREACH && k != MITL_FORMULA && - k != MIN_EXP && // ALREADY CHECKED IN PARSE - k != MAX_EXP) // ALREADY CHECKED IN PARSE + } else if (auto k = expr.get_kind(); k != Kind::SUP_VAR && k != Kind::INF_VAR && k != Kind::BOUNDS_VAR && k != Kind::SCENARIO && + k != Kind::PROBA_MIN_BOX && k != Kind::PROBA_MIN_DIAMOND && k != Kind::PROBA_BOX && + k != Kind::PROBA_DIAMOND && k != Kind::PROBA_EXP && k != Kind::PROBA_CMP && k != Kind::SIMULATE && + k != Kind::SIMULATEREACH && k != Kind::MITL_FORMULA && + k != Kind::MIN_EXP && // ALREADY CHECKED IN PARSE + k != Kind::MAX_EXP) // ALREADY CHECKED IN PARSE { for (uint32_t i = 0; i < expr.get_size(); i++) { // No nesting except for constraints @@ -1318,13 +1330,13 @@ void TypeChecker::visitProperty(Expression& expr) handleError(nested_path_quntifiers_not_supported(expr[i])); } } - if (expr.get_kind() == PO_CONTROL) { + if (expr.get_kind() == Kind::PO_CONTROL) { /* Observations on clock constraints are limited to be * weak for lower bounds and strict for upper bounds. */ checkObservationConstraints(expr); } - if (has_MITL_in_quantified_sub(expr) && expr.get_kind() != MITL_FORMULA) + if (has_MITL_in_quantified_sub(expr) && expr.get_kind() != Kind::MITL_FORMULA) handleError(mitl_inside_forall_or_exists_in_non_mitl(expr)); } } @@ -1355,8 +1367,8 @@ bool TypeChecker::checkAssignmentExpression(Expression& expr) handleError(invalid_assignment(expr)); return false; } - - if (expr.get_kind() != FUN_CALL_EXT && (expr.get_kind() != CONSTANT || expr.get_value() != 1)) { + const auto k = expr.get_kind(); + if (k != Kind::FUN_CALL_EXT && (k != Kind::CONSTANT || expr.get_value() != 1)) { checkIgnoredValue(expr); } @@ -1382,18 +1394,18 @@ void TypeChecker::checkObservationConstraints(const Expression& expr) bool invalid = false; switch (expr.get_kind()) { - case LT: // int < clock - case GE: // int >= clock + case Kind::LT: // int < clock + case Kind::GE: // int >= clock invalid = is_integral(expr[0]) && is_clock(expr[1]); break; - case LE: // clock <= int - case GT: // clock > int + case Kind::LE: // clock <= int + case Kind::GT: // clock > int invalid = is_clock(expr[0]) && is_integral(expr[1]); break; - case EQ: // clock == int || int == clock - case NEQ: // clock != int || int != clock + case Kind::EQ: // clock == int || int == clock + case Kind::NEQ: // clock != int || int != clock invalid = (is_clock(expr[0]) && is_integral(expr[1])) || (is_integral(expr[0]) && is_clock(expr[1])); break; @@ -1405,16 +1417,16 @@ void TypeChecker::checkObservationConstraints(const Expression& expr) else { switch (expr.get_kind()) // No clock differences. { - case LT: - case LE: - case GT: - case GE: - case EQ: - case NEQ: + case Kind::LT: + case Kind::LE: + case Kind::GT: + case Kind::GE: + case Kind::EQ: + case Kind::NEQ: if ((is_clock(expr[0]) && is_clock(expr[1])) || (is_diff(expr[0]) && is_integer(expr[1])) || (is_integer(expr[0]) && is_diff(expr[1]))) { handleError(clock_difference_is_not_supported(expr)); - } + } break; default:; @@ -1501,7 +1513,7 @@ int32_t TypeChecker::visit_iteration_statement(RangeStatement& stat) */ if (!type.is_scalar() && !type.is_integer()) handleError(scalar_or_integer_expected(type)); - else if (!type.is(RANGE)) + else if (!type.is(Kind::RANGE)) handleError(range_expected(type)); return stat.stat->accept(*this); @@ -1585,7 +1597,7 @@ int32_t TypeChecker::visit_return_statement(ReturnStatement& stat) */ bool TypeChecker::isParameterCompatible(const Type& paramType, const Expression& arg) const { - const bool ref = paramType.is(REF); + const bool ref = paramType.is(Kind::REF); const bool constant = paramType.is_constant(); const bool lvalue = isModifiableLValue(arg); const Type& argType = arg.get_type(); @@ -1627,7 +1639,7 @@ Expression TypeChecker::checkInitialiser(const Type& type, const Expression& ini { if (type.is_assignment_compatible(init.get_type(), true)) { return init; - } else if (type.is_array() && init.get_kind() == LIST) { + } else if (type.is_array() && init.get_kind() == Kind::LIST) { auto subtype = type.get_sub(); auto result = std::vector(init.get_size()); for (uint32_t i = 0; i < init.get_type().size(); i++) { @@ -1635,8 +1647,8 @@ Expression TypeChecker::checkInitialiser(const Type& type, const Expression& ini handleError(field_name_not_allowed_in_array_init(init[i])); checkInitialiser(subtype, init[i]); } - return Expression::create_nary(LIST, result, init.get_position(), type); - } else if (type.is_record() && init.get_kind() == LIST) { + return Expression::create_nary(Kind::LIST, result, init.get_position(), type); + } else if (type.is_record() && init.get_kind() == Kind::LIST) { /* In order to access the record labels we have to strip any * prefixes and labels from the record type. */ @@ -1670,7 +1682,7 @@ Expression TypeChecker::checkInitialiser(const Type& type, const Expression& ini break; } } - return Expression::create_nary(LIST, result, init.get_position(), type); + return Expression::create_nary(Kind::LIST, result, init.get_position(), type); } handleError(invalid_initializer(init)); return init; @@ -1683,7 +1695,7 @@ Type TypeChecker::getInlineIfCommonType(const Type& t1, const Type& t2) const else if (t2.is_record()) return t2; else if ((t1.is_clock() && !t2.is_clock()) || (!t1.is_clock() && t2.is_clock())) - return Type{DOUBLE, {}, 0}; + return Type{Kind::DOUBLE, {}, 0}; else if (t1.is_assignment_compatible(t2)) return t1; else if (t2.is_assignment_compatible(t1)) @@ -1733,6 +1745,7 @@ bool TypeChecker::checkExpression(Expression& expr) // Type arg2; // Type arg3; switch (expr.get_kind()) { + using namespace KindNames; // It is possible to have DOT expressions as data.x // with data being an array of struct. The type checker // is broken and trying @@ -1741,8 +1754,8 @@ bool TypeChecker::checkExpression(Expression& expr) // This should be fixed one day. /* case DOT: - if (expr[0].get_type().is_process(Constants::PROCESS) || - expr[0].get_type().is(Constants::RECORD)) + if (expr[0].get_type().is_process(PROCESS) || + expr[0].get_type().is(RECORD)) { return true; } @@ -1756,7 +1769,7 @@ bool TypeChecker::checkExpression(Expression& expr) if (is_integral(expr[2]) || is_double_value(expr[2])) { type = expr[2].get_type(); } else if (is_invariant(expr[2]) || is_guard(expr[2])) { - type = Type::create_primitive(Constants::DOUBLE_INV_GUARD); + type = Type::create_primitive(DOUBLE_INV_GUARD); } else { handleError(invalid_sum(expr)); return false; @@ -1764,43 +1777,43 @@ bool TypeChecker::checkExpression(Expression& expr) break; case FRACTION: if (is_integral(expr[0]) && is_integral(expr[1])) - type = Type::create_primitive(Constants::FRACTION); + type = Type::create_primitive(FRACTION); break; case PLUS: if (is_integral(expr[0]) && is_integral(expr[1])) { - type = Type::create_primitive(Constants::INT); + type = Type::create_primitive(INT); } else if ((is_integer(expr[0]) && is_clock(expr[1])) || (is_clock(expr[0]) && is_integer(expr[1]))) { type = Type::create_primitive(CLOCK); } else if ((is_diff(expr[0]) && is_integer(expr[1])) || (is_integer(expr[0]) && is_diff(expr[1]))) { type = Type::create_primitive(DIFF); } else if (is_number(expr[0]) && is_number(expr[1])) { // SMC extension. - type = Type::create_primitive(Constants::DOUBLE); + type = Type::create_primitive(DOUBLE); } break; case MINUS: if (is_integral(expr[0]) && is_integral(expr[1])) { - type = Type::create_primitive(Constants::INT); + type = Type::create_primitive(INT); } else if (is_clock(expr[0]) && is_integer(expr[1])) - // removed "|| is_integer(expr[0].type) && is_clock(expr[1].type)" - // in order to be able to convert into ClockGuards + // removed "|| is_integer(expr[0].type) && is_clock(expr[1].type)" + // in order to be able to convert into ClockGuards { type = Type::create_primitive(CLOCK); } else if ((is_diff(expr[0]) && is_integer(expr[1])) || (is_integer(expr[0]) && is_diff(expr[1])) || (is_clock(expr[0]) && is_clock(expr[1]))) { type = Type::create_primitive(DIFF); - } else if (is_number(expr[0]) && is_number(expr[1])) { - // SMC extension. - // x-y with that semantic should be written x+(-y) - type = Type::create_primitive(Constants::DOUBLE); - } + } else if (is_number(expr[0]) && is_number(expr[1])) { + // SMC extension. + // x-y with that semantic should be written x+(-y) + type = Type::create_primitive(DOUBLE); + } break; case AND: if (is_integral(expr[0]) && is_integral(expr[1])) { - type = Type::create_primitive(Constants::BOOL); + type = Type::create_primitive(BOOL); } else if (is_invariant(expr[0]) && is_invariant(expr[1])) { type = Type::create_primitive(INVARIANT); } else if (is_invariant_wr(expr[0]) && is_invariant_wr(expr[1])) { @@ -1816,7 +1829,7 @@ bool TypeChecker::checkExpression(Expression& expr) case OR: if (is_integral(expr[0]) && is_integral(expr[1])) { - type = Type::create_primitive(Constants::BOOL); + type = Type::create_primitive(BOOL); } else if (is_integral(expr[0]) && is_invariant(expr[1])) { type = Type::create_primitive(INVARIANT); } else if (is_invariant(expr[0]) && is_integral(expr[1])) { @@ -1836,7 +1849,7 @@ bool TypeChecker::checkExpression(Expression& expr) case XOR: if (is_integral(expr[0]) && is_integral(expr[1])) { - type = Type::create_primitive(Constants::BOOL); + type = Type::create_primitive(BOOL); } break; @@ -1861,13 +1874,13 @@ bool TypeChecker::checkExpression(Expression& expr) handleError(template_only_declared_and_undefined(expr)); return false; } - type = Type::create_primitive(Constants::INT); + type = Type::create_primitive(INT); break; } case NUMOF: { if (document.find_dynamic_template(expr[0].get_symbol().get_name()) != nullptr) { - type = Type::create_primitive(Constants::INT); + type = Type::create_primitive(INT); } else { handleError(not_dynamic_template(expr)); return false; @@ -1882,7 +1895,7 @@ bool TypeChecker::checkExpression(Expression& expr) return false; } - type = Type::create_primitive(Constants::INT); + type = Type::create_primitive(INT); break; } @@ -1890,18 +1903,18 @@ bool TypeChecker::checkExpression(Expression& expr) case LT: case LE: if (is_integral(expr[0]) && is_integral(expr[1])) { - type = Type::create_primitive(Constants::BOOL); + type = Type::create_primitive(BOOL); } else if ((is_clock(expr[0]) && is_clock(expr[1])) || (is_clock(expr[0]) && is_bound(expr[1])) || (is_clock(expr[1]) && is_bound(expr[0])) || (is_diff(expr[0]) && is_bound(expr[1])) || (is_bound(expr[0]) && is_diff(expr[1]))) { type = Type::create_primitive(INVARIANT); - } else if (is_number(expr[0]) && is_clock(expr[1])) { - type = Type::create_primitive(GUARD); - } else if (is_clock(expr[0]) && is_number(expr[1])) { - type = Type::create_primitive(GUARD); - } else if (is_number(expr[0]) && is_number(expr[1])) { - type = Type::create_primitive(Constants::BOOL); - } + } else if (is_number(expr[0]) && is_clock(expr[1])) { + type = Type::create_primitive(GUARD); + } else if (is_clock(expr[0]) && is_number(expr[1])) { + type = Type::create_primitive(GUARD); + } else if (is_number(expr[0]) && is_number(expr[1])) { + type = Type::create_primitive(BOOL); + } break; case EQ: @@ -1911,43 +1924,43 @@ bool TypeChecker::checkExpression(Expression& expr) (is_number(expr[0]) && is_clock(expr[1])) || (is_diff(expr[0]) && is_number(expr[1])) || (is_number(expr[0]) && is_diff(expr[1]))) { type = Type::create_primitive(GUARD); - } else if (expr[0].get_type().is_equality_compatible(expr[1].get_type())) { - type = Type::create_primitive(Constants::BOOL); - } else if ((expr[0].get_type().is(RATE) && (is_integral(expr[1]) || is_double_value(expr[1]))) || - ((is_integral(expr[0]) || is_double_value(expr[0])) && expr[1].get_type().is(RATE))) { - type = Type::create_primitive(INVARIANT_WR); - } else if (is_number(expr[0]) && is_number(expr[1])) { - type = Type::create_primitive(Constants::BOOL); - } + } else if (expr[0].get_type().is_equality_compatible(expr[1].get_type())) { + type = Type::create_primitive(BOOL); + } else if ((expr[0].get_type().is(RATE) && (is_integral(expr[1]) || is_double_value(expr[1]))) || + ((is_integral(expr[0]) || is_double_value(expr[0])) && expr[1].get_type().is(RATE))) { + type = Type::create_primitive(INVARIANT_WR); + } else if (is_number(expr[0]) && is_number(expr[1])) { + type = Type::create_primitive(BOOL); + } break; case NEQ: if (expr[0].get_type().is_equality_compatible(expr[1].get_type())) { - type = Type::create_primitive(Constants::BOOL); + type = Type::create_primitive(BOOL); } else if ((is_clock(expr[0]) && is_clock(expr[1])) || (is_clock(expr[0]) && is_integer(expr[1])) || (is_integer(expr[0]) && is_clock(expr[1])) || (is_diff(expr[0]) && is_integer(expr[1])) || (is_integer(expr[0]) && is_diff(expr[1]))) { type = Type::create_primitive(CONSTRAINT); - } else if (is_number(expr[0]) && is_number(expr[1])) { - type = Type::create_primitive(Constants::BOOL); - } + } else if (is_number(expr[0]) && is_number(expr[1])) { + type = Type::create_primitive(BOOL); + } break; case GE: case GT: if (is_integral(expr[0]) && is_integral(expr[1])) { - type = Type::create_primitive(Constants::BOOL); + type = Type::create_primitive(BOOL); } else if ((is_clock(expr[0]) && is_clock(expr[1])) || (is_integer(expr[0]) && is_clock(expr[1])) || (is_integer(expr[1]) && is_clock(expr[0])) || (is_diff(expr[0]) && is_integer(expr[1])) || (is_integer(expr[0]) && is_diff(expr[1]))) { type = Type::create_primitive(INVARIANT); - } else if (is_number(expr[0]) && is_clock(expr[1])) { - type = Type::create_primitive(GUARD); - } else if (is_clock(expr[0]) && is_number(expr[1])) { - type = Type::create_primitive(GUARD); - } else if (is_number(expr[0]) && is_number(expr[1])) { - type = Type::create_primitive(Constants::BOOL); - } + } else if (is_number(expr[0]) && is_clock(expr[1])) { + type = Type::create_primitive(GUARD); + } else if (is_clock(expr[0]) && is_number(expr[1])) { + type = Type::create_primitive(GUARD); + } else if (is_number(expr[0]) && is_number(expr[1])) { + type = Type::create_primitive(BOOL); + } break; case MULT: @@ -1956,9 +1969,9 @@ bool TypeChecker::checkExpression(Expression& expr) case MIN: case MAX: if (is_integral(expr[0]) && is_integral(expr[1])) { - type = Type::create_primitive(Constants::INT); + type = Type::create_primitive(INT); } else if (is_number(expr[0]) && is_number(expr[1])) { - type = Type::create_primitive(Constants::DOUBLE); + type = Type::create_primitive(DOUBLE); } break; @@ -1969,13 +1982,13 @@ bool TypeChecker::checkExpression(Expression& expr) case BIT_LSHIFT: case BIT_RSHIFT: if (is_integral(expr[0]) && is_integral(expr[1])) { - type = Type::create_primitive(Constants::INT); + type = Type::create_primitive(INT); } break; case NOT: if (is_integral(expr[0])) { - type = Type::create_primitive(Constants::BOOL); + type = Type::create_primitive(BOOL); } else if (is_constraint(expr[0])) { type = Type::create_primitive(CONSTRAINT); } @@ -1983,9 +1996,9 @@ bool TypeChecker::checkExpression(Expression& expr) case UNARY_MINUS: if (is_integral(expr[0])) { - type = Type::create_primitive(Constants::INT); + type = Type::create_primitive(INT); } else if (is_number(expr[0])) { - type = Type::create_primitive(Constants::DOUBLE); + type = Type::create_primitive(DOUBLE); } break; @@ -2007,10 +2020,13 @@ bool TypeChecker::checkExpression(Expression& expr) break; case ASS_PLUS: - if ((!is_integer(expr[0]) && !is_cost(expr[0])) || !is_integral(expr[1])) + if ((!is_integer(expr[0]) && !is_cost(expr[0])) || !is_integral(expr[1])) { handleError(increment_only_integers_and_cost(expr)); - else if (!isModifiableLValue(expr[0])) + return false; + } else if (!isModifiableLValue(expr[0])) { handleError(lvalue_expected(expr[0])); + return false; + } type = expr[0].get_type(); break; @@ -2044,7 +2060,7 @@ bool TypeChecker::checkExpression(Expression& expr) handleError(integer_expected(expr)); return false; } - type = Type::create_primitive(Constants::INT); + type = Type::create_primitive(INT); break; case FMA_F: @@ -2111,7 +2127,7 @@ bool TypeChecker::checkExpression(Expression& expr) handleError(number_expected(expr[0])); return false; } - type = Type::create_primitive(Constants::DOUBLE); + type = Type::create_primitive(DOUBLE); break; case LDEXP_F: @@ -2123,7 +2139,7 @@ bool TypeChecker::checkExpression(Expression& expr) handleError(number_expected(expr[0])); return false; } - type = Type::create_primitive(Constants::DOUBLE); + type = Type::create_primitive(DOUBLE); break; case ABS_F: @@ -2132,7 +2148,7 @@ bool TypeChecker::checkExpression(Expression& expr) handleError(integer_expected(expr[0])); return false; } - type = Type::create_primitive(Constants::INT); + type = Type::create_primitive(INT); break; case ILOGB_F: @@ -2141,7 +2157,7 @@ bool TypeChecker::checkExpression(Expression& expr) handleError(number_expected(expr[0])); return false; } - type = Type::create_primitive(Constants::INT); + type = Type::create_primitive(INT); break; case IS_FINITE_F: @@ -2154,7 +2170,7 @@ bool TypeChecker::checkExpression(Expression& expr) handleError(number_expected(expr[0])); return false; } - type = Type::create_primitive(Constants::BOOL); + type = Type::create_primitive(BOOL); break; case INLINE_IF: @@ -2226,7 +2242,7 @@ bool TypeChecker::checkExpression(Expression& expr) checkType(expr[0].get_symbol().get_type()); if (is_integral(expr[1])) { - type = Type::create_primitive(Constants::BOOL); + type = Type::create_primitive(BOOL); } else if (is_invariant(expr[1])) { type = Type::create_primitive(INVARIANT); } else if (is_invariant_wr(expr[1])) { @@ -2249,7 +2265,7 @@ bool TypeChecker::checkExpression(Expression& expr) checkType(expr[0].get_symbol().get_type()); if (is_integral(expr[1])) { - type = Type::create_primitive(Constants::BOOL); + type = Type::create_primitive(BOOL); } else if (is_constraint(expr[1])) { type = Type::create_primitive(CONSTRAINT); } else { @@ -2266,9 +2282,9 @@ bool TypeChecker::checkExpression(Expression& expr) checkType(expr[0].get_symbol().get_type()); if (is_integral(expr[1])) { - type = Type::create_primitive(Constants::INT); + type = Type::create_primitive(INT); } else if (is_number(expr[1])) { - type = Type::create_primitive(Constants::DOUBLE); + type = Type::create_primitive(DOUBLE); } else { handleError(number_expected(expr[1])); } @@ -2350,11 +2366,11 @@ bool TypeChecker::checkExpression(Expression& expr) } for (uint32_t i = 3; i < nb; ++i) { if (!is_integral(expr[i]) && !is_clock(expr[i]) && !is_double_value(expr[i]) && - !expr[i].get_type().is(Constants::DOUBLE_INV_GUARD) && !is_constraint(expr[i]) && + !expr[i].get_type().is(DOUBLE_INV_GUARD) && !is_constraint(expr[i]) && !expr[i].get_type().is_record() && !expr[i].get_type().is_array()) { handleError(integer_or_clock_expected(expr[i])); return false; - } + } if (expr[i].changes_any_variable()) { handleError(must_be_side_effect_free(expr[i])); return false; @@ -2531,6 +2547,7 @@ bool TypeChecker::checkExpression(Expression& expr) bool TypeChecker::isModifiableLValue(const Expression& expr) const { switch (expr.get_kind()) { + using namespace KindNames; case IDENTIFIER: return expr.get_type().is_mutable(); case DOT: @@ -2580,6 +2597,7 @@ bool TypeChecker::isModifiableLValue(const Expression& expr) const bool TypeChecker::isLValue(const Expression& expr) const { switch (expr.get_kind()) { + using namespace KindNames; case IDENTIFIER: case PRE_INCREMENT: case PRE_DECREMENT: @@ -2620,6 +2638,7 @@ bool TypeChecker::isLValue(const Expression& expr) const bool TypeChecker::isUniqueReference(const Expression& expr) const { switch (expr.get_kind()) { + using namespace KindNames; case IDENTIFIER: return true; case DOT: return isUniqueReference(expr[0]); @@ -2697,10 +2716,10 @@ int32_t parse_XML_fd(int fd, Document& doc, bool newxta, const std::vector #endif -using namespace UTAP; -using namespace Constants; +namespace UTAP { // Explicit instantiations to generate implementation template std::string Stringify::str() const @@ -56,7 +55,6 @@ std::string StringifyIndent::str(const std::string& indent) const return os.str(); } -namespace UTAP { // Explicit instantiations to generate implementation template struct Stringify; template struct Stringify; template struct Stringify; @@ -65,14 +63,16 @@ template struct Stringify; template struct Stringify; template struct Stringify; template struct Stringify; -} // namespace UTAP std::ostream& Location::print(std::ostream& os) const { os << "LOCATION (" << uid.get_name() << ", "; - invariant.print(os) << ", "; - exp_rate.print(os) << ')'; - return os; + if (!invariant.empty()) + invariant.print(os); + os << ", "; + if (!exp_rate.empty()) + exp_rate.print(os); + return os << ')'; } std::ostream& Edge::print(std::ostream& os) const @@ -81,9 +81,14 @@ std::ostream& Edge::print(std::ostream& os) const src->print(os) << ' '; dst->print(os) << ")\n"; os << "\t"; - guard.print(os) << ", "; - sync.print(os) << ", "; - assign.print(os); + if (!guard.empty()) + guard.print(os); + os << ", "; + if (!sync.empty()) + sync.print(os); + os << ", "; + if (!assign.empty()) + assign.print(os); return os; } @@ -148,7 +153,7 @@ std::ostream& Declarations::print_constants(std::ostream& os) const if (!variables.empty()) { bool first = true; for (const auto& variable : variables) { - if (variable.uid.get_type().get_kind() == CONSTANT) { + if (variable.uid.get_type().get_kind() == Kind::CONSTANT) { if (first) { os << "// constants\n"; first = false; @@ -164,7 +169,7 @@ std::ostream& Declarations::print_typedefs(std::ostream& os) const { bool first = true; for (const auto& symbol : frame) { - if (symbol.get_type().get_kind() == TYPEDEF) { + if (symbol.get_type().get_kind() == Kind::TYPEDEF) { if (first) { os << "// type definitions\n"; first = false; @@ -175,12 +180,12 @@ std::ostream& Declarations::print_typedefs(std::ostream& os) const return os; } -std::ostream& Declarations::print_variables(std::ostream& os, bool global) const +std::ostream& Declarations::print_variables(std::ostream& os, bool) const { if (!variables.empty()) { os << "// variables\n"; for (const auto& var : variables) - if (var.uid.get_type().get_kind() != CONSTANT) + if (var.uid.get_type().get_kind() != Kind::CONSTANT) var.print(os) << ";\n"; } return os; @@ -255,7 +260,7 @@ Location& Template::add_location(std::string_view name, Expression inv, Expressi { bool duplicate = frame.contains(name); auto& loc = locations.emplace_back(); - loc.uid = frame.add_symbol(name, Type::create_primitive(LOCATION), pos, &loc); + loc.uid = frame.add_symbol(name, Type::create_primitive(Kind::LOCATION), pos, &loc); loc.nr = static_cast(locations.size() - 1); loc.invariant = std::move(inv); loc.exp_rate = std::move(er); @@ -270,7 +275,7 @@ Branchpoint& Template::add_branchpoint(std::string_view name, position_t pos) { bool duplicate = frame.contains(name); auto& branchpoint = branchpoints.emplace_back(); - branchpoint.uid = frame.add_symbol(name, Type::create_primitive(BRANCHPOINT), pos, &branchpoint); + branchpoint.uid = frame.add_symbol(name, Type::create_primitive(Kind::BRANCHPOINT), pos, &branchpoint); branchpoint.bpNr = static_cast(branchpoints.size() - 1); if (duplicate) throw duplicate_definition_error(name); @@ -531,24 +536,32 @@ std::vector LSCInstanceLine::get_simregions(const std::vector{}; // get the simregions anchored to this instance + // A simregion has 1 or 0 of {message, update, condition} (see get_simregions() + // above), so each must be null-checked before being dereferenced. for (const auto& reg : simregions) { - const LSCMessage* m = reg.message; - if ((m->src->instance_nr == this->instance_nr || m->dst->instance_nr == this->instance_nr)) { - i_simregions.push_back(reg); - continue; + if (reg.has_message()) { + const LSCMessage* m = reg.message; + if (m->src->instance_nr == this->instance_nr || m->dst->instance_nr == this->instance_nr) { + i_simregions.push_back(reg); + continue; + } } - const LSCUpdate* u = reg.update; - if (u->anchor->instance_nr == this->instance_nr) { - i_simregions.push_back(reg); - continue; + if (reg.has_update()) { + const LSCUpdate* u = reg.update; + if (u->anchor->instance_nr == this->instance_nr) { + i_simregions.push_back(reg); + continue; + } } - const LSCCondition* c = reg.condition; - for (auto* instance : c->anchors) { - if (instance->instance_nr == this->instance_nr) { - i_simregions.push_back(reg); - break; + if (reg.has_condition()) { + const LSCCondition* c = reg.condition; + for (auto* instance : c->anchors) { + if (instance->instance_nr == this->instance_nr) { + i_simregions.push_back(reg); + break; + } } } } @@ -932,7 +945,7 @@ void Document::copy_variables_from_to(const Template* from, Template* to) const } } -void Document::copy_functions_from_to(const Template* from, Template* to) const +void Document::copy_functions_from_to(const Template* /*from*/, Template* /*to*/) const { // TODO to be implemented and to be used in Translator::lscProcBegin (see Translator.cpp) } @@ -946,7 +959,7 @@ static void visit(DocumentVisitor& visitor, Frame& frame) { for (uint32_t i = 0; i < frame.get_size(); ++i) { Type type = frame[i].get_type(); - if (type.get_kind() == TYPEDEF) { + if (type.get_kind() == Kind::TYPEDEF) { visitor.visit_typedef(frame[i]); continue; } @@ -954,21 +967,21 @@ static void visit(DocumentVisitor& visitor, Frame& frame) void* data = frame[i].get_data(); type = type.strip_array(); // TODO: use visitor dispatch to recover the type - if ((type.is(Constants::INT) || type.is(Constants::STRING) || type.is(Constants::DOUBLE) || - type.is(Constants::BOOL) || type.is(CLOCK) || type.is(CHANNEL) || type.is(SCALAR) || - type.get_kind() == RECORD) && + if ((type.is(Kind::INT) || type.is(Kind::STRING) || type.is(Kind::DOUBLE) || + type.is(Kind::BOOL) || type.is(Kind::CLOCK) || type.is(Kind::CHANNEL) || type.is(Kind::SCALAR) || + type.get_kind() == Kind::RECORD) && data != nullptr) // <--- ignore parameters { visitor.visit_variable(*static_cast(data)); - } else if (type.is(LOCATION)) { + } else if (type.is(Kind::LOCATION)) { visitor.visit_location(*static_cast(data)); - } else if (type.is(LOCATION_EXPR)) { + } else if (type.is(Kind::LOCATION_EXPR)) { visitor.visit_location(*static_cast(data)); - } else if (type.is(FUNCTION)) { + } else if (type.is(Kind::FUNCTION)) { visitor.visit_function(*static_cast(data)); - } else if (type.is(FUNCTION_EXTERNAL)) { + } else if (type.is(Kind::FUNCTION_EXTERNAL)) { // we cannot look inside a external function, skip. - } else if (type.is(INSTANCE_LINE)) { + } else if (type.is(Kind::INSTANCE_LINE)) { visitor.visit_instance_line(*static_cast(data)); } } @@ -1002,11 +1015,11 @@ void Document::accept(DocumentVisitor& visitor) for (auto i = 0u; i < global.frame.get_size(); ++i) { const Type type = global.frame[i].get_type().strip_array(); void* data = global.frame[i].get_data(); - if (type.is(PROCESS) || type.is(PROCESS_SET)) { + if (type.is(Kind::PROCESS) || type.is(Kind::PROCESS_SET)) { visitor.visit_process(*static_cast(data)); - } else if (type.is(INSTANCE)) { + } else if (type.is(Kind::INSTANCE)) { visitor.visit_instance(*static_cast(data)); - } else if (type.is(LSC_INSTANCE)) { + } else if (type.is(Kind::LSC_INSTANCE)) { visitor.visit_instance(*static_cast(data)); } } @@ -1083,3 +1096,5 @@ void Document::set_supported_methods(const SupportedMethods& supported_methods) { this->supported_methods = supported_methods; } + +} // namespace UTAP diff --git a/src/expression.cpp b/src/expression.cpp index 4da1b43d..afa2cf79 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -43,23 +43,22 @@ #include // uint32_t #include -using namespace UTAP; -using namespace Constants; +namespace UTAP { -struct Expression::expression_data : public std::enable_shared_from_this +struct Expression::Data : std::enable_shared_from_this { position_t position; ///< The position of the expression Kind kind; ///< The kind of the node - std::variant value; + std::variant value; Symbol symbol; ///< The symbol of the node Type type; ///< The type of the expression std::vector sub; ///< Subexpressions - expression_data(const position_t& p, Kind kind, int32_t value): position{p}, kind{kind}, value{value} {} + Data(const position_t& p, Kind kind, int32_t value): position{p}, kind{kind}, value{value} {} }; -Expression::Expression(Kind kind, const position_t& pos) { data = std::make_shared(pos, kind, 0); } +Expression::Expression(Kind kind, const position_t& pos) { data = std::make_shared(pos, kind, 0); } Expression Expression::clone() const { @@ -130,7 +129,7 @@ Expression Expression::subst(const Symbol& symbol, Expression expr) const { if (empty()) { return *this; - } else if (get_kind() == IDENTIFIER && get_symbol() == symbol) { + } else if (get_kind() == Kind::IDENTIFIER && get_symbol() == symbol) { return expr; } else if (get_size() == 0) { return *this; @@ -160,10 +159,11 @@ bool Expression::uses_fp() const if (empty()) { return false; } - if (data->type.is(Constants::DOUBLE)) { + if (data->type.is(Kind::DOUBLE)) { return true; } switch (data->kind) { + using namespace KindNames; case FABS_F: case FMOD_F: case FMA_F: @@ -243,7 +243,7 @@ bool Expression::uses_hybrid() const if (empty()) { return false; } - if (get_type().is(HYBRID)) { + if (get_type().is(Kind::HYBRID)) { return true; } const auto n = get_size(); @@ -278,6 +278,7 @@ bool Expression::is_dynamic() const return false; } else { switch (data->kind) { + using namespace KindNames; case SPAWN: case NUMOF: case EXIT: @@ -310,6 +311,7 @@ uint32_t Expression::get_size() const return 0; switch (data->kind) { + using namespace KindNames; case MINUS: case PLUS: case MULT: @@ -506,7 +508,7 @@ int32_t Expression::get_value() const { assert(data); assert(data->type.is_integral()); - assert(data->kind == CONSTANT || data->kind == IDENTIFIER || data->kind == VAR_INDEX); + assert(data->kind == Kind::CONSTANT || data->kind == Kind::IDENTIFIER || data->kind == Kind::VAR_INDEX); const auto value = std::get(data->value); return data->type.is_integer() ? value : (value != 0 ? 1 : 0); } @@ -521,29 +523,29 @@ int32_t Expression::get_record_label_index() const double Expression::get_double_value() const { assert(data); - assert(data->kind == CONSTANT); - assert(data->type.is(Constants::DOUBLE)); + assert(data->kind == Kind::CONSTANT); + assert(data->type.is(Kind::DOUBLE)); return std::get(data->value); } int32_t Expression::get_index() const { assert(data); - assert(data->kind == DOT); + assert(data->kind == Kind::DOT); return std::get(data->value); } -Synchronisation Expression::get_sync() const +Sync Expression::get_sync() const { assert(data); - assert(data->kind == SYNC); - return std::get(data->value); + assert(data->kind == Kind::SYNC); + return std::get(data->value); } std::string_view Expression::get_string_value() const { assert(data); - assert(data->kind == CONSTANT); + assert(data->kind == Kind::CONSTANT); assert(data->type.is_string()); return std::get(data->value).str(); } @@ -551,7 +553,7 @@ std::string_view Expression::get_string_value() const size_t Expression::get_string_index() const { assert(data); - assert(data->kind == CONSTANT); + assert(data->kind == Kind::CONSTANT); assert(data->type.is_string()); return std::get(data->value).index(); } @@ -584,7 +586,7 @@ bool Expression::empty() const { return data == nullptr; } bool Expression::is_true() const { - return data == nullptr || (get_type().is_integral() && data->kind == CONSTANT && get_value() == 1); + return data == nullptr || (get_type().is_integral() && data->kind == Kind::CONSTANT && get_value() == 1); } /** @@ -614,7 +616,7 @@ bool Expression::equal(const Expression& e) const if (get_size() != e.get_size() || data->kind != e.data->kind || !std::visit(ValueTypeEquality{}, data->value, e.data->value) || data->symbol != e.data->symbol) { return false; - } + } for (uint32_t i = 0; i < get_size(); i++) { if (!data->sub[i].equal(e[i])) { @@ -638,6 +640,7 @@ Symbol Expression::get_symbol() const assert(data); switch (get_kind()) { + using namespace KindNames; case IDENTIFIER: return data->symbol; case DOT: return get(0).get_symbol(); @@ -681,6 +684,7 @@ void Expression::get_symbols(std::set& symbols) const } switch (get_kind()) { + using namespace KindNames; case IDENTIFIER: symbols.insert(data->symbol); break; case DOT: get(0).get_symbols(symbols); break; @@ -728,7 +732,7 @@ bool Expression::is_reference_to(const std::set& symbols) const bool Expression::contains_deadlock() const { - if (get_kind() == UTAP::Constants::DEADLOCK) + if (get_kind() == Kind::DEADLOCK) return true; if (data) for (const auto& subexp : data->sub) @@ -763,6 +767,7 @@ int Expression::get_precedence() const { return get_precedence(data->kind); } int Expression::get_precedence(Kind kind) { switch (kind) { + using namespace KindNames; case PLUS: case MINUS: return 70; @@ -964,8 +969,8 @@ int Expression::get_precedence(Kind kind) std::ostream& Expression::print_bound_type(std::ostream& os, const Expression& e) const { - if (e.get_kind() == CONSTANT) { - assert(e.get_type().is(Constants::INT)); // Encoding used here. + if (e.get_kind() == Kind::CONSTANT) { + assert(e.get_type().is(Kind::INT)); // Encoding used here. if (e.get_value() == 0) { os << "#"; @@ -1041,10 +1046,10 @@ static const char* get_builtin_fun_name(Kind kind) "random_poisson", "random_tri", "random_weibull"}; - static_assert(RANDOM_WEIBULL_F - ABS_F + 1 == std::size(funNames), "Builtin function name list is wrong"); - assert(ABS_F <= kind); - assert(kind <= RANDOM_WEIBULL_F); - return funNames[kind - ABS_F]; + static_assert(Kind::RANDOM_WEIBULL_F - Kind::ABS_F + 1 == std::size(funNames), "Builtin function name list is wrong"); + assert(Kind::ABS_F <= kind); + assert(kind <= Kind::RANDOM_WEIBULL_F); + return funNames[kind - Kind::ABS_F]; } static inline std::ostream& embrace_strict(std::ostream& os, bool old, const Expression& expr, int precedence) @@ -1074,12 +1079,16 @@ static int get_precedence_or_default(const Expression& expr) std::ostream& Expression::print(std::ostream& os, bool old) const { + if (empty()) + return os; + const int precedence = get_precedence_or_default(*this); bool flag = false; uint32_t nb; switch (data->kind) { + using namespace KindNames; case PROBA_MIN_BOX: flag = true; [[fallthrough]]; case PROBA_MIN_DIAMOND: os << "Pr["; @@ -1360,9 +1369,9 @@ std::ostream& Expression::print(std::ostream& os, bool old) const case SYNC: get(0).print(os, old); switch (get_sync()) { - case SYNC_QUE: os << '?'; break; - case SYNC_BANG: os << '!'; break; - case SYNC_CSP: + case Sync::QUE: os << '?'; break; + case Sync::BANG: os << '!'; break; + case Sync::CSP: // no append break; } @@ -1461,7 +1470,7 @@ std::ostream& Expression::print(std::ostream& os, bool old) const os << "minE("; get(3).print(os, old); os << ")["; - if (get(0).get_kind() == Constants::CONSTANT) { + if (get(0).get_kind() == CONSTANT) { if (bool is_step_bound = (get(0).get_value() == 0); is_step_bound) os << "#"; } else { @@ -1470,10 +1479,10 @@ std::ostream& Expression::print(std::ostream& os, bool old) const os << "<="; get(1).print(os, old); os << "]"; - if (auto features1 = get(5); features1.get_kind() == Constants::LIST) { + if (auto features1 = get(5); features1.get_kind() == LIST) { features1.print(os << " {", old); os << "} -> {"; - if (auto features2 = get(6); features2.get_kind() == Constants::LIST) + if (auto features2 = get(6); features2.get_kind() == LIST) features2.print(os, old); os << "}"; } @@ -1485,7 +1494,7 @@ std::ostream& Expression::print(std::ostream& os, bool old) const os << "maxE("; get(3).print(os, old); os << ")["; - if (get(0).get_kind() == Constants::CONSTANT) { + if (get(0).get_kind() == CONSTANT) { if (bool is_step_bound = (get(0).get_value() == 0); is_step_bound) os << "#"; } else { @@ -1494,10 +1503,10 @@ std::ostream& Expression::print(std::ostream& os, bool old) const os << "<="; get(1).print(os, old); os << "]"; - if (auto features1 = get(5); features1.get_kind() == Constants::LIST) { + if (auto features1 = get(5); features1.get_kind() == LIST) { features1.print(os << " {", old); os << "} -> {"; - if (auto features2 = get(6); features2.get_kind() == Constants::LIST) + if (auto features2 = get(6); features2.get_kind() == LIST) features2.print(os, old); os << "}"; } @@ -1628,7 +1637,7 @@ std::ostream& Expression::print(std::ostream& os, bool old) const break; case TYPEDEF: os << "typedef"; break; - // Types - Not applicable in expression printing + // Types - Not applicable in expression printing case RANGE: case RECORD: case REF: @@ -1663,7 +1672,7 @@ std::ostream& Expression::print(std::ostream& os, bool old) const case BRANCHPOINT: case PROBABILITY: case DOUBLE_INV_GUARD: - // Deprecated LSC features + // Deprecated LSC features case SCENARIO: case SCENARIO2: case INSTANCE_LINE: @@ -1671,7 +1680,7 @@ std::ostream& Expression::print(std::ostream& os, bool old) const case CONDITION: case UPDATE: case LSC_INSTANCE: - // Deprecated probability feature + // Deprecated probability feature case PMAX: case UNKNOWN: break; @@ -1703,6 +1712,7 @@ void Expression::collect_possible_writes(std::set& symbols) const } switch (get_kind()) { + using namespace KindNames; case ASSIGN: case ASS_PLUS: case ASS_MINUS: @@ -1735,7 +1745,7 @@ void Expression::collect_possible_writes(std::set& symbols) const get(i).get_symbols(symbols); } } - } + } break; default: break; @@ -1751,6 +1761,7 @@ void Expression::collect_possible_reads(std::set& symbols, bool collectR get(i).collect_possible_reads(symbols); switch (get_kind()) { + using namespace KindNames; case IDENTIFIER: symbols.insert(get_symbol()); break; case FUN_CALL: { @@ -1794,47 +1805,47 @@ void Expression::collect_possible_reads(std::set& symbols, bool collectR Expression Expression::create_constant(int32_t value, position_t pos) { - auto expr = Expression{CONSTANT, pos}; + auto expr = Expression{Kind::CONSTANT, pos}; expr.data->value = value; - expr.data->type = Type::create_primitive(Constants::INT); + expr.data->type = Type::create_primitive(Kind::INT); return expr; } Expression Expression::create_var_index(int32_t value, position_t pos) { - auto expr = Expression{VAR_INDEX, pos}; + auto expr = Expression{Kind::VAR_INDEX, pos}; expr.data->value = value; - expr.data->type = Type::create_primitive(Constants::INT); + expr.data->type = Type::create_primitive(Kind::INT); return expr; } Expression Expression::create_exit(position_t pos) { - auto expr = Expression{EXIT, pos}; + auto expr = Expression{Kind::EXIT, pos}; expr.data->value = 0; - expr.data->type = Type::create_primitive(Constants::VOID_TYPE); + expr.data->type = Type::create_primitive(Kind::VOID_TYPE); return expr; } Expression Expression::create_double(double value, position_t pos) { - auto expr = Expression{CONSTANT, pos}; + auto expr = Expression{Kind::CONSTANT, pos}; expr.data->value = value; - expr.data->type = Type::create_primitive(Constants::DOUBLE); + expr.data->type = Type::create_primitive(Kind::DOUBLE); return expr; } Expression Expression::create_string(StringIndex str, position_t pos) { - auto expr = Expression{CONSTANT, pos}; + auto expr = Expression{Kind::CONSTANT, pos}; expr.data->value = str; - expr.data->type = Type::create_primitive(Constants::STRING); + expr.data->type = Type::create_primitive(Kind::STRING); return expr; } Expression Expression::create_identifier(const Symbol& symbol, position_t pos) { - auto expr = Expression{IDENTIFIER, pos}; + auto expr = Expression{Kind::IDENTIFIER, pos}; expr.data->symbol = symbol; if (symbol != Symbol()) { expr.data->type = symbol.get_type(); @@ -1884,16 +1895,16 @@ Expression Expression::create_ternary(Kind kind, Expression e1, Expression e2, E Expression Expression::create_dot(Expression e, int32_t idx, position_t pos, Type type) { - auto expr = Expression{DOT, pos}; + auto expr = Expression{Kind::DOT, pos}; expr.data->value = idx; expr.data->sub.push_back(std::move(e)); expr.data->type = std::move(type); return expr; } -Expression Expression::create_sync(Expression e, Synchronisation s, position_t pos) +Expression Expression::create_sync(Expression e, Sync s, position_t pos) { - auto expr = Expression{SYNC, pos}; + auto expr = Expression{Kind::SYNC, pos}; expr.data->value = s; expr.data->sub.push_back(std::move(e)); return expr; @@ -1901,7 +1912,9 @@ Expression Expression::create_sync(Expression e, Synchronisation s, position_t p Expression Expression::create_deadlock(position_t pos) { - auto expr = Expression{DEADLOCK, pos}; - expr.data->type = Type::create_primitive(CONSTRAINT); + auto expr = Expression{Kind::DEADLOCK, pos}; + expr.data->type = Type::create_primitive(Kind::CONSTRAINT); return expr; } + +} // nanamespace UTAP \ No newline at end of file diff --git a/test/featurechecker.cpp b/src/featurecheck.cpp similarity index 100% rename from test/featurechecker.cpp rename to src/featurecheck.cpp diff --git a/src/keywords.hpp b/src/keywords.hpp index ed2ccf78..31945ca8 100644 --- a/src/keywords.hpp +++ b/src/keywords.hpp @@ -25,7 +25,6 @@ #include "libparser.hpp" #include -#include // uint32_t namespace UTAP { struct Keyword diff --git a/src/lexer.l b/src/lexer.l index 2142d7cb..df70cee7 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -174,6 +174,7 @@ idchr [a-zA-Z0-9_$#] "#" { return T_HASH; } "location" { return T_LOCATION; } {alpha}{idchr}* { + using namespace UTAP; const auto utap_string = std::string{utap_text}; const auto* keyword_ptr = find_keyword(utap_string); if (keyword_ptr) { diff --git a/src/libparser.hpp b/src/libparser.hpp index 9f3b17ba..1537dd9b 100644 --- a/src/libparser.hpp +++ b/src/libparser.hpp @@ -28,6 +28,8 @@ #include #include +namespace UTAP { + // The maximum length is 4000 (see error message) + 1 for the // terminating \0. constexpr auto MAXLEN = 4001u; @@ -57,7 +59,6 @@ constexpr Syntax operator&(const Syntax& s1, const Syntax& s2) return Syntax{static_cast(s1) & static_cast(s2)}; } -namespace UTAP { /** * Help class used by the lexer, parser and xmlreader to keep * track of the current position. diff --git a/src/parser.y b/src/parser.y index 37908e02..f7bf1e86 100644 --- a/src/parser.y +++ b/src/parser.y @@ -51,8 +51,16 @@ #include #include // strlen -using namespace UTAP; -using namespace Constants; +using UTAP::position_t; +using UTAP::Syntax; +using UTAP::ParserBuilder; +using UTAP::tracker; +using UTAP::TypeException; +using UTAP::MAXLEN; +using UTAP::Kind; +using UTAP::Sync; +using UTAP::XTAPart; +using UTAP::PriceType; #define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ @@ -302,7 +310,7 @@ const char* utap_msg(const char *msg) %union { bool flag; int number; - ParserBuilder::TypePrefix prefix; + UTAP::TypePrefix prefix; Kind kind; char string[MAXLEN]; double floating; @@ -648,56 +656,56 @@ TypeId: Type: T_TYPENAME { - CALL(@1, @1, type_name(ParserBuilder::TypePrefix::NONE, $1)); + CALL(@1, @1, type_name(UTAP::TypePrefix::NONE, $1)); } | TypePrefix T_TYPENAME { CALL(@1, @2, type_name($1, $2)); } | T_STRUCT '{' FieldDeclList '}' { - CALL(@1, @4, type_struct(ParserBuilder::TypePrefix::NONE, $3)); + CALL(@1, @4, type_struct(UTAP::TypePrefix::NONE, $3)); } | TypePrefix T_STRUCT '{' FieldDeclList '}' { CALL(@1, @5, type_struct($1, $4)); } | T_STRUCT '{' error '}' { - CALL(@1, @4, type_struct(ParserBuilder::TypePrefix::NONE, 0)); + CALL(@1, @4, type_struct(UTAP::TypePrefix::NONE, 0)); } | TypePrefix T_STRUCT '{' error '}' { - CALL(@1, @5, type_struct(ParserBuilder::TypePrefix::NONE, 0)); + CALL(@1, @5, type_struct(UTAP::TypePrefix::NONE, 0)); } | T_BOOL { - CALL(@1, @1, type_bool(ParserBuilder::TypePrefix::NONE)); + CALL(@1, @1, type_bool(UTAP::TypePrefix::NONE)); } | TypePrefix T_BOOL { CALL(@1, @2, type_bool($1)); } - | T_DOUBLE { CALL(@1, @1, type_double(ParserBuilder::TypePrefix::NONE)); } + | T_DOUBLE { CALL(@1, @1, type_double(UTAP::TypePrefix::NONE)); } | TypePrefix T_DOUBLE { CALL(@1, @2, type_double($1)); } - | T_STRING { CALL(@1, @1, type_string(ParserBuilder::TypePrefix::NONE)); } + | T_STRING { CALL(@1, @1, type_string(UTAP::TypePrefix::NONE)); } | TypePrefix T_STRING { CALL(@1, @2, type_string($1)); } - | T_INT { CALL(@1, @1, type_int(ParserBuilder::TypePrefix::NONE)); } + | T_INT { CALL(@1, @1, type_int(UTAP::TypePrefix::NONE)); } | TypePrefix T_INT { CALL(@1, @2, type_int($1)); } | T_INT '[' Expression ',' Expression ']' { - CALL(@1, @6, type_bounded_int(ParserBuilder::TypePrefix::NONE)); + CALL(@1, @6, type_bounded_int(UTAP::TypePrefix::NONE)); } | TypePrefix T_INT '[' Expression ',' Expression ']' { CALL(@1, @7, type_bounded_int($1)); } | T_CHAN { - CALL(@1, @1, type_channel(ParserBuilder::TypePrefix::NONE)); + CALL(@1, @1, type_channel(UTAP::TypePrefix::NONE)); } | TypePrefix T_CHAN { CALL(@1, @2, type_channel($1)); } - | T_CLOCK { CALL(@1, @1, type_clock(ParserBuilder::TypePrefix::NONE)); } - | T_HYBRID T_CLOCK { CALL(@1, @1, type_clock(ParserBuilder::TypePrefix::HYBRID)); } + | T_CLOCK { CALL(@1, @1, type_clock(UTAP::TypePrefix::NONE)); } + | T_HYBRID T_CLOCK { CALL(@1, @1, type_clock(UTAP::TypePrefix::HYBRID)); } | T_VOID { CALL(@1, @1, type_void()); } | T_SCALAR '[' Expression ']' { - CALL(@1, @4, type_scalar(ParserBuilder::TypePrefix::NONE)); + CALL(@1, @4, type_scalar(UTAP::TypePrefix::NONE)); } | TypePrefix T_SCALAR '[' Expression ']' { CALL(@1, @5, type_scalar($1)); @@ -749,11 +757,11 @@ FieldDeclId: ; TypePrefix: - T_URGENT { $$ = ParserBuilder::TypePrefix::URGENT; } - | T_BROADCAST { $$ = ParserBuilder::TypePrefix::BROADCAST; } - | T_URGENT T_BROADCAST { $$ = ParserBuilder::TypePrefix::URGENT_BROADCAST; } - | T_CONST { $$ = ParserBuilder::TypePrefix::CONST; } - | T_META { $$ = ParserBuilder::TypePrefix::SYSTEM_META; } + T_URGENT { $$ = UTAP::TypePrefix::URGENT; } + | T_BROADCAST { $$ = UTAP::TypePrefix::BROADCAST; } + | T_URGENT T_BROADCAST { $$ = UTAP::TypePrefix::URGENT_BROADCAST; } + | T_CONST { $$ = UTAP::TypePrefix::CONST; } + | T_META { $$ = UTAP::TypePrefix::SYSTEM_META; } ; /********************************************************************* @@ -903,28 +911,28 @@ Sync: SyncExpr: Expression { - CALL(@1, @1, proc_sync(SYNC_CSP)); + CALL(@1, @1, proc_sync(Sync::CSP)); } | Expression T_EXCLAM { - CALL(@1, @2, proc_sync(SYNC_BANG)); + CALL(@1, @2, proc_sync(Sync::BANG)); } | Expression error T_EXCLAM { - CALL(@1, @2, proc_sync(SYNC_BANG)); + CALL(@1, @2, proc_sync(Sync::BANG)); } | Expression '?' { - CALL(@1, @2, proc_sync(SYNC_QUE)); + CALL(@1, @2, proc_sync(Sync::QUE)); } | Expression error '?' { - CALL(@1, @2, proc_sync(SYNC_QUE)); + CALL(@1, @2, proc_sync(Sync::QUE)); } ; MessExpr: Expression { - CALL(@1, @1, proc_message(SYNC_QUE)); + CALL(@1, @1, proc_message(Sync::QUE)); } | Expression error { - CALL(@1, @1, proc_message(SYNC_QUE)); + CALL(@1, @1, proc_message(Sync::QUE)); } ; @@ -981,7 +989,7 @@ UStateList: ExpRate: Expression | Expression ':' Expression { - CALL(@1,@3, expr_binary(FRACTION)); + CALL(@1,@3, expr_binary(Kind::FRACTION)); }; /********************************************************************** @@ -1190,61 +1198,61 @@ Expression: CALL(@1, @2, expr_unary($1)); } %prec UOPERATOR | Expression T_LT Expression { - CALL(@1, @3, expr_binary(LT)); + CALL(@1, @3, expr_binary(Kind::LT)); } | Expression T_LEQ Expression { - CALL(@1, @3, expr_binary(LE)); + CALL(@1, @3, expr_binary(Kind::LE)); } | Expression T_EQ Expression { - CALL(@1, @3, expr_binary(EQ)); + CALL(@1, @3, expr_binary(Kind::EQ)); } | Expression T_NEQ Expression { - CALL(@1, @3, expr_binary(NEQ)); + CALL(@1, @3, expr_binary(Kind::NEQ)); } | Expression T_GT Expression { - CALL(@1, @3, expr_binary(GT)); + CALL(@1, @3, expr_binary(Kind::GT)); } | Expression T_GEQ Expression { - CALL(@1, @3, expr_binary(GE)); + CALL(@1, @3, expr_binary(Kind::GE)); } | Expression T_PLUS Expression { - CALL(@1, @3, expr_binary(PLUS)); + CALL(@1, @3, expr_binary(Kind::PLUS)); } | Expression T_MINUS Expression { - CALL(@1, @3, expr_binary(MINUS)); + CALL(@1, @3, expr_binary(Kind::MINUS)); } | Expression T_MULT Expression { - CALL(@1, @3, expr_binary(MULT)); + CALL(@1, @3, expr_binary(Kind::MULT)); } | Expression T_DIV Expression { - CALL(@1, @3, expr_binary(DIV)); + CALL(@1, @3, expr_binary(Kind::DIV)); } | Expression T_MOD Expression { - CALL(@1, @3, expr_binary(MOD)); + CALL(@1, @3, expr_binary(Kind::MOD)); } | Expression T_POWOP Expression { - CALL(@1, @3, expr_binary(POW)); + CALL(@1, @3, expr_binary(Kind::POW)); } | Expression '&' Expression { - CALL(@1, @3, expr_binary(BIT_AND)); + CALL(@1, @3, expr_binary(Kind::BIT_AND)); } | Expression T_OR Expression { - CALL(@1, @3, expr_binary(BIT_OR)); + CALL(@1, @3, expr_binary(Kind::BIT_OR)); } | Expression T_XOR Expression { - CALL(@1, @3, expr_binary(BIT_XOR)); + CALL(@1, @3, expr_binary(Kind::BIT_XOR)); } | Expression T_LSHIFT Expression { - CALL(@1, @3, expr_binary(BIT_LSHIFT)); + CALL(@1, @3, expr_binary(Kind::BIT_LSHIFT)); } | Expression T_RSHIFT Expression { - CALL(@1, @3, expr_binary(BIT_RSHIFT)); + CALL(@1, @3, expr_binary(Kind::BIT_RSHIFT)); } | Expression T_BOOL_AND Expression { - CALL(@1, @3, expr_binary(AND)); + CALL(@1, @3, expr_binary(Kind::AND)); } | Expression T_BOOL_OR Expression { - CALL(@1, @3, expr_binary(OR)); + CALL(@1, @3, expr_binary(Kind::OR)); } | Expression '?' Expression ':' Expression { CALL(@1, @5, expr_inline_if()); @@ -1256,30 +1264,30 @@ Expression: CALL(@1, @3, expr_dot($3)); } | Expression T_APOS { - CALL(@1, @2, expr_unary(RATE)); + CALL(@1, @2, expr_unary(Kind::RATE)); } | T_DEADLOCK { CALL(@1, @1, expr_deadlock()); } | Expression T_KW_IMPLY { - CALL(@1, @1, expr_unary(NOT)); + CALL(@1, @1, expr_unary(Kind::NOT)); } Expression { - CALL(@3, @3, expr_binary(OR)); + CALL(@3, @3, expr_binary(Kind::OR)); } | Expression T_KW_AND Expression { - CALL(@1, @3, expr_binary(AND)); + CALL(@1, @3, expr_binary(Kind::AND)); } | Expression T_KW_OR Expression { - CALL(@1, @3, expr_binary(OR)); + CALL(@1, @3, expr_binary(Kind::OR)); } | Expression T_KW_XOR Expression { - CALL(@1, @3, expr_binary(XOR)); + CALL(@1, @3, expr_binary(Kind::XOR)); } | Expression T_MIN Expression { - CALL(@1, @3, expr_binary(MIN)); + CALL(@1, @3, expr_binary(Kind::MIN)); } | Expression T_MAX Expression { - CALL(@1, @3, expr_binary(MAX)); + CALL(@1, @3, expr_binary(Kind::MAX)); } | T_SUM '(' Id ':' Type ')' { CALL(@1, @6, expr_sum_begin($3)); @@ -1348,95 +1356,95 @@ Assignment: AssignOp: /* = += -= /= %= &= |= ^= <<= >>= */ - T_ASSIGNMENT { $$ = ASSIGN; } - | T_ASSPLUS { $$ = ASS_PLUS; } - | T_ASSMINUS { $$ = ASS_MINUS; } - | T_ASSDIV { $$ = ASS_DIV; } - | T_ASSMOD { $$ = ASS_MOD; } - | T_ASSMULT { $$ = ASS_MULT; } - | T_ASSAND { $$ = ASS_AND; } - | T_ASSOR { $$ = ASS_OR; } - | T_ASSXOR { $$ = ASS_XOR; } - | T_ASSLSHIFT { $$ = ASS_LSHIFT; } - | T_ASSRSHIFT { $$ = ASS_RSHIFT; } + T_ASSIGNMENT { $$ = Kind::ASSIGN; } + | T_ASSPLUS { $$ = Kind::ASS_PLUS; } + | T_ASSMINUS { $$ = Kind::ASS_MINUS; } + | T_ASSDIV { $$ = Kind::ASS_DIV; } + | T_ASSMOD { $$ = Kind::ASS_MOD; } + | T_ASSMULT { $$ = Kind::ASS_MULT; } + | T_ASSAND { $$ = Kind::ASS_AND; } + | T_ASSOR { $$ = Kind::ASS_OR; } + | T_ASSXOR { $$ = Kind::ASS_XOR; } + | T_ASSLSHIFT { $$ = Kind::ASS_LSHIFT; } + | T_ASSRSHIFT { $$ = Kind::ASS_RSHIFT; } ; UnaryOp: /* - + ! */ - T_MINUS { $$ = MINUS; } - | T_PLUS { $$ = PLUS; } - | T_EXCLAM { $$ = NOT; } - | T_KW_NOT { $$ = NOT; } + T_MINUS { $$ = Kind::MINUS; } + | T_PLUS { $$ = Kind::PLUS; } + | T_EXCLAM { $$ = Kind::NOT; } + | T_KW_NOT { $$ = Kind::NOT; } ; BuiltinFunction1: - T_ABS { $$ = ABS_F; } - | T_FABS { $$ = FABS_F; } - | T_EXP { $$ = EXP_F; } - | T_EXP2 { $$ = EXP2_F; } - | T_EXPM1 { $$ = EXPM1_F; } - | T_LN { $$ = LN_F; } - | T_LOG { $$ = LOG_F; } - | T_LOG10 { $$ = LOG10_F; } - | T_LOG2 { $$ = LOG2_F; } - | T_LOG1P { $$ = LOG1P_F; } - | T_SQRT { $$ = SQRT_F; } - | T_CBRT { $$ = CBRT_F; } - | T_SIN { $$ = SIN_F; } - | T_COS { $$ = COS_F; } - | T_TAN { $$ = TAN_F; } - | T_ASIN { $$ = ASIN_F; } - | T_ACOS { $$ = ACOS_F; } - | T_ATAN { $$ = ATAN_F; } - | T_SINH { $$ = SINH_F; } - | T_COSH { $$ = COSH_F; } - | T_TANH { $$ = TANH_F; } - | T_ASINH { $$ = ASINH_F; } - | T_ACOSH { $$ = ACOSH_F; } - | T_ATANH { $$ = ATANH_F; } - | T_ERF { $$ = ERF_F; } - | T_ERFC { $$ = ERFC_F; } - | T_TGAMMA { $$ = TGAMMA_F; } - | T_LGAMMA { $$ = LGAMMA_F; } - | T_CEIL { $$ = CEIL_F; } - | T_FLOOR { $$ = FLOOR_F; } - | T_TRUNC { $$ = TRUNC_F; } - | T_ROUND { $$ = ROUND_F; } - | T_FINT { $$ = FINT_F; } - | T_ILOGB { $$ = ILOGB_F; } - | T_LOGB { $$ = LOGB_F; } - | T_FPCLASSIFY { $$ = FP_CLASSIFY_F; } - | T_ISFINITE { $$ = IS_FINITE_F; } - | T_ISINF { $$ = IS_INF_F; } - | T_ISNAN { $$ = IS_NAN_F; } - | T_ISNORMAL { $$ = IS_NORMAL_F; } - | T_SIGNBIT { $$ = SIGNBIT_F; } - | T_ISUNORDERED { $$ = IS_UNORDERED_F; } - | T_RANDOM { $$ = RANDOM_F; } - | T_RANDOM_POISSON { $$ = RANDOM_POISSON_F; } + T_ABS { $$ = Kind::ABS_F; } + | T_FABS { $$ = Kind::FABS_F; } + | T_EXP { $$ = Kind::EXP_F; } + | T_EXP2 { $$ = Kind::EXP2_F; } + | T_EXPM1 { $$ = Kind::EXPM1_F; } + | T_LN { $$ = Kind::LN_F; } + | T_LOG { $$ = Kind::LOG_F; } + | T_LOG10 { $$ = Kind::LOG10_F; } + | T_LOG2 { $$ = Kind::LOG2_F; } + | T_LOG1P { $$ = Kind::LOG1P_F; } + | T_SQRT { $$ = Kind::SQRT_F; } + | T_CBRT { $$ = Kind::CBRT_F; } + | T_SIN { $$ = Kind::SIN_F; } + | T_COS { $$ = Kind::COS_F; } + | T_TAN { $$ = Kind::TAN_F; } + | T_ASIN { $$ = Kind::ASIN_F; } + | T_ACOS { $$ = Kind::ACOS_F; } + | T_ATAN { $$ = Kind::ATAN_F; } + | T_SINH { $$ = Kind::SINH_F; } + | T_COSH { $$ = Kind::COSH_F; } + | T_TANH { $$ = Kind::TANH_F; } + | T_ASINH { $$ = Kind::ASINH_F; } + | T_ACOSH { $$ = Kind::ACOSH_F; } + | T_ATANH { $$ = Kind::ATANH_F; } + | T_ERF { $$ = Kind::ERF_F; } + | T_ERFC { $$ = Kind::ERFC_F; } + | T_TGAMMA { $$ = Kind::TGAMMA_F; } + | T_LGAMMA { $$ = Kind::LGAMMA_F; } + | T_CEIL { $$ = Kind::CEIL_F; } + | T_FLOOR { $$ = Kind::FLOOR_F; } + | T_TRUNC { $$ = Kind::TRUNC_F; } + | T_ROUND { $$ = Kind::ROUND_F; } + | T_FINT { $$ = Kind::FINT_F; } + | T_ILOGB { $$ = Kind::ILOGB_F; } + | T_LOGB { $$ = Kind::LOGB_F; } + | T_FPCLASSIFY { $$ = Kind::FP_CLASSIFY_F; } + | T_ISFINITE { $$ = Kind::IS_FINITE_F; } + | T_ISINF { $$ = Kind::IS_INF_F; } + | T_ISNAN { $$ = Kind::IS_NAN_F; } + | T_ISNORMAL { $$ = Kind::IS_NORMAL_F; } + | T_SIGNBIT { $$ = Kind::SIGNBIT_F; } + | T_ISUNORDERED { $$ = Kind::IS_UNORDERED_F; } + | T_RANDOM { $$ = Kind::RANDOM_F; } + | T_RANDOM_POISSON { $$ = Kind::RANDOM_POISSON_F; } ; BuiltinFunction2: - T_FMOD { $$ = FMOD_F; } - | T_FMAX { $$ = FMAX_F; } - | T_FMIN { $$ = FMIN_F; } - | T_FDIM { $$ = FDIM_F; } - | T_POW { $$ = POW_F; } - | T_HYPOT { $$ = HYPOT_F; } - | T_ATAN2 { $$ = ATAN2_F; } - | T_LDEXP { $$ = LDEXP_F; } - | T_NEXTAFTER { $$ = NEXT_AFTER_F; } - | T_COPYSIGN { $$ = COPY_SIGN_F; } - | T_RANDOM_ARCSINE { $$ = RANDOM_ARCSINE_F; } - | T_RANDOM_BETA { $$ = RANDOM_BETA_F; } - | T_RANDOM_GAMMA { $$ = RANDOM_GAMMA_F; } - | T_RANDOM_NORMAL { $$ = RANDOM_NORMAL_F; } - | T_RANDOM_WEIBULL { $$ = RANDOM_WEIBULL_F; } + T_FMOD { $$ = Kind::FMOD_F; } + | T_FMAX { $$ = Kind::FMAX_F; } + | T_FMIN { $$ = Kind::FMIN_F; } + | T_FDIM { $$ = Kind::FDIM_F; } + | T_POW { $$ = Kind::POW_F; } + | T_HYPOT { $$ = Kind::HYPOT_F; } + | T_ATAN2 { $$ = Kind::ATAN2_F; } + | T_LDEXP { $$ = Kind::LDEXP_F; } + | T_NEXTAFTER { $$ = Kind::NEXT_AFTER_F; } + | T_COPYSIGN { $$ = Kind::COPY_SIGN_F; } + | T_RANDOM_ARCSINE { $$ = Kind::RANDOM_ARCSINE_F; } + | T_RANDOM_BETA { $$ = Kind::RANDOM_BETA_F; } + | T_RANDOM_GAMMA { $$ = Kind::RANDOM_GAMMA_F; } + | T_RANDOM_NORMAL { $$ = Kind::RANDOM_NORMAL_F; } + | T_RANDOM_WEIBULL { $$ = Kind::RANDOM_WEIBULL_F; } ; BuiltinFunction3: - T_FMA { $$ = FMA_F; } - | T_RANDOM_TRI { $$ = RANDOM_TRI_F; } + T_FMA { $$ = Kind::FMA_F; } + | T_RANDOM_TRI { $$ = Kind::RANDOM_TRI_F; } ; ArgList: @@ -1467,7 +1475,7 @@ OldDeclaration: OldVarDecl: VariableDecl | T_OLDCONST { - CALL(@1, @1, type_int(ParserBuilder::TypePrefix::CONST)); + CALL(@1, @1, type_int(UTAP::TypePrefix::CONST)); } OldConstDeclIdList ';' { CALL(@1, @3, type_pop()); } @@ -1554,12 +1562,12 @@ OldProcParam: OldProcConstParam: T_OLDCONST { - CALL(@1, @1, type_int(ParserBuilder::TypePrefix::CONST)); + CALL(@1, @1, type_int(UTAP::TypePrefix::CONST)); } NonTypeId ArrayDecl { CALL(@3, @4, decl_parameter($3, false)); } | OldProcConstParam ',' { - CALL(@1, @1, type_int(ParserBuilder::TypePrefix::CONST)); + CALL(@1, @1, type_int(UTAP::TypePrefix::CONST)); } NonTypeId ArrayDecl { CALL(@4, @5, decl_parameter($4, false)); } @@ -1598,7 +1606,7 @@ OldInvariant: | Expression error ',' { } | OldInvariant ',' Expression { - CALL(@1, @3, expr_binary(AND)); + CALL(@1, @3, expr_binary(Kind::AND)); } ; @@ -1645,19 +1653,19 @@ OldGuard: OldGuardList: Expression | OldGuardList ',' Expression { - CALL(@1, @3, expr_binary(AND)); + CALL(@1, @3, expr_binary(Kind::AND)); } ; /* TIGA-SMC Expanded syntax */ ExpQuantifier: - T_MINEXP { $$ = MIN_EXP;} - | T_MAXEXP { $$ = MAX_EXP;}; + T_MINEXP { $$ = Kind::MIN_EXP;} + | T_MAXEXP { $$ = Kind::MAX_EXP;}; ExpPrQuantifier: - T_MINPR { $$ = MIN_EXP;} - | T_MAXPR { $$ = MAX_EXP;}; + T_MINPR { $$ = Kind::MIN_EXP;} + | T_MAXPR { $$ = Kind::MAX_EXP;}; SubjectionList: // do not allow multiple subjections for the time being /*Id ',' SubjectionList { @@ -1698,30 +1706,30 @@ BoolOrKWAnd: SubProperty: T_AF Expression { - CALL(@1, @2, expr_unary(AF)); + CALL(@1, @2, expr_unary(Kind::AF)); } | T_AG '(' Expression BoolOrKWAnd T_AF Expression ')' { - CALL(@5, @6, expr_unary(AF)); - CALL(@3, @6, expr_binary(AND)); - CALL(@1, @7, expr_unary(AG)); + CALL(@5, @6, expr_unary(Kind::AF)); + CALL(@3, @6, expr_binary(Kind::AND)); + CALL(@1, @7, expr_unary(Kind::AG)); } | T_AG Expression { - CALL(@1, @2, expr_unary(AG)); + CALL(@1, @2, expr_unary(Kind::AG)); } | T_EF Expression { - CALL(@1, @2, expr_unary(EF)); + CALL(@1, @2, expr_unary(Kind::EF)); } | T_EG Expression { - CALL(@1, @2, expr_unary(EG)); + CALL(@1, @2, expr_unary(Kind::EG)); } | Expression T_LEADS_TO Expression { - CALL(@1, @3, expr_binary(LEADS_TO)); + CALL(@1, @3, expr_binary(Kind::LEADS_TO)); } | 'A' '[' Expression 'U' Expression ']' { - CALL(@1, @6, expr_binary(A_UNTIL)); + CALL(@1, @6, expr_binary(Kind::A_UNTIL)); } | 'A' '[' Expression 'W' Expression ']' { - CALL(@1, @6, expr_binary(A_WEAK_UNTIL)); + CALL(@1, @6, expr_binary(Kind::A_WEAK_UNTIL)); } ; @@ -1733,37 +1741,37 @@ Features: { AssignablePropperty: T_CONTROL ':' SubProperty Subjection { - CALL(@1, @3, expr_unary(CONTROL)); + CALL(@1, @3, expr_unary(Kind::CONTROL)); CALL(@1, @3, property()); } | T_CONTROL_T T_MULT '(' Expression ',' Expression ')' ':' SubProperty { - CALL(@1, @9, expr_ternary(CONTROL_TOPT)); + CALL(@1, @9, expr_ternary(Kind::CONTROL_TOPT)); CALL(@1, @9, property()); } | T_CONTROL_T T_MULT '(' Expression ')' ':' SubProperty { - CALL(@1, @7, expr_binary(CONTROL_TOPT_DEF1)); + CALL(@1, @7, expr_binary(Kind::CONTROL_TOPT_DEF1)); CALL(@1, @7, property()); } | T_CONTROL_T T_MULT ':' SubProperty { - CALL(@1, @4, expr_unary(CONTROL_TOPT_DEF2)); + CALL(@1, @4, expr_unary(Kind::CONTROL_TOPT_DEF2)); CALL(@1, @4, property()); } | T_EF T_CONTROL ':' SubProperty Subjection { - CALL(@1, @4, expr_unary(EF_CONTROL)); + CALL(@1, @4, expr_unary(Kind::EF_CONTROL)); CALL(@1, @4, property()); } | BracketExprList T_CONTROL ':' SubProperty Subjection { - CALL(@1, @4, expr_binary(PO_CONTROL)); + CALL(@1, @4, expr_binary(Kind::PO_CONTROL)); CALL(@1, @4, property()); } | ExpQuantifier '(' Expression ')' '[' BoundType ']' Features ':' PathType Expression Subjection Imitation { - CALL(@1, @12, expr_optimize_exp($1, ParserBuilder::EXPRPRICE, $10)); + CALL(@1, @12, expr_optimize_exp($1, PriceType::EXPR, $10)); CALL(@1, @9, property()); } | ExpPrQuantifier '[' BoundType ']' Features ':' PathType Expression Subjection Imitation { - CALL(@1, @9, expr_optimize_exp($1, ParserBuilder::TIMEPRICE, $7)); + CALL(@1, @9, expr_optimize_exp($1, PriceType::TIME, $7)); CALL(@1, @6, property()); } | T_LOAD_STRAT Features '(' Expression ')' { @@ -1772,8 +1780,8 @@ AssignablePropperty: } ; /** - | T_MINPR { $$ = MIN_PR;} - | T_MAXPR { $$ = MAX_PR;} + | T_MINPR { $$ = Kind::MIN_PR;} + | T_MAXPR { $$ = Kind::MAX_PR;} */ PropertyExpr: @@ -1781,7 +1789,7 @@ PropertyExpr: CALL(@1, @1, property()); } | T_PMAX Expression { // Deprecated, comes from old uppaal-prob. - CALL(@1, @2, expr_unary(PMAX)); + CALL(@1, @2, expr_unary(Kind::PMAX)); CALL(@1, @2, property()); } | AssignablePropperty @@ -1801,7 +1809,7 @@ PropertyExpr: CALL(@1, @7, property()); } | T_PROBA SMCBounds '(' Expression 'U' Expression ')' Subjection { - CALL(@1, @8, expr_proba_quantitative(DIAMOND)); + CALL(@1, @8, expr_proba_quantitative(Kind::DIAMOND)); CALL(@1, @8, property()); } | T_PROBA SMCBounds '(' PathType Expression ')' T_GEQ @@ -1874,18 +1882,18 @@ BoundType: ; CmpGLE: - T_GEQ { $$ = GE; } - | T_LEQ { $$ = LE; } + T_GEQ { $$ = Kind::GE; } + | T_LEQ { $$ = Kind::LE; } ; PathType: - T_BOX { $$ = BOX; } - | T_DIAMOND { $$ = DIAMOND; } + T_BOX { $$ = Kind::BOX; } + | T_DIAMOND { $$ = Kind::DIAMOND; } ; BracketExprList: '{' ExpressionList '}' { - CALL(@1, @3, expr_nary(LIST,$2)); + CALL(@1, @3, expr_nary(Kind::LIST,$2)); }; /* There is an ExprList but it's not a list, rather @@ -1934,18 +1942,18 @@ Property: | StrategyAssignment | PropertyExpr | SupPrefix NonEmptyExpressionList Subjection { - CALL(@1, @2, expr_nary(LIST,$2)); - CALL(@1, @2, expr_binary(SUP_VAR)); + CALL(@1, @2, expr_nary(Kind::LIST,$2)); + CALL(@1, @2, expr_binary(Kind::SUP_VAR)); CALL(@1, @2, property()); } | InfPrefix NonEmptyExpressionList Subjection { - CALL(@1, @2, expr_nary(LIST,$2)); - CALL(@1, @2, expr_binary(INF_VAR)); + CALL(@1, @2, expr_nary(Kind::LIST,$2)); + CALL(@1, @2, expr_binary(Kind::INF_VAR)); CALL(@1, @2, property()); } | BoundsPrefix NonEmptyExpressionList Subjection { - CALL(@1, @2, expr_nary(LIST,$2)); - CALL(@1, @2, expr_binary(BOUNDS_VAR)); + CALL(@1, @2, expr_nary(Kind::LIST,$2)); + CALL(@1, @2, expr_binary(Kind::BOUNDS_VAR)); CALL(@1, @2, property()); }; @@ -1965,74 +1973,75 @@ static void setStartToken(XTAPart part, bool newxta) { switch (part) { - case S_XTA: + using namespace UTAP::XTAPartNames; + case XTA: syntax_token = newxta ? T_NEW : T_OLD; break; - case S_DECLARATION: + case DECLARATION: syntax_token = newxta ? T_NEW_DECLARATION : T_OLD_DECLARATION; break; - case S_LOCAL_DECL: + case LOCAL_DECL: syntax_token = newxta ? T_NEW_LOCAL_DECL : T_OLD_LOCAL_DECL; break; - case S_INST: + case INST: syntax_token = newxta ? T_NEW_INST : T_OLD_INST; break; - case S_SYSTEM: + case SYSTEM: syntax_token = T_NEW_SYSTEM; break; - case S_PARAMETERS: + case PARAMETERS: syntax_token = newxta ? T_NEW_PARAMETERS : T_OLD_PARAMETERS; break; - case S_INVARIANT: + case INVARIANT: syntax_token = newxta ? T_NEW_INVARIANT : T_OLD_INVARIANT; break; - case S_EXPONENTIAL_RATE: + case EXPONENTIAL_RATE: syntax_token = T_EXPONENTIAL_RATE; break; - case S_SELECT: + case SELECT: syntax_token = T_NEW_SELECT; break; - case S_GUARD: + case GUARD: syntax_token = newxta ? T_NEW_GUARD : T_OLD_GUARD; break; - case S_SYNC: + case SYNC: syntax_token = T_NEW_SYNC; break; - case S_ASSIGN: + case ASSIGN: syntax_token = newxta ? T_NEW_ASSIGN : T_OLD_ASSIGN; break; - case S_EXPRESSION: + case EXPRESSION: syntax_token = T_EXPRESSION; break; - case S_EXPRESSION_LIST: + case EXPRESSION_LIST: syntax_token = T_EXPRESSION_LIST; break; - case S_PROPERTY: + case PROPERTY: syntax_token = T_PROPERTY; break; - case S_XTA_PROCESS: + case XTA_PROCESS: syntax_token = T_XTA_PROCESS; break; - case S_PROBABILITY: + case PROBABILITY: syntax_token = T_PROBABILITY; break; // LSC - case S_INSTANCE_LINE: + case INSTANCE_LINE: syntax_token = T_INSTANCE_LINE; break; - case S_MESSAGE: + case MESSAGE: syntax_token = T_MESSAGE; break; - case S_UPDATE: + case UPDATE: syntax_token = T_UPDATE; break; - case S_CONDITION: + case CONDITION: syntax_token = T_CONDITION; break; } } -static int32_t parse_XTA(ParserBuilder& aParserBuilder, +static int32_t builder_parse_XTA(ParserBuilder& aParserBuilder, bool newxta, XTAPart part, std::string_view xpath) { // Select syntax @@ -2055,11 +2064,11 @@ static int32_t parse_XTA(ParserBuilder& aParserBuilder, return res; } -static int32_t parse_property(ParserBuilder& aParserBuilder, std::string_view xpath) +static int32_t builder_parse_property(ParserBuilder& aParserBuilder, std::string_view xpath) { // Select syntax syntax = Syntax::PROPERTY; - setStartToken(S_PROPERTY, false); + setStartToken(UTAP::XTAPart::PROPERTY, false); // Set parser builder ch = &aParserBuilder; @@ -2070,14 +2079,15 @@ static int32_t parse_property(ParserBuilder& aParserBuilder, std::string_view xp return (utap_parse() != 0) ? -1 : 0; } -int32_t parse_XTA(const char *str, ParserBuilder& builder, - bool newxta, XTAPart part, std::string_view xpath) +/** Deletes the current flex scan buffer on scope exit, even if parsing + * throws (a ParserBuilder is explicitly allowed to report errors by + * throwing, see builder.hpp), so the buffer is never leaked. */ +struct ScanBufferGuard { - utap__scan_string(str); - int32_t res = parse_XTA(builder, newxta, part, xpath); - utap__delete_buffer(YY_CURRENT_BUFFER); - return res; -} + ~ScanBufferGuard() { utap__delete_buffer(YY_CURRENT_BUFFER); } +}; + +namespace UTAP { const char* utap_builtin_declarations() { static const char* res = @@ -2115,35 +2125,42 @@ static const char* res = return res; } +int32_t parse_XTA(const char *str, ParserBuilder& builder, + bool newxta, XTAPart part, std::string_view xpath) +{ + utap__scan_string(str); + auto guard = ScanBufferGuard{}; + return builder_parse_XTA(builder, newxta, part, xpath); +} + int32_t parse_XTA(const char *str, ParserBuilder& builder, bool newxta) { if (newxta) - parse_XTA(utap_builtin_declarations(), builder, newxta, S_DECLARATION, ""); - return parse_XTA(str, builder, newxta, S_XTA, ""); + parse_XTA(utap_builtin_declarations(), builder, newxta, XTAPart::DECLARATION, ""); + return parse_XTA(str, builder, newxta, XTAPart::XTA, ""); } int32_t parse_XTA(FILE *file, ParserBuilder& builder, bool newxta) { if (newxta) - parse_XTA(utap_builtin_declarations(), builder, newxta, S_DECLARATION, ""); + parse_XTA(utap_builtin_declarations(), builder, newxta, XTAPart::DECLARATION, ""); utap__switch_to_buffer(utap__create_buffer(file, YY_BUF_SIZE)); - int res = parse_XTA(builder, newxta, S_XTA, ""); - utap__delete_buffer(YY_CURRENT_BUFFER); - return res; + auto guard = ScanBufferGuard{}; + return builder_parse_XTA(builder, newxta, XTAPart::XTA, ""); } int32_t parse_property(const char *str, ParserBuilder& aParserBuilder, const std::string& xpath) { utap__scan_string(str); - int32_t res = parse_property(aParserBuilder, xpath); - utap__delete_buffer(YY_CURRENT_BUFFER); - return res; + auto guard = ScanBufferGuard{}; + return builder_parse_property(aParserBuilder, xpath); } int32_t parse_property(FILE *file, ParserBuilder& aParserBuilder) { utap__switch_to_buffer(utap__create_buffer(file, YY_BUF_SIZE)); - int32_t res = parse_property(aParserBuilder, ""); - utap__delete_buffer(YY_CURRENT_BUFFER); - return res; + auto guard = ScanBufferGuard{}; + return builder_parse_property(aParserBuilder, ""); } + +} // namespace UTAP \ No newline at end of file diff --git a/src/position.cpp b/src/position.cpp index 0060054c..77c3c7d5 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -61,7 +61,8 @@ const PositionIndex::Line& PositionIndex::find(uint32_t position) const std::ostream& PositionIndex::print(std::ostream& os) const { for (const auto& line : lines) - os << line.position << " " << line.offset << " " << line.line << " " << line.path << std::endl; + os << line.position << " " << line.offset << " " << line.line << " " << (line.path ? *line.path : "") + << std::endl; return os; } @@ -71,7 +72,7 @@ std::ostream& operator<<(std::ostream& os, const Error& e) os << e.msg << " at line " << e.start.line << " column " << (e.position.start - e.start.position) << " to line " << e.end.line << " column " << (e.position.end - e.end.position); } else { - os << e.msg << " in " << e.start.path << " at line " << e.start.line << " column " + os << e.msg << " in " << *e.start.path << " at line " << e.start.line << " column " << (e.position.start - e.start.position) << " to line " << e.end.line << " column " << (e.position.end - e.end.position); } diff --git a/test/pretty.cpp b/src/pretty.cpp similarity index 95% rename from test/pretty.cpp rename to src/pretty.cpp index ba4279c4..13b015c0 100644 --- a/test/pretty.cpp +++ b/src/pretty.cpp @@ -27,9 +27,6 @@ #include #include -using namespace std; -using namespace UTAP::Constants; - static bool newSyntax = (getenv("UPPAAL_OLD_SYNTAX") == nullptr); /** @@ -49,7 +46,7 @@ int main(int argc, char* argv[]) if (!std::filesystem::is_regular_file(path)) throw std::runtime_error("Path is not a regular file: " + path.string()); - auto pretty = UTAP::PrettyPrinter{cout}; + auto pretty = UTAP::PrettyPrinter{std::cout}; if (path.extension() == ".xml") { parse_XML_file(path, pretty, newSyntax); diff --git a/src/print.hpp b/src/print.hpp index c46bfc73..40fc7e1e 100644 --- a/src/print.hpp +++ b/src/print.hpp @@ -28,8 +28,8 @@ template std::ostream& print_infix(std::ostream& os, const View& view, std::string_view delim = ",") { - auto b = std::begin(view), e = std::end(view); - if (b != e) { + const auto e = std::end(view); + if (auto b = std::begin(view); b != e) { os << *b; while (++b != e) os << delim << *b; @@ -49,10 +49,10 @@ std::ostream& print_infix(std::ostream& os, const View& view, std::string_view d template std::ostream& print_infix_p(std::ostream& os, const View& view, Print&& print, std::string_view delim = ",") { - auto b = std::begin(view), e = std::end(view); - using E = typename std::iterator_traits::value_type; + const auto e = std::end(view); + using E = typename std::iterator_traits::value_type; static_assert(std::is_invocable_v, "print should accept istream and range element"); - if (b != e) { + if (auto b = std::begin(view); b != e) { print(os, *b); while (++b != e) print(os << delim, *b); diff --git a/src/property.cpp b/src/property.cpp index 5e3d9bf0..22941e18 100644 --- a/src/property.cpp +++ b/src/property.cpp @@ -29,10 +29,7 @@ #include #include -using UTAP::Expression; - -using namespace UTAP::Constants; -using namespace UTAP; +namespace UTAP { void PropertyBuilder::typeCheck(Expression& expr) { tc.visitProperty(expr); } @@ -116,27 +113,27 @@ void PropertyBuilder::property() if ( // expr.get_kind() == AF || // expr.get_kind() == EG || // expr.get_kind() == LEADS_TO || - expr.get_kind() == SCENARIO || expr.get_kind() == SCENARIO2) { - throw UTAP::TypeException("$Cannot_handle_this_formula_for_models_with_priorities_or_guarded_broadcast_" - "receivers"); - } + expr.get_kind() == Kind::SCENARIO || expr.get_kind() == Kind::SCENARIO2) { + throw TypeException{"$Cannot_handle_this_formula_for_models_with_priorities_or_guarded_broadcast_" + "receivers"}; + } // Undid Marius' change. // The error says clearly for models with priorities or guarded broadcast. // The reason is theoretical. There is no proof of correctness for either of these // cases. In fact they are very similar because they are both based on partitioning // the states with subtractions. This was added in rev. 4528. if (/*document->has_priority_declaration() &&*/ expr.contains_deadlock()) - throw UTAP::TypeException( + throw TypeException{ "$Cannot_handle_deadlock_predicate_for_models_with_priorities_or_guarded_broadcast_" - "receivers"); + "receivers"}; } - if (expr.get_kind() != EF && expr.get_kind() != AG && expr.contains_deadlock()) { - throw UTAP::TypeException("$Cannot_handle_this_deadlock_predicate"); + if (expr.get_kind() != Kind::EF && expr.get_kind() != Kind::AG && expr.contains_deadlock()) { + throw TypeException{"$Cannot_handle_this_deadlock_predicate"}; } if (document.has_dynamic_templates() && !isSMC(&expr)) - throw UTAP::TypeException("Dynamic templates are only supported for SMC queries"); + throw TypeException{"Dynamic templates are only supported for SMC queries"}; /* Compile expression. */ properties.emplace_back(document.find_position(position.start).line, properties.size(), expr); @@ -148,6 +145,7 @@ void PropertyBuilder::property() static bool symbolicProperty(const Expression& expr) { switch (expr.get_kind()) { + using namespace KindNames; case EF: case EG: case AF: @@ -181,6 +179,7 @@ void PropertyBuilder::typeProperty(Expression expr) // NOLINT bool prob = false; switch (expr.get_kind()) { + using namespace KindNames; case EF: properties.back().type = quant_t::EE; break; case EG: properties.back().type = quant_t::EG; break; case AF: properties.back().type = quant_t::AE; break; @@ -226,20 +225,19 @@ void PropertyBuilder::typeProperty(Expression expr) // NOLINT prob = true; break; case MITL_FORMULA: properties.back().type = quant_t::Mitl; break; - default: throw UTAP::TypeException("$Invalid_property_type"); prob = true; + default: throw TypeException{"$Invalid_property_type"}; } if (prob) { if (document.has_priority_declaration()) - throw UTAP::TypeException("Priorities are not supported"); + throw TypeException{"Priorities are not supported"}; if (!document.all_broadcast()) - throw UTAP::TypeException("All channels must be broadcast"); + throw TypeException{"All channels must be broadcast"}; } if (document.get_sync_used() == 2 && document.has_priority_declaration()) - throw UTAP::TypeException("CSP synchronization is not implemented with priorities."); + throw TypeException{"CSP synchronization is not implemented with priorities."}; if (symbolicProperty(expr) && (expr.uses_hybrid() || expr.uses_fp())) - throw UTAP::TypeException("Symbolic verification and synthesis exclude usage of doubles and hybrid clocks in " - "properties."); + throw TypeException{"Symbolic verification and synthesis exclude usage of doubles and hybrid clocks in properties."}; } void PropertyBuilder::scenario(std::string_view name) @@ -248,7 +246,7 @@ void PropertyBuilder::scenario(std::string_view name) if (!resolve(name, symbol)) throw std::runtime_error("$No_such_scenario: " + std::string{name}); Type type = symbol.get_type(); - if (type.get_kind() != LSC_INSTANCE) + if (type.get_kind() != Kind::LSC_INSTANCE) throw std::runtime_error("$Not_a_LSC_template: " + symbol.get_name()); } @@ -268,7 +266,7 @@ void PropertyBuilder::parse(FILE* file) parse_property(file, *this); } -void PropertyBuilder::parse(const char* buf, const std::string& xpath, const UTAP::Options& options) +void PropertyBuilder::parse(const char* buf, const std::string& xpath, const Options& options) { size_t num_props = properties.size(); parse_property(buf, *this, xpath); @@ -278,21 +276,22 @@ void PropertyBuilder::parse(const char* buf, const std::string& xpath, const UTA properties.back().options = options; } -Variable* PropertyBuilder::addVariable(Type type, std::string_view name, Expression init, position_t pos) +Variable* PropertyBuilder::add_variable(Type, std::string_view, Expression, position_t) { - throw UTAP::NotSupportedException("addVariable is not supported"); + throw NotSupportedException("add_variable"); } -bool PropertyBuilder::addFunction(Type type, std::string_view name, position_t pos) +bool PropertyBuilder::add_function(Type, std::string_view, position_t) { - throw UTAP::NotSupportedException("addFunction is not supported"); + throw NotSupportedException("add_function"); } -bool PropertyBuilder::isSMC(UTAP::Expression* expr) +bool PropertyBuilder::isSMC(Expression* expr) { if (expr == nullptr) expr = &(fragments[0]); - Kind k = expr->get_kind(); + const Kind k = expr->get_kind(); + using namespace KindNames; return (k == PMAX || k == PROBA_MIN_BOX || k == PROBA_MIN_DIAMOND || k == PROBA_BOX || k == PROBA_DIAMOND || k == PROBA_CMP || k == PROBA_EXP || k == SIMULATE || k == SIMULATEREACH || k == MITL_FORMULA || k == MIN_EXP || k == MAX_EXP); @@ -310,6 +309,7 @@ void TigaPropertyBuilder::typeProperty(Expression expr) _imitation = nullptr; switch (expr.get_kind()) { + using namespace KindNames; case LOAD_STRAT: properties.back().result_type = NonZoneStrategy; properties.back().type = quant_t::strategy_load; @@ -335,7 +335,7 @@ void TigaPropertyBuilder::typeProperty(Expression expr) switch (expr[2].get_kind()) { case A_UNTIL: properties.back().type = quant_t::control_SMC_AUntil; break; case AF: properties.back().type = quant_t::control_SMC_AF; break; - default: throw UTAP::TypeException("$Invalid_control_synthesis_property_type"); + default: throw TypeException{"$Invalid_control_synthesis_property_type"}; } break; @@ -361,7 +361,7 @@ void TigaPropertyBuilder::typeProperty(Expression expr) } break; case A_WEAK_UNTIL: properties.back().type = quant_t::control_AWeakUntil; break; - default: throw UTAP::TypeException("$Invalid_control_synthesis_property_type"); + default: throw TypeException{"$Invalid_control_synthesis_property_type"}; } break; @@ -374,7 +374,7 @@ void TigaPropertyBuilder::typeProperty(Expression expr) case A_UNTIL: properties.back().type = quant_t::EF_control_AUntil; break; case AG: properties.back().type = quant_t::EF_control_AG; break; case A_WEAK_UNTIL: properties.back().type = quant_t::EF_control_AWeakUntil; break; - default: throw UTAP::TypeException("$Invalid_control_synthesis_property_type"); + default: throw TypeException{"$Invalid_control_synthesis_property_type"}; } break; @@ -386,7 +386,7 @@ void TigaPropertyBuilder::typeProperty(Expression expr) case AG: properties.back().type = quant_t::PO_control_AG; break; case A_UNTIL: properties.back().type = quant_t::PO_control_AUntil; break; case A_WEAK_UNTIL: properties.back().type = quant_t::PO_control_AWeakUntil; break; - default: throw UTAP::TypeException("$Invalid_control_synthesis_property_type"); + default: throw TypeException{"$Invalid_control_synthesis_property_type"}; } break; @@ -396,7 +396,7 @@ void TigaPropertyBuilder::typeProperty(Expression expr) switch (expr[2].get_kind()) { case AF: properties.back().type = quant_t::control_opt_AF; break; case A_UNTIL: properties.back().type = quant_t::control_opt_AUntil; break; - default: throw UTAP::TypeException("$Invalid_type_of_time_optimal_control_synthesis_property"); + default: throw TypeException{"$Invalid_type_of_time_optimal_control_synthesis_property"}; } break; @@ -406,7 +406,7 @@ void TigaPropertyBuilder::typeProperty(Expression expr) switch (expr[1].get_kind()) { case AF: properties.back().type = quant_t::control_opt_Def1_AF; break; case A_UNTIL: properties.back().type = quant_t::control_opt_Def1_AUntil; break; - default: throw UTAP::TypeException("$Invalid_type_of_time_optimal_control_synthesis_property"); + default: throw TypeException{"$Invalid_type_of_time_optimal_control_synthesis_property"}; } break; @@ -417,7 +417,7 @@ void TigaPropertyBuilder::typeProperty(Expression expr) switch (expr.get_kind()) { case AF: properties.back().type = quant_t::control_opt_Def2_AF; break; case A_UNTIL: properties.back().type = quant_t::control_opt_Def2_AUntil; break; - default: throw UTAP::TypeException("$Invalid_type_of_time_optimal_control_synthesis_property"); + default: throw TypeException{"$Invalid_type_of_time_optimal_control_synthesis_property"}; } break; @@ -425,41 +425,38 @@ void TigaPropertyBuilder::typeProperty(Expression expr) } if (prob && !document.all_broadcast()) - throw UTAP::TypeException("All channels must be broadcast"); + throw TypeException{"All channels must be broadcast"}; if (potigaProp && document.has_strict_lower_bound_on_controllable_edges()) - throw UTAP::TypeException("$(PO)TIGA_properties_cannot_be_checked_for_systems_with_strict_lower_bounds_in_" - "guards"); + throw TypeException{"$(PO)TIGA_properties_cannot_be_checked_for_systems_with_strict_lower_bounds_in_guards"}; if (titiga && document.has_priority_declaration()) // FIXME: always false - throw UTAP::TypeException("$Priorities_are_not_yet_supported_in_TIGA"); + throw TypeException{"$Priorities_are_not_yet_supported_in_TIGA"}; if (!prob) { // FIXME: always true if (document.has_strict_invariants()) - throw UTAP::TypeException("$TIGA_properties_cannot_be_checked_for_systems_with_strict_invariants"); + throw TypeException{"$TIGA_properties_cannot_be_checked_for_systems_with_strict_invariants"}; // Stop-watches are now checked on-the-fly for SMC compatibility. // if (document->has_stop_watch(()) - // throw UTAP::TypeException("$Stop_watches_are_not_yet_supported_in_TIGA"); + // throw TypeException{"$Stop_watches_are_not_yet_supported_in_TIGA"); } } void TigaPropertyBuilder::strategy_declaration(std::string_view id) { - const std::string name = std::string(id); - if (auto it = declarations.find(name); it != declarations.end()) { - declarations.erase(it); - handle_warning(UTAP::duplicate_definition_error(name)); - } - declarations.emplace(name, &properties.back()); + if (auto it = declarations.find(id); it != declarations.end()) { + declarations.erase(it); + handle_warning(duplicate_definition_error(id)); + } + declarations.emplace(std::string(id), &properties.back()); if (!properties.empty()) // this happens when the model and the query file do not correspond. - properties.back().declaration = name; + properties.back().declaration = id; } void TigaPropertyBuilder::subjection(std::string_view id) { - std::string name = std::string(id); - if (auto it = declarations.find(name); it != declarations.end()) + if (auto it = declarations.find(id); it != declarations.end()) subjections.push_back(it->second); else - handle_error(UTAP::strategy_not_declared_error(name)); + handle_error(strategy_not_declared_error(id)); } void TigaPropertyBuilder::imitation(std::string_view id) @@ -467,10 +464,12 @@ void TigaPropertyBuilder::imitation(std::string_view id) if (auto it = declarations.find(id); it != declarations.end()) _imitation = it->second; else - handle_error(UTAP::strategy_not_declared_error(id)); + handle_error(strategy_not_declared_error(id)); } void TigaPropertyBuilder::expr_optimize(int, int, int, int) { // nothing for now } + +} // namespace UTAP \ No newline at end of file diff --git a/src/statement.cpp b/src/statement.cpp index ed6fa190..96dd0f77 100644 --- a/src/statement.cpp +++ b/src/statement.cpp @@ -26,7 +26,9 @@ #include #include -using namespace UTAP; +namespace UTAP { + +Statement::~Statement() noexcept = default; std::string Statement::to_string(const std::string& indent) const { @@ -35,13 +37,21 @@ std::string Statement::to_string(const std::string& indent) const return os.str(); } +int32_t EmptyStatement::accept(StatementVisitor& v) { return v.visit_empty_statement(*this); } +bool EmptyStatement::returns() const { return false; } std::ostream& EmptyStatement::print(std::ostream& os, const std::string& indent) const { return os << indent << ";"; } +int32_t ExprStatement::accept(StatementVisitor& v) { return v.visit_expr_statement(*this); } +bool ExprStatement::returns() const { return false; } + std::ostream& ExprStatement::print(std::ostream& os, const std::string& indent) const { return expr.print(os << indent) << ";"; } +int32_t AssertStatement::accept(StatementVisitor& v) { return v.visit_assert_statement(*this); } +bool AssertStatement::returns() const { return false; } + std::ostream& AssertStatement::print(std::ostream& os, const std::string& indent) const { return expr.print(os << indent << "assert(") << ");"; @@ -53,6 +63,9 @@ IfStatement::IfStatement(Expression cond, std::unique_ptr trueCase, s assert(this->trueCase); } +int32_t IfStatement::accept(StatementVisitor& v) { return v.visit_if_statement(*this); } +bool IfStatement::returns() const { return trueCase->returns() && falseCase != nullptr && falseCase->returns(); } + std::ostream& IfStatement::print(std::ostream& os, const std::string& indent) const { os << indent << "if ("; @@ -71,6 +84,9 @@ ForStatement::ForStatement(Expression init, Expression cond, Expression step, st assert(this->stat != nullptr); } +int32_t ForStatement::accept(StatementVisitor& v) { return v.visit_for_statement(*this); } +bool ForStatement::returns() const { return false; } + std::ostream& ForStatement::print(std::ostream& os, const std::string& indent) const { init.print(os << indent << "for (") << "; "; @@ -79,6 +95,9 @@ std::ostream& ForStatement::print(std::ostream& os, const std::string& indent) c return stat->print(os, indent + INDENT) << "\n"; } +int32_t RangeStatement::accept(StatementVisitor& v) { return v.visit_iteration_statement(*this); } +bool RangeStatement::returns() const { return false; } + std::ostream& RangeStatement::print(std::ostream& os, const std::string& indent) const { auto t = symbol.get_type(); @@ -93,6 +112,9 @@ WhileStatement::WhileStatement(Expression cond, std::unique_ptr stat) assert(this->stat != nullptr); } +int32_t WhileStatement::accept(StatementVisitor& v) { return v.visit_while_statement(*this); } +bool WhileStatement::returns() const { return false; } + std::ostream& WhileStatement::print(std::ostream& os, const std::string& indent) const { cond.print(os << indent << "while (") << ")\n"; @@ -105,12 +127,18 @@ DoWhileStatement::DoWhileStatement(std::unique_ptr stat, Expression c assert(this->stat != nullptr); } +int32_t DoWhileStatement::accept(StatementVisitor& v) { return v.visit_do_while_statement(*this); } +bool DoWhileStatement::returns() const { return stat->returns(); } + std::ostream& DoWhileStatement::print(std::ostream& os, const std::string& indent) const { stat->print(os << indent << "do\n", indent + INDENT) << "\n" << indent << "while ("; return cond.print(os) << ");\n"; } +bool CompositeStatement::returns() const { return empty() || back().returns(); } +bool CompositeStatement::empty() const { return stats.empty(); } + std::ostream& CompositeStatement::print(std::ostream& os, const std::string& indent) const { if (stats.empty()) @@ -151,6 +179,8 @@ std::unique_ptr CompositeStatement::pop() return st; } +int32_t BlockStatement::accept(StatementVisitor& v) { return v.visit_block_statement(*this); } + std::ostream& BlockStatement::print(std::ostream& os, const std::string& indent) const { os << "{\n"; @@ -159,6 +189,9 @@ std::ostream& BlockStatement::print(std::ostream& os, const std::string& indent) return os << indent << "}"; } +int32_t SwitchStatement::accept(StatementVisitor& v) { return v.visit_switch_statement(*this); } +bool SwitchStatement::returns() const { return false; } + std::ostream& SwitchStatement::print(std::ostream& os, const std::string& indent) const { os << indent << "switch ("; @@ -168,6 +201,9 @@ std::ostream& SwitchStatement::print(std::ostream& os, const std::string& indent return CompositeStatement::print(os, indent) << "\n"; } +int32_t CaseStatement::accept(StatementVisitor& v) { return v.visit_case_statement(*this); } +bool CaseStatement::returns() const { return false; } + std::ostream& CaseStatement::print(std::ostream& os, const std::string& indent) const { os << indent << "case "; @@ -177,6 +213,9 @@ std::ostream& CaseStatement::print(std::ostream& os, const std::string& indent) return os; } +int32_t DefaultStatement::accept(StatementVisitor& v) { return v.visit_default_statement(*this); } +bool DefaultStatement::returns() const { return false; } + std::ostream& DefaultStatement::print(std::ostream& os, const std::string& indent) const { os << indent << "default:\n"; @@ -185,16 +224,26 @@ std::ostream& DefaultStatement::print(std::ostream& os, const std::string& inden return os; } +int32_t BreakStatement::accept(StatementVisitor& v) { return v.visit_break_statement(*this); } +bool BreakStatement::returns() const { return false; } + std::ostream& BreakStatement::print(std::ostream& os, const std::string& indent) const { return os << indent << "break;"; } +int32_t ContinueStatement::accept(StatementVisitor& v) { return v.visit_continue_statement(*this); } +bool ContinueStatement::returns() const { return false; } + std::ostream& ContinueStatement::print(std::ostream& os, const std::string& indent) const { return os << indent << "continue;"; } +ReturnStatement::ReturnStatement() = default; +int32_t ReturnStatement::accept(StatementVisitor& v) { return v.visit_return_statement(*this); } +bool ReturnStatement::returns() const { return true; } + std::ostream& ReturnStatement::print(std::ostream& os, const std::string& indent) const { os << indent << "return "; @@ -364,7 +413,7 @@ class CollectChangesVisitor final : public ExpressionVisitor CollectChangesVisitor() = default; }; -std::set UTAP::collect_changes(Statement& stat) +std::set collect_changes(Statement& stat) { auto visitor = CollectChangesVisitor{}; stat.accept(visitor); @@ -381,7 +430,7 @@ class CollectDependenciesVisitor final : public ExpressionVisitor CollectDependenciesVisitor() = default; }; -std::set UTAP::collect_dependencies(Statement& stat) +std::set collect_dependencies(Statement& stat) { auto visitor = CollectDependenciesVisitor{}; stat.accept(visitor); @@ -402,9 +451,11 @@ class CollectDynamicExpressions final : public ExpressionVisitor CollectDynamicExpressions() = default; }; -std::vector UTAP::collect_dynamic_expressions(Statement& stat) +std::vector collect_dynamic_expressions(Statement& stat) { auto visitor = CollectDynamicExpressions{}; stat.accept(visitor); return std::move(visitor.expressions); } + +} // namespace UTAP \ No newline at end of file diff --git a/src/symbols.cpp b/src/symbols.cpp index 4c91615c..06a75dfd 100644 --- a/src/symbols.cpp +++ b/src/symbols.cpp @@ -25,18 +25,16 @@ #include "utap/range.hpp" #include -#include #include #include #include // The base types -using namespace UTAP; -using namespace Constants; +namespace UTAP { ////////////////////////////////////////////////////////////////////////// -struct Symbol::Data : public std::enable_shared_from_this +struct Symbol::Data : std::enable_shared_from_this { Frame::Data* frame = nullptr; // Uncounted pointer to containing frame // TODO: consider removing Type type; // The type of the symbol @@ -53,16 +51,8 @@ Symbol::Symbol(Frame& frame, Type type, std::string_view name, position_t positi data = std::make_shared(frame.data.get(), std::move(type), user, name, position); } -/* Destructor */ Symbol::~Symbol() noexcept = default; -bool Symbol::operator==(const Symbol& symbol) const { return data == symbol.data; } - -/* Inequality operator */ -bool Symbol::operator!=(const Symbol& symbol) const { return data != symbol.data; } - -bool Symbol::operator<(const Symbol& symbol) const { return data < symbol.data; } - /* Get frame this symbol belongs to */ Frame Symbol::get_frame() const { return Frame(data->frame); } @@ -84,13 +74,15 @@ const std::string& Symbol::get_name() const { return data->name; } void Symbol::set_name(std::string name) { data->name = std::move(name); } -std::ostream& operator<<(std::ostream& o, const UTAP::Symbol& t) { return o << t.get_type() << " " << t.get_name(); } +std::ostream& operator<<(std::ostream& o, const Symbol& t) +{ + return o << t.get_type() << " " << t.get_name(); +} ////////////////////////////////////////////////////////////////////////// -struct Frame::Data : public std::enable_shared_from_this +struct Frame::Data : std::enable_shared_from_this { - // bool hasParent; // True if there is a parent Data* parent; // The parent frame data std::vector symbols; // The symbols in the frame std::map> mapping; // Mapping from names to indices @@ -103,12 +95,6 @@ Frame::Frame(Data* frame) { data = frame->shared_from_this(); } /* Destructor */ Frame::~Frame() noexcept = default; -/* Equality operator */ -bool Frame::operator==(const Frame& frame) const { return data == frame.data; } - -/* Inequality operator */ -bool Frame::operator!=(const Frame& frame) const { return data != frame.data; } - /* Returns the number of symbols in this frame */ uint32_t Frame::get_size() const { return static_cast(data->symbols.size()); } bool Frame::empty() const { return data->symbols.empty(); } @@ -244,14 +230,16 @@ Frame Frame::make_sub() return Frame{data.get()}; } -std::ostream& operator<<(std::ostream& os, const UTAP::Frame& t) +std::ostream& operator<<(std::ostream& os, const Frame& t) { os << "{"; - auto b = std::begin(t), e = std::end(t); - if (b != e) { + const auto e = std::end(t); + if (auto b = std::begin(t); b != e) { os << *b; while (++b != e) os << ", " << *b; } return os << "}"; } + +} // namespace UTAP \ No newline at end of file diff --git a/test/syntaxcheck.cpp b/src/syntaxcheck.cpp similarity index 100% rename from test/syntaxcheck.cpp rename to src/syntaxcheck.cpp diff --git a/src/type.cpp b/src/type.cpp index 32e4728c..4beccd79 100644 --- a/src/type.cpp +++ b/src/type.cpp @@ -31,10 +31,9 @@ #include #include // std::pair -using namespace UTAP; -using namespace Constants; +namespace UTAP { -struct child_t +struct Child { std::string label; Type child; @@ -45,7 +44,7 @@ struct Type::type_data Kind kind; // Kind of type object position_t position; // Position in the input file Expression expr; // - std::vector children; + std::vector children; type_data(Kind kind, position_t position): kind{kind}, position{position} {} }; @@ -55,12 +54,6 @@ Type::Type(Kind kind, const position_t& pos, size_t size) data->children.resize(size); } -bool Type::operator==(const Type& type) const { return data == type.data; } - -bool Type::operator!=(const Type& type) const { return data != type.data; } - -bool Type::operator<(const Type& type) const { return data < type.data; } - uint32_t Type::size() const { assert(data); @@ -98,59 +91,60 @@ std::optional Type::find_index_of(std::string_view label) const return {}; } -Kind Type::get_kind() const { return unknown() ? UNKNOWN : data->kind; } +Kind Type::get_kind() const { return unknown() ? Kind::UNKNOWN : data->kind; } bool Type::is_prefix() const { switch (get_kind()) { - case Constants::FRACTION: - case Constants::UNKNOWN: - case Constants::VOID_TYPE: - case Constants::CLOCK: - case Constants::INT: - case Constants::DOUBLE: - case Constants::BOOL: - case Constants::STRING: - case Constants::SCALAR: - case Constants::LOCATION: - case Constants::LOCATION_EXPR: - case Constants::BRANCHPOINT: - case Constants::CHANNEL: - case Constants::COST: - case Constants::INVARIANT: - case Constants::INVARIANT_WR: - case Constants::GUARD: - case Constants::DIFF: - case Constants::CONSTRAINT: - case Constants::FORMULA: - case Constants::ARRAY: - case Constants::RECORD: - case Constants::PROCESS: - case Constants::PROCESS_SET: - case Constants::FUNCTION: - case Constants::FUNCTION_EXTERNAL: - case Constants::INSTANCE: - case Constants::RANGE: - case Constants::REF: - case Constants::TYPEDEF: - case Constants::LABEL: - case Constants::RATE: - case Constants::INSTANCE_LINE: // LSC - case Constants::MESSAGE: // LSC - case Constants::CONDITION: // LSC - case Constants::UPDATE: // LSC - case Constants::LSC_INSTANCE: // LSC + using namespace KindNames; + case FRACTION: + case UNKNOWN: + case VOID_TYPE: + case CLOCK: + case INT: + case DOUBLE: + case BOOL: + case STRING: + case SCALAR: + case LOCATION: + case LOCATION_EXPR: + case BRANCHPOINT: + case CHANNEL: + case COST: + case INVARIANT: + case INVARIANT_WR: + case GUARD: + case DIFF: + case CONSTRAINT: + case FORMULA: + case ARRAY: + case RECORD: + case PROCESS: + case PROCESS_SET: + case FUNCTION: + case FUNCTION_EXTERNAL: + case INSTANCE: + case RANGE: + case REF: + case TYPEDEF: + case LABEL: + case RATE: + case INSTANCE_LINE: // LSC + case MESSAGE: // LSC + case CONDITION: // LSC + case UPDATE: // LSC + case LSC_INSTANCE: // LSC return false; default: return true; } } -bool Type::unknown() const { return data == nullptr || data->kind == UNKNOWN; } +bool Type::unknown() const { return data == nullptr || data->kind == Kind::UNKNOWN; } bool Type::is(Kind kind) const { - using namespace Constants; + using namespace KindNames; const auto k = get_kind(); if (k == PROCESS_VAR) { return kind == PROCESS_VAR; @@ -166,72 +160,71 @@ Type Type::get_sub() const { assert(is_array()); const auto k = get_kind(); - if (k == REF || get_kind() == LABEL) { + if (k == Kind::REF || get_kind() == Kind::LABEL) { return get(0).get_sub(); - } else if (is_prefix()) { + } + if (is_prefix()) { return get(0).get_sub().create_prefix(k); - } else { - return get(0); } + return get(0); } Type Type::get_sub(uint32_t i) const { assert(is_record() || is_process()); const auto k = get_kind(); - if (k == REF || k == LABEL) { + if (k == Kind::REF || k == Kind::LABEL) { return get(0).get_sub(i); - } else if (is_prefix()) { + } + if (is_prefix()) { return get(0).get_sub(i).create_prefix(k); - } else { - return get(i); } + return get(i); } const Type& Type::get_array_size() const { const auto k = get_kind(); - if (is_prefix() || k == REF || k == LABEL) { + if (is_prefix() || k == Kind::REF || k == Kind::LABEL) { return get(0).get_array_size(); - } else { - assert(k == ARRAY); - return get(1); } + assert(k == Kind::ARRAY); + return get(1); } uint32_t Type::get_record_size() const { - if (const auto k = get_kind(); is_prefix() || k == REF || k == LABEL) { + const auto k = get_kind(); + if (is_prefix() || k == Kind::REF || k == Kind::LABEL) { return get(0).get_record_size(); - } else { - assert(k == RECORD); - return size(); } + assert(k == Kind::RECORD); + return size(); } const std::string& Type::get_record_label(uint32_t i) const { static const auto location = std::string{"location"}; - if (const auto k = get_kind(); is_prefix() || k == REF || k == LABEL) { + const auto k = get_kind(); + if (is_prefix() || k == Kind::REF || k == Kind::LABEL) { return get(0).get_record_label(i); - } else if (i == static_cast(std::numeric_limits::max())) { + } + if (i == static_cast(std::numeric_limits::max())) { // TODO: create a separate type for location expressions // TODO: get rid of magical constants return location; - } else { - assert(k == RECORD || k == PROCESS); - return get_label(i); } + assert(k == Kind::RECORD || k == Kind::PROCESS); + return get_label(i); } std::pair Type::get_range() const { - assert(is(RANGE)); - if (get_kind() == RANGE) { + assert(is(Kind::RANGE)); + if (get_kind() == Kind::RANGE) { return std::make_pair(get(1).get_expression(), get(2).get_expression()); - } else { - return get(0).get_range(); } + return get(0).get_range(); } const Expression& Type::get_expression() const @@ -243,7 +236,7 @@ const Expression& Type::get_expression() const Type Type::strip() const { const auto k = get_kind(); - if (is_prefix() || k == RANGE || k == REF || k == LABEL) { + if (is_prefix() || k == Kind::RANGE || k == Kind::REF || k == Kind::LABEL) { return get(0).strip(); } else { return *this; @@ -253,7 +246,7 @@ Type Type::strip() const Type Type::strip_array() const { Type type = strip(); - while (type.get_kind() == ARRAY) { + while (type.get_kind() == Kind::ARRAY) { type = type.get(0).strip(); } return type; @@ -267,7 +260,7 @@ Type Type::rename(const std::string& from, const std::string& to) const type.data->children[i].child = get(i).rename(from, to); type.data->children[i].label = get_label(i); } - if (get_kind() == LABEL && get_label(0) == from) { + if (get_kind() == Kind::LABEL && get_label(0) == from) { type.data->children[0].label = to; } return type; @@ -291,6 +284,7 @@ const position_t& Type::get_position() const { return data->position; } bool Type::is_constant() const { switch (get_kind()) { + using namespace KindNames; case FUNCTION: case FUNCTION_EXTERNAL: case PROCESS: @@ -299,7 +293,7 @@ bool Type::is_constant() const case CONSTANT: return true; case RECORD: return std::all_of(data->children.begin(), data->children.end(), - [](const child_t& c) { return c.child.is_constant(); }); + [](const Child& c) { return c.child.is_constant(); }); default: return size() > 0 && get(0).is_constant(); } } @@ -307,6 +301,7 @@ bool Type::is_constant() const bool Type::is_mutable() const { switch (get_kind()) { + using namespace KindNames; case FUNCTION: case FUNCTION_EXTERNAL: case PROCESS: @@ -315,7 +310,7 @@ bool Type::is_mutable() const case CONSTANT: return false; case RECORD: return std::all_of(data->children.begin(), data->children.end(), - [](const child_t& c) { return c.child.is_mutable(); }); + [](const Child& c) { return c.child.is_mutable(); }); default: return size() == 0 || get(0).is_mutable(); } } @@ -324,11 +319,11 @@ bool Type::is_equality_compatible(const Type& other) const { if (is_integral() && other.is_integral()) { return true; - } else if (is(PROCESS_VAR) && other.is(PROCESS_VAR)) { + } + if (is(Kind::PROCESS_VAR) && other.is(Kind::PROCESS_VAR)) { return true; - } else { - return is_equivalent(other); } + return is_equivalent(other); } bool Type::is_assignment_compatible(const Type& rhs, bool init) const @@ -337,7 +332,8 @@ bool Type::is_assignment_compatible(const Type& rhs, bool init) const (is_double() && (rhs.is_double() || rhs.is_integral()))) : ((is_clock() || is_double()) && (rhs.is_integral() || rhs.is_double() || rhs.is_clock()))) { return true; - } else if (is_integral() && rhs.is_integral()) { + } + if (is_integral() && rhs.is_integral()) { return true; } return is_equivalent(rhs); @@ -353,9 +349,9 @@ bool Type::is_inline_if_compatible(const Type& t1, const Type& t2) const int Type::channel_capability() const { assert(is_channel()); - if (is(URGENT)) + if (is(Kind::URGENT)) return 0; - if (is(BROADCAST)) + if (is(Kind::BROADCAST)) return 1; return 2; } @@ -365,38 +361,47 @@ int Type::channel_capability() const */ bool Type::is_same_scalar(const Type& o) const { - if (get_kind() == REF || get_kind() == CONSTANT || get_kind() == SYSTEM_META) { + if (get_kind() == Kind::REF || get_kind() == Kind::CONSTANT || get_kind() == Kind::SYSTEM_META) { return (*this)[0].is_same_scalar(o); - } else if (o.get_kind() == EF || o.get_kind() == CONSTANT || o.get_kind() == SYSTEM_META) { + } + if (o.get_kind() == Kind::EF || o.get_kind() == Kind::CONSTANT || o.get_kind() == Kind::SYSTEM_META) { return is_same_scalar(o[0]); - } else if (get_kind() == LABEL && o.get_kind() == LABEL) { + } + if (get_kind() == Kind::LABEL && o.get_kind() == Kind::LABEL) { return get_label(0) == o.get_label(0) && (*this)[0].is_same_scalar(o[0]); - } else if (get_kind() == SCALAR && o.get_kind() == SCALAR) { + } + if (get_kind() == Kind::SCALAR && o.get_kind() == Kind::SCALAR) { return true; - } else if (get_kind() == RANGE && o.get_kind() == RANGE) { + } + if (get_kind() == Kind::RANGE && o.get_kind() == Kind::RANGE) { return (*this)[0].is_same_scalar(o[0]) && get_range().first.equal(o.get_range().first) && get_range().second.equal(o.get_range().second); - } else { - return false; } + return false; } bool Type::is_equivalent(const Type& o) const { if (is_integer() && o.is_integer()) { - return !is(RANGE) || !o.is(RANGE) || + return !is(Kind::RANGE) || !o.is(Kind::RANGE) || (get_range().first.equal(o.get_range().first) && get_range().second.equal(o.get_range().second)); - } else if (is_clock() && o.is_clock()) { + } + if (is_clock() && o.is_clock()) { return true; - } else if (is_scalar() && o.is_scalar()) { + } + if (is_scalar() && o.is_scalar()) { return is_same_scalar(o); - } else if (is_double() && o.is_double()) { + } + if (is_double() && o.is_double()) { return true; - } else if (is_boolean() && o.is_boolean()) { + } + if (is_boolean() && o.is_boolean()) { return true; - } else if (is_channel() && o.is_channel()) { + } + if (is_channel() && o.is_channel()) { return channel_capability() == o.channel_capability(); - } else if (is_record() && o.is_record()) { + } + if (is_record() && o.is_record()) { const auto size = get_record_size(); if (const auto oSize = o.get_record_size(); size == oSize) { for (uint32_t i = 0; i < size; ++i) { @@ -423,10 +428,10 @@ bool Type::is_equivalent(const Type& o) const Type Type::create_range(Type type, Expression lower, Expression upper, position_t pos) { - auto t = Type{RANGE, pos, 3}; + auto t = Type{Kind::RANGE, pos, 3}; t.data->children[0].child = std::move(type); - t.data->children[1].child = Type{UNKNOWN, pos, 0}; - t.data->children[2].child = Type{UNKNOWN, pos, 0}; + t.data->children[1].child = Type{Kind::UNKNOWN, pos, 0}; + t.data->children[2].child = Type{Kind::UNKNOWN, pos, 0}; t[1].data->expr = std::move(lower); t[2].data->expr = std::move(upper); return t; @@ -435,7 +440,7 @@ Type Type::create_range(Type type, Expression lower, Expression upper, position_ Type Type::create_record(const std::vector& types, const std::vector& labels, position_t pos) { assert(types.size() == labels.size()); - auto type = Type{RECORD, pos, types.size()}; + auto type = Type{Kind::RECORD, pos, types.size()}; for (size_t i = 0; i < types.size(); i++) { type.data->children[i].child = types[i]; type.data->children[i].label = labels[i]; @@ -447,7 +452,7 @@ Type Type::create_function(Type ret, const std::vector& parameters, const position_t pos) { assert(parameters.size() == labels.size()); - auto type = Type{FUNCTION, pos, parameters.size() + 1}; + auto type = Type{Kind::FUNCTION, pos, parameters.size() + 1}; type.data->children[0].child = std::move(ret); for (size_t i = 0; i < parameters.size(); i++) { type.data->children[i + 1].child = parameters[i]; @@ -460,7 +465,7 @@ Type Type::create_external_function(Type ret, const std::vector& parameter const std::vector& labels, position_t pos) { assert(parameters.size() == labels.size()); - auto type = Type{FUNCTION_EXTERNAL, pos, parameters.size() + 1}; + auto type = Type{Kind::FUNCTION_EXTERNAL, pos, parameters.size() + 1}; type.data->children[0].child = std::move(ret); for (size_t i = 0; i < parameters.size(); i++) { type.data->children[i + 1].child = parameters[i]; @@ -471,7 +476,7 @@ Type Type::create_external_function(Type ret, const std::vector& parameter Type Type::create_array(Type sub, Type size, position_t pos) { - auto type = Type{ARRAY, pos, 2}; + auto type = Type{Kind::ARRAY, pos, 2}; type.data->children[0].child = std::move(sub); type.data->children[1].child = std::move(size); return type; @@ -479,7 +484,7 @@ Type Type::create_array(Type sub, Type size, position_t pos) Type Type::create_typedef(std::string label, Type type, position_t pos) { - auto t = Type{TYPEDEF, pos, 1}; + auto t = Type{Kind::TYPEDEF, pos, 1}; t.data->children[0].label = std::move(label); t.data->children[0].child = std::move(type); return t; @@ -487,7 +492,7 @@ Type Type::create_typedef(std::string label, Type type, position_t pos) Type Type::create_instance(const Frame& parameters, position_t pos) { - auto type = Type{INSTANCE, pos, parameters.get_size()}; + auto type = Type{Kind::INSTANCE, pos, parameters.get_size()}; for (auto i = 0u; i < parameters.get_size(); ++i) { type.data->children[i].child = parameters[i].get_type(); type.data->children[i].label = parameters[i].get_name(); @@ -497,7 +502,7 @@ Type Type::create_instance(const Frame& parameters, position_t pos) Type Type::create_LSC_instance(const Frame& parameters, position_t pos) { - auto type = Type{LSC_INSTANCE, pos, parameters.get_size()}; + auto type = Type{Kind::LSC_INSTANCE, pos, parameters.get_size()}; for (auto i = 0u; i < parameters.get_size(); ++i) { type.data->children[i].child = parameters[i].get_type(); type.data->children[i].label = parameters[i].get_name(); @@ -507,7 +512,7 @@ Type Type::create_LSC_instance(const Frame& parameters, position_t pos) Type Type::create_process(const Frame& frame, position_t pos) { - auto type = Type{PROCESS, pos, frame.get_size()}; + auto type = Type{Kind::PROCESS, pos, frame.get_size()}; for (auto i = 0u; i < frame.get_size(); ++i) { type.data->children[i].child = frame[i].get_type(); type.data->children[i].label = frame[i].get_name(); @@ -517,7 +522,7 @@ Type Type::create_process(const Frame& frame, position_t pos) Type Type::create_process_set(const Type& instance, position_t pos) { - auto type = Type{PROCESS_SET, pos, instance.size()}; + auto type = Type{Kind::PROCESS_SET, pos, instance.size()}; for (auto i = 0u; i < instance.size(); ++i) { type.data->children[i].child = instance[i]; type.data->children[i].label = instance.get_label(i); @@ -536,7 +541,7 @@ Type Type::create_prefix(Kind kind, position_t pos) const Type Type::create_label(std::string_view label, position_t pos) const { - auto type = Type{LABEL, pos, 1}; + auto type = Type{Kind::LABEL, pos, 1}; type.data->children[0].child = *this; type.data->children[0].label = label; return type; @@ -552,6 +557,7 @@ std::ostream& Type::print(std::ostream& os) const os << "("; switch (get_kind()) { + using namespace KindNames; case UNKNOWN: os << "unknown"; break; case RANGE: os << "range"; break; case ARRAY: os << "array"; break; @@ -586,7 +592,7 @@ std::ostream& Type::print(std::ostream& os) const case LOCATION_EXPR: case LOCATION: os << "location"; break; case BRANCHPOINT: os << "branchpoint"; break; - // LSC + // LSC case INSTANCE_LINE: os << "instance line"; break; case MESSAGE: os << "message"; break; case CONDITION: os << "condition"; break; @@ -620,6 +626,7 @@ std::ostream& Type::print_declaration(std::ostream& os) const auto typeDef = false; switch (get_kind()) { + using namespace KindNames; case UNKNOWN: kind = "unknown"; break; case RANGE: range = true; break; case ARRAY: array = true; break; @@ -699,3 +706,5 @@ std::string Type::declaration() const } std::ostream& operator<<(std::ostream& os, const Type& t) { return t.print(os); } + +} // namespace UTAP \ No newline at end of file diff --git a/src/xmlreader.cpp b/src/xmlreader.cpp index b384e033..651e6721 100644 --- a/src/xmlreader.cpp +++ b/src/xmlreader.cpp @@ -45,7 +45,7 @@ #include namespace UTAP { -enum class tag_t { +enum class Tag { NTA, PROJECT, IMPORTS, @@ -95,50 +95,50 @@ enum class tag_t { }; // clang-format off - static const auto tag_map = std::unordered_map{ - {"nta", tag_t::NTA}, - {"project", tag_t::PROJECT}, - {"imports", tag_t::IMPORTS}, - {"declaration", tag_t::DECLARATION}, - {"template", tag_t::TEMPLATE}, - {"instantiation", tag_t::INSTANTIATION}, - {"system", tag_t::SYSTEM}, - {"name", tag_t::NAME}, - {"parameter", tag_t::PARAMETER}, - {"location", tag_t::LOCATION}, - {"init", tag_t::INIT}, - {"transition", tag_t::TRANSITION}, - {"urgent", tag_t::URGENT}, - {"committed", tag_t::COMMITTED}, - {"branchpoint", tag_t::BRANCHPOINT}, - {"source", tag_t::SOURCE}, - {"target", tag_t::TARGET}, - {"label", tag_t::LABEL}, - {"nail", tag_t::NAIL}, - {"lsc", tag_t::LSC}, - {"type", tag_t::TYPE}, - {"mode", tag_t::MODE}, - {"yloccoord", tag_t::YLOCCOORD}, - {"lsclocation", tag_t::LSCLOCATION}, - {"prechart", tag_t::PRECHART}, - {"instance", tag_t::INSTANCE}, - {"temperature", tag_t::TEMPERATURE}, - {"message", tag_t::MESSAGE}, - {"condition", tag_t::CONDITION}, - {"update", tag_t::UPDATE}, - {"anchor", tag_t::ANCHOR}, - {"queries", tag_t::QUERIES}, - {"query", tag_t::QUERY}, - {"formula", tag_t::FORMULA}, - {"comment", tag_t::COMMENT}, - {"option", tag_t::OPTION}, - {"resource", tag_t::RESOURCE}, - {"expect", tag_t::EXPECT}, - {"result", tag_t::RESULT}, - {"details", tag_t::DETAILS}, - {"samples", tag_t::SAMPLES}, - {"plot", tag_t::PLOT}, - {"series", tag_t::SERIES} + static const auto tag_map = std::unordered_map{ + {"nta", Tag::NTA}, + {"project", Tag::PROJECT}, + {"imports", Tag::IMPORTS}, + {"declaration", Tag::DECLARATION}, + {"template", Tag::TEMPLATE}, + {"instantiation", Tag::INSTANTIATION}, + {"system", Tag::SYSTEM}, + {"name", Tag::NAME}, + {"parameter", Tag::PARAMETER}, + {"location", Tag::LOCATION}, + {"init", Tag::INIT}, + {"transition", Tag::TRANSITION}, + {"urgent", Tag::URGENT}, + {"committed", Tag::COMMITTED}, + {"branchpoint", Tag::BRANCHPOINT}, + {"source", Tag::SOURCE}, + {"target", Tag::TARGET}, + {"label", Tag::LABEL}, + {"nail", Tag::NAIL}, + {"lsc", Tag::LSC}, + {"type", Tag::TYPE}, + {"mode", Tag::MODE}, + {"yloccoord", Tag::YLOCCOORD}, + {"lsclocation", Tag::LSCLOCATION}, + {"prechart", Tag::PRECHART}, + {"instance", Tag::INSTANCE}, + {"temperature", Tag::TEMPERATURE}, + {"message", Tag::MESSAGE}, + {"condition", Tag::CONDITION}, + {"update", Tag::UPDATE}, + {"anchor", Tag::ANCHOR}, + {"queries", Tag::QUERIES}, + {"query", Tag::QUERY}, + {"formula", Tag::FORMULA}, + {"comment", Tag::COMMENT}, + {"option", Tag::OPTION}, + {"resource", Tag::RESOURCE}, + {"expect", Tag::EXPECT}, + {"result", Tag::RESULT}, + {"details", Tag::DETAILS}, + {"samples", Tag::SAMPLES}, + {"plot", Tag::PLOT}, + {"series", Tag::SERIES} }; // clang-format on @@ -148,25 +148,25 @@ enum class tag_t { */ static bool is_blank(std::string_view str) { return std::all_of(str.cbegin(), str.cend(), ::isspace); } -static inline bool is_blank(const xmlChar* str) { return is_blank((const char*)str); } +static bool is_blank(const xmlChar* str) { return is_blank((const char*)str); } -static inline bool is_alpha(char c) { return std::isalpha(c) != 0 || c == '_'; } +static bool is_alpha(char c) { return std::isalpha(c) != 0 || c == '_'; } static bool is_id_char(char c) { return std::isalnum(c) != 0 || c == '_' || c == '$' || c == '#'; } -struct id_expected_error : std::logic_error +struct IdExpectedError : std::logic_error { - id_expected_error(): std::logic_error{"Identifier expected"} {} + IdExpectedError(): std::logic_error{"Identifier expected"} {} }; -struct invalid_id_error : std::logic_error +struct InvalidIdError : std::logic_error { - invalid_id_error(): std::logic_error{"Invalid identifier"} {} + InvalidIdError(): std::logic_error{"Invalid identifier"} {} }; -struct xpath_corrupt_error : std::logic_error +struct XPathCorruptError : std::logic_error { - xpath_corrupt_error(): std::logic_error{"XPath is corrupted"} {} + XPathCorruptError(): std::logic_error{"XPath is corrupted"} {} }; std::string_view trim(std::string_view text) @@ -192,12 +192,12 @@ static std::string_view symbol(std::string_view text) { text = trim(text); if (text.empty()) - throw id_expected_error{}; + throw IdExpectedError{}; if (!is_alpha(text[0])) - throw id_expected_error{}; + throw IdExpectedError{}; for (const auto& c : text) if (!is_id_char(c)) - throw invalid_id_error{}; + throw InvalidIdError{}; return text; } @@ -210,81 +210,80 @@ static std::string_view symbol(std::string_view text) */ class Path { -private: - std::list> path; + std::list> path; public: Path() { path.emplace_back(); }; - void push(tag_t tag) + void push(Tag tag) { path.back().push_back(tag); path.emplace_back(); } - tag_t pop() + Tag pop() { path.pop_back(); return path.back().back(); } - [[nodiscard]] std::string str(tag_t tag = tag_t::NONE) const; + [[nodiscard]] std::string str(Tag tag = Tag::NONE) const; }; -static inline size_t count(const std::vector& level, tag_t tag) +static size_t count(const std::vector& level, Tag tag) { return static_cast(std::count(std::begin(level), std::end(level), tag)); } /** Returns the XPath encoding of the current path. */ -[[nodiscard]] std::string Path::str(tag_t tag) const +[[nodiscard]] std::string Path::str(Tag tag) const { std::ostringstream str; for (auto&& level : path) { if (level.empty()) break; switch (level.back()) { - case tag_t::NTA: str << "/nta"; break; - case tag_t::PROJECT: str << "/project"; break; - case tag_t::IMPORTS: str << "/imports"; break; - case tag_t::DECLARATION: str << "/declaration"; break; - case tag_t::TEMPLATE: str << "/template[" << count(level, tag_t::TEMPLATE) << "]"; break; - case tag_t::INSTANTIATION: str << "/instantiation"; break; - case tag_t::SYSTEM: str << "/system"; break; - case tag_t::NAME: str << "/name"; break; - case tag_t::PARAMETER: str << "/parameter"; break; - case tag_t::LOCATION: str << "/location[" << count(level, tag_t::LOCATION) << "]"; break; - case tag_t::BRANCHPOINT: str << "/branchpoint[" << count(level, tag_t::BRANCHPOINT) << "]"; break; - case tag_t::INIT: str << "/init"; break; - case tag_t::TRANSITION: str << "/transition[" << count(level, tag_t::TRANSITION) << "]"; break; - case tag_t::LABEL: str << "/label[" << count(level, tag_t::LABEL) << "]"; break; - case tag_t::URGENT: str << "/urgent"; break; - case tag_t::COMMITTED: str << "/committed"; break; - case tag_t::SOURCE: str << "/source"; break; - case tag_t::TARGET: str << "/target"; break; - case tag_t::NAIL: str << "/nail[" << count(level, tag_t::NAIL) << "]"; break; - case tag_t::LSC: str << "/lscTemplate[" << count(level, tag_t::LSC) << "]"; break; - case tag_t::TYPE: str << "/type"; break; - case tag_t::MODE: str << "/mode"; break; - case tag_t::YLOCCOORD: str << "/ylocoord[" << count(level, tag_t::YLOCCOORD) << "]"; break; - case tag_t::LSCLOCATION: str << "/lsclocation"; break; - case tag_t::PRECHART: str << "/prechart"; break; - case tag_t::INSTANCE: str << "/instance[" << count(level, tag_t::INSTANCE) << "]"; break; - case tag_t::TEMPERATURE: str << "/temperature[" << count(level, tag_t::TEMPERATURE) << "]"; break; - case tag_t::MESSAGE: str << "/message[" << count(level, tag_t::MESSAGE) << "]"; break; - case tag_t::CONDITION: str << "/condition[" << count(level, tag_t::CONDITION) << "]"; break; - case tag_t::UPDATE: str << "/update[" << count(level, tag_t::UPDATE) << "]"; break; - case tag_t::ANCHOR: str << "/anchor[" << count(level, tag_t::ANCHOR) << "]"; break; - case tag_t::QUERIES: str << "/queries"; break; - case tag_t::QUERY: str << "/query[" << count(level, tag_t::QUERY) << "]"; break; - case tag_t::FORMULA: str << "/formula"; break; - case tag_t::COMMENT: str << "/comment"; break; - case tag_t::OPTION: str << "/option"; break; - case tag_t::RESOURCE: str << "/resource"; break; - case tag_t::EXPECT: str << "/expect"; break; - case tag_t::RESULT: str << "/result"; break; - case tag_t::DETAILS: str << "/details"; break; - case tag_t::SAMPLES: str << "/samples"; break; + case Tag::NTA: str << "/nta"; break; + case Tag::PROJECT: str << "/project"; break; + case Tag::IMPORTS: str << "/imports"; break; + case Tag::DECLARATION: str << "/declaration"; break; + case Tag::TEMPLATE: str << "/template[" << count(level, Tag::TEMPLATE) << "]"; break; + case Tag::INSTANTIATION: str << "/instantiation"; break; + case Tag::SYSTEM: str << "/system"; break; + case Tag::NAME: str << "/name"; break; + case Tag::PARAMETER: str << "/parameter"; break; + case Tag::LOCATION: str << "/location[" << count(level, Tag::LOCATION) << "]"; break; + case Tag::BRANCHPOINT: str << "/branchpoint[" << count(level, Tag::BRANCHPOINT) << "]"; break; + case Tag::INIT: str << "/init"; break; + case Tag::TRANSITION: str << "/transition[" << count(level, Tag::TRANSITION) << "]"; break; + case Tag::LABEL: str << "/label[" << count(level, Tag::LABEL) << "]"; break; + case Tag::URGENT: str << "/urgent"; break; + case Tag::COMMITTED: str << "/committed"; break; + case Tag::SOURCE: str << "/source"; break; + case Tag::TARGET: str << "/target"; break; + case Tag::NAIL: str << "/nail[" << count(level, Tag::NAIL) << "]"; break; + case Tag::LSC: str << "/lscTemplate[" << count(level, Tag::LSC) << "]"; break; + case Tag::TYPE: str << "/type"; break; + case Tag::MODE: str << "/mode"; break; + case Tag::YLOCCOORD: str << "/ylocoord[" << count(level, Tag::YLOCCOORD) << "]"; break; + case Tag::LSCLOCATION: str << "/lsclocation"; break; + case Tag::PRECHART: str << "/prechart"; break; + case Tag::INSTANCE: str << "/instance[" << count(level, Tag::INSTANCE) << "]"; break; + case Tag::TEMPERATURE: str << "/temperature[" << count(level, Tag::TEMPERATURE) << "]"; break; + case Tag::MESSAGE: str << "/message[" << count(level, Tag::MESSAGE) << "]"; break; + case Tag::CONDITION: str << "/condition[" << count(level, Tag::CONDITION) << "]"; break; + case Tag::UPDATE: str << "/update[" << count(level, Tag::UPDATE) << "]"; break; + case Tag::ANCHOR: str << "/anchor[" << count(level, Tag::ANCHOR) << "]"; break; + case Tag::QUERIES: str << "/queries"; break; + case Tag::QUERY: str << "/query[" << count(level, Tag::QUERY) << "]"; break; + case Tag::FORMULA: str << "/formula"; break; + case Tag::COMMENT: str << "/comment"; break; + case Tag::OPTION: str << "/option"; break; + case Tag::RESOURCE: str << "/resource"; break; + case Tag::EXPECT: str << "/expect"; break; + case Tag::RESULT: str << "/result"; break; + case Tag::DETAILS: str << "/details"; break; + case Tag::SAMPLES: str << "/samples"; break; default: /* Strange tag on stack */ - throw xpath_corrupt_error{}; + throw XPathCorruptError{}; } if (level.back() == tag) { break; @@ -299,11 +298,10 @@ static inline size_t count(const std::vector& level, tag_t tag) */ class XMLReader { -private: - using elementmap_t = std::map; + using ElementMap = std::map; using xmlTextReader_ptr = std::unique_ptr; xmlTextReader_ptr reader; /**< The underlying xmlTextReader */ - elementmap_t names; /**< Map from id to name */ + ElementMap names; /**< Map from id to name */ ParserBuilder& parser; /**< The parser builder to which to push the model. */ bool newxta; /**< True if we should use new syntax. */ Path path; @@ -312,7 +310,7 @@ class XMLReader std::string currentType; /**< type of the current LSC template */ std::string currentMode; /**< mode of the current LSC template */ - [[nodiscard]] tag_t getElement() const; + [[nodiscard]] Tag getElement() const; /** Reads an attribute value of the currently parsed tag with manual deallocation. * @param name the name of the XML tag attribute * @return the value of the attribute, remember to xmlFree() it! @@ -327,10 +325,10 @@ class XMLReader bool isEmpty() const; int getNodeType() const; void read(); - bool begin(tag_t, bool skipEmpty = true); - bool end(tag_t); + bool begin(Tag, bool skipEmpty = true); + bool end(Tag); /** skips the content until tag is closed and then looks ahead */ - void close(tag_t tag) + void close(Tag tag) { if (!isEmpty()) { while (!end(tag)) @@ -340,14 +338,14 @@ class XMLReader } /** calls fn zero or one times unless closing tag is found */ template - void zero_or_one(tag_t closing_tag, Fn&& fn) + void zero_or_one(Tag closing_tag, Fn&& fn) { if (!end(closing_tag)) fn(); } /** calls fn zero or more times unless closing tag is found */ template - void zero_or_more(tag_t closing_tag, Fn&& fn) + void zero_or_more(Tag closing_tag, Fn&& fn) { while (!end(closing_tag) && fn()) ; @@ -375,7 +373,7 @@ class XMLReader bool init(); /** Parse optional name tag. */ std::string name(bool instanceLine = false); - std::string readString(tag_t tag, bool instanceLine = false); + std::string readString(Tag tag, bool instanceLine = false); std::string readText(bool instanceLine = false); int readNumber(); /** Parse obligatory source tag. */ @@ -445,13 +443,13 @@ int XMLReader::getNodeType() const { return xmlTextReaderNodeType(reader.get()); * Returns the tag of the current element. Throws an exception if * the tag is not known. */ -tag_t XMLReader::getElement() const +Tag XMLReader::getElement() const { const char* element = (const char*)xmlTextReaderConstLocalName(reader.get()); const auto tag = tag_map.find(element); if (tag == std::end(tag_map)) { /* Unknown element. */ - return tag_t::NONE; + return Tag::NONE; } return tag->second; } @@ -483,7 +481,7 @@ bool XMLReader::isEmpty() const * given tag. If skipEmpty is true, empty elements with the given * tag are ignored. */ -bool XMLReader::begin(tag_t tag, bool skipEmpty) +bool XMLReader::begin(Tag tag, bool skipEmpty) { for (;;) { int node_type = getNodeType(); @@ -491,12 +489,12 @@ bool XMLReader::begin(tag_t tag, bool skipEmpty) read(); node_type = getNodeType(); } - tag_t elem = getElement(); + Tag elem = getElement(); if (elem != tag) { // if the tag was not recognized, try skipping over it until // an end element is found with unknown tag. - if (elem == tag_t::NONE) { - end(tag_t::NONE); + if (elem == Tag::NONE) { + end(Tag::NONE); read(); continue; } @@ -513,7 +511,7 @@ bool XMLReader::begin(tag_t tag, bool skipEmpty) * @return True - if tag found * Ignores whitespace */ -bool UTAP::XMLReader::end(UTAP::tag_t tag) +bool XMLReader::end(Tag tag) { int node_type = getNodeType(); // Ignore whitespace @@ -562,10 +560,10 @@ int XMLReader::parse(const xmlChar* text, XTAPart syntax) bool XMLReader::declaration() { - if (begin(tag_t::DECLARATION)) { + if (begin(Tag::DECLARATION)) { read(); if (getNodeType() == XML_READER_TYPE_TEXT) { - parse(xmlTextReaderConstValue(reader.get()), S_DECLARATION); + parse(xmlTextReaderConstValue(reader.get()), XTAPart::DECLARATION); } return true; } @@ -574,7 +572,18 @@ bool XMLReader::declaration() bool XMLReader::label(bool required, const std::string& s_kind) { - if (begin(tag_t::LABEL)) { + static const auto xta_map = std::map{ + {"invariant", XTAPart::INVARIANT}, + {"select", XTAPart::SELECT}, + {"guard", XTAPart::GUARD}, + {"synchronisation", XTAPart::SYNC}, + {"assignment", XTAPart::ASSIGN}, + {"probability", XTAPart::PROBABILITY}, + {"message", XTAPart::MESSAGE}, + {"update", XTAPart::UPDATE}, + {"condition", XTAPart::CONDITION}, + }; + if (begin(Tag::LABEL)) { /* Get kind attribute. */ char* kind = getAttribute("kind"); if (kind == nullptr) @@ -583,17 +592,13 @@ bool XMLReader::label(bool required, const std::string& s_kind) /* Read the text and push it to the parser. */ if (getNodeType() == XML_READER_TYPE_TEXT) { const xmlChar* text = xmlTextReaderConstValue(reader.get()); - static const auto map = std::map{ - {"invariant", S_INVARIANT}, {"select", S_SELECT}, {"guard", S_GUARD}, - {"synchronisation", S_SYNC}, {"assignment", S_ASSIGN}, {"probability", S_PROBABILITY}, - {"message", S_MESSAGE}, {"update", S_UPDATE}, {"condition", S_CONDITION}, - }; - if (auto part = map.find(kind); part != map.end()) + if (auto part = xta_map.find(kind); part != xta_map.end()) parse(text, part->second); } xmlFree(kind); return true; - } else if (required) { + } + if (required) { tracker.setPath(&parser, path.str()); if (s_kind == "message") // LSC parser.handle_error(TypeException{"$Message_label_is_required"}); @@ -608,7 +613,7 @@ bool XMLReader::label(bool required, const std::string& s_kind) int XMLReader::invariant() { int result = -1; - if (begin(tag_t::LABEL)) { + if (begin(Tag::LABEL)) { /* Get kind attribute. */ char* kind = getAttribute("kind"); if (kind == nullptr) @@ -621,10 +626,10 @@ int XMLReader::invariant() // This is a terrible mess but it's too badly designed // to fix at this moment. if (kind_sv == "invariant") { - if (parse(text, S_INVARIANT) == 0) + if (parse(text, XTAPart::INVARIANT) == 0) result = 0; } else if (kind_sv == "exponentialrate") { - if (parse(text, S_EXPONENTIAL_RATE) == 0) + if (parse(text, XTAPart::EXPONENTIAL_RATE) == 0) result = 1; } } @@ -635,7 +640,7 @@ int XMLReader::invariant() std::string XMLReader::name(bool instanceLine) { - std::string text = readString(tag_t::NAME, instanceLine); + std::string text = readString(Tag::NAME, instanceLine); if (instanceLine && text.empty()) parser.handle_error(TypeException{"$Instance_name_is_required"}); return text; @@ -687,7 +692,7 @@ int XMLReader::readNumber() return -1; } -std::string XMLReader::readString(tag_t tag, bool instanceLine) +std::string XMLReader::readString(Tag tag, bool instanceLine) { if (begin(tag)) { read(); @@ -696,14 +701,14 @@ std::string XMLReader::readString(tag_t tag, bool instanceLine) return ""; } -std::string XMLReader::type() { return readString(tag_t::TYPE); } +std::string XMLReader::type() { return readString(Tag::TYPE); } -std::string XMLReader::mode() { return readString(tag_t::MODE); } +std::string XMLReader::mode() { return readString(Tag::MODE); } int XMLReader::lscLocation() { int n = -1; - if (begin(tag_t::LSCLOCATION)) { + if (begin(Tag::LSCLOCATION)) { n = readNumber(); } if (n == -1) @@ -713,7 +718,7 @@ int XMLReader::lscLocation() bool XMLReader::committed() { - if (begin(tag_t::COMMITTED, false)) { + if (begin(Tag::COMMITTED, false)) { read(); return true; } @@ -722,7 +727,7 @@ bool XMLReader::committed() bool XMLReader::urgent() { - if (begin(tag_t::URGENT, false)) { + if (begin(Tag::URGENT, false)) { read(); return true; } @@ -734,9 +739,9 @@ bool XMLReader::location() bool l_invariant = false; bool l_exponentialRate = false; - if (begin(tag_t::LOCATION, false)) { + if (begin(Tag::LOCATION, false)) { try { - std::string l_path = path.str(tag_t::LOCATION); + std::string l_path = path.str(Tag::LOCATION); /* Extract ID attribute. */ auto l_id = getAttributeStr("id"); if (is_blank(l_id)) @@ -745,7 +750,7 @@ bool XMLReader::location() /* Get name of the location. */ std::string l_name = name(); /* Read the invariant. */ - while (begin(tag_t::LABEL)) { + while (begin(Tag::LABEL)) { int res = invariant(); l_invariant |= res == 0; l_exponentialRate |= res == 1; @@ -786,9 +791,9 @@ bool XMLReader::location() /** Parse optional instance. */ bool XMLReader::instance() { - if (begin(tag_t::INSTANCE, false)) { + if (begin(Tag::INSTANCE, false)) { try { - auto i_path = path.str(tag_t::INSTANCE); + auto i_path = path.str(Tag::INSTANCE); /* Extract ID attribute. */ auto i_id = getAttributeStr("id"); read(); @@ -813,7 +818,7 @@ bool XMLReader::instance() tracker.increment(&parser, 1); /* Push instance to parser builder. */ parser.proc_instance_line(); - parse((xmlChar*)i_name.c_str(), S_INSTANCE_LINE); + parse((xmlChar*)i_name.c_str(), XTAPart::INSTANCE_LINE); } catch (TypeException& e) { parser.handle_error(e); } @@ -825,7 +830,7 @@ bool XMLReader::instance() /** Parse optional yloccoord */ bool XMLReader::yloccoord() { - if (begin(tag_t::YLOCCOORD, false)) { + if (begin(Tag::YLOCCOORD, false)) { read(); // used only for the GUI return true; } @@ -834,7 +839,7 @@ bool XMLReader::yloccoord() std::string XMLReader::temperature() { - if (begin(tag_t::TEMPERATURE, false)) { + if (begin(Tag::TEMPERATURE, false)) { read(); /* Get the temperature of the condition */ return readText(); @@ -844,9 +849,9 @@ std::string XMLReader::temperature() bool XMLReader::prechart() { - if (begin(tag_t::PRECHART, false)) { + if (begin(Tag::PRECHART, false)) { try { - std::string p_path = path.str(tag_t::PRECHART); + std::string p_path = path.str(Tag::PRECHART); /* Get the bottom location number */ read(); bottomPrechart = lscLocation(); @@ -860,19 +865,18 @@ bool XMLReader::prechart() parser.handle_error(e); } return true; - } else { - bottomPrechart = -1; - parser.prechart_set(false); } + bottomPrechart = -1; + parser.prechart_set(false); return false; } bool XMLReader::message() { - if (begin(tag_t::MESSAGE)) { + if (begin(Tag::MESSAGE)) { /* Add dummy position mapping to the message element. */ try { - std::string m_path = path.str(tag_t::MESSAGE); + std::string m_path = path.str(Tag::MESSAGE); read(); std::string from = source(); std::string to = target(); @@ -894,9 +898,9 @@ bool XMLReader::message() bool XMLReader::condition() { - if (begin(tag_t::CONDITION)) { + if (begin(Tag::CONDITION)) { try { - std::string c_path = path.str(tag_t::CONDITION); + std::string c_path = path.str(Tag::CONDITION); read(); std::vector instance_anchors = anchors(); @@ -920,9 +924,9 @@ bool XMLReader::condition() bool XMLReader::update() { - if (begin(tag_t::UPDATE)) { + if (begin(Tag::UPDATE)) { try { - std::string u_path = path.str(tag_t::UPDATE); + std::string u_path = path.str(Tag::UPDATE); // location = atoi((char*)xmlTextReaderGetAttribute(reader, (const xmlChar*)"y")); // pch = (location < bottomPrechart); read(); @@ -944,9 +948,9 @@ bool XMLReader::update() bool XMLReader::branchpoint() { - if (begin(tag_t::BRANCHPOINT, false)) { + if (begin(Tag::BRANCHPOINT, false)) { try { - std::string b_path = path.str(tag_t::BRANCHPOINT); + std::string b_path = path.str(Tag::BRANCHPOINT); auto b_id = getAttributeStr("id"); if (is_blank(b_id)) { throw TypeException{"Branchpoint must have a unique \"id\" attribute"}; @@ -977,7 +981,7 @@ bool XMLReader::branchpoint() bool XMLReader::init() { - if (begin(tag_t::INIT, false)) { + if (begin(Tag::INIT, false)) { /* Get reference attribute. */ char* ref = getAttribute("ref"); /* Find location name for the reference. */ @@ -994,9 +998,8 @@ bool XMLReader::init() xmlFree(ref); read(); return true; - } else { - parser.handle_error(TypeException{"$Missing_initial_location"}); } + parser.handle_error(TypeException{"$Missing_initial_location"}); return false; } @@ -1011,29 +1014,29 @@ std::string XMLReader::reference(const std::string& attributeName) std::string XMLReader::source() { - if (begin(tag_t::SOURCE, false)) + if (begin(Tag::SOURCE, false)) return reference("ref"); throw TypeException{"Missing source element"}; } std::string XMLReader::target() { - if (begin(tag_t::TARGET, false)) + if (begin(Tag::TARGET, false)) return reference("ref"); throw TypeException{"Missing target element"}; } std::string XMLReader::anchor() { - if (begin(tag_t::ANCHOR, false)) + if (begin(Tag::ANCHOR, false)) return reference("instanceid"); throw TypeException{"Missing anchor element"}; } std::vector XMLReader::anchors() { - std::vector res; - while (begin(tag_t::ANCHOR, false)) + auto res = std::vector{}; + while (begin(Tag::ANCHOR, false)) res.push_back(reference("instanceid")); if (res.empty()) throw TypeException{"Missing anchor element"}; @@ -1042,7 +1045,7 @@ std::vector XMLReader::anchors() bool XMLReader::transition() { - if (begin(tag_t::TRANSITION)) { + if (begin(Tag::TRANSITION)) { /* Add dummy position mapping to the transition element. */ try { char* type = getAttribute("controllable"); @@ -1060,7 +1063,7 @@ bool XMLReader::transition() parser.proc_edge_begin(from.c_str(), to.c_str(), control, actname.c_str()); while (label()) ; - while (begin(tag_t::NAIL)) + while (begin(Tag::NAIL)) read(); parser.proc_edge_end(from.c_str(), to.c_str()); } catch (TypeException& e) { @@ -1074,10 +1077,10 @@ bool XMLReader::transition() int XMLReader::parameter() { int count = 0; - if (begin(tag_t::PARAMETER)) { + if (begin(Tag::PARAMETER)) { read(); if (getNodeType() == XML_READER_TYPE_TEXT) { - count = parse(xmlTextReaderConstValue(reader.get()), S_PARAMETERS); + count = parse(xmlTextReaderConstValue(reader.get()), XTAPart::PARAMETERS); } } return count; @@ -1085,8 +1088,8 @@ int XMLReader::parameter() bool XMLReader::templ() { - if (begin(tag_t::TEMPLATE)) { - auto t_path = std::make_shared(path.str(tag_t::TEMPLATE)); + if (begin(Tag::TEMPLATE)) { + auto t_path = std::make_shared(path.str(Tag::TEMPLATE)); read(); try { /* Get the name and the parameters of the template. */ @@ -1127,8 +1130,8 @@ bool XMLReader::templ() bool XMLReader::lscTempl() { - if (begin(tag_t::LSC)) { - std::string t_path = path.str(tag_t::LSC); + if (begin(Tag::LSC)) { + std::string t_path = path.str(Tag::LSC); read(); try { /* Get the name and the parameters of the template. */ @@ -1172,12 +1175,12 @@ bool XMLReader::lscTempl() bool XMLReader::instantiation() { - if (begin(tag_t::INSTANTIATION, false)) { + if (begin(Tag::INSTANTIATION, false)) { const auto* text = (const xmlChar*)""; read(); if (getNodeType() == XML_READER_TYPE_TEXT) text = xmlTextReaderConstValue(reader.get()); - parse(text, S_INST); + parse(text, XTAPart::INST); return true; } return false; @@ -1185,7 +1188,7 @@ bool XMLReader::instantiation() void XMLReader::system() { - if (begin(tag_t::SYSTEM, false)) { + if (begin(Tag::SYSTEM, false)) { const auto* text = (const xmlChar*)""; read(); auto nodeType = getNodeType(); @@ -1195,16 +1198,16 @@ void XMLReader::system() // bison doesn't manage to properly set the position of errors, // leading to nonsense error placements. if (nodeType == XML_READER_TYPE_END_ELEMENT || is_blank(text)) { - tracker.setPath(&parser, path.str(tag_t::SYSTEM)); + tracker.setPath(&parser, path.str(Tag::SYSTEM)); tracker.increment(&parser, 1); parser.handle_error(TypeException{"$syntax_error: $unexpected $end"}); - close(tag_t::SYSTEM); + close(Tag::SYSTEM); return; } - parse(text, S_SYSTEM); - close(tag_t::SYSTEM); + parse(text, XTAPart::SYSTEM); + close(Tag::SYSTEM); } else { - std::string s = (nta) ? path.str(tag_t::NTA) : path.str(tag_t::PROJECT); + std::string s = (nta) ? path.str(Tag::NTA) : path.str(Tag::PROJECT); tracker.setPath(&parser, s); tracker.increment(&parser, 1); parser.handle_error(TypeException{"$Missing_system_tag"}); @@ -1213,28 +1216,28 @@ void XMLReader::system() bool XMLReader::queries() { - if (begin(tag_t::QUERIES, false)) { + if (begin(Tag::QUERIES, false)) { read(); - zero_or_one(tag_t::QUERIES, [this] { return model_options(); }); - zero_or_more(tag_t::QUERIES, [this] { return query(); }); - close(tag_t::QUERIES); + zero_or_one(Tag::QUERIES, [this] { return model_options(); }); + zero_or_more(Tag::QUERIES, [this] { return query(); }); + close(Tag::QUERIES); return true; } return false; } bool XMLReader::query() { - if (begin(tag_t::QUERY, false)) { + if (begin(Tag::QUERY, false)) { if (!isEmpty()) { read(); parser.query_begin(); - zero_or_one(tag_t::QUERY, [this] { return formula(); }); - zero_or_one(tag_t::QUERY, [this] { return comment(); }); - zero_or_more(tag_t::QUERY, [this] { return option(); }); - zero_or_one(tag_t::QUERY, [this] { return expectation(); }); - zero_or_more(tag_t::QUERY, [this] { return result(); }); + zero_or_one(Tag::QUERY, [this] { return formula(); }); + zero_or_one(Tag::QUERY, [this] { return comment(); }); + zero_or_more(Tag::QUERY, [this] { return option(); }); + zero_or_one(Tag::QUERY, [this] { return expectation(); }); + zero_or_more(Tag::QUERY, [this] { return result(); }); parser.query_end(); - close(tag_t::QUERY); + close(Tag::QUERY); } else read(); // look ahead next tag return true; @@ -1243,13 +1246,13 @@ bool XMLReader::query() } bool XMLReader::formula() { - if (begin(tag_t::FORMULA, false)) { + if (begin(Tag::FORMULA, false)) { if (!isEmpty()) { read(); const auto* text = xmlTextReaderConstValue(reader.get()); if (text != nullptr) - parser.query_formula((const char*)text, path.str(tag_t::FORMULA)); - close(tag_t::FORMULA); + parser.query_formula((const char*)text, path.str(Tag::FORMULA)); + close(Tag::FORMULA); } else read(); return true; @@ -1258,13 +1261,13 @@ bool XMLReader::formula() } bool XMLReader::comment() { - if (begin(tag_t::COMMENT, false)) { + if (begin(Tag::COMMENT, false)) { if (!isEmpty()) { read(); const auto* text = xmlTextReaderConstValue(reader.get()); if (text != nullptr) parser.query_comment((const char*)text); - close(tag_t::COMMENT); + close(Tag::COMMENT); } else read(); return true; @@ -1274,13 +1277,13 @@ bool XMLReader::comment() bool XMLReader::option() { - if (begin(tag_t::OPTION, false)) { + if (begin(Tag::OPTION, false)) { char* key = getAttribute("key"); char* value = getAttribute("value"); parser.query_options(key, value); xmlFree(key); xmlFree(value); - close(tag_t::OPTION); + close(Tag::OPTION); return true; } return false; @@ -1288,26 +1291,30 @@ bool XMLReader::option() bool XMLReader::expectation() { - if (begin(tag_t::EXPECT, false)) { + if (begin(Tag::EXPECT, false)) { if (!isEmpty()) { parser.expectation_begin(); char* outcome = getAttribute("outcome"); char* type = getAttribute("type"); char* value = getAttribute("value"); parser.expectation_value(outcome, type, value); - zero_or_more(tag_t::EXPECT, [this] { - if (begin(tag_t::RESOURCE, false)) { + xmlFree(outcome); + xmlFree(type); + xmlFree(value); + read(); + zero_or_more(Tag::EXPECT, [this] { + if (begin(Tag::RESOURCE, false)) { auto type = getAttributeStr("type"); auto value = getAttributeStr("value"); auto unit = getAttributeStr("unit"); parser.expect_resource(type.c_str(), value.c_str(), unit.c_str()); - close(tag_t::RESOURCE); + close(Tag::RESOURCE); return true; } return false; }); parser.expectation_end(); - close(tag_t::EXPECT); + close(Tag::EXPECT); } else read(); return true; @@ -1316,8 +1323,8 @@ bool XMLReader::expectation() } bool XMLReader::result() { - if (begin(tag_t::RESULT, false)) { - close(tag_t::RESULT); + if (begin(Tag::RESULT, false)) { + close(Tag::RESULT); return true; } return false; @@ -1325,11 +1332,11 @@ bool XMLReader::result() void XMLReader::project() { - if (!begin(tag_t::NTA) && !begin(tag_t::PROJECT)) + if (!begin(Tag::NTA) && !begin(Tag::PROJECT)) throw TypeException{"$Missing_nta_or_project_tag"}; - nta = begin(tag_t::NTA); // "nta" or "project"? + nta = begin(Tag::NTA); // "nta" or "project"? if (newxta) - parse((const xmlChar*)utap_builtin_declarations(), S_DECLARATION); + parse((const xmlChar*)utap_builtin_declarations(), XTAPart::DECLARATION); read(); declaration(); while (templ()) @@ -1338,25 +1345,23 @@ void XMLReader::project() ; instantiation(); system(); - if ((nta && !end(tag_t::NTA)) || (!nta && !end(tag_t::PROJECT))) + if ((nta && !end(Tag::NTA)) || (!nta && !end(Tag::PROJECT))) queries(); parser.done(); } bool XMLReader::model_options() { - while (begin(tag_t::OPTION)) { - read(); + while (begin(Tag::OPTION, false)) { char* key = getAttribute("key"); char* value = getAttribute("value"); parser.model_option(key, value); - close(tag_t::OPTION); + xmlFree(key); + xmlFree(value); + close(Tag::OPTION); } return true; } -} // namespace UTAP - -using namespace UTAP; int32_t parse_XML_fd(int fd, ParserBuilder& pb, bool newxta) { @@ -1442,3 +1447,5 @@ static std::string getXMLElement(const char *xmlBuffer, const std::string &path) } } */ + +} // namespace UTAP diff --git a/src/xmlwriter.cpp b/src/xmlwriter.cpp index dad63b65..69e065fa 100644 --- a/src/xmlwriter.cpp +++ b/src/xmlwriter.cpp @@ -29,7 +29,6 @@ #include // strlen namespace UTAP { -using namespace Constants; static constexpr auto MY_ENCODING = "utf-8"; // xml encoding static constexpr auto ERR_STATE_COLOR = "#ff6666"; // pink @@ -197,10 +196,10 @@ void XMLWriter::location(const Location& loc) label("exponentialrate", loc.exp_rate.str(), x, y); } // "committed" or "urgent" element - if (loc.uid.get_type().is(COMMITTED)) { + if (loc.uid.get_type().is(Kind::COMMITTED)) { startElement("committed"); endElement(); - } else if (loc.uid.get_type().is(URGENT)) { + } else if (loc.uid.get_type().is(Kind::URGENT)) { startElement("urgent"); endElement(); } @@ -427,17 +426,16 @@ xmlChar* ConvertInput(const char* in, const char* encoding) return out; } -} // namespace UTAP - -int32_t write_XML_file(const char* filename, UTAP::Document& doc) +int32_t write_XML_file(const char* filename, Document& doc) { /* Create a new XmlWriter for filename, with no compression. */ auto* writer = xmlNewTextWriterFilename(filename, 0); if (writer == nullptr) { - throw UTAP::XMLWriterError{"construction"}; + throw XMLWriterError{"construction"}; } - UTAP::XMLWriter(writer, doc).project(); - + XMLWriter{writer, doc}.project(); // xmlFreeTextWriter(writer); return 0; } + +} // namespace UTAP diff --git a/test/AbstractBuilder_test.cpp b/test/AbstractBuilder_test.cpp new file mode 100644 index 00000000..814fa55d --- /dev/null +++ b/test/AbstractBuilder_test.cpp @@ -0,0 +1,331 @@ +// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- + +/* libutap - Uppaal Timed Automata Parser. + Copyright (C) 2026 Aalborg University. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA +*/ + +#include "utap/AbstractBuilder.hpp" + +#include + +#include +#include + +using namespace UTAP; + +namespace { +/// Concrete builder implementing only the members that AbstractBuilder itself +/// leaves pure virtual (inherited straight from ParserBuilder), so that every +/// other method exercises AbstractBuilder's own "not supported" default. +struct MinimalBuilder : AbstractBuilder +{ + void add_position(uint32_t, uint32_t, uint32_t, std::shared_ptr) override {} + void handle_error(const TypeException&) override {} + void handle_warning(const TypeException&) override {} +}; +} // namespace + +TEST_SUITE_BEGIN("AbstractBuilder"); + +TEST_CASE("Default query and no-op methods") +{ + auto b = MinimalBuilder{}; + CHECK_NOTHROW(b.set_position(0, 1)); + CHECK_FALSE(b.is_type("int")); + CHECK_FALSE(b.is_type("")); + CHECK_NOTHROW(b.done()); + CHECK_NOTHROW(b.handle_expect("anything")); +} + +TEST_CASE("Exception carries the throwing function's name") +{ + auto b = MinimalBuilder{}; + try { + b.type_duplicate(); + FAIL("expected NotSupportedException"); + } catch (const NotSupportedException& e) { + CHECK(std::string{e.what()}.find("type_duplicate") != std::string::npos); + } +} + +TEST_CASE("Types") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.type_duplicate(), NotSupportedException); + CHECK_THROWS_AS(b.type_pop(), NotSupportedException); + CHECK_THROWS_AS(b.type_bool(TypePrefix::NONE), NotSupportedException); + CHECK_THROWS_AS(b.type_int(TypePrefix::NONE), NotSupportedException); + CHECK_THROWS_AS(b.type_string(TypePrefix::NONE), NotSupportedException); + CHECK_THROWS_AS(b.type_double(TypePrefix::NONE), NotSupportedException); + CHECK_THROWS_AS(b.type_bounded_int(TypePrefix::NONE), NotSupportedException); + CHECK_THROWS_AS(b.type_channel(TypePrefix::NONE), NotSupportedException); + CHECK_THROWS_AS(b.type_clock(TypePrefix::NONE), NotSupportedException); + CHECK_THROWS_AS(b.type_void(), NotSupportedException); + CHECK_THROWS_AS(b.type_scalar(TypePrefix::NONE), NotSupportedException); + CHECK_THROWS_AS(b.type_name(TypePrefix::NONE, "T"), NotSupportedException); + CHECK_THROWS_AS(b.type_struct(TypePrefix::NONE, 0u), NotSupportedException); + CHECK_THROWS_AS(b.type_array_of_size(0u), NotSupportedException); + CHECK_THROWS_AS(b.type_array_of_type(0u), NotSupportedException); + CHECK_THROWS_AS(b.struct_field("f"), NotSupportedException); + CHECK_THROWS_AS(b.decl_typedef("T"), NotSupportedException); +} + +TEST_CASE("Variable declarations") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.decl_var("x", false), NotSupportedException); + CHECK_THROWS_AS(b.decl_init_list(0u), NotSupportedException); + CHECK_THROWS_AS(b.decl_field_init("f"), NotSupportedException); +} + +TEST_CASE("Gantt chart declarations") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.gantt_decl_begin("g"), NotSupportedException); + CHECK_THROWS_AS(b.gantt_decl_select("id"), NotSupportedException); + CHECK_THROWS_AS(b.gantt_decl_end(), NotSupportedException); + CHECK_THROWS_AS(b.gantt_entry_begin(), NotSupportedException); + CHECK_THROWS_AS(b.gantt_entry_select("id"), NotSupportedException); + CHECK_THROWS_AS(b.gantt_entry_end(), NotSupportedException); +} + +TEST_CASE("Progress measure declarations") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.decl_progress(false), NotSupportedException); +} + +TEST_CASE("Function declarations") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.decl_parameter("p", false), NotSupportedException); + CHECK_THROWS_AS(b.decl_func_begin("f"), NotSupportedException); + CHECK_THROWS_AS(b.decl_func_end(), NotSupportedException); + CHECK_THROWS_AS(b.dynamic_load_lib("lib"), NotSupportedException); + CHECK_THROWS_AS(b.decl_external_func("f", "a"), NotSupportedException); +} + +TEST_CASE("Process declarations") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.proc_begin("P", true, "", ""), NotSupportedException); + CHECK_THROWS_AS(b.proc_end(), NotSupportedException); + CHECK_THROWS_AS(b.proc_location("L", false, false), NotSupportedException); + CHECK_THROWS_AS(b.proc_location_commit("L"), NotSupportedException); + CHECK_THROWS_AS(b.proc_location_urgent("L"), NotSupportedException); + CHECK_THROWS_AS(b.proc_location_init("L"), NotSupportedException); + CHECK_THROWS_AS(b.proc_branchpoint("B"), NotSupportedException); + CHECK_THROWS_AS(b.proc_edge_begin("L1", "L2", true, ""), NotSupportedException); + CHECK_THROWS_AS(b.proc_edge_end("L1", "L2"), NotSupportedException); + CHECK_THROWS_AS(b.proc_select("id"), NotSupportedException); + CHECK_THROWS_AS(b.proc_guard(), NotSupportedException); + CHECK_THROWS_AS(b.proc_sync(Sync::QUE), NotSupportedException); + CHECK_THROWS_AS(b.proc_update(), NotSupportedException); + CHECK_THROWS_AS(b.proc_prob(), NotSupportedException); +} + +TEST_CASE("Process declarations for LSC") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.proc_instance_line(), NotSupportedException); + CHECK_THROWS_AS(b.instance_name("I", true), NotSupportedException); + CHECK_THROWS_AS(b.instance_name_begin("I"), NotSupportedException); + CHECK_THROWS_AS(b.instance_name_end("I", 0u), NotSupportedException); + CHECK_THROWS_AS(b.proc_message("A", "B", 0, false), NotSupportedException); + CHECK_THROWS_AS(b.proc_message(Sync::QUE), NotSupportedException); + CHECK_THROWS_AS(b.proc_condition(std::vector{}, 0, false, false), NotSupportedException); + CHECK_THROWS_AS(b.proc_condition(), NotSupportedException); + CHECK_THROWS_AS(b.proc_LSC_update("a", 0, false), NotSupportedException); + CHECK_THROWS_AS(b.proc_LSC_update(), NotSupportedException); + CHECK_THROWS_AS(b.prechart_set(false), NotSupportedException); +} + +TEST_CASE("Statements") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.block_begin(), NotSupportedException); + CHECK_THROWS_AS(b.block_end(), NotSupportedException); + CHECK_THROWS_AS(b.empty_statement(), NotSupportedException); + CHECK_THROWS_AS(b.for_begin(), NotSupportedException); + CHECK_THROWS_AS(b.for_end(), NotSupportedException); + CHECK_THROWS_AS(b.iteration_begin("i"), NotSupportedException); + CHECK_THROWS_AS(b.iteration_end("i"), NotSupportedException); + CHECK_THROWS_AS(b.while_begin(), NotSupportedException); + CHECK_THROWS_AS(b.while_end(), NotSupportedException); + CHECK_THROWS_AS(b.do_while_begin(), NotSupportedException); + CHECK_THROWS_AS(b.do_while_end(), NotSupportedException); + CHECK_THROWS_AS(b.if_begin(), NotSupportedException); + CHECK_THROWS_AS(b.if_condition(), NotSupportedException); + CHECK_THROWS_AS(b.if_then(), NotSupportedException); + CHECK_THROWS_AS(b.if_end(false), NotSupportedException); + CHECK_THROWS_AS(b.break_statement(), NotSupportedException); + CHECK_THROWS_AS(b.continue_statement(), NotSupportedException); + CHECK_THROWS_AS(b.switch_begin(), NotSupportedException); + CHECK_THROWS_AS(b.switch_end(), NotSupportedException); + CHECK_THROWS_AS(b.case_begin(), NotSupportedException); + CHECK_THROWS_AS(b.case_end(), NotSupportedException); + CHECK_THROWS_AS(b.default_begin(), NotSupportedException); + CHECK_THROWS_AS(b.default_end(), NotSupportedException); + CHECK_THROWS_AS(b.expr_statement(), NotSupportedException); + CHECK_THROWS_AS(b.return_statement(false), NotSupportedException); + CHECK_THROWS_AS(b.assert_statement(), NotSupportedException); +} + +TEST_CASE("Expressions") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.expr_true(), NotSupportedException); + CHECK_THROWS_AS(b.expr_false(), NotSupportedException); + CHECK_THROWS_AS(b.expr_double(0.0), NotSupportedException); + CHECK_THROWS_AS(b.expr_string("s"), NotSupportedException); + CHECK_THROWS_AS(b.expr_location(), NotSupportedException); + CHECK_THROWS_AS(b.expr_identifier("x"), NotSupportedException); + CHECK_THROWS_AS(b.expr_nat(0), NotSupportedException); + CHECK_THROWS_AS(b.expr_call_begin(), NotSupportedException); + CHECK_THROWS_AS(b.expr_call_end(0u), NotSupportedException); + CHECK_THROWS_AS(b.expr_array(), NotSupportedException); + CHECK_THROWS_AS(b.expr_post_increment(), NotSupportedException); + CHECK_THROWS_AS(b.expr_pre_increment(), NotSupportedException); + CHECK_THROWS_AS(b.expr_post_decrement(), NotSupportedException); + CHECK_THROWS_AS(b.expr_pre_decrement(), NotSupportedException); + CHECK_THROWS_AS(b.expr_assignment(Kind::ASSIGN), NotSupportedException); + CHECK_THROWS_AS(b.expr_unary(Kind::NOT), NotSupportedException); + CHECK_THROWS_AS(b.expr_binary(Kind::PLUS), NotSupportedException); + CHECK_THROWS_AS(b.expr_nary(Kind::LIST, 0u), NotSupportedException); + CHECK_THROWS_AS(b.expr_scenario("S"), NotSupportedException); + CHECK_THROWS_AS(b.expr_ternary(Kind::INLINE_IF, false), NotSupportedException); + CHECK_THROWS_AS(b.expr_inline_if(), NotSupportedException); + CHECK_THROWS_AS(b.expr_comma(), NotSupportedException); + CHECK_THROWS_AS(b.expr_dot("f"), NotSupportedException); + CHECK_THROWS_AS(b.expr_deadlock(), NotSupportedException); + CHECK_THROWS_AS(b.expr_forall_begin("i"), NotSupportedException); + CHECK_THROWS_AS(b.expr_forall_end("i"), NotSupportedException); + CHECK_THROWS_AS(b.expr_exists_begin("i"), NotSupportedException); + CHECK_THROWS_AS(b.expr_exists_end("i"), NotSupportedException); + CHECK_THROWS_AS(b.expr_sum_begin("i"), NotSupportedException); + CHECK_THROWS_AS(b.expr_sum_end("i"), NotSupportedException); +} + +TEST_CASE("SMC and learning extensions") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.expr_proba_qualitative(Kind::PROBA_BOX, Kind::LE, 0.5), NotSupportedException); + CHECK_THROWS_AS(b.expr_proba_quantitative(Kind::PROBA_CMP), NotSupportedException); + CHECK_THROWS_AS(b.expr_proba_compare(Kind::PROBA_BOX, Kind::PROBA_DIAMOND), NotSupportedException); + CHECK_THROWS_AS(b.expr_proba_expected("x"), NotSupportedException); + CHECK_THROWS_AS(b.expr_simulate(1, false, 0), NotSupportedException); + CHECK_THROWS_AS(b.expr_builtin_function1(Kind::SQRT_F), NotSupportedException); + CHECK_THROWS_AS(b.expr_builtin_function2(Kind::POW_F), NotSupportedException); + CHECK_THROWS_AS(b.expr_builtin_function3(Kind::FMA_F), NotSupportedException); + CHECK_THROWS_AS(b.expr_optimize_exp(Kind::MIN_EXP, PriceType::TIME, Kind::LE), NotSupportedException); + CHECK_THROWS_AS(b.expr_load_strategy(), NotSupportedException); + CHECK_THROWS_AS(b.expr_save_strategy("strat"), NotSupportedException); +} + +TEST_CASE("MITL extensions") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.expr_MITL_formula(), NotSupportedException); + CHECK_THROWS_AS(b.expr_MITL_until(0, 1), NotSupportedException); + CHECK_THROWS_AS(b.expr_MITL_release(0, 1), NotSupportedException); + CHECK_THROWS_AS(b.expr_MITL_disj(), NotSupportedException); + CHECK_THROWS_AS(b.expr_MITL_conj(), NotSupportedException); + CHECK_THROWS_AS(b.expr_MITL_next(), NotSupportedException); + CHECK_THROWS_AS(b.expr_MITL_atom(), NotSupportedException); + CHECK_THROWS_AS(b.expr_MITL_diamond(0, 1), NotSupportedException); + CHECK_THROWS_AS(b.expr_MITL_box(0, 1), NotSupportedException); + CHECK_THROWS_AS(b.expr_optimize(0, 0, 0, 0), NotSupportedException); +} + +TEST_CASE("System declaration") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.instantiation_begin("P", 0u, "T"), NotSupportedException); + CHECK_THROWS_AS(b.instantiation_end("P", 0u, "T", 0u), NotSupportedException); + CHECK_THROWS_AS(b.process("P"), NotSupportedException); + CHECK_THROWS_AS(b.process_list_end(), NotSupportedException); +} + +TEST_CASE("Properties") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.property(), NotSupportedException); + CHECK_THROWS_AS(b.scenario("S"), NotSupportedException); + CHECK_THROWS_AS(b.parse(""), NotSupportedException); + CHECK_THROWS_AS(b.strategy_declaration("strat"), NotSupportedException); + CHECK_THROWS_AS(b.subjection("s"), NotSupportedException); + CHECK_THROWS_AS(b.imitation("s"), NotSupportedException); +} + +TEST_CASE("Guiding") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.before_update(), NotSupportedException); + CHECK_THROWS_AS(b.after_update(), NotSupportedException); +} + +TEST_CASE("Priority") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.chan_priority_begin(), NotSupportedException); + CHECK_THROWS_AS(b.chan_priority_add('<'), NotSupportedException); + CHECK_THROWS_AS(b.chan_priority_default(), NotSupportedException); + CHECK_THROWS_AS(b.proc_priority_inc(), NotSupportedException); + CHECK_THROWS_AS(b.proc_priority("P"), NotSupportedException); +} + +TEST_CASE("Dynamic templates") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.decl_dynamic_template("T"), NotSupportedException); + CHECK_THROWS_AS(b.expr_spawn(0), NotSupportedException); + CHECK_THROWS_AS(b.expr_exit(), NotSupportedException); + CHECK_THROWS_AS(b.expr_numof(), NotSupportedException); + CHECK_THROWS_AS(b.expr_forall_dynamic_begin("i", "T"), NotSupportedException); + CHECK_THROWS_AS(b.expr_forall_dynamic_end("i"), NotSupportedException); + CHECK_THROWS_AS(b.expr_exists_dynamic_begin("i", "T"), NotSupportedException); + CHECK_THROWS_AS(b.expr_exists_dynamic_end("i"), NotSupportedException); + CHECK_THROWS_AS(b.expr_sum_dynamic_begin("i", "T"), NotSupportedException); + CHECK_THROWS_AS(b.expr_sum_dynamic_end("i"), NotSupportedException); + CHECK_THROWS_AS(b.expr_foreach_dynamic_begin("i", "T"), NotSupportedException); + CHECK_THROWS_AS(b.expr_foreach_dynamic_end("i"), NotSupportedException); + CHECK_THROWS_AS(b.expr_dynamic_process_expr("P"), NotSupportedException); + CHECK_THROWS_AS(b.expr_MITL_forall_dynamic_begin("i", "T"), NotSupportedException); + CHECK_THROWS_AS(b.expr_MITL_forall_dynamic_end("i"), NotSupportedException); + CHECK_THROWS_AS(b.expr_MITL_exists_dynamic_begin("i", "T"), NotSupportedException); + CHECK_THROWS_AS(b.expr_MITL_exists_dynamic_end("i"), NotSupportedException); +} + +TEST_CASE("Verification queries") +{ + auto b = MinimalBuilder{}; + CHECK_THROWS_AS(b.model_option("k", "v"), NotSupportedException); + CHECK_THROWS_AS(b.query_begin(), NotSupportedException); + CHECK_THROWS_AS(b.query_formula("A[] true", ""), NotSupportedException); + CHECK_THROWS_AS(b.query_comment("c"), NotSupportedException); + CHECK_THROWS_AS(b.query_options("o", ""), NotSupportedException); + CHECK_THROWS_AS(b.expectation_begin(), NotSupportedException); + CHECK_THROWS_AS(b.expectation_end(), NotSupportedException); + CHECK_THROWS_AS(b.expectation_value("r", "t", "v"), NotSupportedException); + CHECK_THROWS_AS(b.expect_resource("t", "v", "u"), NotSupportedException); + CHECK_THROWS_AS(b.query_results_begin(), NotSupportedException); + CHECK_THROWS_AS(b.query_results_end(), NotSupportedException); + CHECK_THROWS_AS(b.query_end(), NotSupportedException); +} + +TEST_SUITE_END(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d10fe210..08b4851a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,71 +1,122 @@ -add_executable(pretty pretty.cpp) -target_link_libraries(pretty PRIVATE UTAP) - -add_executable(syntaxcheck syntaxcheck.cpp) -target_link_libraries(syntaxcheck PRIVATE UTAP) - -add_executable(featurecheck featurechecker.cpp) -target_link_libraries(featurecheck PRIVATE UTAP) - -if (UTAP_STATIC) - target_link_options(pretty PRIVATE -static) - target_link_options(syntaxcheck PRIVATE -static) - target_link_options(featurecheck PRIVATE -static) -endif (UTAP_STATIC) - -install(TARGETS pretty syntaxcheck featurecheck) - -if(UTAP_TESTS) - #target_compile_definitions(MODELS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/models") - add_executable(expression_test expression_test.cpp) - target_link_libraries(expression_test PRIVATE UTAP doctest::doctest_with_main) - add_test(NAME expression_test COMMAND expression_test) - - add_executable(statement_test statement_test.cpp) - target_link_libraries(statement_test PRIVATE UTAP doctest::doctest_with_main) - add_test(NAME statement_test COMMAND statement_test) - - add_library(external_fn SHARED external_fn.cpp) - target_compile_features(external_fn PUBLIC cxx_std_11) - - add_executable(parser_test parser_test.cpp) - target_compile_definitions(parser_test PRIVATE MODELS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/models") - target_link_libraries(parser_test PRIVATE UTAP doctest::doctest_with_main) - add_dependencies(parser_test external_fn) - add_test(NAME parser_test COMMAND parser_test) - - add_executable(featurechecker_test featurechecker_test.cpp) - target_compile_definitions(featurechecker_test PRIVATE MODELS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/models") - target_link_libraries(featurechecker_test PRIVATE UTAP doctest::doctest_with_main) - add_test(NAME featurechecker_test COMMAND featurechecker_test) - - add_executable(range_test range_test.cpp) - target_link_libraries(range_test PRIVATE UTAP doctest::doctest_with_main) - add_test(NAME range_test COMMAND range_test) - - add_executable(typechecker_test typechecker_test.cpp) - target_compile_definitions(typechecker_test PRIVATE MODELS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/models") - target_link_libraries(typechecker_test PRIVATE UTAP doctest::doctest_with_main) - add_test(NAME typechecker_test COMMAND typechecker_test) - - add_executable(prettyprint_test prettyprint_test.cpp) - target_compile_definitions(prettyprint_test PRIVATE MODELS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/models") - target_link_libraries(prettyprint_test PRIVATE UTAP doctest::doctest_with_main) - add_test(NAME prettyprint_test COMMAND prettyprint_test) - - add_executable(example_test example_test.cpp) - target_link_libraries(example_test PRIVATE UTAP) - add_test(NAME example_train_gate COMMAND example_test ${PROJECT_SOURCE_DIR}/examples/train-gate.xml ${PROJECT_SOURCE_DIR}/examples/train-gate-out.xml) - - if (UTAP_STATIC) - target_link_options(expression_test PRIVATE -static) - target_link_options(statement_test PRIVATE -static) - target_link_options(parser_test PRIVATE -static) - target_link_options(featurechecker_test PRIVATE -static) - target_link_options(range_test PRIVATE -static) - target_link_options(typechecker_test PRIVATE -static) - target_link_options(prettyprint_test PRIVATE -static) - target_link_options(example_test PRIVATE -static) - message(STATUS "Enabled Unit Tests -static") - endif (UTAP_STATIC) -endif(UTAP_TESTS) +set(MODELS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/models") +set(EXAMPLES_PATH "${PROJECT_SOURCE_DIR}/examples") + +add_executable(abstractbuilder_test AbstractBuilder_test.cpp) +target_link_libraries(abstractbuilder_test PRIVATE UTAP doctest_with_main) +add_test(NAME abstractbuilder_test COMMAND abstractbuilder_test) + +add_executable(expression_test expression_test.cpp) +target_compile_definitions(expression_test PRIVATE MODELS_DIR="${MODELS_PATH}") +target_link_libraries(expression_test PRIVATE UTAP doctest_with_main) +add_test(NAME expression_test COMMAND expression_test) + +add_executable(statement_test statement_test.cpp) +target_link_libraries(statement_test PRIVATE UTAP doctest_with_main) +add_test(NAME statement_test COMMAND statement_test) + +add_library(external_fn SHARED external_fn.cpp) +target_compile_features(external_fn PUBLIC cxx_std_11) + +add_executable(parser_test parser_test.cpp) +target_compile_definitions(parser_test PRIVATE MODELS_DIR="${MODELS_PATH}") +target_link_libraries(parser_test PRIVATE UTAP doctest_with_main) +add_dependencies(parser_test external_fn) +add_test(NAME parser_test COMMAND parser_test WORKING_DIRECTORY $) + +add_executable(featurechecker_test featurechecker_test.cpp) +target_compile_definitions(featurechecker_test PRIVATE MODELS_DIR="${MODELS_PATH}") +target_link_libraries(featurechecker_test PRIVATE UTAP + doctest_with_main) +add_test(NAME featurechecker_test COMMAND featurechecker_test) + +add_executable(range_test range_test.cpp) +target_link_libraries(range_test PRIVATE UTAP doctest_with_main) +add_test(NAME range_test COMMAND range_test) + +add_executable(typechecker_test typechecker_test.cpp) +target_compile_definitions( + typechecker_test PRIVATE MODELS_DIR="${MODELS_PATH}") +target_link_libraries(typechecker_test PRIVATE UTAP doctest_with_main) +add_test(NAME typechecker_test COMMAND typechecker_test) + +add_executable(prettyprint_test prettyprint_test.cpp) +target_compile_definitions( + prettyprint_test PRIVATE MODELS_DIR="${MODELS_PATH}") +target_link_libraries(prettyprint_test PRIVATE UTAP doctest_with_main) +add_test(NAME prettyprint_test COMMAND prettyprint_test) + +add_executable(prettyprinter_test PrettyPrinter_test.cpp) +target_compile_definitions( + prettyprinter_test PRIVATE MODELS_DIR="${MODELS_PATH}") +target_link_libraries(prettyprinter_test PRIVATE UTAP doctest_with_main) +add_test(NAME prettyprinter_test COMMAND prettyprinter_test) + +add_executable(typeexception_test typeexception_test.cpp) +target_link_libraries(typeexception_test PRIVATE UTAP doctest_with_main) +add_test(NAME typeexception_test COMMAND typeexception_test) + +add_executable(print_test print_test.cpp) +target_include_directories(print_test PRIVATE "${PROJECT_SOURCE_DIR}/src") +target_link_libraries(print_test PRIVATE UTAP doctest_with_main) +# print.hpp is header-only, so its templates are instantiated directly in +# this test binary rather than inside the already-instrumented UTAP library; +# it needs its own coverage instrumentation to be measured. +target_coverage(print_test) +add_test(NAME print_test COMMAND print_test) + +add_executable(property_test property_test.cpp) +target_compile_definitions(property_test PRIVATE MODELS_DIR="${MODELS_PATH}") +target_link_libraries(property_test PRIVATE UTAP doctest_with_main) +add_test(NAME property_test COMMAND property_test) + +add_executable(expressionbuilder_test ExpressionBuilder_test.cpp) +target_compile_definitions(expressionbuilder_test PRIVATE MODELS_DIR="${MODELS_PATH}") +target_link_libraries(expressionbuilder_test PRIVATE UTAP doctest_with_main) +add_test(NAME expressionbuilder_test COMMAND expressionbuilder_test) + +add_executable(document_test document_test.cpp) +target_compile_definitions(document_test PRIVATE MODELS_DIR="${MODELS_PATH}") +target_link_libraries(document_test PRIVATE UTAP doctest_with_main) +add_test(NAME document_test COMMAND document_test) + +add_executable(documentbuilder_test DocumentBuilder_test.cpp) +target_compile_definitions(documentbuilder_test PRIVATE MODELS_DIR="${MODELS_PATH}") +target_link_libraries(documentbuilder_test PRIVATE UTAP doctest_with_main) +add_test(NAME documentbuilder_test COMMAND documentbuilder_test) + +add_executable(position_test position_test.cpp) +target_link_libraries(position_test PRIVATE UTAP doctest_with_main) +add_test(NAME position_test COMMAND position_test) + +add_executable(xmlwriter_test xmlwriter_test.cpp) +target_compile_definitions(xmlwriter_test PRIVATE MODELS_DIR="${MODELS_PATH}") +target_link_libraries(xmlwriter_test PRIVATE UTAP doctest_with_main) +add_test(NAME xmlwriter_test COMMAND xmlwriter_test) + +add_executable(example_test example_test.cpp) +target_link_libraries(example_test PRIVATE UTAP) +add_test(NAME example_train_gate + COMMAND example_test "${EXAMPLES_PATH}/train-gate.xml" + "${EXAMPLES_PATH}/train-gate-out.xml") + +if(UTAP_STATIC) + target_link_options(abstractbuilder_test PRIVATE -static) + target_link_options(expression_test PRIVATE -static) + target_link_options(statement_test PRIVATE -static) + target_link_options(parser_test PRIVATE -static) + target_link_options(featurechecker_test PRIVATE -static) + target_link_options(range_test PRIVATE -static) + target_link_options(typechecker_test PRIVATE -static) + target_link_options(prettyprint_test PRIVATE -static) + target_link_options(prettyprinter_test PRIVATE -static) + target_link_options(typeexception_test PRIVATE -static) + target_link_options(print_test PRIVATE -static) + target_link_options(property_test PRIVATE -static) + target_link_options(expressionbuilder_test PRIVATE -static) + target_link_options(document_test PRIVATE -static) + target_link_options(documentbuilder_test PRIVATE -static) + target_link_options(position_test PRIVATE -static) + target_link_options(xmlwriter_test PRIVATE -static) + target_link_options(example_test PRIVATE -static) + message(STATUS "Enabled Unit Tests -static") +endif(UTAP_STATIC) diff --git a/test/DocumentBuilder_test.cpp b/test/DocumentBuilder_test.cpp new file mode 100644 index 00000000..9b86accc --- /dev/null +++ b/test/DocumentBuilder_test.cpp @@ -0,0 +1,219 @@ +// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- + +/* libutap - Uppaal Timed Automata Parser. + Copyright (C) 2026 Aalborg University. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA +*/ + +#include "document_fixture.h" + +#include "utap/DocumentBuilder.hpp" + +#include + +TEST_SUITE_BEGIN("DocumentBuilder"); + +using namespace UTAP; + +TEST_CASE("before_update/after_update declarations") +{ + auto doc = + document_fixture{} + .add_default_process() + .add_global_decl("bool b; before_update { b = true } after_update { b = false }") + .parse(); + const auto& errs = doc.get_errors(); + CHECK_MESSAGE(errs.empty(), errs.front().msg); +} + +TEST_CASE("gantt chart with a declaration-level select") +{ + // Exercises gantt_decl_select() via the "G(i:int[0,2])" select clause. + // The gantt block must follow `system ...;` per the grammar (System: + // SysDecl Progress GanttDecl), which document_fixture's + // add_system_decl() cannot express since it inserts text before that + // line -- build the document manually. + static constexpr auto xml = R"XML( + + + bool b; + + +Process = Template(); +system Process; +gantt { G(i:int[0,2]) : b -> b; } + + +)XML"; + auto doc = UTAP::Document{}; + parse_XML_buffer(xml, doc, true); + const auto& errs = doc.get_errors(); + CHECK_MESSAGE(errs.empty(), errs.front().msg); + CHECK(doc.get_globals().ganttChart.size() == 1); +} + +TEST_CASE("gantt chart entry with a for-select") +{ + // Exercises gantt_entry_select() via "for (j:int[0,2])". + static constexpr auto xml = R"XML( + + + bool b; + + +Process = Template(); +system Process; +gantt { H : for (j:int[0,2]) b -> b; } + + +)XML"; + auto doc = UTAP::Document{}; + parse_XML_buffer(xml, doc, true); + const auto& errs = doc.get_errors(); + CHECK_MESSAGE(errs.empty(), errs.front().msg); + CHECK(doc.get_globals().ganttChart.size() == 1); +} + +TEST_CASE("edge probability label") +{ + auto doc = document_fixture{} + .add_template(R"XML()XML") + .add_system_decl("Process = T();") + .add_process("Process") + .parse(); + const auto& errs = doc.get_errors(); + CHECK_MESSAGE(errs.empty(), errs.front().msg); +} + +TEST_CASE("queries-level option registers a model option") +{ + // Regression test: model_options() used to call begin(Tag::OPTION) with + // the default skipEmpty=true, which silently skips self-closing + //