diff --git a/.github/workflows/api-stability.yml b/.github/workflows/api-stability.yml index c577e49..a58ae17 100644 --- a/.github/workflows/api-stability.yml +++ b/.github/workflows/api-stability.yml @@ -5,20 +5,39 @@ on: jobs: build_linux: - strategy: - matrix: - os: [ubuntu-latest, ubuntu-22.04, ubuntu-20.04, macos-latest] - swift: ["5.9", "5.8", "5.7"] - name: Check Swift ${{ matrix.swift }} API Stability on ${{ matrix.os }} - runs-on: ${{ matrix.os }} + name: Check Swift API Stability on Linux. + runs-on: ubuntu-latest steps: - - if: ${{ runner.os == 'Linux' }} + - name: Install Swift uses: slashmo/install-swift@v0.4.0 with: - version: ${{ matrix.swift }} - - - if: ${{ runner.os == 'macOS' }} + version: "5.10" + + - name: Setup SSH Key + run: | + rm -rf ~/.ssh + mkdir -m 0700 ~/.ssh + echo "${{ secrets.WORKFLOWS_SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519 + echo "${{ secrets.WORKFLOWS_SSH_PUBLIC_KEY }}" > ~/.ssh/id_ed25519.pub + chmod 0600 ~/.ssh/id_ed25519 + eval "$(ssh-agent -s)" + ssh-add ~/.ssh/id_ed25519 + + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Check API Stability + run: swift package diagnose-api-breaking-changes `git tag | sort --version-sort | tail -n1` + + build_macos: + name: Check Swift API Stability on MacOs. + runs-on: macos-latest + steps: + - name: Install Xcode uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: latest @@ -44,3 +63,35 @@ jobs: - name: Check API Stability run: swift package diagnose-api-breaking-changes `git tag | sort --version-sort | tail -n1` + + build_windows: + name: Check Swift API Stability on Windows. + runs-on: windows-latest + steps: + - name: Setup Swift + uses: compnerd/gha-setup-swift@main + with: + branch: swift-5.9.2-release + tag: 5.9.2-RELEASE + + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Setup SSH Key + uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: ${{ secrets.WORKFLOWS_SSH_PRIVATE_KEY }} + + - name: Disable NTFS protection + run: git config --global core.protectNTFS false + + - name: Clone dependencies + run: swift package update + + - name: Check API Stability + shell: bash + run: swift package diagnose-api-breaking-changes `git tag | sort --version-sort | tail -n1` + diff --git a/Sources/TCTLParser/GloballyQuantifiedExpression.swift b/Sources/TCTLParser/GloballyQuantifiedExpression.swift index deb6655..78054db 100644 --- a/Sources/TCTLParser/GloballyQuantifiedExpression.swift +++ b/Sources/TCTLParser/GloballyQuantifiedExpression.swift @@ -106,14 +106,14 @@ public indirect enum GloballyQuantifiedExpression: RawRepresentable, Equatable, else { return nil } - if case .some(let expr) = expression.expression, case .quantified = expr { - // Nested quantified expressions are invalid syntax. - return nil - } - if case .some(let expr) = expression.lhs, case .quantified = expr { - // Nested quantified expressions are invalid syntax. - return nil - } + // if case .some(let expr) = expression.expression, case .quantified = expr { + // // Nested quantified expressions are invalid syntax. + // return nil + // } + // if case .some(let expr) = expression.lhs, case .quantified = expr { + // // Nested quantified expressions are invalid syntax. + // return nil + // } self.init(quantifier: firstChar, expression: expression) } diff --git a/Tests/TCTLParserTests/ExpressionSubExpressionTests.swift b/Tests/TCTLParserTests/ExpressionSubExpressionTests.swift new file mode 100644 index 0000000..82ab705 --- /dev/null +++ b/Tests/TCTLParserTests/ExpressionSubExpressionTests.swift @@ -0,0 +1,110 @@ +// ExpressionSubExpressionTests.swift +// TCTLParser +// +// Created by Morgan McColl. +// Copyright © 2024 Morgan McColl. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// 3. All advertising materials mentioning features or use of this +// software must display the following acknowledgement: +// +// This product includes software developed by Morgan McColl. +// +// 4. Neither the name of the author nor the names of contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or +// modify it under the above terms or under the terms of the GNU +// General Public License as published by the Free Software Foundation; +// either version 2 of the License, or (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see http://www.gnu.org/licenses/ +// or write to the Free Software Foundation, Inc., 51 Franklin Street, +// Fifth Floor, Boston, MA 02110-1301, USA. + +@testable import TCTLParser +import VHDLParsing +import XCTest + +/// Test class for sub-expressions within an expression. +final class ExpressionSubExpressionTests: XCTestCase { + + /// Test sub-quantified expressions are parsed correctly. + func testSubExpression() { + guard + let operationalMode = VariableName(rawValue: "operationalMode"), + let bootMode = VariableName(rawValue: "bootMode") + else { + XCTFail("Incorrect variables names!") + return + } + let expected = Expression.quantified(expression: .always(expression: .next(expression: .quantified( + expression: .always(expression: .globally(expression: .implies( + lhs: .language(expression: .vhdl(expression: .conditional(expression: .comparison( + value: .equality( + lhs: .reference(variable: .variable(reference: .variable(name: operationalMode))), + rhs: .literal(value: .bit(value: .high)) + ) + )))), + rhs: .quantified(expression: .eventually(expression: .until( + lhs: .language(expression: .vhdl(expression: .conditional(expression: .comparison( + value: .equality( + lhs: .reference(variable: .variable(reference: .variable( + name: operationalMode + ))), + rhs: .literal(value: .bit(value: .high)) + ) + )))), + rhs: .language(expression: .vhdl(expression: .conditional( + expression: .comparison(value: .equality( + lhs: .reference(variable: .variable(reference: .variable(name: bootMode))), + rhs: .literal(value: .bit(value: .high)) + )) + ))) + ))) + ))) + )))) + XCTAssertEqual( + Expression(rawValue: "A X A G operationalMode = '1' -> E operationalMode = '1' U bootMode = '1'"), + expected + ) + XCTAssertEqual( + Expression( + rawValue: "A X A G operationalMode = \'1\' -> E operationalMode = \'1\' U bootMode = \'1\'" + ), + expected + ) + } + +} diff --git a/Tests/TCTLParserTests/GloballyQuantifiedExpressionTests.swift b/Tests/TCTLParserTests/GloballyQuantifiedExpressionTests.swift index ca61557..8097d04 100644 --- a/Tests/TCTLParserTests/GloballyQuantifiedExpressionTests.swift +++ b/Tests/TCTLParserTests/GloballyQuantifiedExpressionTests.swift @@ -103,9 +103,9 @@ final class GloballyQuantifiedExpressionTests: XCTestCase { XCTAssertNil(GloballyQuantifiedExpression(rawValue: "A A recoveryMode = '1'")) XCTAssertNil(GloballyQuantifiedExpression(rawValue: "A A G recoveryMode = '1'")) XCTAssertNil(GloballyQuantifiedExpression(rawValue: "")) - XCTAssertNil(GloballyQuantifiedExpression(rawValue: "A G A G recoveryMode = '1'")) + XCTAssertNil(GloballyQuantifiedExpression(rawValue: "A G A E recoveryMode = '1'")) XCTAssertNil(GloballyQuantifiedExpression(rawValue: "A G recoveryMode = '1' U failureCount = 3")) - XCTAssertNil(GloballyQuantifiedExpression(rawValue: "A A G recoveryMode = '1' U failureCount = 3")) + XCTAssertNil(GloballyQuantifiedExpression(rawValue: "A G A G recoveryMode = '1' U failureCount = 3")) } /// Test `init(quantifier:, expression:)` correctly initializes the globally quantified expression.