├── .github └── workflows │ ├── black.yml │ ├── release.yml │ └── workflows.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── doc-cov.svg ├── docs ├── Makefile ├── make.bat ├── requirements.txt └── source │ ├── conf.py │ └── index.rst ├── pyproject.toml ├── requirements.txt ├── src └── sysml2py │ ├── __init__.py │ ├── definition.py │ ├── formatting.py │ ├── grammar │ ├── KerML.tx │ ├── KerMLExpressions.tx │ ├── SysML.tx │ ├── SysML_compiled.tx │ └── classes.py │ ├── textx │ ├── KerML.xtext │ ├── KerMLExpressions.xtext │ ├── SysML.xtext │ └── xtext_to_textx.py │ └── usage.py └── tests ├── .DS_Store ├── __init__.py ├── class_test.py ├── conftest.py ├── functions.py ├── grammar_test.py └── main_test.py /.github/workflows/black.yml: -------------------------------------------------------------------------------- 1 | name: Format code 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | - '!main' 8 | 9 | permissions: write-all 10 | 11 | jobs: 12 | lint: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: ":robot: Format code with black" 17 | run: | 18 | pip install black 19 | black . 20 | - name: Test ${{ github.event.push.head }} docstring coverage 21 | run: | 22 | pip install docstr-coverage 23 | docstr-coverage src/sysml2py --badge=doc-cov --fail-under=0 -e ".*/(textx|tests)" 24 | - name: Commit changes 25 | uses: EndBug/add-and-commit@v4 26 | with: 27 | author_name: ${{ github.actor }} 28 | author_email: ${{ github.actor }}@users.noreply.github.com 29 | message: ":robot: Format code with black" 30 | add: "." 31 | branch: ${{ github.ref }} 32 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Workflow 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: write-all 9 | 10 | jobs: 11 | documentation: 12 | name: Build Sphinx Documentation 13 | runs-on: ubuntu-latest 14 | environment: 15 | name: github-pages 16 | url: ${{ steps.deployment.outputs.page_url }} 17 | steps: 18 | - uses: actions/setup-python@v4 19 | with: 20 | python-version: '3.9' 21 | - id: deployment 22 | uses: sphinx-notes/pages@v3 23 | with: 24 | documentation_path: ./docs/source 25 | 26 | codecoverage: 27 | name: Determine code and documentation coverage 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v3 31 | - name: Set up Python 32 | uses: actions/setup-python@v4 33 | with: 34 | python-version: '3.9' 35 | - name: Install dependencies 36 | run: | 37 | python -m pip install --upgrade pip 38 | pip install --upgrade setuptools 39 | pip install -r requirements.txt 40 | - name: Test ${{ github.event.push.head }} coverage 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | run: | 44 | python -m pip install coveralls pytest pyyaml textx 45 | python -m coverage run --source=src -m pytest tests/ && coverage report 46 | coveralls 47 | 48 | versioning: 49 | name: Semantic Versioning 50 | runs-on: ubuntu-latest 51 | environment: 52 | name: pypi 53 | url: https://pypi.org/p/sysml2py 54 | needs: [documentation, codecoverage] 55 | steps: 56 | - uses: actions/checkout@v3 57 | with: 58 | fetch-depth: 0 59 | - name: Python Semantic Release 📦 to PyPI 60 | id: release 61 | uses: python-semantic-release/python-semantic-release@v8.0.3 62 | with: 63 | github_token: ${{ secrets.GITHUB_TOKEN }} 64 | repository_username: __token__ 65 | repository_password: ${{ secrets.PYPI_API_TOKEN }} 66 | - name: Publish package to PyPI 67 | uses: pypa/gh-action-pypi-publish@release/v1 68 | if: ${{ steps.release.outputs.released }} == 'true' 69 | with: 70 | password: ${{ secrets.PYPI_API_TOKEN }} 71 | - name: Publish package to GitHub Release 72 | uses: python-semantic-release/upload-to-gh-release@main 73 | if: ${{ steps.release.outputs.released }} == 'true' 74 | with: 75 | github_token: ${{ secrets.GITHUB_TOKEN }} 76 | tag: ${{ steps.release.outputs.tag }} 77 | -------------------------------------------------------------------------------- /.github/workflows/workflows.yml: -------------------------------------------------------------------------------- 1 | name: Test Commit 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | - '!main' 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | python-version: ["3.11"] 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Set up Python 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: '3.x' 23 | - name: Install dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | pip install --upgrade setuptools 27 | pip install -r requirements.txt 28 | - name: Test ${{ github.event.push.head }} coverage 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | run: | 32 | python -m pip install coveralls pytest 33 | python -m coverage run --source=src -m pytest tests && coverage report 34 | coveralls 35 | - name: Test with pytest 36 | run: | 37 | pip install pytest-timeout pytest-html 38 | pytest --timeout=300 tests --doctest-modules --html=report-${{ matrix.python-version }}.html --self-contained-html --junitxml=junit/test-results-${{ matrix.python-version }}.xml 39 | - name: Upload pytest test results 40 | uses: actions/upload-artifact@v3 41 | with: 42 | name: pytest-junit-results-${{ matrix.python-version }} 43 | path: junit/test-results-${{ matrix.python-version }}.xml 44 | # Use always() to always run this step to publish test results when there are test failures 45 | if: ${{ always() }} 46 | - name: Upload pytest test results 47 | uses: actions/upload-artifact@v3 48 | with: 49 | name: pytest-html-results-${{ matrix.python-version }} 50 | path: report-${{ matrix.python-version }}.html 51 | # Use always() to always run this step to publish test results when there are test failures 52 | if: ${{ always() }} 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | 4 | 5 | ## v0.5.3 (2024-05-30) 6 | 7 | ### :memo: 8 | 9 | * :memo: Added full docstrings to init ([`0e06f1d`](https://github.com/Westfall-io/sysml2py/commit/0e06f1d73b476706eae4dddf02ff3e3b3c052ada)) 10 | 11 | ### Other 12 | 13 | * :green_heart: Deployment fix and updates for pypi ([`ee89465`](https://github.com/Westfall-io/sysml2py/commit/ee894656417cdf5be5f2126f0374d15377bd12c6)) 14 | 15 | * :green_heart: Updating release workflow as well ([`8c72ce9`](https://github.com/Westfall-io/sysml2py/commit/8c72ce97d613b4d59d0773bb8498cdeb8bbc992d)) 16 | 17 | * :green_heart: Removing distribute ([`2dd552e`](https://github.com/Westfall-io/sysml2py/commit/2dd552e55097193d3cf6d181015c51a6b1fd795f)) 18 | 19 | * :green_heart: Updating test script to ensure available resources for pytest ([`6a9c297`](https://github.com/Westfall-io/sysml2py/commit/6a9c29790e53f06e382d74f3b5e36bbfc1ed9de9)) 20 | 21 | * :arrow_up: Fixing issue with dependencies for astropy ([`ac3b2ee`](https://github.com/Westfall-io/sysml2py/commit/ac3b2ee6965e899854d4e0f4f1946a61bd4f9e67)) 22 | 23 | * :arrow_up: Fixing issue with dependencies and cython3 failing ([`bb4feb6`](https://github.com/Westfall-io/sysml2py/commit/bb4feb6b4227c40a6f4b0f3d6cb6d87e43ec3565)) 24 | 25 | 26 | ## v0.5.2 (2023-08-12) 27 | 28 | ### :ambulance: 29 | 30 | * :ambulance: Permissions fix ([`8c5ea13`](https://github.com/Westfall-io/sysml2py/commit/8c5ea13b9d28aa2f846fc9f1e7f985eeae7e615d)) 31 | 32 | * :ambulance: Added configuration to workflow ([`e8b932b`](https://github.com/Westfall-io/sysml2py/commit/e8b932b9ab4e3e16ff43cf4549c571e70a5cd218)) 33 | 34 | 35 | ## v0.5.1 (2023-08-12) 36 | 37 | ### :ambulance: 38 | 39 | * :ambulance: Correct workflow yaml ([`8c410ee`](https://github.com/Westfall-io/sysml2py/commit/8c410ee7e486b7624e31d19faf94c6692b110f88)) 40 | 41 | * :ambulance: Fix to upload to pypi ([`3309eb5`](https://github.com/Westfall-io/sysml2py/commit/3309eb5641f3671e6690bd61ac04b986c5d0a0c8)) 42 | 43 | 44 | ## v0.5.0 (2023-08-12) 45 | 46 | ### :ambulance: 47 | 48 | * :ambulance: Fix for attribute change when adding units ([`1daacac`](https://github.com/Westfall-io/sysml2py/commit/1daacac3e81062bd35a5cac832f3cafccc9317a9)) 49 | 50 | * :ambulance: Fixed critical grammar changes with SysML and KerML overwrites. ([`34978bb`](https://github.com/Westfall-io/sysml2py/commit/34978bbd33a0793cb618605aa87950fda64d5f68)) 51 | 52 | ### :bug: 53 | 54 | * :bug: Removing optional from in flow statement that won't return programmatically. ([`716961b`](https://github.com/Westfall-io/sysml2py/commit/716961b003e51c286af8c63e2cad5d5806acef20)) 55 | 56 | * :bug: Fixed issue with Primary expression get definition response. ([`5512466`](https://github.com/Westfall-io/sysml2py/commit/55124661dd6f8c08efb2136db65bb22111012ae4)) 57 | 58 | * :bug: Updated secondary primary expression in attribute. ([`97f2086`](https://github.com/Westfall-io/sysml2py/commit/97f20867c29b577ce0f3d6d3eb5dd1cabe0dafaf)) 59 | 60 | * :bug: Fixed changes to primary expression in attribute ([`ace773c`](https://github.com/Westfall-io/sysml2py/commit/ace773c595db76e208fe4d909f91ceae4171fef6)) 61 | 62 | * :bug: Duplicate feature chaining in primary expression. ([`8217463`](https://github.com/Westfall-io/sysml2py/commit/821746349450467c3ab9b46bc86922d2476f8640)) 63 | 64 | ### :sparkles: 65 | 66 | * :sparkles: Adding analysis grammar and tests. ([`9400f9b`](https://github.com/Westfall-io/sysml2py/commit/9400f9bef19757733b4d8a90d66f7e9678a42f6c)) 67 | 68 | * :sparkles: Adding requirement grammar classes and tests. ([`0d73498`](https://github.com/Westfall-io/sysml2py/commit/0d7349852aa361fe45ff5ffbc457226675f87b73)) 69 | 70 | * :sparkles: Adding constraint grammar and tests. ([`6212fd0`](https://github.com/Westfall-io/sysml2py/commit/6212fd0fa4cd2261cd0b17e3871b5367080a0005)) 71 | 72 | * :sparkles: State grammar with appropriate tests. ([`b896efe`](https://github.com/Westfall-io/sysml2py/commit/b896efe2e0331383aa520621275ec8ae911f1871)) 73 | 74 | * :sparkles: State grammar classes initial implementation with first test. ([`61d3df1`](https://github.com/Westfall-io/sysml2py/commit/61d3df1571b25e554bad631d005d11ce9ac5c0a4)) 75 | 76 | * :sparkles: Added all calculation grammar classes and tests that pass. ([`393fa4c`](https://github.com/Westfall-io/sysml2py/commit/393fa4cce83471500401c3c7737a89c94e17f8cc)) 77 | 78 | * :sparkles: Adding grammar for expressions. ([`f69c1ef`](https://github.com/Westfall-io/sysml2py/commit/f69c1ef446730912ef9feb34638cde7596cc6ecc)) 79 | 80 | * :sparkles: Partial addition of constraint grammar classes ([`5fc5c23`](https://github.com/Westfall-io/sysml2py/commit/5fc5c23aea9b8c27a151dfa21f89f06d5a8a237d)) 81 | 82 | * :sparkles: Action definition with 2 of 4 tests complete. ([`9530eed`](https://github.com/Westfall-io/sysml2py/commit/9530eed3aeda5bb059cdcff2555cc5c041d6e3bc)) 83 | 84 | * :sparkles: Adding first action definition grammar classes. ([`3454a50`](https://github.com/Westfall-io/sysml2py/commit/3454a5048789917e7a4e02092ab3c602ba180157)) 85 | 86 | * :sparkles: Adding flow grammar and test. ([`4fe01c9`](https://github.com/Westfall-io/sysml2py/commit/4fe01c9f2394bada05cc703f95177c90a32f37ee)) 87 | 88 | * :sparkles: Flow Connector added to grammar and initial test built. ([`872b76d`](https://github.com/Westfall-io/sysml2py/commit/872b76ded8c366f1b429968041f4214817395e1d)) 89 | 90 | ### :white_check_mark: 91 | 92 | * :white_check_mark: Completed tests for state grammar. ([`2c2213c`](https://github.com/Westfall-io/sysml2py/commit/2c2213cbc96b4fe16e66f680f3a10672f09f05d3)) 93 | 94 | * :white_check_mark: Added two additional tests for expressions, tests all pass. ([`afae042`](https://github.com/Westfall-io/sysml2py/commit/afae0426a30b4cebffec8a974c7b7823dbb80f3c)) 95 | 96 | * :white_check_mark: Grammar changes now pass all tests. ([`7771f05`](https://github.com/Westfall-io/sysml2py/commit/7771f053121a6edce9277b1de0536e2323d6276b)) 97 | 98 | * :white_check_mark: Added final training example tests for action definition. ([`a399f5b`](https://github.com/Westfall-io/sysml2py/commit/a399f5b295dd17de4979c3f2937f3016524ef8d6)) 99 | 100 | * :white_check_mark: Second example test for flow connector. ([`7d00034`](https://github.com/Westfall-io/sysml2py/commit/7d00034efbfd60e993a69a697210896cab16cfb5)) 101 | 102 | ### :zap: 103 | 104 | * :zap: Removing commits to push off main, should not run into pull error for semantic parsing ([`77272f3`](https://github.com/Westfall-io/sysml2py/commit/77272f3202378dbf637ad38c8e1cf69c68484198)) 105 | 106 | * :zap: Removing excess lines from code coverage. ([`442bc0c`](https://github.com/Westfall-io/sysml2py/commit/442bc0c32048c9575de9f9025963bcca5f0bdfbc)) 107 | 108 | * :zap: Now loads from a single compiled grammar file that overwrites any previous grammar from imports. ([`2f90c7b`](https://github.com/Westfall-io/sysml2py/commit/2f90c7b57a6a9e738601d42b75863bfd03f457bc)) 109 | 110 | ### Other 111 | 112 | * :art: Updating semantic parsing with lessons learned from windstorm ([`2f66dbf`](https://github.com/Westfall-io/sysml2py/commit/2f66dbf4b023d05397d2fa5267d0ae4d29846f87)) 113 | 114 | 115 | ## v0.4.4 (2023-07-26) 116 | 117 | ### :bug: 118 | 119 | * :bug: Fixes for load_grammar functions. ([`0e45818`](https://github.com/Westfall-io/sysml2py/commit/0e4581889f55928576e939026a8ab5c3debdccc0)) 120 | 121 | ### Other 122 | 123 | * :test_tube: Fix for test that can't find grammar. ([`18f7aca`](https://github.com/Westfall-io/sysml2py/commit/18f7acab8be6b0d3d70ea7ee1f17fb8d3a11377d)) 124 | 125 | * :test_tube: Adding to coverage with failure tests. ([`7c2e96e`](https://github.com/Westfall-io/sysml2py/commit/7c2e96eae65cb536027f01501b1dcc876d3a163e)) 126 | 127 | 128 | ## v0.4.3 (2023-07-25) 129 | 130 | ### :bug: 131 | 132 | * :bug: Fixed issue with port subnodes. ([`67720b1`](https://github.com/Westfall-io/sysml2py/commit/67720b19307df138dff10d5138f74aba1fa87734)) 133 | 134 | * :bug: Fixed issue with usage classes with body objects. ([`afc5522`](https://github.com/Westfall-io/sysml2py/commit/afc5522c64088595030f68d578af2f303613226e)) 135 | 136 | 137 | ## v0.4.2 (2023-07-24) 138 | 139 | ### :bug: 140 | 141 | * :bug: Enforce some syntax with Models always starting with packages. ([`0cccdf1`](https://github.com/Westfall-io/sysml2py/commit/0cccdf1d5f97c864d82edffc9ec54bd93cf1cb54)) 142 | 143 | ### Other 144 | 145 | * :green_heart: Adding github actions back into commit. ([`e1ab9f4`](https://github.com/Westfall-io/sysml2py/commit/e1ab9f4b7fa53591ce11de3f5813a67b7070dc8c)) 146 | 147 | 148 | ## v0.4.1 (2023-07-24) 149 | 150 | ### :bug: 151 | 152 | * :bug: Fix poetry build for pypi builds. ([`3c90e28`](https://github.com/Westfall-io/sysml2py/commit/3c90e28707710002018569509f87e9266ccef446)) 153 | 154 | 155 | ## v0.4.0 (2023-07-21) 156 | 157 | ### :bug: 158 | 159 | * :bug: Fix for definition naming. ([`ff62dc1`](https://github.com/Westfall-io/sysml2py/commit/ff62dc10131d8c53fd4361f7100403dc1c4424f6)) 160 | 161 | * :bug: Reverting change to author. ([`ae5d19e`](https://github.com/Westfall-io/sysml2py/commit/ae5d19e5581b3493e985bd01bb356b1dcd3d1618)) 162 | 163 | * :bug: Added test and definition file that was causing the error. ([`b7787d4`](https://github.com/Westfall-io/sysml2py/commit/b7787d4ccba53e421e3f877a46eca331698e2950)) 164 | 165 | * :bug: Fixed an issue where something defined within a package could not be typed by another definition ([`ee257eb`](https://github.com/Westfall-io/sysml2py/commit/ee257eba9cdaec2a8ac52f65cf702881879aa445)) 166 | 167 | ### :heavy_plus_sign: 168 | 169 | * :heavy_plus_sign: Using poetry package management, added dependencies. ([`5c625dd`](https://github.com/Westfall-io/sysml2py/commit/5c625dd6e51a6090a699aab229c335d8946d7bd5)) 170 | 171 | * :heavy_plus_sign: Adding pytest-html to test workflow. ([`4f2cedc`](https://github.com/Westfall-io/sysml2py/commit/4f2cedc50162ac2013b5dc60481a7bc646debad3)) 172 | 173 | ### :memo: 174 | 175 | * :memo: Updates to project info to assist sphinx build. ([`939d2ff`](https://github.com/Westfall-io/sysml2py/commit/939d2ff4867ccc792b78c8a1229ef937653093ec)) 176 | 177 | * :memo: Fixing spacing. ([`25e78d0`](https://github.com/Westfall-io/sysml2py/commit/25e78d01066b96146be587988e1735367747f52c)) 178 | 179 | * :memo: Adding more badges. ([`76899b1`](https://github.com/Westfall-io/sysml2py/commit/76899b192545087066493c7a65c388266c09d01c)) 180 | 181 | * :memo: Added trello to Readme ([`26e304c`](https://github.com/Westfall-io/sysml2py/commit/26e304c10ea7599259d75f43992996887161183a)) 182 | 183 | ### :sparkles: 184 | 185 | * :sparkles: Added a new base model class to replace collapse function. Model will create packages and other custom classes for use. Additionally, packages can be created from grammar. ([`3dc5fca`](https://github.com/Westfall-io/sysml2py/commit/3dc5fcad2e892b0e14c1c9f74cbea868df6844a5)) 186 | 187 | * :sparkles: Added port with ability to create subfeatures with directionality. ([`94c0a19`](https://github.com/Westfall-io/sysml2py/commit/94c0a19b08203a3db953858bf968de5c2f2084bc)) 188 | 189 | * :sparkles: New package class. ([`3766690`](https://github.com/Westfall-io/sysml2py/commit/3766690bd848de0475eb047af1870da358dd51ab)) 190 | 191 | ### :white_check_mark: 192 | 193 | * :white_check_mark: Adding child as optional to get def functions. ([`da90c49`](https://github.com/Westfall-io/sysml2py/commit/da90c49e3b6d80258ea6bdc2391031ead534833f)) 194 | 195 | * :white_check_mark: Correcting tests ([`fba8dce`](https://github.com/Westfall-io/sysml2py/commit/fba8dcef847f4d5c39ad97c72b9cb711236df335)) 196 | 197 | * :white_check_mark: Package tests added. ([`803192b`](https://github.com/Westfall-io/sysml2py/commit/803192b75749facc0d19cae596038663b3708714)) 198 | 199 | ### Other 200 | 201 | * :construction_worker: Adding src to path for pytest in pyproject.toml ([`510d672`](https://github.com/Westfall-io/sysml2py/commit/510d672b98c747c7ad573aa1d7fbf28d2252b4a1)) 202 | 203 | * :construction_worker: Corrected test directory again. ([`92d5dc2`](https://github.com/Westfall-io/sysml2py/commit/92d5dc2c1bf1f416d6e248ddbf4bb45727a3e5fe)) 204 | 205 | * :construction_worker: Corrected test directory. ([`2bfc6df`](https://github.com/Westfall-io/sysml2py/commit/2bfc6dfc1f6767a4caddd0e69fbc459fc5a0ed4a)) 206 | 207 | * :green_heart: Adding coveralls to all branches. ([`425024d`](https://github.com/Westfall-io/sysml2py/commit/425024d1b7ebf80010c2f8a7e7d866b32ba4e5d8)) 208 | 209 | * :construction_worker: Adding html to artifacts. ([`4b74045`](https://github.com/Westfall-io/sysml2py/commit/4b74045fc81d32fe33629dc215d1126145f572c3)) 210 | 211 | * :green_heart: Adding conftest.py ([`dbd32b9`](https://github.com/Westfall-io/sysml2py/commit/dbd32b967febd7396de40ff7e73a9b75182e7507)) 212 | 213 | * :green_heart: Adding path to init to correct test workflow. ([`d29bfb6`](https://github.com/Westfall-io/sysml2py/commit/d29bfb6692d950bf384182dda96ebb017c8231af)) 214 | 215 | 216 | ## v0.3.1 (2023-07-11) 217 | 218 | ### :memo: 219 | 220 | * :memo: Documentation changes. ([`edfd629`](https://github.com/Westfall-io/sysml2py/commit/edfd629ec5ef6611d2b9643706cee6b1bf40ea47)) 221 | 222 | 223 | ## v0.3.0 (2023-07-11) 224 | 225 | ### :memo: 226 | 227 | * :memo: Updates to readme, also added a loadfromgrammar function to Usage. ([`e999436`](https://github.com/Westfall-io/sysml2py/commit/e999436193ccee31dfadaf5a193705cf61e99496)) 228 | 229 | ### :sparkles: 230 | 231 | * :sparkles: Added some rollup classes the abstract underlying grammar. They have functions to manipulate the grammar. ([`b1e01a4`](https://github.com/Westfall-io/sysml2py/commit/b1e01a465200e79f96a30da4f2ce5b861850ddd5)) 232 | 233 | ### Other 234 | 235 | * :arrow_up: Merge from main and add astropy to main dependencies to handle units. ([`98f260b`](https://github.com/Westfall-io/sysml2py/commit/98f260b888f54f9f6911b043387cd0fbc4d81c88)) 236 | 237 | 238 | ## v0.2.10 (2023-06-21) 239 | 240 | 241 | ## v0.2.9 (2023-06-21) 242 | 243 | 244 | ## v0.2.8 (2023-06-21) 245 | 246 | 247 | ## v0.2.7 (2023-06-21) 248 | 249 | 250 | ## v0.2.6 (2023-06-21) 251 | 252 | 253 | ## v0.2.5 (2023-06-21) 254 | 255 | 256 | ## v0.2.4 (2023-06-21) 257 | 258 | 259 | ## v0.2.3 (2023-06-21) 260 | 261 | 262 | ## v0.2.2 (2023-06-21) 263 | 264 | 265 | ## v0.2.1 (2023-06-21) 266 | 267 | 268 | ## v0.2.0 (2023-06-21) 269 | 270 | ### :ambulance: 271 | 272 | * :ambulance: Fixing merge errors from black ([`e101e70`](https://github.com/Westfall-io/sysml2py/commit/e101e70ea50ccd52cc5226c6860bcbe1b9411d3a)) 273 | 274 | * :ambulance: Fix for build script ([`4c6f238`](https://github.com/Westfall-io/sysml2py/commit/4c6f238afcf37c8620f082dfee19a8a4282a47e3)) 275 | 276 | ### :bug: 277 | 278 | * :bug: Adding textx to requirements. ([`d3c1c76`](https://github.com/Westfall-io/sysml2py/commit/d3c1c767b39a68d67c0eea7802982de770c1bc48)) 279 | 280 | * :bug: Workflow fixes ([`9b883ea`](https://github.com/Westfall-io/sysml2py/commit/9b883eaef9932e80299dc94ede0646a2ceb1a405)) 281 | 282 | ### :construction: 283 | 284 | * :construction: Forgot to git pull ([`4cf3100`](https://github.com/Westfall-io/sysml2py/commit/4cf3100b719f9ee17beb556b116cf46fd9db1886)) 285 | 286 | * :construction: Adding more documentation and cleanup ([`8a8675e`](https://github.com/Westfall-io/sysml2py/commit/8a8675e3828beef65903491a578477e14ba5ffa5)) 287 | 288 | * :construction: More adds. ([`42258b6`](https://github.com/Westfall-io/sysml2py/commit/42258b66704bb42a2f2b2632722bab30887cb8a9)) 289 | 290 | * :construction: Fix yaml ([`0fc1c2f`](https://github.com/Westfall-io/sysml2py/commit/0fc1c2f860cfc3a5e61138c53cfc5b4b8a24ab84)) 291 | 292 | * :construction: Fixes and updates to CI/CD ([`c0640f1`](https://github.com/Westfall-io/sysml2py/commit/c0640f1ded084d7d178d0a1a0ad87e434c388d37)) 293 | 294 | ### :memo: 295 | 296 | * :memo: Updates to version ([`208cdd6`](https://github.com/Westfall-io/sysml2py/commit/208cdd62db514b466b0b64aa70134e54cea46ce0)) 297 | 298 | * :memo: remove excess brackets ([`e258d1c`](https://github.com/Westfall-io/sysml2py/commit/e258d1cdccbf3614b6be37f6322ddee006756809)) 299 | 300 | * :memo: Docstring coverage add to README ([`3720f3a`](https://github.com/Westfall-io/sysml2py/commit/3720f3a07002b1129b90d552f7a291c8662c6c09)) 301 | 302 | * :memo: Time to add documentationgit add docsgit add docs ([`f933521`](https://github.com/Westfall-io/sysml2py/commit/f9335216ae484aa2145fd2178b206bcff510958b)) 303 | 304 | ### :sparkles: 305 | 306 | * :sparkles: More tests. ([`41d1f5e`](https://github.com/Westfall-io/sysml2py/commit/41d1f5eb343c4afe02224fd6b9d68bed3f5cebaa)) 307 | 308 | * :sparkles: More tests and classes. ([`cd59e2e`](https://github.com/Westfall-io/sysml2py/commit/cd59e2e7b2ff2c2eeb599480293f09efabcd79d9)) 309 | 310 | * :sparkles: More badge for readme. ([`4be8d54`](https://github.com/Westfall-io/sysml2py/commit/4be8d54efb78fa6030c8c80702f13e9ce295c5da)) 311 | 312 | ### :white_check_mark: 313 | 314 | * :white_check_mark: Adding import test, namespaces are bugged. ([`6d35922`](https://github.com/Westfall-io/sysml2py/commit/6d35922290ee468a3604102ce78da9f7f2846b36)) 315 | 316 | * :white_check_mark: Added test, updated workflow ([`b21d14b`](https://github.com/Westfall-io/sysml2py/commit/b21d14bdff81269f58f648ae44cc87466385b328)) 317 | 318 | ### :zap: 319 | 320 | * :zap: Adding code coverage badge to readme. ([`c72fe86`](https://github.com/Westfall-io/sysml2py/commit/c72fe8699891d30a588abdafc27d3f030900a31a)) 321 | 322 | ### Other 323 | 324 | * :green_heart: Ignore repo upload. ([`c5efb11`](https://github.com/Westfall-io/sysml2py/commit/c5efb1139b987c89374ab3acf2586589e65d963e)) 325 | 326 | * :rocket: Moving to 0.1.2. ([`e6b7c2d`](https://github.com/Westfall-io/sysml2py/commit/e6b7c2d92da8d0a26f4baf438c363fca75f4141c)) 327 | 328 | * :construction_worker: Fix to build script to include grammar files. ([`9a85d55`](https://github.com/Westfall-io/sysml2py/commit/9a85d5547ba7c5343e1966d87d501583b2bc4c88)) 329 | 330 | * :rocket: Moving to 0.1.0 baseline, most of the base functionality is here. ([`aa7333d`](https://github.com/Westfall-io/sysml2py/commit/aa7333dffb77f364da4ee4f4c9375838e49d5568)) 331 | 332 | * :green_heart: Fixing?? ([`21824c9`](https://github.com/Westfall-io/sysml2py/commit/21824c9c0f34b6f436b84f257bf373ceaf8cf98d)) 333 | 334 | * :green_heart: Fixing? ([`0f9b849`](https://github.com/Westfall-io/sysml2py/commit/0f9b849174ca818f6de6076e4a8362ea32def4b6)) 335 | 336 | * :green_heart: Fixing code coverage with better import flat file usage. ([`1a11479`](https://github.com/Westfall-io/sysml2py/commit/1a114792dcce922388f014acb26e8691e3a4fe02)) 337 | 338 | * :green_heart: Fixes for tests. ([`e11d3e9`](https://github.com/Westfall-io/sysml2py/commit/e11d3e948c266bd6dc814cc68460f6d0bdc0e86a)) 339 | 340 | * :green_heart: Fixes to doc? ([`1f27b22`](https://github.com/Westfall-io/sysml2py/commit/1f27b220215f9c91836b7f5945cc8e62ad3fcaf3)) 341 | 342 | * :green_heart: I broke it. ([`38243bc`](https://github.com/Westfall-io/sysml2py/commit/38243bce4125a204eb74f4692572731fc07c31eb)) 343 | 344 | * :green_heart: Let's see if this breaks github actions. ([`3cf03e8`](https://github.com/Westfall-io/sysml2py/commit/3cf03e82e64da027ffd9aa9f727ff0183cc2ee82)) 345 | 346 | * :green_heart: Fix for correct path to code coverage check. ([`2fccb2c`](https://github.com/Westfall-io/sysml2py/commit/2fccb2c5333a8a5001854b1f759eef91c9d60c6e)) 347 | 348 | * :green_heart: Fixes???? ([`0955e8b`](https://github.com/Westfall-io/sysml2py/commit/0955e8b6ee5ca7182ecd25a7a0fc80cea58b7dee)) 349 | 350 | * :green_heart: Fixes??? ([`2616e90`](https://github.com/Westfall-io/sysml2py/commit/2616e900bc0cec252b7d04bce61f47740782f229)) 351 | 352 | * :green_heart: Fixes?? ([`b414758`](https://github.com/Westfall-io/sysml2py/commit/b4147584a2d74aa9cd910932e36f58f6c865df66)) 353 | 354 | * :green_heart: Fixes? ([`37fa8a5`](https://github.com/Westfall-io/sysml2py/commit/37fa8a5bca43c05d4432cbfc894d30d4f0c8b6fc)) 355 | 356 | * :green_heart: Adding code coverage detection. ([`b977536`](https://github.com/Westfall-io/sysml2py/commit/b977536f2a1289ef8a69a00ec4761e277d7a2c1b)) 357 | 358 | * :green_heart: Seeing if I can drop the separate document workflow. ([`7692fc7`](https://github.com/Westfall-io/sysml2py/commit/7692fc71ed63a03b3266f3408fbac56f12d5496b)) 359 | 360 | * :green_heart: Need more in req.txt ([`2a65bfc`](https://github.com/Westfall-io/sysml2py/commit/2a65bfcbf1599ae8999735a02b99366950fbca3f)) 361 | 362 | * :green_heart: Testing if we need to change directory. ([`96fc0c5`](https://github.com/Westfall-io/sysml2py/commit/96fc0c552930c697616caf7d9ef6fca68a1e4d77)) 363 | 364 | * :green_heart: Test to check for new build changes to documentation. ([`382c9de`](https://github.com/Westfall-io/sysml2py/commit/382c9debe679ef82abe288da8d1a26647c16bfd4)) 365 | 366 | * :green_heart: Fixes?? ([`c6c0b0f`](https://github.com/Westfall-io/sysml2py/commit/c6c0b0fdbf6db0924296fe5eb0a261be80d29667)) 367 | 368 | * :green_heart: Fixes? ([`1d57172`](https://github.com/Westfall-io/sysml2py/commit/1d57172c96128dca989c7799c6b84ab22dd55b57)) 369 | 370 | * :green_heart: Adding documentation to github action ([`124645c`](https://github.com/Westfall-io/sysml2py/commit/124645c3b0629f15090da7a71b1315fce26ebd1d)) 371 | 372 | * :fire: Removing mac files. ([`18174bd`](https://github.com/Westfall-io/sysml2py/commit/18174bdc0d678666fa56e8a1233e7bd64a095a36)) 373 | 374 | * :green_heart: Set write all ([`6ed68a0`](https://github.com/Westfall-io/sysml2py/commit/6ed68a0149cd237eb8be070c3f63d8cc52ac278e)) 375 | 376 | * :green_heart: Let's see if this works, adding permissions in the script/ ([`e21687a`](https://github.com/Westfall-io/sysml2py/commit/e21687ad1f165f6da83b5ccca119f25bf2f885dc)) 377 | 378 | * :green_heart: Trying this for autoformat. ([`4fa5563`](https://github.com/Westfall-io/sysml2py/commit/4fa5563b5a4e7e49f5807e979480d1346ae08379)) 379 | 380 | * :green_heart: Adding autoformatting instead of checking ([`b7b38dc`](https://github.com/Westfall-io/sysml2py/commit/b7b38dc71d7c0bdc4770d64fb7d2b3b79e8ad955)) 381 | 382 | * :green_heart: Adding Black linting ([`ee365ae`](https://github.com/Westfall-io/sysml2py/commit/ee365aec7c3471a5843522a08c9afb951cef623c)) 383 | 384 | * :fire: Getting rid of mac files. ([`b41512a`](https://github.com/Westfall-io/sysml2py/commit/b41512a0aaea95c5a2791967ed01df9e67dba129)) 385 | 386 | * :clown: Rework into textx which has similar syntax to current standard. ([`b0f5991`](https://github.com/Westfall-io/sysml2py/commit/b0f599120a4c2c2258011e610ad340072d02213e)) 387 | 388 | * :poop Removing more excess files. ([`4bbe0f3`](https://github.com/Westfall-io/sysml2py/commit/4bbe0f3a3e5795bb570cb378df8b4fb05f0f190c)) 389 | 390 | * :clown: Adding workflows ([`e4cfccd`](https://github.com/Westfall-io/sysml2py/commit/e4cfccd1660a608333f64f0549e52cd9cb3491fb)) 391 | 392 | * :clown_face: First commit of some data ([`42c1782`](https://github.com/Westfall-io/sysml2py/commit/42c1782455b44ea207e586993c7d362769f5b156)) 393 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Westfall-io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sysml2py 2 | [![PyPI version](https://badge.fury.io/py/sysml2py.svg)](https://badge.fury.io/py/sysml2py)[![PyPI status](https://img.shields.io/pypi/status/sysml2py.svg)](https://pypi.python.org/pypi/sysml2py/)[![Coverage Status](https://coveralls.io/repos/github/Westfall-io/sysml2py/badge.svg)](https://coveralls.io/github/Westfall-io/sysml2py)![Docstring Coverage](https://raw.githubusercontent.com/Westfall-io/sysml2py/main/doc-cov.svg)[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/) 3 | 4 | [![Trello](https://img.shields.io/badge/Trello-%23026AA7.svg?style=for-the-badge&logo=Trello&logoColor=white)](https://trello.com/b/xHfFUzlk/sysml2py) 5 | 6 | ## Description 7 | sysml2py is an open source pure Python library for constructing python-based 8 | classes consistent with the [SysML v2.0 standard](https://github.com/Systems-Modeling/SysML-v2-Release). 9 | 10 | ## Requirements 11 | sysml2py requires the following Python packages: 12 | - [textX](https://github.com/textX/textX) 13 | - [pyyaml](https://github.com/yaml/pyyaml) 14 | - [astropy](https://github.com/astropy/astropy) 15 | 16 | ## Installation 17 | 18 | Multiple installation methods are supported by sysml2py, including: 19 | 20 | | **Logo** | **Platform** | **Command** | 21 | |:-----------------------------------------------------------------:|:------------:|:---------------------------------------------------------------------------------:| 22 | | ![PyPI logo](https://simpleicons.org/icons/pypi.svg) | PyPI | ``python -m pip install sysml2py`` | 23 | | ![GitHub logo](https://simpleicons.org/icons/github.svg) | GitHub | ``python -m pip install https://github.com/Westfall-io/sysml2py/archive/refs/heads/main.zip`` | 24 | 25 | ## Documentation 26 | 27 | Documentation can be found [here.](https://westfall-io.github.io/sysml2py/) 28 | 29 | ### Basic Usage 30 | 31 | The code below will create a part called Stage 1, with a shortname of <'3.1'> 32 | referencing a specific requirement or document. It has a mass attribute of 100 33 | kg. It has a thrust attribute of 1000 N. These attributes are created and placed 34 | as a child of the part. Next, we recall the part value for thrust and add 199 N. 35 | Finally, we can dump the output from this class. 36 | ``` 37 | from sysml2py import Attribute, Part 38 | 39 | import astropy.units as u 40 | a = Attribute()._set_name('mass') 41 | a.set_value(100*u.kg) 42 | b = Attribute()._set_name('thrust') 43 | b.set_value(1000*u.N) 44 | c = Part()._set_name("Stage_1")._set_name("'3.1'", short=True) 45 | c._set_child(a) 46 | c._set_child(b) 47 | v = "Stage_1.thrust" 48 | c._get_child(v).set_value(c._get_child(v).get_value()+199*u.N) 49 | print(c.dump()) 50 | ``` 51 | 52 | It will output the following, which isn't yet fully correct as we need to import 53 | the SI units to be valid SysML. 54 | ``` 55 | part <'3.1'> Stage_1 { 56 | attribute mass= 100.0 [kg]; 57 | attribute thrust= 1199.0 [N]; 58 | } 59 | ``` 60 | 61 | The package is able to handle Items, Parts, and Attributes. 62 | 63 | ``` 64 | a = Part()._set_name('camera') 65 | b = Item()._set_name('lens') 66 | d = Attribute()._set_name('mass') 67 | c = Part()._set_name("sensor") 68 | c._set_child(a) 69 | c._set_child(b) 70 | a._set_child(d) 71 | print(c.dump()) 72 | ``` 73 | 74 | will return: 75 | ``` 76 | part sensor { 77 | part camera { 78 | attribute mass; 79 | } 80 | item lens; 81 | } 82 | ``` 83 | 84 | ## Release Planning 85 | Development can be tracked via [Trello.](https://trello.com/b/xHfFUzlk/sysml2py) 86 | 87 | ## License 88 | sysml2py is released under the MIT license, hence allowing commercial use of the library. 89 | -------------------------------------------------------------------------------- /doc-cov.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | docstr-coverage 16 | docstr-coverage 17 | 1% 18 | 1% 19 | 20 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.https://www.sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx-rtd-theme==1.2.1 2 | PyYAML==6.0 3 | textX==3.1.1 4 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | 16 | sys.path.insert(0, os.path.abspath("../../src")) 17 | sys.path.insert(0, os.path.abspath("../src")) 18 | 19 | # -- Project information ----------------------------------------------------- 20 | 21 | project = "sysml2py" 22 | copyright = "2023, Christopher Cox" 23 | author = "Christopher Cox" 24 | 25 | # The full version, including alpha/beta/rc tags 26 | release = "0.1.2" 27 | 28 | 29 | # -- General configuration --------------------------------------------------- 30 | 31 | # Add any Sphinx extension module names here, as strings. They can be 32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 33 | # ones. 34 | extensions = ["sphinx.ext.autodoc", "sphinx.ext.coverage", "sphinx.ext.napoleon"] 35 | 36 | # Add any paths that contain templates here, relative to this directory. 37 | templates_path = ["_templates"] 38 | 39 | # List of patterns, relative to source directory, that match files and 40 | # directories to ignore when looking for source files. 41 | # This pattern also affects html_static_path and html_extra_path. 42 | exclude_patterns = [] 43 | 44 | 45 | # -- Options for HTML output ------------------------------------------------- 46 | 47 | # The theme to use for HTML and HTML Help pages. See the documentation for 48 | # a list of builtin themes. 49 | # 50 | html_theme = "sphinx_rtd_theme" 51 | 52 | # Add any paths that contain custom static files (such as style sheets) here, 53 | # relative to this directory. They are copied after the builtin static files, 54 | # so a file named "default.css" will overwrite the builtin "default.css". 55 | html_static_path = ["_static"] 56 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to sysml2py's documentation! 2 | ==================================== 3 | 4 | .. automodule:: sysml2py 5 | :members: 6 | 7 | .. toctree:: 8 | :maxdepth: 2 9 | :caption: Contents: 10 | 11 | 12 | 13 | Indices and tables 14 | ================== 15 | 16 | * :ref:`genindex` 17 | * :ref:`modindex` 18 | * :ref:`search` 19 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | #requires = ["setuptools>=61.0"] 3 | #build-backend = "setuptools.build_meta" 4 | requires = ["poetry-core"] 5 | build-backend = "poetry.core.masonry.api" 6 | 7 | [project] 8 | name = "sysml2py" 9 | version = "0.5.3" 10 | description = "SysML v2.0 Parser" 11 | authors = [ 12 | { name="Christopher Cox", email="chris.cox@westfall.io" }, 13 | ] 14 | readme = "README.md" 15 | license = {file = "LICENSE"} 16 | requires-python = ">=3.7" 17 | classifiers = [ 18 | "Development Status :: 3 - Alpha", 19 | "Programming Language :: Python :: 3", 20 | "License :: OSI Approved :: MIT License", 21 | "Operating System :: OS Independent", 22 | ] 23 | 24 | [tool.setuptools] 25 | include-package-data = true 26 | 27 | [tool.setuptools.packages.find] 28 | where = ["src/sysml2py", "src"] 29 | 30 | [tool.setuptools.package-data] 31 | grammar = ["*.tx"] 32 | 33 | [tool.pytest.ini_options] 34 | pythonpath = [ 35 | "src" 36 | ] 37 | 38 | [tool.semantic_release] 39 | version_variable = [ 40 | "src/sysml2py/__init__.py:version", 41 | ] 42 | version_toml=[ 43 | "pyproject.toml:tool.poetry.version", 44 | "pyproject.toml:project.version", 45 | ] 46 | commit_parser = "emoji" 47 | build_command = "pip install poetry && poetry build" 48 | commit_message = ":bookmark:{version}\n\nAutomatically generated by python-semantic-release" 49 | 50 | [tool.semantic_release.changelog] 51 | exclude_commit_patterns = [":robot:",":twisted_rightwards_arrows:", 52 | ":poop:", "^[^:].*"] 53 | 54 | [tool.semantic_release.commit_parser_options] 55 | major_tags = [":boom:"] 56 | minor_tags = [ 57 | ":sparkles:", 58 | ":children_crossing:", 59 | ":lipstick:", 60 | ":iphone:", 61 | ":egg:", 62 | ":chart_with_upwards_trend:", 63 | ] 64 | patch_tags = [ 65 | ":ambulance:", 66 | ":lock:", 67 | ":bug:", 68 | ":zap:", 69 | ":goal_net:", 70 | ":alien:", 71 | ":wheelchair:", 72 | ":speech_balloon:", 73 | ":mag:", 74 | ":apple:", 75 | ":penguin:", 76 | ":checkered_flag:", 77 | ":robot:", 78 | ":green_apple:", 79 | ":memo:", 80 | ":heavy_plus_sign:", 81 | ":construction:", 82 | ":white_check_mark:", 83 | ] 84 | 85 | [tool.semantic_release.branches.main] 86 | match = "(main|master)" 87 | prerelease = false 88 | build_command = "pip install poetry && poetry build" 89 | 90 | [tool.semantic_release.branches."dev0.5.x"] 91 | match = "dev0.5.x" 92 | prerelease = true 93 | prerelease_token = "rc" 94 | build_command = "pip install poetry && poetry build" 95 | 96 | [project.urls] 97 | "Homepage" = "https://github.com/Westfall-io/sysml2py" 98 | "Bug Tracker" = "https://github.com/Westfall-io/sysml2py/issues" 99 | 100 | [tool.poetry] 101 | name = "sysml2py" 102 | version = "0.5.3" 103 | description = "" 104 | authors = ["Christopher Cox "] 105 | readme = "README.md" 106 | packages = [{ include = "sysml2py", from = "src" }] 107 | 108 | [tool.poetry.dependencies] 109 | python = "^3.9" 110 | textx = "^3.1.1" 111 | astropy = "^5.3.1" 112 | pyyaml = "^6.0.1" 113 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | PyYAML==6.0.1 2 | textX==3.1.1 3 | astropy==5.3.4 4 | mypy==1.4.1 5 | -------------------------------------------------------------------------------- /src/sysml2py/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Mon May 29 23:26:16 2023 5 | 6 | @author: christophercox 7 | """ 8 | 9 | __all__ = ["load", "loads", "load_grammar"] 10 | __author__ = "Christopher Cox" 11 | __version__ = "0.1.0" 12 | 13 | # These are interchangable 14 | from sysml2py.usage import Item, Attribute, Part, Port 15 | 16 | # These are definition only 17 | from sysml2py.definition import Model, Package 18 | 19 | 20 | def enforce_grammar(): # pragma: no cover 21 | """Enforce grammar compiles the language for xtext 22 | 23 | This opens each of the files: KerMLExpressions, KerML, and SysML and 24 | makes a superfile with all of the definitions and strips the comments. This 25 | includes changes made to shift from java textx to the python xtext library. 26 | 27 | """ 28 | import re 29 | 30 | comments_strip_rule = r"(?:(?:(? ModelType: 36 | from sysml2py import load_grammar 37 | 38 | # Try to load the grammar from the string 39 | definition = load_grammar(s)["ownedRelationship"] 40 | 41 | # Add each sub-element to children. 42 | member_grammar = [] 43 | for member in definition: 44 | if member["ownedRelatedElement"]["name"] == "DefinitionElement": 45 | de = member["ownedRelatedElement"] 46 | if de["ownedRelatedElement"]["name"] == "Package": 47 | p = Package().load_from_grammar( 48 | PackageGrammar(de["ownedRelatedElement"]) 49 | ) 50 | self.children.append(p) 51 | member_grammar.append(p._get_definition(child="PackageBody")) 52 | else: 53 | raise ValueError("Base Model must be encapsulated by a package.") 54 | else: 55 | raise ValueError("Base Model must be encapsulated by a package.") 56 | 57 | self.grammar = RootNamespace( 58 | {"name": "PackageBodyElement", "ownedRelationship": member_grammar} 59 | ) 60 | 61 | return self 62 | 63 | def _ensure_body(self): 64 | # Add children 65 | body = [] 66 | for abc in self.children: 67 | v = abc._get_definition(child="PackageBody") 68 | if isinstance(v, list): 69 | for subchild in v: 70 | body.append(PackageMember(subchild).get_definition()) 71 | else: 72 | body.append(PackageMember(v).get_definition()) 73 | 74 | if len(body) > 0: 75 | self.grammar = RootNamespace( 76 | {"name": "PackageBodyElement", "ownedRelationship": body} 77 | ) 78 | 79 | return self 80 | 81 | def _get_definition(self): 82 | return self.grammar.get_definition() 83 | 84 | def dump(self): 85 | if len(self.children) == 0: 86 | raise ValueError("Base Model has no elements to output.") 87 | 88 | self._ensure_body() 89 | return classtree(self._get_definition()).dump() 90 | 91 | def _set_child(self, child): 92 | self.children.append(child) 93 | return self 94 | 95 | def _get_child(self, featurechain): 96 | # 'x.y.z' 97 | if isinstance(featurechain, str): 98 | fc = featurechain.split(".") 99 | else: 100 | raise TypeError 101 | 102 | if fc[0] == self.name: 103 | # This first one must match self name, otherwise pass it all 104 | featurechain = ".".join(fc[1:]) 105 | 106 | for child in self.children: 107 | fcs = featurechain.split(".") 108 | if child.name == fcs[0]: 109 | if len(fcs) == 1: 110 | return child 111 | else: 112 | return child._get_child(featurechain) 113 | 114 | 115 | class Package: 116 | def __init__(self): 117 | self.name = str(uuidlib.uuid4()) 118 | self.children = [] 119 | self.typedby = None 120 | self.grammar = PackageGrammar() 121 | 122 | def _set_name(self, name, short=False): 123 | if short: 124 | if self.grammar.declaration.identification is None: 125 | self.grammar.declaration.identification = Identification() 126 | self.grammar.declaration.identification.declaredShortName = "<" + name + ">" 127 | else: 128 | self.name = name 129 | if self.grammar.declaration.identification is None: 130 | self.grammar.declaration.identification = Identification() 131 | self.grammar.declaration.identification.declaredName = name 132 | 133 | return self 134 | 135 | def _get_name(self): 136 | return self.grammar.declaration.identification.declaredName 137 | 138 | def _set_child(self, child): 139 | self.children.append(child) 140 | return self 141 | 142 | def _get_child(self, featurechain): 143 | # 'x.y.z' 144 | if isinstance(featurechain, str): 145 | fc = featurechain.split(".") 146 | else: 147 | raise TypeError 148 | 149 | if fc[0] == self.name: 150 | # This first one must match self name, otherwise pass it all 151 | featurechain = ".".join(fc[1:]) 152 | 153 | for child in self.children: 154 | fcs = featurechain.split(".") 155 | if child.name == fcs[0]: 156 | if len(fcs) == 1: 157 | return child 158 | else: 159 | return child._get_child(featurechain) 160 | 161 | def _ensure_body(self): 162 | # Add children 163 | body = [] 164 | for abc in self.children: 165 | v = abc._get_definition(child="PackageBody") 166 | if isinstance(v, list): 167 | for subchild in v: 168 | body.append(PackageMember(subchild).get_definition()) 169 | else: 170 | body.append(PackageMember(v).get_definition()) 171 | if len(body) > 0: 172 | self.grammar.body = PackageBody( 173 | {"name": "PackageBody", "ownedRelationship": body} 174 | ) 175 | 176 | def _get_definition(self, child=None): 177 | self._ensure_body() 178 | 179 | package = { 180 | "name": "DefinitionElement", 181 | "ownedRelatedElement": self.grammar.get_definition(), 182 | } 183 | package = { 184 | "name": "PackageMember", 185 | "ownedRelatedElement": package, 186 | "prefix": None, 187 | } 188 | if not child: 189 | package = { 190 | "name": "PackageBodyElement", 191 | "ownedRelationship": [package], 192 | "prefix": None, 193 | } 194 | 195 | # Add the typed by definition to the package output 196 | if self.typedby is not None: 197 | # Packages cannot be typed, they should import from other packages 198 | raise NotImplementedError 199 | 200 | return package 201 | 202 | def dump(self, child=None): 203 | return classtree(self._get_definition(child=False)).dump() 204 | 205 | def load_from_grammar(self, grammar): 206 | self.name = grammar.declaration.identification.declaredName 207 | self.grammar = grammar 208 | for child in grammar.body.children: 209 | if child.children[0].__class__.__name__ == "UsageElement": 210 | # PackageMember -> UsageElement 211 | if ( 212 | child.children[0].children.children.children.__class__.__name__ 213 | == "ItemUsage" 214 | ): 215 | self.children.append( 216 | Item().load_from_grammar( 217 | child.children[0].children.children.children 218 | ) 219 | ) 220 | elif ( 221 | child.children[0].children.children.children.__class__.__name__ 222 | == "PartUsage" 223 | ): 224 | self.children.append( 225 | Part().load_from_grammar( 226 | child.children[0].children.children.children 227 | ) 228 | ) 229 | else: 230 | print(child.children[0].children[0].__class__.__name__) 231 | raise NotImplementedError 232 | else: 233 | # Not a UsageElement 234 | if child.children[0].children[0].__class__.__name__ == "Package": 235 | self.children.append( 236 | Package().load_from_grammar(child.children[0].children[0]) 237 | ) 238 | elif ( 239 | child.children[0].children[0].__class__.__name__ == "ItemDefinition" 240 | ): 241 | self.children.append( 242 | Item().load_from_grammar(child.children[0].children[0]) 243 | ) 244 | else: 245 | print(child.children[0].children[0].__class__.__name__) 246 | raise NotImplementedError 247 | 248 | # self.children.append() 249 | return self 250 | 251 | def _get_grammar(self): 252 | # Force updates to grammar if something has changed. 253 | self._ensure_body() 254 | return self.grammar 255 | -------------------------------------------------------------------------------- /src/sysml2py/formatting.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Wed May 31 13:26:53 2023 5 | 6 | @author: christophercox 7 | """ 8 | 9 | from sysml2py.grammar.classes import RootNamespace 10 | 11 | 12 | def remove_classes(model): 13 | """An example docstring for a class definition.""" 14 | if type(model) == type(dict()): 15 | output = {} 16 | for element in model: 17 | if not "_" in element[0] and not "parent" in element: 18 | # Remove internal parsing elements 19 | output[element] = remove_classes(model[element]) 20 | elif type(model) == type(list()): 21 | # List of classes 22 | output = [] 23 | for member in model: 24 | output.append(remove_classes(member)) 25 | elif type(model) == type(None): 26 | return None 27 | elif type(model) == type(bool()) or type(model) == type(str()): 28 | return model 29 | else: 30 | output = {"name": model.__class__.__name__} 31 | model_out = remove_classes(model.__dict__) 32 | output.update(model_out) 33 | 34 | return output 35 | 36 | 37 | def reformat(model): 38 | """An example docstring for a class definition.""" 39 | # Convert to dictionary format 40 | model_out = {"name": model.__class__.__name__} 41 | model_out.update(remove_classes(model.__dict__)) 42 | 43 | return model_out 44 | 45 | 46 | def classtree(model): 47 | return RootNamespace(model) 48 | -------------------------------------------------------------------------------- /src/sysml2py/grammar/KerML.tx: -------------------------------------------------------------------------------- 1 | import KerMLExpressions 2 | /***************************************************************************** 3 | * SysML 2 Pilot Implementation 4 | * Copyright (c) 2018-2023 Model Driven Solutions, Inc. 5 | * Copyright (c) 2018 IncQuery Labs Ltd. 6 | * Copyright (c) 2019 Maplesoft (Waterloo Maple, Inc.) 7 | * Copyright (c) 2019 Mgnite Inc. 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public License 20 | * along with this program. If not, see . 21 | * 22 | * @license LGPL-3.0-or-later 23 | * 24 | * Contributors: 25 | * Ed Seidewitz, MDS 26 | * Zoltan Kiss, IncQuery 27 | * Balazs Grill, IncQuery 28 | * Hisashi Miyashita, Maplesoft/Mgnite 29 | * 30 | *****************************************************************************/ 31 | 32 | /* ROOT NAMESPACE */ 33 | 34 | RootNamespace : 35 | NamespaceBodyElement* 36 | ; 37 | 38 | /* ELEMENTS */ 39 | 40 | /* Elements */ 41 | 42 | Identification : 43 | '<' declaredShortName = Name '>' ( declaredName = Name )? 44 | | declaredName = Name 45 | ; 46 | 47 | /* Relationships */ 48 | 49 | RelationshipBody : 50 | ';' | '{' RelationshipOwnedElement* '}' 51 | ; 52 | 53 | RelationshipOwnedElement : 54 | ownedRelatedElement += OwnedRelatedElement 55 | | ownedRelationship += OwnedAnnotation 56 | ; 57 | 58 | OwnedRelatedElement : 59 | NonFeatureElement | FeatureElement 60 | ; 61 | 62 | /* DEPENDENCIES */ 63 | 64 | Dependency : 65 | ( ownedRelationship += PrefixMetadataAnnotation )* 66 | 'dependency' ( Identification? 'from' )? 67 | client += QualifiedName ( ',' client += QualifiedName )* 'to' 68 | supplier += QualifiedName ( ',' supplier += QualifiedName )* 69 | RelationshipBody 70 | ; 71 | 72 | /* ANNOTATIONS */ 73 | 74 | Annotation : 75 | annotatedElement = QualifiedName 76 | ; 77 | 78 | OwnedAnnotation : 79 | ownedRelatedElement += AnnotatingElement 80 | ; 81 | 82 | AnnotatingElement : 83 | CommentKerML 84 | | Documentation 85 | | TextualRepresentation 86 | | MetadataFeature 87 | ; 88 | 89 | /* Comments */ 90 | 91 | CommentKerML : 92 | // Comment is reserved in TextX 93 | ( 'comment' Identification? 94 | ('about' ownedRelationship += Annotation 95 | ( ',' ownedRelationship += Annotation )* )? 96 | )? 97 | body = REGULAR_COMMENT 98 | ; 99 | 100 | Documentation : 101 | 'doc' Identification? body=REGULAR_COMMENT 102 | ; 103 | 104 | /* Textual Representation */ 105 | 106 | TextualRepresentation : 107 | ( 'rep' Identification? )? 108 | 'language' language = STRING_VALUE 109 | body = REGULAR_COMMENT 110 | ; 111 | 112 | /* NAMESPACES */ 113 | 114 | Namespace : 115 | ( ownedRelationship += PrefixMetadataMember )* 116 | NamespaceDeclaration NamespaceBody 117 | ; 118 | 119 | NamespaceDeclaration : 120 | 'namespace' Identification? 121 | ; 122 | 123 | NamespaceBody : 124 | ';' 125 | | '{' ( // Note: PackageBodyElement is expanded here to avoid 126 | // infinite loops in the incremental parser. 127 | ownedRelationship += NamespaceMember 128 | | ownedRelationship += AliasMember 129 | | ownedRelationship += Import )* 130 | '}' 131 | ; 132 | 133 | /* Namespace Bodies */ 134 | 135 | NamespaceBodyElement : 136 | ownedRelationship += NamespaceMember 137 | | ownedRelationship += AliasMember 138 | | ownedRelationship += Import 139 | ; 140 | 141 | MemberPrefix : 142 | ( visibility = VisibilityIndicator )? 143 | ; 144 | 145 | NamespaceMember : 146 | NonFeatureMember | NamespaceFeatureMember 147 | ; 148 | 149 | NonFeatureMember : 150 | MemberPrefix ownedRelatedElement += MemberElement 151 | ; 152 | 153 | NamespaceFeatureMember : 154 | MemberPrefix ownedRelatedElement += FeatureElement 155 | ; 156 | 157 | AliasMember : 158 | MemberPrefix 159 | 'alias' ( '<' memberShortName = Name '>' )? ( memberName = Name )? 160 | 'for' memberElement = QualifiedName 161 | RelationshipBody 162 | ; 163 | 164 | ImportPrefix : 165 | ( visibility = VisibilityIndicator )? 166 | 'import' ( isImportAll ?= 'all' )? 167 | ; 168 | 169 | Import : 170 | ( MembershipImport | NamespaceImport ) 171 | RelationshipBody 172 | ; 173 | 174 | MembershipImport : 175 | ImportPrefix ImportedMembership 176 | ; 177 | 178 | ImportedMembership : 179 | importedMembership = QualifiedName 180 | ( '::' isRecursive ?= '**' )? 181 | ; 182 | 183 | NamespaceImport : 184 | ImportPrefix 185 | ( ImportedNamespace 186 | | ownedRelatedElement += FilterPackage 187 | ) 188 | ; 189 | 190 | ImportedNamespace : 191 | importedNamespace = QualifiedName '::' '*' 192 | ( '::' isRecursive ?= '**' )? 193 | ; 194 | 195 | FilterPackage : 196 | ownedRelationship += FilterPackageImport 197 | ( ownedRelationship += FilterPackageMember )+ 198 | ; 199 | 200 | FilterPackageImport : 201 | FilterPackageMembershipImport | FilterPackageNamespaceImport 202 | ; 203 | 204 | FilterPackageMembershipImport : 205 | ImportedMembership 206 | ; 207 | 208 | FilterPackageNamespaceImport : 209 | ImportedNamespace 210 | ; 211 | 212 | FilterPackageMember : 213 | visibility = FilterPackageMemberVisibility ownedRelatedElement += OwnedExpression ']' 214 | ; 215 | 216 | FilterPackageMemberVisibility : 217 | private = '[' 218 | ; 219 | 220 | VisibilityIndicator : 221 | public = 'public' | private = 'private' | protected = 'protected' 222 | ; 223 | 224 | /* Namespace Elements */ 225 | 226 | MemberElement : 227 | AnnotatingElement | NonFeatureElement 228 | ; 229 | 230 | NonFeatureElement : 231 | Dependency 232 | | Namespace 233 | | Package 234 | | LibraryPackage 235 | | Multiplicity 236 | | Type 237 | | Classifier 238 | | Class 239 | | Structure 240 | | Metaclass 241 | | DataType 242 | | Association 243 | | AssociationStructure 244 | | Interaction 245 | | Behavior 246 | | Function 247 | | Predicate 248 | | Specialization 249 | | Conjugation 250 | | FeatureTyping 251 | | Subclassification 252 | | Disjoining 253 | | FeatureInverting 254 | | Subsetting 255 | | Redefinition 256 | | TypeFeaturing 257 | ; 258 | 259 | FeatureElement : 260 | Feature 261 | | Step 262 | | Expression 263 | | BooleanExpression 264 | | Invariant 265 | | Connector 266 | | BindingConnector 267 | | Succession 268 | | ItemFlow 269 | | SuccessionItemFlow 270 | ; 271 | 272 | /* PACKAGES */ 273 | 274 | Package : 275 | ( ownedRelationship += PrefixMetadataMember )* 276 | PackageDeclaration PackageBody 277 | ; 278 | 279 | LibraryPackage : 280 | ( isStandard ?= 'standard' )? 'library' 281 | ( ownedRelationship += PrefixMetadataMember )* 282 | PackageDeclaration PackageBody 283 | ; 284 | 285 | PackageDeclaration : 286 | 'package' Identification? 287 | ; 288 | 289 | PackageBody : 290 | ';' 291 | | '{' ( // Note: PackageBodyElement is expanded here to avoid 292 | // infinite loops in the incremental parser. 293 | ownedRelationship += NamespaceMember 294 | | ownedRelationship += ElementFilterMember 295 | | ownedRelationship += AliasMember 296 | | ownedRelationship += Import )* 297 | '}' 298 | ; 299 | 300 | ElementFilterMember : 301 | MemberPrefix 302 | 'filter' ownedRelatedElement += OwnedExpression ';' 303 | ; 304 | 305 | /* TYPES */ 306 | 307 | /* Types */ 308 | 309 | TypePrefix : 310 | ( isAbstract ?= 'abstract' )? 311 | ( ownedRelationship += PrefixMetadataMember )* 312 | ; 313 | 314 | Type : 315 | TypePrefix 'type' 316 | TypeDeclaration TypeBody 317 | ; 318 | 319 | TypeDeclaration : 320 | ( isSufficient ?= 'all' )? Identification? 321 | ( ownedRelationship += OwnedMultiplicity )? 322 | ( SpecializationPart | ConjugationPart )+ 323 | TypeRelationshipPart* 324 | ; 325 | 326 | SpecializationPart : 327 | ( ':>' | 'specializes' ) ownedRelationship += OwnedSpecialization 328 | ( ',' ownedRelationship += OwnedSpecialization )* 329 | ; 330 | 331 | ConjugationPart : 332 | ( '~' | 'conjugates' ) ownedRelationship += OwnedConjugation 333 | ; 334 | 335 | TypeRelationshipPart : 336 | DisjoiningPart | UnioningPart | IntersectingPart | DifferencingPart 337 | ; 338 | 339 | DisjoiningPart : 340 | 'disjoint' 'from' ownedRelationship += OwnedDisjoining 341 | ( ',' ownedRelationship += OwnedDisjoining )* 342 | ; 343 | 344 | UnioningPart : 345 | 'unions' ownedRelationship += Unioning 346 | ( ',' ownedRelationship += Unioning )* 347 | ; 348 | 349 | IntersectingPart : 350 | 'intersects' ownedRelationship += Intersecting 351 | ( ',' ownedRelationship += Intersecting )* 352 | ; 353 | 354 | DifferencingPart : 355 | 'differences' ownedRelationship += Differencing 356 | ( ',' ownedRelationship += Differencing )* 357 | ; 358 | 359 | TypeBody : 360 | ';' 361 | | '{' ( ownedRelationship += NonFeatureMember 362 | | ownedRelationship += FeatureMember 363 | | ownedRelationship += AliasMember 364 | | ownedRelationship += Import 365 | )* 366 | '}' 367 | ; 368 | 369 | /* Feature Membership */ 370 | 371 | FeatureMember : 372 | TypeFeatureMember | OwnedFeatureMember 373 | ; 374 | 375 | TypeFeatureMember : 376 | MemberPrefix 'member' ownedRelatedElement += FeatureElement 377 | ; 378 | 379 | OwnedFeatureMember : 380 | MemberPrefix ownedRelatedElement += FeatureElement 381 | ; 382 | 383 | /* Specialization */ 384 | 385 | Specialization : 386 | ( 'specialization' Identification? )? 387 | 'subtype' 388 | ( specific = QualifiedName 389 | | ownedRelatedElement += OwnedFeatureChain ) 390 | ( ':>' | 'specializes') 391 | ( general = QualifiedName 392 | | ownedRelatedElement += OwnedFeatureChain ) 393 | RelationshipBody 394 | ; 395 | 396 | OwnedSpecialization : 397 | general = QualifiedName 398 | | ownedRelatedElement += OwnedFeatureChain 399 | ; 400 | 401 | /* Conjugation */ 402 | 403 | Conjugation : 404 | ( 'conjugation' Identification? )? 405 | 'conjugate' 406 | ( conjugatedType = QualifiedName 407 | | ownedRelatedElement += OwnedFeatureChain ) 408 | ( '~' | 'conjugates') 409 | ( originalType = QualifiedName 410 | | ownedRelatedElement += OwnedFeatureChain ) 411 | RelationshipBody 412 | ; 413 | 414 | OwnedConjugation : 415 | originalType = QualifiedName 416 | | ownedRelatedElement += OwnedFeatureChain 417 | ; 418 | 419 | /* Disjoining */ 420 | 421 | Disjoining : 422 | ( 'disjoining' Identification? )? 423 | 'disjoint' 424 | ( typeDisjoined = QualifiedName 425 | | ownedRelatedElement += OwnedFeatureChain ) 426 | 'from' 427 | ( disjoiningType = QualifiedName 428 | | ownedRelatedElement += OwnedFeatureChain ) 429 | RelationshipBody 430 | ; 431 | 432 | OwnedDisjoining : 433 | disjoiningType = QualifiedName 434 | | ownedRelatedElement += OwnedFeatureChain 435 | ; 436 | 437 | /* Unioning, Intersecting and Differencing */ 438 | 439 | Unioning : 440 | unioningType = QualifiedName 441 | | ownedRelatedElement += OwnedFeatureChain 442 | ; 443 | 444 | Intersecting : 445 | intersectingType = QualifiedName 446 | | ownedRelatedElement += OwnedFeatureChain 447 | ; 448 | 449 | Differencing : 450 | differencingType = QualifiedName 451 | | ownedRelatedElement += OwnedFeatureChain 452 | ; 453 | 454 | /* CLASSIFIERS */ 455 | 456 | /* Classifiers */ 457 | 458 | Classifier : 459 | TypePrefix 'classifier' 460 | ClassifierDeclaration TypeBody 461 | ; 462 | 463 | ClassifierDeclaration : 464 | (isSufficient ?= 'all' )? Identification? 465 | ( ownedRelationship += OwnedMultiplicity )? 466 | ( SuperclassingPart | ClassifierConjugationPart )? 467 | TypeRelationshipPart* 468 | ; 469 | 470 | SuperclassingPart : 471 | ( ':>' | 'specializes' ) ownedRelationship += Ownedsubclassification 472 | ( ',' ownedRelationship += Ownedsubclassification )* 473 | ; 474 | 475 | ClassifierConjugationPart : 476 | ( '~' | 'conjugates' ) ownedRelationship += ClassifierConjugation 477 | ; 478 | 479 | /* Subclassification */ 480 | 481 | Subclassification : 482 | ( 'specialization' Identification? )? 483 | 'subclassifier' subclassifier = QualifiedName 484 | ( ':>' | 'specializes') superclassifier = QualifiedName 485 | RelationshipBody 486 | ; 487 | 488 | Ownedsubclassification : 489 | superclassifier = QualifiedName 490 | ; 491 | 492 | /* Classifier Conjugation */ 493 | 494 | ClassifierConjugation : 495 | originalType = QualifiedName 496 | ; 497 | 498 | /* FEATURES */ 499 | 500 | /* Features */ 501 | 502 | FeatureDirection : 503 | in = 'in' | out = 'out' | inout = 'inout' 504 | ; 505 | 506 | FeaturePrefix : 507 | ( direction = FeatureDirection )? 508 | ( isAbstract ?= 'abstract' )? 509 | ( isComposite ?= 'composite' | isPortion ?= 'portion' )? 510 | ( isReadOnly ?= 'readonly' )? 511 | ( isDerived ?= 'derived' )? 512 | ( isEnd ?= 'end' )? 513 | ( ownedRelationship += PrefixMetadataMember )* 514 | ; 515 | 516 | Feature : 517 | FeaturePrefix 518 | ( 'feature'? FeatureDeclaration 519 | | ownedRelationship += PrefixMetadataMember 520 | | 'feature' 521 | ) 522 | ValuePart? TypeBody 523 | ; 524 | 525 | FeatureDeclaration : 526 | ( isSufficient ?= 'all' )? 527 | ( Identification ( FeatureSpecializationPart | FeatureConjugationPart )? 528 | | FeatureSpecializationPart 529 | | FeatureConjugationPart 530 | ) 531 | FeatureRelationshipPart* 532 | ; 533 | 534 | FeatureRelationshipPart : 535 | TypeRelationshipPart | ChainingPart | InvertingPart | TypeFeaturingPart 536 | ; 537 | 538 | ChainingPart : 539 | 'chains' ( ownedRelationship += OwnedFeatureChaining | FeatureChain ) 540 | ; 541 | 542 | InvertingPart : 543 | 'inverse' 'of' ownedRelationship += OwnedFeatureInverting 544 | ; 545 | 546 | TypeFeaturingPart : 547 | 'featured' 'by' ownedRelationship += OwnedTypeFeaturing 548 | ( ',' ownedRelationship += OwnedTypeFeaturing )* 549 | ; 550 | 551 | FeatureSpecializationPart : 552 | ( FeatureSpecialization )+ MultiplicityPart? FeatureSpecialization* 553 | | MultiplicityPart FeatureSpecialization* 554 | ; 555 | 556 | MultiplicityPart : 557 | ownedRelationship += OwnedMultiplicity 558 | | ( ownedRelationship += OwnedMultiplicity )? 559 | 560 | ( isOrdered ?= 'ordered' isNonunique ?= 'nonunique' 561 | | isNonunique2 ?= 'nonunique' isOrdered2 ?= 'ordered' 562 | ) 563 | 564 | ; 565 | 566 | FeatureSpecialization : 567 | typings=Typings | Subsettings | References | Redefinitions 568 | ; 569 | 570 | Typings : 571 | typedby=TypedBy ( ',' ownedRelationship += OwnedFeatureTyping )* 572 | ; 573 | 574 | TypedBy : 575 | ( ':' | 'typed' 'by' ) ownedRelationship += OwnedFeatureTyping 576 | ; 577 | 578 | Subsettings : 579 | Subsets ( ',' ownedRelationship += OwnedSubsetting )* 580 | ; 581 | 582 | Subsets : 583 | ( ':>' | 'subsets' ) ownedRelationship += OwnedSubsetting 584 | ; 585 | 586 | References : 587 | ReferencesKeyword ownedRelationship += OwnedReferenceSubsetting 588 | ; 589 | 590 | ReferencesKeyword : 591 | '::>' | 'references' 592 | ; 593 | 594 | Redefinitions : 595 | Redefines ( ',' ownedRelationship += OwnedRedefinition )* 596 | ; 597 | 598 | Redefines : 599 | ( ':>>' | 'redefines' ) ownedRelationship += OwnedRedefinition 600 | ; 601 | 602 | /* Feature Inverting */ 603 | 604 | FeatureInverting : 605 | ( 'inverting' Identification? )? 606 | 'inverse' 607 | ( featureInverted = QualifiedName 608 | | ownedRelatedElement += OwnedFeatureChain ) 609 | 'of' 610 | ( invertingFeature = QualifiedName 611 | | ownedRelatedElement += OwnedFeatureChain ) 612 | RelationshipBody 613 | ; 614 | 615 | OwnedFeatureInverting : 616 | invertingFeature = QualifiedName 617 | | ownedRelatedElement += OwnedFeatureChain 618 | ; 619 | 620 | /* Type Featuring */ 621 | 622 | TypeFeaturing : 623 | 'featuring' ( Identification? 'of')? 624 | featureOfType = QualifiedName 625 | 'by' featuringType = QualifiedName 626 | RelationshipBody 627 | ; 628 | 629 | OwnedTypeFeaturing : 630 | featuringType = QualifiedName 631 | ; 632 | 633 | /* Feature Typing */ 634 | 635 | FeatureTyping : 636 | ( 'specialization' Identification? )? 637 | 'typing' typedFeature = QualifiedName 638 | (':' | 'typed' 'by') type=FeatureType 639 | RelationshipBody 640 | ; 641 | 642 | 643 | OwnedFeatureTyping : 644 | type=FeatureType 645 | ; 646 | 647 | FeatureType : 648 | type = QualifiedName | ownedRelatedElement += OwnedFeatureChain 649 | ; 650 | 651 | /* Subsetting */ 652 | 653 | Subsetting : 654 | ( 'specialization' Identification? )? 655 | 'subset' 656 | ( subsettingFeature = QualifiedName 657 | | ownedRelatedElement += OwnedFeatureChain ) 658 | ( ':>' | 'subsets' ) 659 | ( subsettedFeature = QualifiedName 660 | | ownedRelatedElement += OwnedFeatureChain ) 661 | RelationshipBody 662 | ; 663 | 664 | OwnedSubsetting : 665 | subsettedFeature = QualifiedName 666 | | ownedRelatedElement += OwnedFeatureChain 667 | ; 668 | 669 | OwnedReferenceSubsetting : 670 | referencedFeature = QualifiedName 671 | | ownedRelatedElement += OwnedFeatureChain 672 | ; 673 | 674 | /* Redefinition */ 675 | 676 | Redefinition : 677 | ( 'specialization' Identification? )? 678 | 'redefinition' 679 | ( redefiningFeature = QualifiedName 680 | | ownedRelatedElement += OwnedFeatureChain ) 681 | ( ':>>' | 'redefines' ) 682 | ( redefinedFeature = QualifiedName 683 | | ownedRelatedElement += OwnedFeatureChain ) 684 | RelationshipBody 685 | ; 686 | 687 | OwnedRedefinition : 688 | redefinedFeature = QualifiedName 689 | | ownedRelatedElement += OwnedFeatureChain 690 | ; 691 | 692 | /* Feature Conjugation */ 693 | 694 | FeatureConjugationPart : 695 | ( '~' | 'conjugates' ) ownedRelationship += FeatureConjugation 696 | ; 697 | 698 | FeatureConjugation : 699 | originalType = QualifiedName 700 | ; 701 | 702 | /* FEATURE VALUES */ 703 | 704 | ValuePart : 705 | ownedRelationship += FeatureValue 706 | | ownedRelationship += FeatureValueExpression 707 | ownedRelationship += EmptyFeatureWriteMember 708 | ; 709 | 710 | FeatureValue : 711 | ( '=' | isDefault ?= 'default' ( '=' | isInitial ?= ':=' )? ) 712 | ownedRelatedElement = OwnedExpression 713 | ; 714 | 715 | FeatureValueExpression : 716 | isInitial ?= ':=' 717 | ownedRelatedElement += OwnedExpression 718 | ; 719 | 720 | EmptyFeatureWriteMember : 721 | ownedRelatedElement += EmptyFeatureWrite 722 | ; 723 | 724 | EmptyFeatureWrite : 725 | ownedRelationship += EmptyTargetMember 726 | ownedRelationship += EmptyParameterMember 727 | ; 728 | 729 | EmptyTargetMember : 730 | ownedRelatedElement += EmptyTargetParameter 731 | ; 732 | 733 | EmptyTargetParameter : 734 | ownedRelationship += TargetFeatureMember 735 | ; 736 | 737 | TargetFeatureMember : 738 | ownedRelatedElement += TargetFeature 739 | ; 740 | 741 | TargetFeature : 742 | ownedRelationship += EmptyFeatureMember 743 | ; 744 | 745 | EmptyFeatureMember : 746 | ownedRelatedElement += EmptyFeature 747 | ; 748 | 749 | EmptyParameterMember : 750 | ownedRelatedElement += EmptyFeature 751 | ; 752 | 753 | /* MULTIPLICITIES */ 754 | 755 | Multiplicity : 756 | MultiplicitySubset | MultiplicityRange 757 | ; 758 | 759 | MultiplicitySubset : 760 | 'multiplicity' Identification? Subsets TypeBody 761 | ; 762 | 763 | MultiplicityRange : 764 | 'multiplicity' Identification? MultiplicityBounds TypeBody 765 | ; 766 | 767 | OwnedMultiplicity : 768 | ownedRelatedElement += OwnedMultiplicityRange 769 | ; 770 | 771 | OwnedMultiplicityRange : 772 | MultiplicityBounds 773 | ; 774 | 775 | MultiplicityBounds : 776 | // TODO: Allow general expressions for bounds. (Causes LL parsing issues.) 777 | '[' ownedRelationship += MultiplicityExpressionMember 778 | ( '..' ownedRelationship += MultiplicityExpressionMember )? ']' 779 | ; 780 | 781 | 782 | MultiplicityRelatedElement : 783 | (LiteralExpression | FeatureReferenceExpression) 784 | ; 785 | 786 | MultiplicityExpressionMember : 787 | ownedRelatedElement += MultiplicityRelatedElement 788 | ; 789 | 790 | /* CLASSIFICATION */ 791 | 792 | /* Data Types */ 793 | 794 | DataType : 795 | TypePrefix 'datatype' 796 | ClassifierDeclaration TypeBody 797 | ; 798 | 799 | /* Classes */ 800 | 801 | Class : 802 | TypePrefix 'class' 803 | ClassifierDeclaration TypeBody 804 | ; 805 | 806 | /* STRUCTURES */ 807 | 808 | Structure : 809 | TypePrefix 'struct' 810 | ClassifierDeclaration TypeBody 811 | ; 812 | 813 | 814 | /* ASSOCIATIONS */ 815 | 816 | Association : 817 | TypePrefix 'assoc' 818 | ClassifierDeclaration TypeBody 819 | ; 820 | 821 | AssociationStructure : 822 | TypePrefix 'assoc' 'struct' 823 | ClassifierDeclaration TypeBody 824 | ; 825 | 826 | /* CONNECTORS */ 827 | 828 | /* Connectors */ 829 | 830 | Connector : 831 | FeaturePrefix 'connector' 832 | ConnectorDeclaration TypeBody 833 | ; 834 | 835 | ConnectorDeclaration : 836 | BinaryConnectorDeclaration | NaryConnectorDeclaration 837 | ; 838 | 839 | BinaryConnectorDeclaration : 840 | ( FeatureDeclaration? 'from' | isSufficient ?= 'all' 'from'? )? 841 | ownedRelationship += ConnectorEndMember 'to' 842 | ownedRelationship += ConnectorEndMember 843 | ; 844 | 845 | NaryConnectorDeclaration : 846 | FeatureDeclaration? 847 | ( '(' ownedRelationship += ConnectorEndMember ',' 848 | ownedRelationship += ConnectorEndMember 849 | ( ',' ownedRelationship += ConnectorEndMember )* 850 | ')' )? 851 | ; 852 | 853 | ConnectorEndMember : 854 | ownedRelatedElement += ConnectorEnd 855 | ; 856 | 857 | ConnectorEnd : 858 | ( declaredName = Name ReferencesKeyword )? 859 | ownedRelationship += OwnedReferenceSubsetting 860 | ( ownedRelationship += OwnedMultiplicity )? 861 | ; 862 | 863 | /* Binding Connectors */ 864 | 865 | BindingConnector : 866 | FeaturePrefix 'binding' 867 | BindingConnectorDeclaration TypeBody 868 | ; 869 | 870 | BindingConnectorDeclaration : 871 | FeatureDeclaration 872 | ( 'of' ownedRelationship += ConnectorEndMember 873 | '=' ownedRelationship += ConnectorEndMember )? 874 | | ( isSufficient ?= 'all' )? 875 | ( 'of'? ownedRelationship += ConnectorEndMember 876 | '=' ownedRelationship += ConnectorEndMember )? 877 | ; 878 | 879 | /* Successions */ 880 | 881 | Succession : 882 | FeaturePrefix 'succession' 883 | SuccessionDeclaration TypeBody 884 | ; 885 | 886 | SuccessionDeclaration : 887 | FeatureDeclaration 888 | ( 'first' ownedRelationship += ConnectorEndMember 889 | 'then' ownedRelationship += ConnectorEndMember )? 890 | | ( isSufficient ?= 'all' )? 891 | ( 'first'? ownedRelationship += ConnectorEndMember 892 | 'then' ownedRelationship += ConnectorEndMember )? 893 | ; 894 | 895 | /* BEHAVIORS */ 896 | 897 | /* Behaviors */ 898 | 899 | Behavior : 900 | TypePrefix 'behavior' 901 | ClassifierDeclaration TypeBody 902 | ; 903 | 904 | /* Steps */ 905 | 906 | Step : 907 | FeaturePrefix 'step' 908 | StepDeclaration TypeBody 909 | ; 910 | 911 | StepDeclaration : 912 | FeatureDeclaration? ValuePart? 913 | ; 914 | 915 | /* FUNCTIONS */ 916 | 917 | /* Functions */ 918 | 919 | Function : 920 | TypePrefix 'function' 921 | ClassifierDeclaration FunctionBody 922 | ; 923 | 924 | FunctionBody : 925 | ';' | '{' FunctionBodyPart '}' 926 | ; 927 | 928 | FunctionBodyPart : 929 | ( ownedRelationship += NonFeatureMember 930 | | ownedRelationship += FeatureMember 931 | | ownedRelationship += AliasMember 932 | | ownedRelationship += Import 933 | | ownedRelationship += ReturnFeatureMember 934 | )* 935 | ( ownedRelationship += ResultExpressionMember )? 936 | ; 937 | 938 | ReturnFeatureMember : 939 | MemberPrefix 'return' ownedRelatedElement += FeatureElement 940 | ; 941 | 942 | 943 | ResultExpressionMember : 944 | MemberPrefix ownedRelatedElement += OwnedExpression 945 | ; 946 | 947 | /* Expressions */ 948 | 949 | Expression : 950 | FeaturePrefix 'expr' 951 | ExpressionDeclaration FunctionBody 952 | ; 953 | 954 | ExpressionDeclaration : 955 | FeatureDeclaration? ValuePart? 956 | ; 957 | 958 | /* Predicates */ 959 | 960 | Predicate : 961 | TypePrefix 'predicate' 962 | ClassifierDeclaration FunctionBody 963 | ; 964 | 965 | /* Boolean Expressions */ 966 | 967 | BooleanExpression : 968 | FeaturePrefix 'bool' 969 | ExpressionDeclaration FunctionBody 970 | ; 971 | 972 | /* Invariants */ 973 | 974 | Invariant : 975 | FeaturePrefix 'inv' ( 'true' | isNegated ?= 'false' )? 976 | ExpressionDeclaration FunctionBody 977 | ; 978 | 979 | /* INTERACTIONS */ 980 | 981 | /* Interactions */ 982 | 983 | Interaction : 984 | TypePrefix 'interaction' 985 | ClassifierDeclaration TypeBody 986 | ; 987 | 988 | /* Item Flows */ 989 | 990 | ItemFlow : 991 | FeaturePrefix 'flow' 992 | ItemFlowDeclaration TypeBody 993 | ; 994 | 995 | SuccessionItemFlow : 996 | FeaturePrefix 'succession' 'flow' ItemFlowDeclaration TypeBody 997 | ; 998 | 999 | ItemFlowDeclaration : 1000 | FeatureDeclaration? ValuePart? 1001 | ( 'of' ownedRelationship += ItemFeatureMember )? 1002 | ( 'from' ownedRelationship += ItemFlowEndMember 1003 | 'to' ownedRelationship += ItemFlowEndMember )? 1004 | | ( isSufficient ?= 'all' )? 1005 | ownedRelationship += ItemFlowEndMember 'to' 1006 | ownedRelationship += ItemFlowEndMember 1007 | ; 1008 | 1009 | ItemFeatureMember : 1010 | ownedRelatedElement += ItemFeature 1011 | ; 1012 | 1013 | ItemFeature : 1014 | Identification? ItemFeatureSpecializationPart ValuePart? 1015 | | Identification? ValuePart 1016 | | ownedRelationship += OwnedFeatureTyping ( ownedRelationship += OwnedMultiplicity )? 1017 | | ownedRelationship += OwnedMultiplicity ownedRelationship += OwnedFeatureTyping 1018 | ; 1019 | 1020 | ItemFeatureSpecializationPart : 1021 | ( FeatureSpecialization )+ MultiplicityPart? FeatureSpecialization* 1022 | | MultiplicityPart FeatureSpecialization+ 1023 | ; 1024 | 1025 | ItemFlowEndMember : 1026 | ownedRelatedElement += ItemFlowEnd 1027 | ; 1028 | 1029 | ItemFlowEnd : 1030 | ( ownedRelationship += ItemFlowEndSubsetting )? 1031 | ownedRelationship += ItemFlowFeatureMember 1032 | ; 1033 | 1034 | ItemFlowEndSubsetting : 1035 | referencedFeature = QualifiedName '.' 1036 | | ownedRelatedElement += FeatureChainPrefix 1037 | ; 1038 | 1039 | FeatureChainPrefix : 1040 | ( ownedRelationship += OwnedFeatureChaining '.' )+ 1041 | ownedRelationship += OwnedFeatureChaining '.' 1042 | ; 1043 | 1044 | ItemFlowFeatureMember : 1045 | ownedRelatedElement += ItemFlowFeature 1046 | ; 1047 | 1048 | ItemFlowFeature : 1049 | ownedRelationship += ItemFlowRedefinition 1050 | ; 1051 | 1052 | ItemFlowRedefinition : 1053 | redefinedFeature = QualifiedName 1054 | ; 1055 | 1056 | /* METADATA */ 1057 | 1058 | Metaclass : 1059 | TypePrefix 'metaclass' 1060 | ClassifierDeclaration TypeBody 1061 | ; 1062 | 1063 | PrefixMetadataAnnotation : 1064 | '#' ownedRelatedElement += PrefixMetadataFeature 1065 | ; 1066 | 1067 | PrefixMetadataMember : 1068 | '#' ownedRelatedElement += PrefixMetadataFeature 1069 | ; 1070 | 1071 | PrefixMetadataFeature : 1072 | ownedRelationship += MetadataTyping 1073 | ; 1074 | 1075 | MetadataFeature : 1076 | ( '@' | 'metadata' ) MetadataFeatureDeclaration 1077 | ( 'about' ownedRelationship += Annotation 1078 | ( ',' ownedRelationship += Annotation )* 1079 | )? 1080 | MetadataBody 1081 | ; 1082 | 1083 | MetadataFeatureDeclaration : 1084 | ( Identification ( ':' | 'typed' 'by' ) )? ownedRelationship += MetadataTyping 1085 | ; 1086 | 1087 | MetadataTyping : 1088 | type = QualifiedName 1089 | ; 1090 | 1091 | MetadataBody : 1092 | ';' 1093 | | '{' ( ownedRelationship += NonFeatureMember 1094 | | ownedRelationship += MetadataBodyFeatureMember 1095 | | ownedRelationship += AliasMember 1096 | | ownedRelationship += Import 1097 | )* 1098 | '}' 1099 | ; 1100 | 1101 | MetadataBodyFeatureMember : 1102 | ownedRelatedElement += MetadataBodyFeature 1103 | ; 1104 | 1105 | MetadataBodyFeature : 1106 | 'feature'? ( ':>>' | 'redefines' )? ownedRelationship += OwnedRedefinition 1107 | FeatureSpecializationPart? ValuePart? 1108 | MetadataBody 1109 | ; 1110 | 1111 | /* EXPRESSIONS */ 1112 | 1113 | 1114 | ExpressionBody : 1115 | '{' FunctionBodyPart '}' 1116 | ; 1117 | -------------------------------------------------------------------------------- /src/sysml2py/grammar/KerMLExpressions.tx: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * SysML 2 Pilot Implementation 3 | * Copyright (c) 2018-2023 Model Driven Solutions, Inc. 4 | * Copyright (c) 2018 IncQuery Labs Ltd. 5 | * Copyright (c) 2019 Maplesoft (Waterloo Maple, Inc.) 6 | * Copyright (c) 2019 Mgnite Inc. 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with this program. If not, see . 20 | * 21 | * @license LGPL-3.0-or-later 22 | * 23 | * Contributors: 24 | * Ed Seidewitz, MDS 25 | * Zoltan Kiss, IncQuery 26 | * Balazs Grill, IncQuery 27 | * Hisashi Miyashita, Maplesoft/Mgnite 28 | * 29 | *****************************************************************************/ 30 | 31 | /* EXPRESSIONS */ 32 | 33 | /* Operator Expressions */ 34 | 35 | OwnedExpressionMember : 36 | ownedRelatedElement = OwnedExpression 37 | ; 38 | 39 | OwnedExpression : 40 | expression=ConditionalExpression 41 | ; 42 | 43 | // Conditional Test Expressions 44 | 45 | OwnedExpressionReference : 46 | ownedRelationship += OwnedExpressionMember 47 | ; 48 | 49 | ConditionalExpression : 50 | operand = NullCoalescingExpression 51 | | operator = ConditionalOperator operand += NullCoalescingExpression 52 | '?' operand += OwnedExpressionReference 'else' operand += OwnedExpressionReference 53 | ; 54 | 55 | ConditionalOperator : 56 | 'if' 57 | ; 58 | 59 | // Null Coalescing Expressions 60 | 61 | NullCoalescingExpression : 62 | implies = ImpliesExpression ( 63 | operator = NullCoalescingOperator operand += ImpliesExpressionReference )* 64 | ; 65 | 66 | NullCoalescingOperator : 67 | '??' 68 | ; 69 | 70 | // Logical Expressions 71 | 72 | ImpliesExpressionReference : 73 | ownedRelationship += ImpliesExpressionMember 74 | ; 75 | 76 | ImpliesExpressionMember : 77 | ownedRelatedElement += ImpliesExpression 78 | ; 79 | 80 | ImpliesExpression : 81 | or = OrExpression ( 82 | operator = ImpliesOperator operand += OrExpressionReference )* 83 | ; 84 | 85 | ImpliesOperator : 86 | 'implies' 87 | ; 88 | 89 | OrExpressionReference : 90 | ownedRelationship += OrExpressionMember 91 | ; 92 | 93 | OrExpressionMember : 94 | ownedRelatedElement += OrExpression 95 | ; 96 | 97 | OrExpression : 98 | xor=XorExpression ( 99 | ( operator = OrOperator operand += XorExpression 100 | | operator = ConditionalOrOperator operand += XorExpressionReference ) )* 101 | ; 102 | 103 | OrOperator : 104 | '|' 105 | ; 106 | 107 | ConditionalOrOperator : 108 | 'or' 109 | ; 110 | 111 | XorExpressionReference : 112 | ownedRelationship += XorExpressionMember 113 | ; 114 | 115 | XorExpressionMember : 116 | ownedRelatedElement += XorExpression 117 | ; 118 | 119 | XorExpression : 120 | and=AndExpression ( 121 | operator = XorOperator operand += AndExpression )* 122 | ; 123 | 124 | XorOperator : 125 | 'xor' 126 | ; 127 | 128 | AndOperand : 129 | (operator = AndOperator operand = EqualityExpression) 130 | | 131 | (operator = ConditionalAndOperator operand = EqualityExpressionReference) 132 | ; 133 | 134 | AndExpression : 135 | equality=EqualityExpression 136 | (operation+=AndOperand)* 137 | ; 138 | 139 | AndOperator : 140 | '&' 141 | ; 142 | 143 | ConditionalAndOperator : 144 | 'and' 145 | ; 146 | 147 | // Equality Expressions 148 | 149 | EqualityExpressionReference : 150 | ownedRelationship = EqualityExpressionMember 151 | ; 152 | 153 | EqualityExpressionMember : 154 | ownedRelatedElement = EqualityExpression 155 | ; 156 | 157 | EqualityOperand: 158 | operator=EqualityOperator operand=ClassificationExpression 159 | ; 160 | 161 | EqualityExpression : 162 | classification=ClassificationExpression 163 | (operation+=EqualityOperand)* 164 | ; 165 | 166 | EqualityOperator : 167 | '==' | '!=' | '===' | '!==' 168 | ; 169 | 170 | // Classification Expressions 171 | 172 | ClassificationExpression : 173 | relational=RelationalExpression 174 | ( 175 | operator = ClassificationTestOperator ownedRelationship += TypeReferenceMember 176 | | 177 | operator = CastOperator ownedRelationship += TypeResultMember 178 | )? 179 | | operand += SelfReferenceExpression 180 | operator = ClassificationTestOperator ownedRelationship += TypeReferenceMember 181 | | operand += MetadataReference 182 | operator = MetaClassificationTestOperator ownedRelationship += TypeReferenceMember 183 | | operand += SelfReferenceExpression 184 | operator = CastOperator ownedRelationship += TypeResultMember 185 | | operand += MetadataReference 186 | operator = MetaCastOperator ownedRelationship += TypeResultMember 187 | ; 188 | 189 | ClassificationTestOperator : 190 | 'hastype' | 'istype' | '@' 191 | ; 192 | 193 | MetaClassificationTestOperator : 194 | '@@' 195 | ; 196 | 197 | CastOperator : 198 | 'as' 199 | ; 200 | 201 | MetaCastOperator : 202 | 'meta' 203 | ; 204 | 205 | MetadataReference : 206 | referencedElement = QualifiedName 207 | ; 208 | 209 | TypeReferenceMember : 210 | ownedRelatedElement += TypeReference 211 | ; 212 | 213 | TypeResultMember : 214 | ownedRelatedElement += TypeReference 215 | ; 216 | 217 | TypeReference : 218 | ownedRelationship += ReferenceTyping 219 | ; 220 | 221 | ReferenceTyping : 222 | type = QualifiedName 223 | ; 224 | 225 | SelfReferenceExpression : 226 | ownedRelationship += SelfReferenceMember 227 | ; 228 | 229 | SelfReferenceMember : 230 | ownedRelatedElement += EmptyFeature 231 | ; 232 | 233 | EmptyFeature ://This doesn't work. 234 | 'emptyfeature' 235 | ; 236 | 237 | // Relational Expressions 238 | RelationalOperand: 239 | operator=RelationalOperator operand=RangeExpression 240 | ; 241 | 242 | RelationalExpression : 243 | range=RangeExpression operation+=RelationalOperand* 244 | ; 245 | 246 | RelationalOperator : 247 | '<=' | '>=' | '<' | '>' 248 | ; 249 | 250 | // Range Expressions 251 | 252 | RangeExpression : 253 | additive=AdditiveExpression ('..' operand = AdditiveExpression )? 254 | ; 255 | 256 | // Arithmetic Expressions 257 | 258 | AdditiveOperand: 259 | operator=AdditiveOperator operand=MultiplicativeExpression 260 | ; 261 | 262 | AdditiveExpression : 263 | multiplicitive=MultiplicativeExpression 264 | (operation+=AdditiveOperand)* 265 | ; 266 | 267 | AdditiveOperator : 268 | '+' | '-' 269 | ; 270 | 271 | MultiplicativeOperand: 272 | operator=MultiplicativeOperator operand=ExponentiationExpression 273 | ; 274 | 275 | MultiplicativeExpression : 276 | exponential=ExponentiationExpression operation+=MultiplicativeOperand* 277 | ; 278 | 279 | MultiplicativeOperator : 280 | '*' | '/' | '%' 281 | ; 282 | 283 | ExponentiationExpression : 284 | unary=UnaryExpression ( 285 | operator = ExponentiationOperator operand += UnaryExpression )* 286 | ; 287 | 288 | ExponentiationOperator : 289 | '**' | '^' 290 | ; 291 | 292 | // Unary Expressions 293 | 294 | UnaryExpression : 295 | operator = UnaryOperator operand += ExtentExpression 296 | | extent=ExtentExpression 297 | ; 298 | 299 | UnaryOperator : 300 | '+' | '-' | '~' | 'not' 301 | ; 302 | 303 | // Extent Expressions 304 | 305 | ExtentExpression : 306 | operator = 'all' ownedRelationship += TypeResultMember 307 | | primary=PrimaryExpression 308 | ; 309 | 310 | /* Primary Expressions */ 311 | 312 | PrimaryExpression : 313 | base=BaseExpression 314 | ( '.' ownedRelationship1 += FeatureChainMember )? 315 | ( 316 | ( operator += '#' '(' operand += SequenceExpression ')' 317 | | operator += '[' operand += SequenceExpression ']' 318 | | operator += '->' ownedRelationship = ReferenceTyping 319 | ( operand += BodyExpression | operand += FunctionReferenceExpression | operand+= ArgumentList ) 320 | | operator += '.' operand += BodyExpression 321 | | operator += '.?' operand += BodyExpression 322 | ) 323 | ( '.' ownedRelationship2 += FeatureChainMember )? 324 | )* 325 | ; 326 | 327 | FunctionReferenceExpression : 328 | ownedRelationship += FunctionReferenceMember 329 | ; 330 | 331 | FunctionReferenceMember : 332 | ownedRelatedElement += FunctionReference 333 | ; 334 | 335 | FunctionReference : 336 | ownedRelationship += ReferenceTyping 337 | ; 338 | 339 | FeatureChainMember : 340 | ownedRelatedElement = OwnedFeatureChain 341 | | memberElement = QualifiedName 342 | ; 343 | 344 | /* Base Expressions */ 345 | 346 | BaseExpression : 347 | ownedRelationship=NullExpression 348 | | ownedRelationship=LiteralExpression 349 | | ownedRelationship=InvocationExpression 350 | | ownedRelationship=FeatureReferenceExpression 351 | | ownedRelationship=MetadataAccessExpression 352 | | ownedRelationship=BodyExpression 353 | | '(' ownedRelationship=SequenceExpression ')' 354 | ; 355 | 356 | // Expression Bodies 357 | 358 | BodyExpression : 359 | ownedRelationship = ExpressionBodyMember 360 | ; 361 | 362 | ExpressionBodyMember : 363 | ownedRelatedElement = ExpressionBody 364 | ; 365 | 366 | // This default production is overridden in the KerML and SysML grammars. 367 | ExpressionBody : 368 | '{' ( ownedRelationship += BodyParameterMember ';' )* 369 | ownedRelationship += ResultExpressionMember '}' 370 | ; 371 | 372 | ResultExpressionMember : 373 | ownedRelatedElement += OwnedExpression 374 | ; 375 | 376 | BodyParameterMember : 377 | 'in' ownedRelatedElement += BodyParameter 378 | ; 379 | 380 | BodyParameter : 381 | declaredName = Name 382 | ; 383 | 384 | // Sequence Expressions 385 | 386 | SequenceOperand: 387 | (',' operand = OwnedExpression) 388 | | 389 | ',' 390 | ; 391 | 392 | SequenceExpression : 393 | ownedRelationship=OwnedExpression operation+=SequenceOperand* 394 | ; 395 | 396 | // Feature Reference Expressions 397 | 398 | FeatureReferenceExpression : 399 | ownedRelationship += FeatureReferenceMember 400 | ; 401 | 402 | FeatureReferenceMember : 403 | memberElement = QualifiedName 404 | ; 405 | 406 | // Metadata Access Expressions 407 | 408 | MetadataAccessExpression : 409 | referencedElement = QualifiedName '.' 'metadata' 410 | ; 411 | 412 | // Invocation Expressions 413 | 414 | InvocationExpression : 415 | ownedRelationship=OwnedFeatureTyping arg_list=ArgumentList 416 | ; 417 | 418 | OwnedFeatureTyping : 419 | type = QualifiedName 420 | | ownedRelatedElement += OwnedFeatureChain 421 | ; 422 | 423 | OwnedFeatureChain : 424 | feature=FeatureChain 425 | ; 426 | 427 | // For use in KerML and SysML grammars 428 | FeatureChain : 429 | ownedRelationship += OwnedFeatureChaining['.'] 430 | ; 431 | 432 | OwnedFeatureChaining : 433 | chainingFeature = QualifiedName 434 | ; 435 | 436 | ArgumentList : 437 | '(' ( pos_list=PositionalArgumentList | named_list=NamedArgumentList )? ')' 438 | ; 439 | 440 | PositionalArgumentList : 441 | ownedRelationship += ArgumentMember[','] 442 | ; 443 | 444 | ArgumentMember : 445 | ownedRelatedElement = Argument 446 | ; 447 | 448 | Argument : 449 | ownedRelationship = ArgumentValue 450 | ; 451 | 452 | NamedArgumentList : 453 | ownedRelationship += NamedArgumentMember[','] 454 | ; 455 | 456 | NamedArgumentMember : 457 | ownedRelatedElement = NamedArgument 458 | ; 459 | 460 | NamedArgument : 461 | redefinition = ParameterRedefinition '=' value = ArgumentValue 462 | ; 463 | 464 | ParameterRedefinition : 465 | redefinedFeature = QualifiedName 466 | ; 467 | 468 | ArgumentValue : 469 | ownedRelatedElement = OwnedExpression 470 | ; 471 | 472 | // Null Expressions 473 | 474 | NullExpression : 475 | ( 'null' | '(' ')' ) 476 | ; 477 | 478 | /* Literal Expressions */ 479 | 480 | LiteralExpression : 481 | LiteralBoolean 482 | | LiteralString 483 | | LiteralReal 484 | | LiteralInteger 485 | | LiteralInfinity 486 | ; 487 | 488 | LiteralBoolean : 489 | value = BooleanValue 490 | ; 491 | 492 | BooleanValue : 493 | 'true' | 'false' 494 | ; 495 | 496 | LiteralString : 497 | value = STRING_VALUE 498 | ; 499 | 500 | LiteralInteger : 501 | value = DECIMAL_VALUE 502 | ; 503 | 504 | LiteralReal : 505 | value = RealValue 506 | ; 507 | 508 | RealValue : 509 | DECIMAL_VALUE? '.' ( DECIMAL_VALUE | EXP_VALUE ) | EXP_VALUE 510 | ; 511 | 512 | LiteralInfinity : 513 | value='*' 514 | ; 515 | 516 | /* NAMES */ 517 | 518 | ReservedKeyword: 519 | 'about' | /to[\s]/ | 'connect' | 'connection' | 'from' | /of[\s]/ | 'then' | 520 | 'entry' | /accept[\s]/ | /do[\s]/ | /exit[\s]/ | /action[\s]/ | /at[\s]/ | 521 | /assign[\s]/ 522 | ; 523 | 524 | Name: 525 | !ReservedKeyword ID | UNRESTRICTED_NAME 526 | ; 527 | 528 | Qualification : 529 | ( '::' Name )+ 530 | ; 531 | 532 | QualifiedName: 533 | //name1=Name ( '::' names+=Name )* 534 | names+=Name['::'] 535 | ; 536 | 537 | /* TERMINALS */ 538 | 539 | DECIMAL_VALUE : 540 | /[0-9]+/; 541 | 542 | EXP_VALUE: 543 | DECIMAL_VALUE ('e' | 'E') ('+' | '-')? DECIMAL_VALUE; 544 | 545 | ID : 546 | /[a-zA-Z_][a-zA-Z_0-9]*/; 547 | 548 | UNRESTRICTED_NAME : 549 | /* Old format? 550 | /''' ('\' ('b' | 't' | 'n' | 'f' | 'r' | '"' | "'" | '\') | !('\' | '''))* '''/; 551 | */ 552 | /[\'].*[\']/; 553 | 554 | STRING_VALUE : 555 | /*/'"' ('\' ('b' | 't' | 'n' | 'f' | 'r' | '"' | "'" | '\') | !('\' | '"'))* '"'/;*/ 556 | /[\"].*[\"]/; 557 | 558 | REGULAR_COMMENT: 559 | /\/\*(.|\n)*?\*\// 560 | ; 561 | 562 | Comment: 563 | // Reserved for textx, but in the model 564 | /\/\/.*$/ 565 | ; 566 | 567 | ML_NOTE: 568 | /'\/*'->'*\/'/; 569 | 570 | SL_NOTE: 571 | /'\/\/' (!(' 572 | ' | ' ') !(' 573 | ' | ' ')*)? (' '? ' 574 | ')?/; 575 | 576 | WS: 577 | /(' ' | ' ' | ' ' | ' 578 | ')+/; 579 | -------------------------------------------------------------------------------- /src/sysml2py/textx/KerML.xtext: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * SysML 2 Pilot Implementation 3 | * Copyright (c) 2018-2023 Model Driven Solutions, Inc. 4 | * Copyright (c) 2018 IncQuery Labs Ltd. 5 | * Copyright (c) 2019 Maplesoft (Waterloo Maple, Inc.) 6 | * Copyright (c) 2019 Mgnite Inc. 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with this program. If not, see . 20 | * 21 | * @license LGPL-3.0-or-later 22 | * 23 | * Contributors: 24 | * Ed Seidewitz, MDS 25 | * Zoltan Kiss, IncQuery 26 | * Balazs Grill, IncQuery 27 | * Hisashi Miyashita, Maplesoft/Mgnite 28 | * 29 | *****************************************************************************/ 30 | 31 | grammar org.omg.kerml.xtext.KerML with org.omg.kerml.expressions.xtext.KerMLExpressions 32 | 33 | import "http://www.eclipse.org/emf/2002/Ecore" as Ecore 34 | import "https://www.omg.org/spec/SysML/20230201" as SysML 35 | 36 | /* ROOT NAMESPACE */ 37 | 38 | RootNamespace returns SysML::Namespace : 39 | {SysML::Namespace}NamespaceBodyElement* 40 | ; 41 | 42 | /* ELEMENTS */ 43 | 44 | /* Elements */ 45 | 46 | fragment Identification returns SysML::Element : 47 | '<' declaredShortName = Name '>' ( declaredName = Name )? 48 | | declaredName = Name 49 | ; 50 | 51 | /* Relationships */ 52 | 53 | fragment RelationshipBody returns SysML::Relationship : 54 | ';' | '{' RelationshipOwnedElement* '}' 55 | ; 56 | 57 | fragment RelationshipOwnedElement returns SysML::Relationship: 58 | ownedRelatedElement += OwnedRelatedElement 59 | | ownedRelationship += OwnedAnnotation 60 | ; 61 | 62 | OwnedRelatedElement returns SysML::Element : 63 | NonFeatureElement | FeatureElement 64 | ; 65 | 66 | /* DEPENDENCIES */ 67 | 68 | Dependency returns SysML::Dependency : 69 | ( ownedRelationship += PrefixMetadataAnnotation )* 70 | 'dependency' ( Identification? 'from' )? 71 | client += [SysML::Element|QualifiedName] ( ',' client += [SysML::Element|QualifiedName] )* 'to' 72 | supplier += [SysML::Element|QualifiedName] ( ',' supplier += [SysML::Element|QualifiedName] )* 73 | RelationshipBody 74 | ; 75 | 76 | /* ANNOTATIONS */ 77 | 78 | Annotation returns SysML::Annotation : 79 | annotatedElement = [SysML::Element|QualifiedName] 80 | ; 81 | 82 | OwnedAnnotation returns SysML::Annotation : 83 | ownedRelatedElement += AnnotatingElement 84 | ; 85 | 86 | AnnotatingElement returns SysML::AnnotatingElement : 87 | Comment 88 | | Documentation 89 | | TextualRepresentation 90 | | MetadataFeature 91 | ; 92 | 93 | /* Comments */ 94 | 95 | Comment returns SysML::Comment : 96 | ( 'comment' Identification? 97 | ('about' ownedRelationship += Annotation 98 | ( ',' ownedRelationship += Annotation )* )? 99 | )? 100 | body = REGULAR_COMMENT 101 | ; 102 | 103 | Documentation returns SysML::Documentation : 104 | 'doc' Identification? body = REGULAR_COMMENT 105 | ; 106 | 107 | /* Textual Representation */ 108 | 109 | TextualRepresentation returns SysML::TextualRepresentation : 110 | ( 'rep' Identification? )? 111 | 'language' language = STRING_VALUE 112 | body = REGULAR_COMMENT 113 | ; 114 | 115 | /* NAMESPACES */ 116 | 117 | Namespace returns SysML::Namespace : 118 | ( ownedRelationship += PrefixMetadataMember )* 119 | NamespaceDeclaration NamespaceBody 120 | ; 121 | 122 | fragment NamespaceDeclaration returns SysML::Namespace : 123 | 'namespace' Identification? 124 | ; 125 | 126 | fragment NamespaceBody returns SysML::Namespace : 127 | ';' 128 | | '{' ( // Note: PackageBodyElement is expanded here to avoid 129 | // infinite loops in the incremental parser. 130 | ownedRelationship += NamespaceMember 131 | | ownedRelationship += AliasMember 132 | | ownedRelationship += Import )* 133 | '}' 134 | ; 135 | 136 | /* Namespace Bodies */ 137 | 138 | fragment NamespaceBodyElement returns SysML::Namespace : 139 | ownedRelationship += NamespaceMember 140 | | ownedRelationship += AliasMember 141 | | ownedRelationship += Import 142 | ; 143 | 144 | fragment MemberPrefix returns SysML::Membership : 145 | ( visibility = VisibilityIndicator )? 146 | ; 147 | 148 | NamespaceMember returns SysML::OwningMembership : 149 | NonFeatureMember | NamespaceFeatureMember 150 | ; 151 | 152 | NonFeatureMember returns SysML::OwningMembership : 153 | MemberPrefix ownedRelatedElement += MemberElement 154 | ; 155 | 156 | NamespaceFeatureMember returns SysML::OwningMembership : 157 | MemberPrefix ownedRelatedElement += FeatureElement 158 | ; 159 | 160 | AliasMember returns SysML::Membership : 161 | MemberPrefix 162 | 'alias' ( '<' memberShortName = Name '>' )? ( memberName = Name )? 163 | 'for' memberElement = [SysML::Element|QualifiedName] 164 | RelationshipBody 165 | ; 166 | 167 | fragment ImportPrefix returns SysML::Import : 168 | ( visibility = VisibilityIndicator )? 169 | 'import' ( isImportAll ?= 'all' )? 170 | ; 171 | 172 | Import returns SysML::Import : 173 | ( MembershipImport | NamespaceImport ) 174 | RelationshipBody 175 | ; 176 | 177 | MembershipImport returns SysML::MembershipImport : 178 | ImportPrefix ImportedMembership 179 | ; 180 | 181 | fragment ImportedMembership returns SysML::MembershipImport : 182 | importedMembership = [SysML::Membership|QualifiedName] 183 | ( '::' isRecursive ?= '**' )? 184 | ; 185 | 186 | NamespaceImport returns SysML::NamespaceImport : 187 | ImportPrefix 188 | ( ImportedNamespace 189 | | ownedRelatedElement += FilterPackage 190 | ) 191 | ; 192 | 193 | fragment ImportedNamespace returns SysML::NamespaceImport : 194 | importedNamespace = [SysML::Namespace|QualifiedName] '::' '*' 195 | ( '::' isRecursive ?= '**' )? 196 | ; 197 | 198 | FilterPackage returns SysML::Package : 199 | ownedRelationship += FilterPackageImport 200 | ( ownedRelationship += FilterPackageMember )+ 201 | ; 202 | 203 | FilterPackageImport returns SysML::Import : 204 | FilterPackageMembershipImport | FilterPackageNamespaceImport 205 | ; 206 | 207 | FilterPackageMembershipImport returns SysML::MembershipImport : 208 | ImportedMembership 209 | ; 210 | 211 | FilterPackageNamespaceImport returns SysML::NamespaceImport : 212 | ImportedNamespace 213 | ; 214 | 215 | FilterPackageMember returns SysML::ElementFilterMembership : 216 | visibility = FilterPackageMemberVisibility ownedRelatedElement += OwnedExpression ']' 217 | ; 218 | 219 | enum FilterPackageMemberVisibility returns SysML::VisibilityKind : 220 | private = '[' 221 | ; 222 | 223 | enum VisibilityIndicator returns SysML::VisibilityKind : 224 | public = 'public' | private = 'private' | protected = 'protected' 225 | ; 226 | 227 | /* Namespace Elements */ 228 | 229 | MemberElement returns SysML::Element : 230 | AnnotatingElement | NonFeatureElement 231 | ; 232 | 233 | NonFeatureElement returns SysML::Element : 234 | Dependency 235 | | Namespace 236 | | Package 237 | | LibraryPackage 238 | | Multiplicity 239 | | Type 240 | | Classifier 241 | | Class 242 | | Structure 243 | | Metaclass 244 | | DataType 245 | | Association 246 | | AssociationStructure 247 | | Interaction 248 | | Behavior 249 | | Function 250 | | Predicate 251 | | Specialization 252 | | Conjugation 253 | | FeatureTyping 254 | | Subclassification 255 | | Disjoining 256 | | FeatureInverting 257 | | Subsetting 258 | | Redefinition 259 | | TypeFeaturing 260 | ; 261 | 262 | FeatureElement returns SysML::Feature : 263 | Feature 264 | | Step 265 | | Expression 266 | | BooleanExpression 267 | | Invariant 268 | | Connector 269 | | BindingConnector 270 | | Succession 271 | | ItemFlow 272 | | SuccessionItemFlow 273 | ; 274 | 275 | /* PACKAGES */ 276 | 277 | Package returns SysML::Package : 278 | ( ownedRelationship += PrefixMetadataMember )* 279 | PackageDeclaration PackageBody 280 | ; 281 | 282 | LibraryPackage returns SysML::LibraryPackage : 283 | ( isStandard ?= 'standard' )? 'library' 284 | ( ownedRelationship += PrefixMetadataMember )* 285 | PackageDeclaration PackageBody 286 | ; 287 | 288 | fragment PackageDeclaration returns SysML::Package : 289 | 'package' Identification? 290 | ; 291 | 292 | fragment PackageBody returns SysML::Namespace : 293 | ';' 294 | | '{' ( // Note: PackageBodyElement is expanded here to avoid 295 | // infinite loops in the incremental parser. 296 | ownedRelationship += NamespaceMember 297 | | ownedRelationship += ElementFilterMember 298 | | ownedRelationship += AliasMember 299 | | ownedRelationship += Import )* 300 | '}' 301 | ; 302 | 303 | ElementFilterMember returns SysML::ElementFilterMembership : 304 | MemberPrefix 305 | 'filter' ownedRelatedElement += OwnedExpression ';' 306 | ; 307 | 308 | /* TYPES */ 309 | 310 | /* Types */ 311 | 312 | fragment TypePrefix returns SysML::Type : 313 | ( isAbstract ?= 'abstract' )? 314 | ( ownedRelationship += PrefixMetadataMember )* 315 | ; 316 | 317 | Type returns SysML::Type : 318 | TypePrefix 'type' 319 | TypeDeclaration TypeBody 320 | ; 321 | 322 | fragment TypeDeclaration returns SysML::Type : 323 | ( isSufficient ?= 'all' )? Identification? 324 | ( ownedRelationship += OwnedMultiplicity )? 325 | ( SpecializationPart | ConjugationPart )+ 326 | TypeRelationshipPart* 327 | ; 328 | 329 | fragment SpecializationPart returns SysML::Type : 330 | ( ':>' | 'specializes' ) ownedRelationship += OwnedSpecialization 331 | ( ',' ownedRelationship += OwnedSpecialization )* 332 | ; 333 | 334 | fragment ConjugationPart returns SysML::Type : 335 | ( '~' | 'conjugates' ) ownedRelationship += OwnedConjugation 336 | ; 337 | 338 | fragment TypeRelationshipPart returns SysML::Type : 339 | DisjoiningPart | UnioningPart | IntersectingPart | DifferencingPart 340 | ; 341 | 342 | fragment DisjoiningPart returns SysML::Type : 343 | 'disjoint' 'from' ownedRelationship += OwnedDisjoining 344 | ( ',' ownedRelationship += OwnedDisjoining )* 345 | ; 346 | 347 | fragment UnioningPart returns SysML::Type : 348 | 'unions' ownedRelationship += Unioning 349 | ( ',' ownedRelationship += Unioning )* 350 | ; 351 | 352 | fragment IntersectingPart returns SysML::Type : 353 | 'intersects' ownedRelationship += Intersecting 354 | ( ',' ownedRelationship += Intersecting )* 355 | ; 356 | 357 | fragment DifferencingPart returns SysML::Type : 358 | 'differences' ownedRelationship += Differencing 359 | ( ',' ownedRelationship += Differencing )* 360 | ; 361 | 362 | fragment TypeBody returns SysML::Type : 363 | ';' 364 | | '{' ( ownedRelationship += NonFeatureMember 365 | | ownedRelationship += FeatureMember 366 | | ownedRelationship += AliasMember 367 | | ownedRelationship += Import 368 | )* 369 | '}' 370 | ; 371 | 372 | /* Feature Membership */ 373 | 374 | FeatureMember returns SysML::OwningMembership : 375 | TypeFeatureMember | OwnedFeatureMember 376 | ; 377 | 378 | TypeFeatureMember returns SysML::OwningMembership : 379 | MemberPrefix 'member' ownedRelatedElement += FeatureElement 380 | ; 381 | 382 | OwnedFeatureMember returns SysML::FeatureMembership : 383 | MemberPrefix ownedRelatedElement += FeatureElement 384 | ; 385 | 386 | /* Specialization */ 387 | 388 | Specialization returns SysML::Specialization : 389 | ( 'specialization' Identification? )? 390 | 'subtype' 391 | ( specific = [SysML::Type | QualifiedName] 392 | | ownedRelatedElement += OwnedFeatureChain ) 393 | ( ':>' | 'specializes') 394 | ( general = [SysML::Type | QualifiedName] 395 | | ownedRelatedElement += OwnedFeatureChain ) 396 | RelationshipBody 397 | ; 398 | 399 | OwnedSpecialization returns SysML::Specialization : 400 | general = [SysML::Type | QualifiedName] 401 | | ownedRelatedElement += OwnedFeatureChain 402 | ; 403 | 404 | /* Conjugation */ 405 | 406 | Conjugation returns SysML::Conjugation : 407 | ( 'conjugation' Identification? )? 408 | 'conjugate' 409 | ( conjugatedType = [SysML::Type | QualifiedName] 410 | | ownedRelatedElement += OwnedFeatureChain ) 411 | ( '~' | 'conjugates') 412 | ( originalType = [SysML::Type | QualifiedName] 413 | | ownedRelatedElement += OwnedFeatureChain ) 414 | RelationshipBody 415 | ; 416 | 417 | OwnedConjugation returns SysML::Conjugation : 418 | originalType = [SysML::Type | QualifiedName] 419 | | ownedRelatedElement += OwnedFeatureChain 420 | ; 421 | 422 | /* Disjoining */ 423 | 424 | Disjoining returns SysML::Disjoining : 425 | ( 'disjoining' Identification? )? 426 | 'disjoint' 427 | ( typeDisjoined = [SysML::Type | QualifiedName] 428 | | ownedRelatedElement += OwnedFeatureChain ) 429 | 'from' 430 | ( disjoiningType = [SysML::Type | QualifiedName] 431 | | ownedRelatedElement += OwnedFeatureChain ) 432 | RelationshipBody 433 | ; 434 | 435 | OwnedDisjoining returns SysML::Disjoining : 436 | disjoiningType = [SysML::Type | QualifiedName] 437 | | ownedRelatedElement += OwnedFeatureChain 438 | ; 439 | 440 | /* Unioning, Intersecting and Differencing */ 441 | 442 | Unioning returns SysML::Unioning : 443 | unioningType = [SysML::Type | QualifiedName] 444 | | ownedRelatedElement += OwnedFeatureChain 445 | ; 446 | 447 | Intersecting returns SysML::Intersecting : 448 | intersectingType = [SysML::Type | QualifiedName] 449 | | ownedRelatedElement += OwnedFeatureChain 450 | ; 451 | 452 | Differencing returns SysML::Differencing : 453 | differencingType = [SysML::Type | QualifiedName] 454 | | ownedRelatedElement += OwnedFeatureChain 455 | ; 456 | 457 | /* CLASSIFIERS */ 458 | 459 | /* Classifiers */ 460 | 461 | Classifier returns SysML::Classifier : 462 | TypePrefix 'classifier' 463 | ClassifierDeclaration TypeBody 464 | ; 465 | 466 | fragment ClassifierDeclaration returns SysML::Classifier : 467 | (isSufficient ?= 'all' )? Identification? 468 | ( ownedRelationship += OwnedMultiplicity )? 469 | ( SuperclassingPart | ClassifierConjugationPart )? 470 | TypeRelationshipPart* 471 | ; 472 | 473 | fragment SuperclassingPart returns SysML::Classifier : 474 | ( ':>' | 'specializes' ) ownedRelationship += Ownedsubclassification 475 | ( ',' ownedRelationship += Ownedsubclassification )* 476 | ; 477 | 478 | fragment ClassifierConjugationPart returns SysML::Classifier : 479 | ( '~' | 'conjugates' ) ownedRelationship += ClassifierConjugation 480 | ; 481 | 482 | /* Subclassification */ 483 | 484 | Subclassification returns SysML::Subclassification : 485 | ( 'specialization' Identification? )? 486 | 'subclassifier' subclassifier = [SysML::Classifier | QualifiedName] 487 | ( ':>' | 'specializes') superclassifier = [SysML::Classifier | QualifiedName] 488 | RelationshipBody 489 | ; 490 | 491 | Ownedsubclassification returns SysML::Subclassification : 492 | superclassifier = [SysML::Classifier | QualifiedName] 493 | ; 494 | 495 | /* Classifier Conjugation */ 496 | 497 | ClassifierConjugation returns SysML::Conjugation : 498 | originalType = [SysML::Classifier | QualifiedName] 499 | ; 500 | 501 | /* FEATURES */ 502 | 503 | /* Features */ 504 | 505 | enum FeatureDirection returns SysML::FeatureDirectionKind: 506 | in = 'in' | out = 'out' | inout = 'inout' 507 | ; 508 | 509 | fragment FeaturePrefix returns SysML::Feature : 510 | ( direction = FeatureDirection )? 511 | ( isAbstract ?= 'abstract' )? 512 | ( isComposite ?= 'composite' | isPortion ?= 'portion' )? 513 | ( isReadOnly ?= 'readonly' )? 514 | ( isDerived ?= 'derived' )? 515 | ( isEnd ?= 'end' )? 516 | ( ownedRelationship += PrefixMetadataMember )* 517 | ; 518 | 519 | Feature returns SysML::Feature : 520 | FeaturePrefix 521 | ( 'feature'? FeatureDeclaration 522 | | ownedRelationship += PrefixMetadataMember 523 | | 'feature' 524 | ) 525 | ValuePart? TypeBody 526 | ; 527 | 528 | fragment FeatureDeclaration returns SysML::Feature : 529 | ( isSufficient ?= 'all' )? 530 | ( Identification ( FeatureSpecializationPart | FeatureConjugationPart )? 531 | | FeatureSpecializationPart 532 | | FeatureConjugationPart 533 | ) 534 | FeatureRelationshipPart* 535 | ; 536 | 537 | fragment FeatureRelationshipPart returns SysML::Feature : 538 | TypeRelationshipPart | ChainingPart | InvertingPart | TypeFeaturingPart 539 | ; 540 | 541 | fragment ChainingPart returns SysML::Feature : 542 | 'chains' ( ownedRelationship += OwnedFeatureChaining | FeatureChain ) 543 | ; 544 | 545 | fragment InvertingPart returns SysML::Feature : 546 | 'inverse' 'of' ownedRelationship += OwnedFeatureInverting 547 | ; 548 | 549 | fragment TypeFeaturingPart returns SysML::Feature : 550 | 'featured' 'by' ownedRelationship += OwnedTypeFeaturing 551 | ( ',' ownedRelationship += OwnedTypeFeaturing )* 552 | ; 553 | 554 | fragment FeatureSpecializationPart returns SysML::Feature : 555 | ( -> FeatureSpecialization )+ MultiplicityPart? FeatureSpecialization* 556 | | MultiplicityPart FeatureSpecialization* 557 | ; 558 | 559 | fragment MultiplicityPart returns SysML::Feature : 560 | ownedRelationship += OwnedMultiplicity 561 | | ( ownedRelationship += OwnedMultiplicity )? 562 | ( isOrdered ?= 'ordered' isNonunique ?= 'nonunique'? 563 | | isNonunique ?= 'nonunique' isOrdered ?= 'ordered'? 564 | ) 565 | ; 566 | 567 | fragment FeatureSpecialization returns SysML::Feature : 568 | Typings | Subsettings | References | Redefinitions 569 | ; 570 | 571 | fragment Typings returns SysML::Feature : 572 | TypedBy ( ',' ownedRelationship += OwnedFeatureTyping )* 573 | ; 574 | 575 | fragment TypedBy returns SysML::Feature : 576 | ( ':' | 'typed' 'by' ) ownedRelationship += OwnedFeatureTyping 577 | ; 578 | 579 | fragment Subsettings returns SysML::Feature : 580 | Subsets ( ',' ownedRelationship += OwnedSubsetting )* 581 | ; 582 | 583 | fragment Subsets returns SysML::Feature : 584 | ( ':>' | 'subsets' ) ownedRelationship += OwnedSubsetting 585 | ; 586 | 587 | fragment References returns SysML::Feature : 588 | ReferencesKeyword ownedRelationship += OwnedReferenceSubsetting 589 | ; 590 | 591 | ReferencesKeyword : 592 | '::>' | 'references' 593 | ; 594 | 595 | fragment Redefinitions returns SysML::Feature : 596 | Redefines ( ',' ownedRelationship += OwnedRedefinition )* 597 | ; 598 | 599 | fragment Redefines returns SysML::Feature : 600 | ( ':>>' | 'redefines' ) ownedRelationship += OwnedRedefinition 601 | ; 602 | 603 | /* Feature Inverting */ 604 | 605 | FeatureInverting returns SysML::FeatureInverting : 606 | ( 'inverting' Identification? )? 607 | 'inverse' 608 | ( featureInverted = [SysML::Feature| QualifiedName] 609 | | ownedRelatedElement += OwnedFeatureChain ) 610 | 'of' 611 | ( invertingFeature = [SysML::Feature | QualifiedName] 612 | | ownedRelatedElement += OwnedFeatureChain ) 613 | RelationshipBody 614 | ; 615 | 616 | OwnedFeatureInverting returns SysML::FeatureInverting : 617 | invertingFeature = [SysML::Feature | QualifiedName] 618 | | ownedRelatedElement += OwnedFeatureChain 619 | ; 620 | 621 | /* Type Featuring */ 622 | 623 | TypeFeaturing returns SysML::TypeFeaturing : 624 | 'featuring' ( Identification? 'of')? 625 | featureOfType = [SysML::Feature | QualifiedName] 626 | 'by' featuringType = [SysML::Feature | QualifiedName] 627 | RelationshipBody 628 | ; 629 | 630 | OwnedTypeFeaturing returns SysML::TypeFeaturing : 631 | featuringType = [SysML::Type | QualifiedName] 632 | ; 633 | 634 | /* Feature Typing */ 635 | 636 | FeatureTyping returns SysML::FeatureTyping : 637 | ( 'specialization' Identification? )? 638 | 'typing' typedFeature = [SysML::Feature | QualifiedName] 639 | (':' | 'typed' 'by') FeatureType 640 | RelationshipBody 641 | ; 642 | 643 | @Override 644 | OwnedFeatureTyping returns SysML::FeatureTyping : 645 | FeatureType 646 | ; 647 | 648 | fragment FeatureType returns SysML::FeatureTyping : 649 | type = [SysML::Type | QualifiedName] 650 | | ownedRelatedElement += OwnedFeatureChain 651 | ; 652 | 653 | /* Subsetting */ 654 | 655 | Subsetting returns SysML::Subsetting : 656 | ( 'specialization' Identification? )? 657 | 'subset' 658 | ( subsettingFeature = [SysML::Feature | QualifiedName] 659 | | ownedRelatedElement += OwnedFeatureChain ) 660 | ( ':>' | 'subsets' ) 661 | ( subsettedFeature = [SysML::Feature | QualifiedName] 662 | | ownedRelatedElement += OwnedFeatureChain ) 663 | RelationshipBody 664 | ; 665 | 666 | OwnedSubsetting returns SysML::Subsetting: 667 | subsettedFeature = [SysML::Feature | QualifiedName] 668 | | ownedRelatedElement += OwnedFeatureChain 669 | ; 670 | 671 | OwnedReferenceSubsetting returns SysML::ReferenceSubsetting: 672 | referencedFeature = [SysML::Feature | QualifiedName] 673 | | ownedRelatedElement += OwnedFeatureChain 674 | ; 675 | 676 | /* Redefinition */ 677 | 678 | Redefinition returns SysML::Redefinition : 679 | ( 'specialization' Identification? )? 680 | 'redefinition' 681 | ( redefiningFeature = [SysML::Feature | QualifiedName] 682 | | ownedRelatedElement += OwnedFeatureChain ) 683 | ( ':>>' | 'redefines' ) 684 | ( redefinedFeature = [SysML::Feature | QualifiedName] 685 | | ownedRelatedElement += OwnedFeatureChain ) 686 | RelationshipBody 687 | ; 688 | 689 | OwnedRedefinition returns SysML::Redefinition: 690 | redefinedFeature = [SysML::Feature | QualifiedName] 691 | | ownedRelatedElement += OwnedFeatureChain 692 | ; 693 | 694 | /* Feature Conjugation */ 695 | 696 | fragment FeatureConjugationPart returns SysML::Feature : 697 | ( '~' | 'conjugates' ) ownedRelationship += FeatureConjugation 698 | ; 699 | 700 | FeatureConjugation returns SysML::Conjugation : 701 | originalType = [SysML::Feature | QualifiedName ] 702 | ; 703 | 704 | /* FEATURE VALUES */ 705 | 706 | fragment ValuePart returns SysML::Feature : 707 | ownedRelationship += FeatureValue 708 | | ownedRelationship += FeatureValueExpression 709 | ownedRelationship += EmptyFeatureWriteMember 710 | ; 711 | 712 | FeatureValue returns SysML::FeatureValue : 713 | ( '=' | isDefault ?= 'default' ( '=' | isInitial ?= ':=' )? ) 714 | ownedRelatedElement += OwnedExpression 715 | ; 716 | 717 | FeatureValueExpression returns SysML::FeatureValue : 718 | isInitial ?= ':=' 719 | ownedRelatedElement += OwnedExpression 720 | ; 721 | 722 | EmptyFeatureWriteMember returns SysML::OwningMembership : 723 | ownedRelatedElement += EmptyFeatureWrite 724 | ; 725 | 726 | EmptyFeatureWrite returns SysML::Step : 727 | ownedRelationship += EmptyTargetMember 728 | ownedRelationship += EmptyParameterMember 729 | ; 730 | 731 | EmptyTargetMember returns SysML::ParameterMembership : 732 | ownedRelatedElement += EmptyTargetParameter 733 | ; 734 | 735 | EmptyTargetParameter returns SysML::ReferenceUsage : 736 | ownedRelationship += TargetFeatureMember 737 | ; 738 | 739 | TargetFeatureMember returns SysML::FeatureMembership : 740 | ownedRelatedElement += TargetFeature 741 | ; 742 | 743 | TargetFeature returns SysML::Feature : 744 | ownedRelationship += EmptyFeatureMember 745 | ; 746 | 747 | EmptyFeatureMember returns SysML::FeatureMembership : 748 | ownedRelatedElement += EmptyFeature 749 | ; 750 | 751 | EmptyParameterMember returns SysML::ParameterMembership : 752 | ownedRelatedElement += EmptyFeature 753 | ; 754 | 755 | /* MULTIPLICITIES */ 756 | 757 | Multiplicity returns SysML::Multiplicity : 758 | MultiplicitySubset | MultiplicityRange 759 | ; 760 | 761 | MultiplicitySubset returns SysML::Multiplicity : 762 | 'multiplicity' Identification? Subsets TypeBody 763 | ; 764 | 765 | MultiplicityRange returns SysML::MultiplicityRange : 766 | 'multiplicity' Identification? MultiplicityBounds TypeBody 767 | ; 768 | 769 | OwnedMultiplicity returns SysML::OwningMembership : 770 | ownedRelatedElement += OwnedMultiplicityRange 771 | ; 772 | 773 | OwnedMultiplicityRange returns SysML::MultiplicityRange : 774 | MultiplicityBounds 775 | ; 776 | 777 | fragment MultiplicityBounds returns SysML::MultiplicityRange : 778 | // TODO: Allow general expressions for bounds. (Causes LL parsing issues.) 779 | '[' ownedRelationship += MultiplicityExpressionMember 780 | ( '..' ownedRelationship += MultiplicityExpressionMember )? ']' 781 | ; 782 | 783 | MultiplicityExpressionMember returns SysML::OwningMembership : 784 | ownedRelatedElement += ( LiteralExpression | FeatureReferenceExpression ) 785 | ; 786 | 787 | /* CLASSIFICATION */ 788 | 789 | /* Data Types */ 790 | 791 | DataType returns SysML::DataType : 792 | TypePrefix 'datatype' 793 | ClassifierDeclaration TypeBody 794 | ; 795 | 796 | /* Classes */ 797 | 798 | Class returns SysML::Class : 799 | TypePrefix 'class' 800 | ClassifierDeclaration TypeBody 801 | ; 802 | 803 | /* STRUCTURES */ 804 | 805 | Structure returns SysML::Structure : 806 | TypePrefix 'struct' 807 | ClassifierDeclaration TypeBody 808 | ; 809 | 810 | 811 | /* ASSOCIATIONS */ 812 | 813 | Association returns SysML::Association : 814 | TypePrefix 'assoc' 815 | ClassifierDeclaration TypeBody 816 | ; 817 | 818 | AssociationStructure returns SysML::AssociationStructure : 819 | TypePrefix 'assoc' 'struct' 820 | ClassifierDeclaration TypeBody 821 | ; 822 | 823 | /* CONNECTORS */ 824 | 825 | /* Connectors */ 826 | 827 | Connector returns SysML::Connector : 828 | FeaturePrefix 'connector' 829 | ConnectorDeclaration TypeBody 830 | ; 831 | 832 | fragment ConnectorDeclaration returns SysML::Connector : 833 | BinaryConnectorDeclaration | NaryConnectorDeclaration 834 | ; 835 | 836 | fragment BinaryConnectorDeclaration returns SysML::Connector : 837 | ( FeatureDeclaration? 'from' | isSufficient ?= 'all' 'from'? )? 838 | ownedRelationship += ConnectorEndMember 'to' 839 | ownedRelationship += ConnectorEndMember 840 | ; 841 | 842 | fragment NaryConnectorDeclaration returns SysML::Connector : 843 | FeatureDeclaration? 844 | ( '(' ownedRelationship += ConnectorEndMember ',' 845 | ownedRelationship += ConnectorEndMember 846 | ( ',' ownedRelationship += ConnectorEndMember )* 847 | ')' )? 848 | ; 849 | 850 | ConnectorEndMember returns SysML::EndFeatureMembership : 851 | ownedRelatedElement += ConnectorEnd 852 | ; 853 | 854 | ConnectorEnd returns SysML::Feature : 855 | ( declaredName = Name ReferencesKeyword )? 856 | ownedRelationship += OwnedReferenceSubsetting 857 | ( ownedRelationship += OwnedMultiplicity )? 858 | ; 859 | 860 | /* Binding Connectors */ 861 | 862 | BindingConnector returns SysML::BindingConnector : 863 | FeaturePrefix 'binding' 864 | BindingConnectorDeclaration TypeBody 865 | ; 866 | 867 | fragment BindingConnectorDeclaration returns SysML::BindingConnector : 868 | FeatureDeclaration 869 | ( 'of' ownedRelationship += ConnectorEndMember 870 | '=' ownedRelationship += ConnectorEndMember )? 871 | | ( isSufficient ?= 'all' )? 872 | ( 'of'? ownedRelationship += ConnectorEndMember 873 | '=' ownedRelationship += ConnectorEndMember )? 874 | ; 875 | 876 | /* Successions */ 877 | 878 | Succession returns SysML::Succession : 879 | FeaturePrefix 'succession' 880 | SuccessionDeclaration TypeBody 881 | ; 882 | 883 | fragment SuccessionDeclaration returns SysML::Succession : 884 | FeatureDeclaration 885 | ( 'first' ownedRelationship += ConnectorEndMember 886 | 'then' ownedRelationship += ConnectorEndMember )? 887 | | ( isSufficient ?= 'all' )? 888 | ( 'first'? ownedRelationship += ConnectorEndMember 889 | 'then' ownedRelationship += ConnectorEndMember )? 890 | ; 891 | 892 | /* BEHAVIORS */ 893 | 894 | /* Behaviors */ 895 | 896 | Behavior returns SysML::Behavior : 897 | TypePrefix 'behavior' 898 | ClassifierDeclaration TypeBody 899 | ; 900 | 901 | /* Steps */ 902 | 903 | Step returns SysML::Step : 904 | FeaturePrefix 'step' 905 | StepDeclaration TypeBody 906 | ; 907 | 908 | fragment StepDeclaration returns SysML::Step : 909 | FeatureDeclaration? ValuePart? 910 | ; 911 | 912 | /* FUNCTIONS */ 913 | 914 | /* Functions */ 915 | 916 | Function returns SysML::Function : 917 | TypePrefix 'function' 918 | ClassifierDeclaration FunctionBody 919 | ; 920 | 921 | fragment FunctionBody returns SysML::Type : 922 | ';' | '{' FunctionBodyPart '}' 923 | ; 924 | 925 | fragment FunctionBodyPart returns SysML::Type : 926 | ( ownedRelationship += NonFeatureMember 927 | | ownedRelationship += FeatureMember 928 | | ownedRelationship += AliasMember 929 | | ownedRelationship += Import 930 | | ownedRelationship += ReturnFeatureMember 931 | )* 932 | ( ownedRelationship += ResultExpressionMember )? 933 | ; 934 | 935 | ReturnFeatureMember returns SysML::ReturnParameterMembership : 936 | MemberPrefix 'return' 937 | ownedRelatedElement += FeatureElement 938 | ; 939 | 940 | @Override 941 | ResultExpressionMember returns SysML::ResultExpressionMembership : 942 | MemberPrefix ownedRelatedElement += OwnedExpression 943 | ; 944 | 945 | /* Expressions */ 946 | 947 | Expression returns SysML::Expression : 948 | FeaturePrefix 'expr' 949 | ExpressionDeclaration FunctionBody 950 | ; 951 | 952 | fragment ExpressionDeclaration returns SysML::Expression : 953 | FeatureDeclaration? ValuePart? 954 | ; 955 | 956 | /* Predicates */ 957 | 958 | Predicate returns SysML::Predicate : 959 | TypePrefix 'predicate' 960 | ClassifierDeclaration FunctionBody 961 | ; 962 | 963 | /* Boolean Expressions */ 964 | 965 | BooleanExpression returns SysML::BooleanExpression : 966 | FeaturePrefix 'bool' 967 | ExpressionDeclaration FunctionBody 968 | ; 969 | 970 | /* Invariants */ 971 | 972 | Invariant returns SysML::Invariant : 973 | FeaturePrefix 'inv' ( 'true' | isNegated ?= 'false' )? 974 | ExpressionDeclaration FunctionBody 975 | ; 976 | 977 | /* INTERACTIONS */ 978 | 979 | /* Interactions */ 980 | 981 | Interaction returns SysML::Interaction : 982 | TypePrefix 'interaction' 983 | ClassifierDeclaration TypeBody 984 | ; 985 | 986 | /* Item Flows */ 987 | 988 | ItemFlow returns SysML::ItemFlow : 989 | FeaturePrefix 'flow' 990 | ItemFlowDeclaration TypeBody 991 | ; 992 | 993 | SuccessionItemFlow returns SysML::SuccessionItemFlow : 994 | FeaturePrefix 'succession' 'flow' ItemFlowDeclaration TypeBody 995 | ; 996 | 997 | fragment ItemFlowDeclaration returns SysML::ItemFlow : 998 | FeatureDeclaration? ValuePart? 999 | ( 'of' ownedRelationship += ItemFeatureMember )? 1000 | ( 'from' ownedRelationship += ItemFlowEndMember 1001 | 'to' ownedRelationship += ItemFlowEndMember )? 1002 | | ( isSufficient ?= 'all' )? 1003 | ownedRelationship += ItemFlowEndMember 'to' 1004 | ownedRelationship += ItemFlowEndMember 1005 | ; 1006 | 1007 | ItemFeatureMember returns SysML::FeatureMembership : 1008 | ownedRelatedElement += ItemFeature 1009 | ; 1010 | 1011 | ItemFeature returns SysML::ItemFeature : 1012 | Identification? ItemFeatureSpecializationPart ValuePart? 1013 | | Identification? ValuePart 1014 | | ownedRelationship += OwnedFeatureTyping ( ownedRelationship += OwnedMultiplicity )? 1015 | | ownedRelationship += OwnedMultiplicity ownedRelationship += OwnedFeatureTyping 1016 | ; 1017 | 1018 | fragment ItemFeatureSpecializationPart returns SysML::Feature : 1019 | ( -> FeatureSpecialization )+ MultiplicityPart? FeatureSpecialization* 1020 | | MultiplicityPart FeatureSpecialization+ 1021 | ; 1022 | 1023 | ItemFlowEndMember returns SysML::EndFeatureMembership : 1024 | ownedRelatedElement += ItemFlowEnd 1025 | ; 1026 | 1027 | ItemFlowEnd returns SysML::ItemFlowEnd : 1028 | ( ownedRelationship += ItemFlowEndSubsetting )? 1029 | ownedRelationship += ItemFlowFeatureMember 1030 | ; 1031 | 1032 | ItemFlowEndSubsetting returns SysML::ReferenceSubsetting : 1033 | referencedFeature = [SysML::Feature | QualifiedName] '.' 1034 | | ownedRelatedElement += FeatureChainPrefix 1035 | ; 1036 | 1037 | FeatureChainPrefix returns SysML::Feature : 1038 | ( ownedRelationship += OwnedFeatureChaining '.' )+ 1039 | ownedRelationship += OwnedFeatureChaining '.' 1040 | ; 1041 | 1042 | ItemFlowFeatureMember returns SysML::FeatureMembership : 1043 | ownedRelatedElement += ItemFlowFeature 1044 | ; 1045 | 1046 | ItemFlowFeature returns SysML::Feature : 1047 | ownedRelationship += ItemFlowRedefinition 1048 | ; 1049 | 1050 | ItemFlowRedefinition returns SysML::Redefinition : 1051 | redefinedFeature = [SysML::Feature|QualifiedName] 1052 | ; 1053 | 1054 | /* METADATA */ 1055 | 1056 | Metaclass returns SysML::Metaclass : 1057 | TypePrefix 'metaclass' 1058 | ClassifierDeclaration TypeBody 1059 | ; 1060 | 1061 | PrefixMetadataAnnotation returns SysML::Annotation : 1062 | '#' ownedRelatedElement += PrefixMetadataFeature 1063 | ; 1064 | 1065 | PrefixMetadataMember returns SysML::OwningMembership : 1066 | '#' ownedRelatedElement += PrefixMetadataFeature 1067 | ; 1068 | 1069 | PrefixMetadataFeature returns SysML::MetadataFeature : 1070 | ownedRelationship += MetadataTyping 1071 | ; 1072 | 1073 | MetadataFeature returns SysML::MetadataFeature : 1074 | ( '@' | 'metadata' ) MetadataFeatureDeclaration 1075 | ( 'about' ownedRelationship += Annotation 1076 | ( ',' ownedRelationship += Annotation )* 1077 | )? 1078 | MetadataBody 1079 | ; 1080 | 1081 | fragment MetadataFeatureDeclaration returns SysML::MetadataFeature : 1082 | ( Identification ( ':' | 'typed' 'by' ) )? ownedRelationship += MetadataTyping 1083 | ; 1084 | 1085 | MetadataTyping returns SysML::FeatureTyping : 1086 | type = [SysML::Metaclass | QualifiedName] 1087 | ; 1088 | 1089 | fragment MetadataBody returns SysML::Feature : 1090 | ';' 1091 | | '{' ( ownedRelationship += NonFeatureMember 1092 | | ownedRelationship += MetadataBodyFeatureMember 1093 | | ownedRelationship += AliasMember 1094 | | ownedRelationship += Import 1095 | )* 1096 | '}' 1097 | ; 1098 | 1099 | MetadataBodyFeatureMember returns SysML::FeatureMembership : 1100 | ownedRelatedElement += MetadataBodyFeature 1101 | ; 1102 | 1103 | MetadataBodyFeature returns SysML::Feature : 1104 | 'feature'? ( ':>>' | 'redefines' )? ownedRelationship += OwnedRedefinition 1105 | FeatureSpecializationPart? ValuePart? 1106 | MetadataBody 1107 | ; 1108 | 1109 | /* EXPRESSIONS */ 1110 | 1111 | @Override 1112 | ExpressionBody returns SysML::Expression : 1113 | '{' FunctionBodyPart '}' 1114 | ; 1115 | -------------------------------------------------------------------------------- /src/sysml2py/textx/KerMLExpressions.xtext: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * SysML 2 Pilot Implementation 3 | * Copyright (c) 2018-2023 Model Driven Solutions, Inc. 4 | * Copyright (c) 2018 IncQuery Labs Ltd. 5 | * Copyright (c) 2019 Maplesoft (Waterloo Maple, Inc.) 6 | * Copyright (c) 2019 Mgnite Inc. 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with this program. If not, see . 20 | * 21 | * @license LGPL-3.0-or-later 22 | * 23 | * Contributors: 24 | * Ed Seidewitz, MDS 25 | * Zoltan Kiss, IncQuery 26 | * Balazs Grill, IncQuery 27 | * Hisashi Miyashita, Maplesoft/Mgnite 28 | * 29 | *****************************************************************************/ 30 | 31 | grammar org.omg.kerml.expressions.xtext.KerMLExpressions hidden(WS, ML_NOTE, SL_NOTE) 32 | 33 | import "http://www.eclipse.org/emf/2002/Ecore" as Ecore 34 | import "https://www.omg.org/spec/SysML/20230201" as SysML 35 | 36 | /* EXPRESSIONS */ 37 | 38 | /* Operator Expressions */ 39 | 40 | OwnedExpressionMember returns SysML::FeatureMembership : 41 | ownedRelatedElement += OwnedExpression 42 | ; 43 | 44 | OwnedExpression returns SysML::Expression : 45 | ConditionalExpression 46 | ; 47 | 48 | // Conditional Test Expressions 49 | 50 | OwnedExpressionReference returns SysML::FeatureReferenceExpression : 51 | ownedRelationship += OwnedExpressionMember 52 | ; 53 | 54 | ConditionalExpression returns SysML::Expression : 55 | NullCoalescingExpression 56 | | {SysML::OperatorExpression} operator = ConditionalOperator operand += NullCoalescingExpression 57 | '?' operand += OwnedExpressionReference 'else' operand += OwnedExpressionReference 58 | ; 59 | 60 | ConditionalOperator : 61 | 'if' 62 | ; 63 | 64 | // Null Coalescing Expressions 65 | 66 | NullCoalescingExpression returns SysML::Expression : 67 | ImpliesExpression ( {SysML::OperatorExpression.operand += current} 68 | operator = NullCoalescingOperator operand += ImpliesExpressionReference )* 69 | ; 70 | 71 | NullCoalescingOperator : 72 | '??' 73 | ; 74 | 75 | // Logical Expressions 76 | 77 | ImpliesExpressionReference returns SysML::FeatureReferenceExpression : 78 | ownedRelationship += ImpliesExpressionMember 79 | ; 80 | 81 | ImpliesExpressionMember returns SysML::FeatureMembership : 82 | ownedRelatedElement += ImpliesExpression 83 | ; 84 | 85 | ImpliesExpression returns SysML::Expression : 86 | OrExpression ( {SysML::OperatorExpression.operand += current} 87 | operator = ImpliesOperator operand += OrExpressionReference )* 88 | ; 89 | 90 | ImpliesOperator : 91 | 'implies' 92 | ; 93 | 94 | OrExpressionReference returns SysML::FeatureReferenceExpression : 95 | ownedRelationship += OrExpressionMember 96 | ; 97 | 98 | OrExpressionMember returns SysML::FeatureMembership : 99 | ownedRelatedElement += OrExpression 100 | ; 101 | 102 | OrExpression returns SysML::Expression : 103 | XorExpression ( {SysML::OperatorExpression.operand += current} 104 | ( operator = OrOperator operand += XorExpression 105 | | operator = ConditionalOrOperator operand += XorExpressionReference ) )* 106 | ; 107 | 108 | OrOperator : 109 | '|' 110 | ; 111 | 112 | ConditionalOrOperator : 113 | 'or' 114 | ; 115 | 116 | XorExpressionReference returns SysML::FeatureReferenceExpression : 117 | ownedRelationship += XorExpressionMember 118 | ; 119 | 120 | XorExpressionMember returns SysML::FeatureMembership : 121 | ownedRelatedElement += XorExpression 122 | ; 123 | 124 | XorExpression returns SysML::Expression : 125 | AndExpression ( {SysML::OperatorExpression.operand += current} 126 | operator = XorOperator operand += AndExpression )* 127 | ; 128 | 129 | XorOperator : 130 | 'xor' 131 | ; 132 | 133 | AndExpression returns SysML::Expression : 134 | EqualityExpression ( {SysML::OperatorExpression.operand += current} 135 | ( operator = AndOperator operand += EqualityExpression 136 | | operator = ConditionalAndOperator operand += EqualityExpressionReference ) )* 137 | ; 138 | 139 | AndOperator : 140 | '&' 141 | ; 142 | 143 | ConditionalAndOperator : 144 | 'and' 145 | ; 146 | 147 | // Equality Expressions 148 | 149 | EqualityExpressionReference returns SysML::FeatureReferenceExpression : 150 | ownedRelationship += EqualityExpressionMember 151 | ; 152 | 153 | EqualityExpressionMember returns SysML::FeatureMembership : 154 | ownedRelatedElement += EqualityExpression 155 | ; 156 | 157 | EqualityExpression returns SysML::Expression : 158 | ClassificationExpression ( {SysML::OperatorExpression.operand += current} 159 | operator = EqualityOperator operand += ClassificationExpression )* 160 | 161 | ; 162 | 163 | EqualityOperator : 164 | '==' | '!=' | '===' | '!==' 165 | ; 166 | 167 | // Classification Expressions 168 | 169 | ClassificationExpression returns SysML::Expression : 170 | RelationalExpression 171 | ( {SysML::OperatorExpression.operand += current} 172 | operator = ClassificationTestOperator ownedRelationship += TypeReferenceMember 173 | | {SysML::OperatorExpression.operand += current} 174 | operator = CastOperator ownedRelationship += TypeResultMember 175 | )? 176 | | {SysML::OperatorExpression} operand += SelfReferenceExpression 177 | operator = ClassificationTestOperator ownedRelationship += TypeReferenceMember 178 | | {SysML::OperatorExpression} operand += MetadataReference 179 | operator = MetaClassificationTestOperator ownedRelationship += TypeReferenceMember 180 | | {SysML::OperatorExpression} operand += SelfReferenceExpression 181 | operator = CastOperator ownedRelationship += TypeResultMember 182 | | {SysML::OperatorExpression} operand += MetadataReference 183 | operator = MetaCastOperator ownedRelationship += TypeResultMember 184 | ; 185 | 186 | ClassificationTestOperator : 187 | 'hastype' | 'istype' | '@' 188 | ; 189 | 190 | MetaClassificationTestOperator : 191 | '@@' 192 | ; 193 | 194 | CastOperator : 195 | 'as' 196 | ; 197 | 198 | MetaCastOperator : 199 | 'meta' 200 | ; 201 | 202 | MetadataReference returns SysML::MetadataAccessExpression : 203 | referencedElement = [SysML::Element | QualifiedName] 204 | ; 205 | 206 | TypeReferenceMember returns SysML::FeatureMembership : 207 | ownedRelatedElement += TypeReference 208 | ; 209 | 210 | TypeResultMember returns SysML::ReturnParameterMembership : 211 | ownedRelatedElement += TypeReference 212 | ; 213 | 214 | TypeReference returns SysML::Feature : 215 | ownedRelationship += ReferenceTyping 216 | ; 217 | 218 | ReferenceTyping returns SysML::FeatureTyping : 219 | type = [SysML::Type | QualifiedName] 220 | ; 221 | 222 | SelfReferenceExpression returns SysML::FeatureReferenceExpression : 223 | ownedRelationship += SelfReferenceMember 224 | ; 225 | 226 | SelfReferenceMember returns SysML::ReturnParameterMembership : 227 | ownedRelatedElement += EmptyFeature 228 | ; 229 | 230 | EmptyFeature returns SysML::Feature : 231 | {SysML::Feature} 232 | ; 233 | 234 | // Relational Expressions 235 | 236 | RelationalExpression returns SysML::Expression : 237 | RangeExpression ( {SysML::OperatorExpression.operand += current} 238 | operator = RelationalOperator operand += RangeExpression )* 239 | ; 240 | 241 | RelationalOperator : 242 | '<' | '>' | '<=' | '>=' 243 | ; 244 | 245 | // Range Expressions 246 | 247 | RangeExpression returns SysML::Expression : 248 | AdditiveExpression ( {SysML::OperatorExpression.operand += current} 249 | operator = '..' operand += AdditiveExpression )? 250 | ; 251 | 252 | // Arithmetic Expressions 253 | 254 | AdditiveExpression returns SysML::Expression : 255 | MultiplicativeExpression ( {SysML::OperatorExpression.operand += current} 256 | operator = AdditiveOperator operand += MultiplicativeExpression )* 257 | ; 258 | 259 | AdditiveOperator : 260 | '+' | '-' 261 | ; 262 | 263 | MultiplicativeExpression returns SysML::Expression : 264 | ExponentiationExpression ( {SysML::OperatorExpression.operand += current} 265 | operator = MultiplicativeOperator operand += ExponentiationExpression )* 266 | ; 267 | 268 | MultiplicativeOperator : 269 | '*' | '/' | '%' 270 | ; 271 | 272 | ExponentiationExpression returns SysML::Expression : 273 | UnaryExpression ( {SysML::OperatorExpression.operand += current} 274 | operator = ExponentiationOperator operand += UnaryExpression )* 275 | ; 276 | 277 | ExponentiationOperator : 278 | '**' | '^' 279 | ; 280 | 281 | // Unary Expressions 282 | 283 | UnaryExpression returns SysML::Expression: 284 | {SysML::OperatorExpression} operator = UnaryOperator operand += ExtentExpression 285 | | ExtentExpression 286 | ; 287 | 288 | UnaryOperator : 289 | '+' | '-' | '~' | 'not' 290 | ; 291 | 292 | // Extent Expressions 293 | 294 | ExtentExpression returns SysML::Expression : 295 | {SysML::OperatorExpression} operator = 'all' ownedRelationship += TypeResultMember 296 | | PrimaryExpression 297 | ; 298 | 299 | /* Primary Expressions */ 300 | 301 | PrimaryExpression returns SysML::Expression : 302 | BaseExpression 303 | ( {SysML::FeatureChainExpression.operand += current} '.' 304 | ownedRelationship += FeatureChainMember 305 | )? 306 | ( ( {SysML::OperatorExpression.operand += current} 307 | operator = '#' '(' operand += SequenceExpression ')' 308 | | {SysML::OperatorExpression.operand += current} 309 | operator = '[' operand += SequenceExpression ']' 310 | | {SysML::OperatorExpression.operand += current} '->' 311 | ownedRelationship += ReferenceTyping 312 | ( operand += BodyExpression 313 | | operand += FunctionReferenceExpression 314 | | ArgumentList 315 | ) 316 | | {SysML::CollectExpression.operand += current} '.' 317 | operand += BodyExpression 318 | | {SysML::SelectExpression.operand += current} '.?' 319 | operand += BodyExpression 320 | ) 321 | ( {SysML::FeatureChainExpression.operand += current} '.' 322 | ownedRelationship += FeatureChainMember 323 | )? 324 | )* 325 | ; 326 | 327 | FunctionReferenceExpression returns SysML::FeatureReferenceExpression : 328 | ownedRelationship += FunctionReferenceMember 329 | ; 330 | 331 | FunctionReferenceMember returns SysML::FeatureMembership : 332 | ownedRelatedElement += FunctionReference 333 | ; 334 | 335 | FunctionReference returns SysML::Expression : 336 | ownedRelationship += ReferenceTyping 337 | ; 338 | 339 | FeatureChainMember returns SysML::Membership : 340 | memberElement = [SysML::Feature | QualifiedName] 341 | | {SysML::OwningMembership} ownedRelatedElement += OwnedFeatureChain 342 | ; 343 | 344 | /* Base Expressions */ 345 | 346 | BaseExpression returns SysML::Expression : 347 | NullExpression 348 | | LiteralExpression 349 | | FeatureReferenceExpression 350 | | MetadataAccessExpression 351 | | InvocationExpression 352 | | BodyExpression 353 | | '(' SequenceExpression ')' 354 | ; 355 | 356 | // Expression Bodies 357 | 358 | BodyExpression returns SysML::FeatureReferenceExpression : 359 | ownedRelationship += ExpressionBodyMember 360 | ; 361 | 362 | ExpressionBodyMember returns SysML::FeatureMembership : 363 | ownedRelatedElement += ExpressionBody 364 | ; 365 | 366 | // This default production is overridden in the KerML and SysML grammars. 367 | ExpressionBody returns SysML::Expression : 368 | '{' ( ownedRelationship += BodyParameterMember ';' )* 369 | ownedRelationship += ResultExpressionMember '}' 370 | ; 371 | 372 | ResultExpressionMember returns SysML::ResultExpressionMembership : 373 | ownedRelatedElement += OwnedExpression 374 | ; 375 | 376 | BodyParameterMember returns SysML::ParameterMembership : 377 | 'in' ownedRelatedElement += BodyParameter 378 | ; 379 | 380 | BodyParameter returns SysML::Feature : 381 | declaredName = Name 382 | ; 383 | 384 | // Sequence Expressions 385 | 386 | SequenceExpression returns SysML::Expression : 387 | OwnedExpression 388 | ( ',' 389 | | {SysML::OperatorExpression.operand += current} operator = ',' 390 | operand += SequenceExpression 391 | )? 392 | ; 393 | 394 | // Feature Reference Expressions 395 | 396 | FeatureReferenceExpression returns SysML::FeatureReferenceExpression : 397 | ownedRelationship += FeatureReferenceMember 398 | ; 399 | 400 | FeatureReferenceMember returns SysML::Membership : 401 | memberElement = [SysML::Feature | QualifiedName] 402 | ; 403 | 404 | // Metadata Access Expressions 405 | 406 | MetadataAccessExpression returns SysML::MetadataAccessExpression : 407 | referencedElement = [SysML::Element | QualifiedName] '.' 'metadata' 408 | ; 409 | 410 | // Invocation Expressions 411 | 412 | InvocationExpression returns SysML::InvocationExpression : 413 | ownedRelationship += OwnedFeatureTyping ArgumentList 414 | ; 415 | 416 | OwnedFeatureTyping returns SysML::FeatureTyping : 417 | type = [SysML::Type | QualifiedName] 418 | | ownedRelatedElement += OwnedFeatureChain 419 | ; 420 | 421 | OwnedFeatureChain returns SysML::Feature : 422 | FeatureChain 423 | ; 424 | 425 | // For use in KerML and SysML grammars 426 | fragment FeatureChain returns SysML::Feature : 427 | ownedRelationship += OwnedFeatureChaining 428 | ( '.' ownedRelationship += OwnedFeatureChaining )+ 429 | ; 430 | 431 | OwnedFeatureChaining returns SysML::FeatureChaining : 432 | chainingFeature = [SysML::Feature | QualifiedName] 433 | ; 434 | 435 | fragment ArgumentList returns SysML::Expression : 436 | '(' ( PositionalArgumentList | NamedArgumentList )? ')' 437 | ; 438 | 439 | fragment PositionalArgumentList returns SysML::Expression : 440 | ownedRelationship += ArgumentMember 441 | ( ',' ownedRelationship += ArgumentMember )* 442 | ; 443 | 444 | ArgumentMember returns SysML::ParameterMembership : 445 | ownedRelatedElement += Argument 446 | ; 447 | 448 | Argument returns SysML::Feature : 449 | ownedRelationship += ArgumentValue 450 | ; 451 | 452 | fragment NamedArgumentList returns SysML::Expression : 453 | ownedRelationship += NamedArgumentMember 454 | ( ',' ownedRelationship += NamedArgumentMember )* 455 | ; 456 | 457 | NamedArgumentMember returns SysML::ParameterMembership : 458 | ownedRelatedElement += NamedArgument 459 | ; 460 | 461 | NamedArgument returns SysML::Feature : 462 | ownedRelationship += ParameterRedefinition '=' ownedRelationship += ArgumentValue 463 | ; 464 | 465 | ParameterRedefinition returns SysML::Redefinition: 466 | redefinedFeature = [SysML::Feature | QualifiedName] 467 | ; 468 | 469 | ArgumentValue returns SysML::FeatureValue : 470 | ownedRelatedElement += OwnedExpression 471 | ; 472 | 473 | // Null Expressions 474 | 475 | NullExpression returns SysML::NullExpression : 476 | {SysML::NullExpression} ( 'null' | '(' ')' ) 477 | ; 478 | 479 | /* Literal Expressions */ 480 | 481 | LiteralExpression returns SysML::LiteralExpression : 482 | LiteralBoolean 483 | | LiteralString 484 | | LiteralInteger 485 | | LiteralReal 486 | | LiteralInfinity 487 | ; 488 | 489 | LiteralBoolean returns SysML::LiteralBoolean : 490 | value = BooleanValue 491 | ; 492 | 493 | BooleanValue returns Ecore::EBoolean : 494 | 'true' | 'false' 495 | ; 496 | 497 | LiteralString returns SysML::LiteralString : 498 | value = STRING_VALUE 499 | ; 500 | 501 | LiteralInteger returns SysML::LiteralInteger: 502 | value = DECIMAL_VALUE 503 | ; 504 | 505 | LiteralReal returns SysML::LiteralRational: 506 | value = RealValue 507 | ; 508 | 509 | RealValue returns Ecore::EDouble: 510 | DECIMAL_VALUE? '.' ( DECIMAL_VALUE | EXP_VALUE ) | EXP_VALUE 511 | ; 512 | 513 | LiteralInfinity returns SysML::LiteralInfinity : 514 | {SysML::LiteralInfinity} '*' 515 | ; 516 | 517 | /* NAMES */ 518 | 519 | Name: 520 | ID | UNRESTRICTED_NAME 521 | ; 522 | 523 | Qualification : 524 | ( Name '::' )+ 525 | ; 526 | 527 | QualifiedName: 528 | Qualification? Name 529 | ; 530 | 531 | /* TERMINALS */ 532 | 533 | terminal DECIMAL_VALUE returns Ecore::EInt: 534 | '0'..'9' ('0'..'9')*; 535 | 536 | terminal EXP_VALUE: 537 | DECIMAL_VALUE ('e' | 'E') ('+' | '-')? DECIMAL_VALUE; 538 | 539 | terminal ID: 540 | ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*; 541 | 542 | terminal UNRESTRICTED_NAME returns Ecore::EString: 543 | '\'' ('\\' ('b' | 't' | 'n' | 'f' | 'r' | '"' | "'" | '\\') | !('\\' | '\''))* '\''; 544 | 545 | terminal STRING_VALUE returns Ecore::EString: 546 | '"' ('\\' ('b' | 't' | 'n' | 'f' | 'r' | '"' | "'" | '\\') | !('\\' | '"'))* '"'; 547 | 548 | terminal REGULAR_COMMENT: 549 | '/*' ->'*/'; 550 | 551 | terminal ML_NOTE: 552 | '//*'->'*/'; 553 | 554 | terminal SL_NOTE: 555 | '//' (!('\n' | '\r') !('\n' | '\r')*)? ('\r'? '\n')?; 556 | 557 | terminal WS: 558 | (' ' | '\t' | '\r' | '\n')+; -------------------------------------------------------------------------------- /src/sysml2py/textx/xtext_to_textx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Wed May 24 16:41:15 2023 5 | 6 | @author: christophercox 7 | """ 8 | import re 9 | 10 | 11 | def xtext_to_textx(rules): 12 | # Remove grammar 13 | rules = re.sub("grammar .*", "", rules) 14 | 15 | # Remove imports 16 | rules = re.sub("import .*", "", rules) 17 | 18 | # Remove returns 19 | rules = re.sub("returns .*", ":", rules) 20 | 21 | # Remove terminal 22 | rules = re.sub("terminal ", "", rules) 23 | 24 | # Remove fragments 25 | rules = re.sub("fragment", "", rules) 26 | rules = re.sub("enum", "", rules) 27 | rules = re.sub(" ->", "", rules) 28 | rules = re.sub("[\s]?=>", "", rules) 29 | rules = re.sub("@Override", "", rules) 30 | 31 | # Remove SysML object references 32 | rules = re.sub("{SysML::[a-zA-Z]*}", "", rules) 33 | rules = re.sub("{SysML::[a-zA-Z\.\+\=\s]*}", "", rules) 34 | 35 | # Remove more SysML object references 36 | # rules = re.sub('SysML::Membership\|QualifiedName', 'QualifiedName', rules) 37 | # rules = re.sub('SysML::Namespace\|QualifiedName', 'QualifiedName', rules) 38 | # rules = re.sub('SysML::Element\|QualifiedName', 'QualifiedName', rules) 39 | # rules = re.sub('SysML::Feature[\s]?\|[\s]?QualifiedName', 'QualifiedName', rules) 40 | rules = re.sub( 41 | "\[[\s]?SysML::[a-zA-Z]*[\s]?\|[\s]?QualifiedName[\s]?\]", 42 | "[QualifiedName]", 43 | rules, 44 | ) 45 | rules = re.sub( 46 | "SysML::ConjugatedPortDefinition | ConjugatedQualifiedName", 47 | "ConjugatedQualifiedName", 48 | rules, 49 | ) 50 | 51 | # Fix doubles 52 | rules = re.sub("\[QualifiedName | QualifiedName\]", "[QualifiedName]", rules) 53 | rules = re.sub("\[QualifiedName\|QualifiedName\]", "[QualifiedName]", rules) 54 | 55 | # Special cases 56 | good_str = r""" 57 | MultiplicityRelatedElement : 58 | (LiteralExpression | FeatureReferenceExpression) 59 | ; 60 | 61 | MultiplicityExpressionMember : 62 | ownedRelatedElement += MultiplicityRelatedElement 63 | ;""" 64 | 65 | rules = re.sub("MultiplicityExpressionMember :[\s\S]*?;", good_str, rules) 66 | 67 | good_str = r""" 68 | ActionBodyItemTarget : 69 | ( BehaviorUsageMember | ActionNodeMember ) 70 | ; 71 | 72 | ActionBodyItem : 73 | ownedRelationship += Import 74 | | ownedRelationship += AliasMember 75 | | ownedRelationship += DefinitionMember 76 | | ownedRelationship += VariantUsageMember 77 | | ownedRelationship += NonOccurrenceUsageMember 78 | | ( ownedRelationship += EmptySuccessionMember )? 79 | ownedRelationship += StructureUsageMember 80 | | ownedRelationship += InitialNodeMember 81 | ( ownedRelationship += TargetSuccessionMember )* 82 | | ( ownedRelationship += EmptySuccessionMember )? 83 | ownedRelationship += ActionBodyItemTarget 84 | ( ownedRelationship += TargetSuccessionMember )* 85 | | ownedRelationship += GuardedSuccessionMember 86 | ; 87 | """ 88 | rules = re.sub("ActionBodyItem :[\s\S]*?;", good_str, rules) 89 | 90 | good_str = r""" 91 | IfNodeElseMember : 92 | ( ActionBodyParameterMember | IfNodeParameterMember ) 93 | ; 94 | 95 | IfNode : 96 | ActionNodePrefix 97 | 'if' ownedRelationship += ExpressionParameterMember 98 | ownedRelationship += ActionBodyParameterMember 99 | ( 'else' ownedRelationship += IfNodeElseMember )? 100 | ; 101 | """ 102 | rules = re.sub("IfNode :[\s\S]*?;", good_str, rules) 103 | 104 | good_str = r""" 105 | ( isOrdered ?= 'ordered' isNonunique ?= 'nonunique' 106 | | isNonunique2 ?= 'nonunique' isOrdered2 ?= 'ordered' 107 | ) 108 | """ 109 | rules = re.sub("\( isOrdered[a-zA-Z0-9\?\=\s'\|]*\)", good_str, rules) 110 | 111 | # These are totally broken 112 | empty_rule = "LifeClass" 113 | rules = re.sub( 114 | empty_rule + " :[\s\S]*?;", 115 | empty_rule + " ://This doesn't work.\n\t'" + empty_rule.lower() + "'\n;", 116 | rules, 117 | ) 118 | empty_rule = "EmptyTargetEnd" 119 | rules = re.sub( 120 | empty_rule + " :[\s\S]*?;", 121 | empty_rule + " ://This doesn't work.\n\t'" + empty_rule.lower() + "'\n;", 122 | rules, 123 | ) 124 | empty_rule = "PortConjugation" 125 | rules = re.sub( 126 | empty_rule + " :[\s\S]*?;", 127 | empty_rule + " ://This doesn't work.\n\t'" + empty_rule.lower() + "'\n;", 128 | rules, 129 | ) 130 | empty_rule = "EmptySourceEnd" 131 | rules = re.sub( 132 | empty_rule + " :[\s\S]*?;", 133 | empty_rule + " ://This doesn't work.\n\t'" + empty_rule.lower() + "'\n;", 134 | rules, 135 | ) 136 | empty_rule = "EmptyUsage" 137 | rules = re.sub( 138 | empty_rule + " :[\s\S]*?;", 139 | empty_rule + " ://This doesn't work.\n\t'" + empty_rule.lower() + "'\n;", 140 | rules, 141 | ) 142 | empty_rule = "EmptyActionUsage" 143 | rules = re.sub( 144 | empty_rule + " :[\s\S]*?;", 145 | empty_rule + " ://This doesn't work.\n\t'" + empty_rule.lower() + "'\n;", 146 | rules, 147 | ) 148 | empty_rule = "EmptyFeature" 149 | rules = re.sub( 150 | empty_rule + " :[\s\S]*?;", 151 | empty_rule + " ://This doesn't work.\n\t'" + empty_rule.lower() + "'\n;", 152 | rules, 153 | ) 154 | 155 | # Base rules 156 | rules = re.sub( 157 | "DECIMAL_VALUE[\s]:[\s0-9\(\)'\*\.]*;", "DECIMAL_VALUE :\n /[0-9]*/;", rules 158 | ) 159 | rules = re.sub( 160 | "ID[\s]?:[\sa-zA-Z0-9_'|().*]*;", "ID :\n /[a-zA-Z_][a-zA-Z_0-9]*/;", rules 161 | ) 162 | # rules = re.sub("UNRESTRICTED_NAME[ ]?:[\sbtnfr\"!\\_'|().*]*;", 163 | # "UNRESTRICTED_NAME: \n /'\'' ('\\' ('b' | 't' | 'n' | 'f' | 'r' | '"' | "'" | '\\') | !('\\' | '\''))* '\''/;", rules) 164 | 165 | final_rules = """; 166 | 167 | ID : 168 | /[a-zA-Z_][a-zA-Z_0-9]*/; 169 | 170 | UNRESTRICTED_NAME : 171 | /'\'' ('\\' ('b' | 't' | 'n' | 'f' | 'r' | '"' | "'" | '\\') | !('\\' | '\''))* '\''/; 172 | 173 | STRING_VALUE : 174 | /'"' ('\\' ('b' | 't' | 'n' | 'f' | 'r' | '"' | "'" | '\\') | !('\\' | '"'))* '"'/; 175 | 176 | REGULAR_COMMENT: 177 | '/*''*/'; 178 | 179 | ML_NOTE: 180 | /'\/*'->'*\/'/; 181 | 182 | SL_NOTE: 183 | /'\/\/' (!('\n' | '\r') !('\n' | '\r')*)? ('\r'? '\n')?/; 184 | 185 | WS: 186 | /(' ' | '\t' | '\r' | '\n')+/; 187 | """ 188 | rules = re.sub(";[\s]*ID[\s\S]*;", final_rules, rules) 189 | return rules 190 | 191 | 192 | if __name__ == "__main__": 193 | with open("SysML.xtext", "r") as f: 194 | rules = f.read() 195 | f.close() 196 | 197 | rules = xtext_to_textx(rules) 198 | 199 | with open("SysML.tx", "w") as f: 200 | f.write("import KerML\nimport KerMLExpressions\n" + rules) 201 | f.close() 202 | 203 | with open("KerML.xtext", "r") as f: 204 | rules = f.read() 205 | f.close() 206 | 207 | rules = xtext_to_textx(rules) 208 | 209 | with open("KerML.tx", "w") as f: 210 | f.write("import KerMLExpressions\n" + rules) 211 | f.close() 212 | 213 | with open("KerMLExpressions.xtext", "r") as f: 214 | rules = f.read() 215 | f.close() 216 | 217 | rules = xtext_to_textx(rules) 218 | 219 | with open("KerMLExpressions.tx", "w") as f: 220 | f.write(rules) 221 | f.close() 222 | -------------------------------------------------------------------------------- /src/sysml2py/usage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Fri Jun 30 23:23:31 2023 5 | 6 | @author: christophercox 7 | """ 8 | 9 | 10 | # import os 11 | 12 | # os.chdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) 13 | 14 | import uuid as uuidlib 15 | 16 | import astropy.units as u 17 | 18 | from sysml2py.formatting import classtree 19 | 20 | from sysml2py.grammar.classes import ( 21 | Identification, 22 | DefinitionBody, 23 | DefinitionBodyItem, 24 | FeatureSpecializationPart, 25 | ) 26 | 27 | from sysml2py.grammar.classes import ( 28 | AttributeUsage, 29 | AttributeDefinition, 30 | ValuePart, 31 | PartUsage, 32 | PartDefinition, 33 | ItemUsage, 34 | ItemDefinition, 35 | PortUsage, 36 | PortDefinition, 37 | DefaultReferenceUsage, 38 | RefPrefix, 39 | ) 40 | 41 | 42 | class Usage: 43 | def __init__(self): 44 | self.name = str(uuidlib.uuid4()) 45 | self.children = [] 46 | self.typedby = None 47 | return self 48 | 49 | def _ensure_body(self, subgrammar="usage"): 50 | # Add children 51 | body = [] 52 | for abc in self.children: 53 | body.append( 54 | DefinitionBodyItem( 55 | abc._get_definition(child="DefinitionBody") 56 | ).get_definition() 57 | ) 58 | 59 | if len(body) > 0: 60 | getattr(self.grammar, subgrammar).completion.body.body = DefinitionBody( 61 | {"name": "DefinitionBody", "ownedRelatedElement": body} 62 | ) 63 | return self 64 | 65 | def usage_dump(self, child): 66 | # This is a usage. 67 | 68 | self._ensure_body("usage") 69 | 70 | # Add packaging 71 | package = { 72 | "name": "StructureUsageElement", 73 | "ownedRelatedElement": self.grammar.get_definition(), 74 | } 75 | package = {"name": "OccurrenceUsageElement", "ownedRelatedElement": package} 76 | 77 | if child == "DefinitionBody": 78 | package = { 79 | "name": "OccurrenceUsageMember", 80 | "prefix": None, 81 | "ownedRelatedElement": [package], 82 | } 83 | 84 | package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]} 85 | elif "PackageBody": 86 | package = {"name": "UsageElement", "ownedRelatedElement": package} 87 | package = { 88 | "name": "PackageMember", 89 | "ownedRelatedElement": package, 90 | "prefix": None, 91 | } 92 | 93 | return package 94 | 95 | def definition_dump(self, child): 96 | # This is a definition. 97 | 98 | self._ensure_body("definition") 99 | 100 | package = { 101 | "name": "DefinitionElement", 102 | "ownedRelatedElement": self.grammar.get_definition(), 103 | } 104 | 105 | if child == "DefinitionBody": 106 | package = { 107 | "name": "DefinitionMember", 108 | "prefix": None, 109 | "ownedRelatedElement": [package], 110 | } 111 | 112 | package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]} 113 | 114 | elif child == "PackageBody" or child == None: 115 | # Add these packets to make this dump without parents 116 | 117 | package = { 118 | "name": "PackageMember", 119 | "ownedRelatedElement": package, 120 | "prefix": None, 121 | } 122 | 123 | return package 124 | 125 | def _get_definition(self, child=None): 126 | if "usage" in self.grammar.__dict__: 127 | package = self.usage_dump(child) 128 | else: 129 | package = self.definition_dump(child) 130 | 131 | if child is None: 132 | package = { 133 | "name": "PackageBodyElement", 134 | "ownedRelationship": [package], 135 | "prefix": None, 136 | } 137 | 138 | # Add the typed by definition to the package output 139 | if self.typedby is not None: 140 | if child is None: 141 | package["ownedRelationship"].insert( 142 | 0, self.typedby._get_definition(child="PackageBody") 143 | ) 144 | elif child == "PackageBody": 145 | package = [self.typedby._get_definition(child="PackageBody"), package] 146 | else: 147 | package["ownedRelationship"].insert( 148 | 0, self.typedby._get_definition(child=child)["ownedRelationship"][0] 149 | ) 150 | 151 | return package 152 | 153 | def dump(self, child=None): 154 | return classtree(self._get_definition(child)).dump() 155 | 156 | def _set_name(self, name, short=False): 157 | if hasattr(self.grammar, "usage"): 158 | path = self.grammar.usage.declaration.declaration 159 | elif hasattr(self.grammar, "definition"): 160 | path = self.grammar.definition.declaration 161 | else: 162 | if hasattr(self.grammar.declaration, "declaration"): 163 | path = self.grammar.declaration.declaration 164 | else: 165 | path = self.grammar.declaration 166 | 167 | if path.identification is None: 168 | path.identification = Identification() 169 | 170 | if short: 171 | path.identification.declaredShortName = "<" + name + ">" 172 | else: 173 | self.name = name 174 | path.identification.declaredName = name 175 | 176 | return self 177 | 178 | def _get_name(self): 179 | return self.grammar.usage.declaration.declaration.identification.declaredName 180 | 181 | def _set_child(self, child): 182 | self.children.append(child) 183 | return self 184 | 185 | def _get_child(self, featurechain): 186 | # 'x.y.z' 187 | if isinstance(featurechain, str): 188 | fc = featurechain.split(".") 189 | else: 190 | raise TypeError 191 | 192 | if fc[0] == self.name: 193 | # This first one must match self name, otherwise pass it all 194 | featurechain = ".".join(fc[1:]) 195 | 196 | for child in self.children: 197 | fcs = featurechain.split(".") 198 | if child.name == fcs[0]: 199 | if len(fcs) == 1: 200 | return child 201 | else: 202 | return child._get_child(featurechain) 203 | 204 | def _set_typed_by(self, typed): 205 | # Only set if the pointed object is a definition 206 | if "definition" in typed.grammar.__dict__: 207 | self.typedby = typed 208 | if "definition" in self.grammar.__dict__: 209 | raise ValueError("A definition element cannot be defined.") 210 | else: 211 | if self.grammar.usage.declaration.declaration.specialization is None: 212 | package = { 213 | "name": "QualifiedName", 214 | "names": [typed.name], 215 | } 216 | package = { 217 | "name": "FeatureType", 218 | "type": package, 219 | "ownedRelatedElement": [], 220 | } 221 | package = {"name": "OwnedFeatureTyping", "type": package} 222 | package = {"name": "FeatureTyping", "ownedRelationship": package} 223 | package = {"name": "TypedBy", "ownedRelationship": [package]} 224 | package = { 225 | "name": "Typings", 226 | "typedby": package, 227 | "ownedRelationship": [], 228 | } 229 | package = { 230 | "name": "FeatureSpecialization", 231 | "ownedRelationship": package, 232 | } 233 | package = { 234 | "name": "FeatureSpecializationPart", 235 | "specialization": [package], 236 | "multiplicity": None, 237 | "specialization2": [], 238 | "multiplicity2": None, 239 | } 240 | self.grammar.usage.declaration.declaration.specialization = ( 241 | FeatureSpecializationPart(package) 242 | ) 243 | else: 244 | raise ValueError("Typed by element was not a definition.") 245 | return self 246 | 247 | def _get_grammar(self): 248 | self._ensure_body() 249 | return self.grammar 250 | 251 | def load_from_grammar(self, grammar): 252 | #!TODO Typed By 253 | self.__init__() 254 | self.grammar = grammar 255 | children = [] 256 | if "usage" in self.grammar.__dict__: 257 | # This is a usage 258 | u_name = grammar.usage.declaration.declaration.identification.declaredName 259 | a_children = grammar.usage.completion.body.body.children 260 | 261 | for child in a_children: 262 | children.append(child.children[0].children[0]) 263 | else: 264 | # This is a definition 265 | u_name = grammar.definition.declaration.identification.declaredName 266 | a_children = grammar.definition.body.children 267 | if len(a_children) > 0: 268 | children = a_children[0] 269 | 270 | if u_name is not None: 271 | self.name = u_name 272 | 273 | for child in children: 274 | sc = child.children 275 | if isinstance(sc, list): 276 | if len(sc) == 1: 277 | sc = sc[0] 278 | 279 | if sc.__class__.__name__ == "AttributeUsage": 280 | self.children.append(Attribute().load_from_grammar(sc)) 281 | elif sc.__class__.__name__ == "ItemDefinition": 282 | self.children.append(Item().load_from_grammar(sc)) 283 | elif sc.__class__.__name__ == "StructureUsageElement": 284 | if sc.children.__class__.__name__ == "PartUsage": 285 | self.children.append(Part().load_from_grammar(sc.children)) 286 | elif sc.children.__class__.__name__ == "ItemUsage": 287 | self.children.append(Item().load_from_grammar(sc.children)) 288 | else: 289 | print(child.children.children.__class__.__name__) 290 | raise NotImplementedError 291 | else: 292 | print(sc.__class__.__name__) 293 | raise NotImplementedError 294 | 295 | return self 296 | 297 | def add_directed_feature(self, direction, name=str(uuidlib.uuid4())): 298 | self._set_child(DefaultReference()._set_name(name).set_direction(direction)) 299 | return self 300 | 301 | # def modify_directed_feature(self, direction, name): 302 | # child = self._get_child(name) 303 | # if child is not None: 304 | # pass 305 | # else: 306 | # raise AttributeError("Invalid Feature Name or Chain") 307 | 308 | 309 | class Attribute(Usage): 310 | def __init__(self, definition=False, name=None): 311 | Usage.__init__(self) 312 | 313 | if definition: 314 | self.grammar = AttributeDefinition() 315 | else: 316 | self.grammar = AttributeUsage() 317 | 318 | def usage_dump(self, child): 319 | # Override - base output 320 | 321 | # Add children 322 | body = [] 323 | for abc in self.children: 324 | body.append(DefinitionBodyItem(abc.dump(child=True)).get_definition()) 325 | if len(body) > 0: 326 | self.grammar.usage.completion.body.body = DefinitionBody( 327 | {"name": "DefinitionBody", "ownedRelatedElement": body} 328 | ) 329 | 330 | # Add packaging 331 | package = { 332 | "name": "NonOccurrenceUsageElement", 333 | "ownedRelatedElement": self.grammar.get_definition(), 334 | } 335 | 336 | if child: 337 | package = { 338 | "name": "NonOccurrenceUsageMember", 339 | "prefix": None, 340 | "ownedRelatedElement": [package], 341 | } 342 | package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]} 343 | else: 344 | # Add these packets to make this dump without parents 345 | package = {"name": "UsageElement", "ownedRelatedElement": package} 346 | package = { 347 | "name": "PackageMember", 348 | "ownedRelatedElement": package, 349 | "prefix": None, 350 | } 351 | return package 352 | 353 | def set_value(self, value): 354 | if not isinstance(value, u.quantity.Quantity): 355 | value = value * u.one 356 | if isinstance(value, u.quantity.Quantity): 357 | if str(value.unit) != "": 358 | package_units = { 359 | "name": "QualifiedName", 360 | "names": [str(value.unit)], 361 | } 362 | package_units = { 363 | "name": "FeatureReferenceMember", 364 | "memberElement": package_units, 365 | } 366 | package_units = { 367 | "name": "FeatureReferenceExpression", 368 | "ownedRelationship": [package_units], 369 | } 370 | package_units = { 371 | "name": "BaseExpression", 372 | "ownedRelationship": package_units, 373 | } 374 | package_units = { 375 | "name": "PrimaryExpression", 376 | "operand": [], 377 | "base": package_units, 378 | "operator": [], 379 | "ownedRelationship1": [], 380 | "ownedRelationship2": [], 381 | } 382 | package_units = { 383 | "name": "ExtentExpression", 384 | "operator": "", 385 | "ownedRelationship": [], 386 | "primary": package_units, 387 | } 388 | package_units = { 389 | "name": "UnaryExpression", 390 | "operand": [], 391 | "operator": None, 392 | "extent": package_units, 393 | } 394 | package_units = { 395 | "name": "ExponentiationExpression", 396 | "operand": [], 397 | "operator": [], 398 | "unary": package_units, 399 | } 400 | package_units = { 401 | "name": "MultiplicativeExpression", 402 | "operation": [], 403 | "exponential": package_units, 404 | } 405 | package_units = { 406 | "name": "AdditiveExpression", 407 | "operation": [], 408 | "multiplicitive": package_units, 409 | } 410 | package_units = { 411 | "name": "RangeExpression", 412 | "operand": None, 413 | "additive": package_units, 414 | } 415 | package_units = { 416 | "name": "RelationalExpression", 417 | "operation": [], 418 | "range": package_units, 419 | } 420 | package_units = { 421 | "name": "ClassificationExpression", 422 | "operand": [], 423 | "operator": None, 424 | "ownedRelationship": [], 425 | "relational": package_units, 426 | } 427 | package_units = { 428 | "name": "EqualityExpression", 429 | "operation": [], 430 | "classification": package_units, 431 | } 432 | package_units = { 433 | "name": "AndExpression", 434 | "operation": [], 435 | "equality": package_units, 436 | } 437 | package_units = { 438 | "name": "XorExpression", 439 | "operand": [], 440 | "operator": [], 441 | "and": package_units, 442 | } 443 | package_units = { 444 | "name": "OrExpression", 445 | "xor": package_units, 446 | "operand": [], 447 | "operator": [], 448 | } 449 | package_units = { 450 | "name": "ImpliesExpression", 451 | "operand": [], 452 | "operator": [], 453 | "or": package_units, 454 | } 455 | package_units = { 456 | "name": "NullCoalescingExpression", 457 | "implies": package_units, 458 | "operator": [], 459 | "operand": [], 460 | } 461 | package_units = { 462 | "name": "ConditionalExpression", 463 | "operator": None, 464 | "operand": [package_units], 465 | } 466 | package_units = {"name": "OwnedExpression", "expression": package_units} 467 | package_units = { 468 | "name": "SequenceExpression", 469 | "operation": [], 470 | "ownedRelationship": package_units, 471 | } 472 | package_units = [package_units] 473 | operator = ["["] 474 | else: 475 | package_units = [] 476 | operator = [] 477 | 478 | package = { 479 | "name": "BaseExpression", 480 | "ownedRelationship": { 481 | "name": "LiteralInteger", 482 | "value": str(value.value), 483 | }, 484 | } 485 | package = { 486 | "name": "PrimaryExpression", 487 | "operand": package_units, 488 | "base": package, 489 | "operator": operator, 490 | "ownedRelationship1": [], 491 | "ownedRelationship2": [], 492 | } 493 | package = { 494 | "name": "ExtentExpression", 495 | "operator": "", 496 | "ownedRelationship": [], 497 | "primary": package, 498 | } 499 | package = { 500 | "name": "UnaryExpression", 501 | "operand": [], 502 | "operator": None, 503 | "extent": package, 504 | } 505 | package = { 506 | "name": "ExponentiationExpression", 507 | "operand": [], 508 | "operator": [], 509 | "unary": package, 510 | } 511 | package = { 512 | "name": "MultiplicativeExpression", 513 | "operation": [], 514 | "exponential": package, 515 | } 516 | package = { 517 | "name": "AdditiveExpression", 518 | "operation": [], 519 | "multiplicitive": package, 520 | } 521 | package = { 522 | "name": "RangeExpression", 523 | "operand": None, 524 | "additive": package, 525 | } 526 | package = { 527 | "name": "RelationalExpression", 528 | "operation": [], 529 | "range": package, 530 | } 531 | package = { 532 | "name": "ClassificationExpression", 533 | "operand": [], 534 | "operator": None, 535 | "ownedRelationship": [], 536 | "relational": package, 537 | } 538 | package = { 539 | "name": "EqualityExpression", 540 | "operation": [], 541 | "classification": package, 542 | } 543 | package = { 544 | "name": "AndExpression", 545 | "operation": [], 546 | "equality": package, 547 | } 548 | package = { 549 | "name": "XorExpression", 550 | "operand": [], 551 | "operator": [], 552 | "and": package, 553 | } 554 | package = { 555 | "name": "OrExpression", 556 | "xor": package, 557 | "operand": [], 558 | "operator": [], 559 | } 560 | package = { 561 | "name": "ImpliesExpression", 562 | "operand": [], 563 | "operator": [], 564 | "or": package, 565 | } 566 | package = { 567 | "name": "NullCoalescingExpression", 568 | "implies": package, 569 | "operator": [], 570 | "operand": [], 571 | } 572 | package = { 573 | "name": "ConditionalExpression", 574 | "operator": None, 575 | "operand": [package], 576 | } 577 | package = {"name": "OwnedExpression", "expression": package} 578 | package = { 579 | "name": "FeatureValue", 580 | "isDefault": False, 581 | "isEqual": False, 582 | "isInitial": False, 583 | "ownedRelatedElement": package, 584 | } 585 | package = {"name": "ValuePart", "ownedRelationship": [package]} 586 | self.grammar.usage.completion.valuepart = ValuePart(package) 587 | # value.unit 588 | 589 | return self 590 | 591 | def get_value(self): 592 | realpart = ( 593 | self.grammar.usage.completion.valuepart.relationships[0] 594 | .element.expression.operands[0] 595 | .implies.orexpression.xor.andexpression.equality.classification.relational.range.additive.left_hand.exponential.unary.extent.primary 596 | ) 597 | real = float(realpart.base.relationship.dump()) 598 | unit = ( 599 | realpart.operand[0] 600 | .relationship.expression.operands[0] 601 | .implies.orexpression.xor.andexpression.equality.classification.relational.range.additive.left_hand.exponential.unary.extent.primary.base.relationship.children[ 602 | 0 603 | ] 604 | .memberElement.dump() 605 | ) 606 | return real * u.Unit(unit) 607 | 608 | 609 | class Part(Usage): 610 | def __init__(self, definition=False, name=None): 611 | Usage.__init__(self) 612 | if definition: 613 | self.grammar = PartDefinition() 614 | else: 615 | self.grammar = PartUsage() 616 | 617 | 618 | class Item(Usage): 619 | def __init__(self, definition=False, name=None): 620 | Usage.__init__(self) 621 | if definition: 622 | self.grammar = ItemDefinition() 623 | else: 624 | self.grammar = ItemUsage() 625 | 626 | 627 | class Port(Usage): 628 | def __init__(self, definition=False, name=None): 629 | Usage.__init__(self) 630 | if definition: 631 | self.grammar = PortDefinition() 632 | else: 633 | self.grammar = PortUsage() 634 | 635 | 636 | class DefaultReference(Usage): 637 | def __init__(self): 638 | Usage.__init__(self) 639 | self.grammar = DefaultReferenceUsage() 640 | 641 | def set_direction(self, direction): 642 | r = RefPrefix() 643 | if direction == "in": 644 | r.direction.isIn = True 645 | elif direction == "out": 646 | r.direction.isOut = True 647 | elif direction == "inout": 648 | r.direction.isInOut = True 649 | else: 650 | raise ValueError 651 | self.grammar.prefix = r 652 | return self 653 | 654 | def usage_dump(self, child): 655 | # This is a usage. 656 | 657 | self._ensure_body("definition") 658 | 659 | # Add packaging 660 | package = { 661 | "name": "NonOccurrenceUsageElement", 662 | "ownedRelatedElement": self.grammar.get_definition(), 663 | } 664 | 665 | if child == "DefinitionBody": 666 | package = { 667 | "name": "NonOccurrenceUsageMember", 668 | "prefix": None, 669 | "ownedRelatedElement": [package], 670 | } 671 | 672 | package = {"name": "DefinitionBodyItem", "ownedRelationship": [package]} 673 | elif "PackageBody": 674 | package = {"name": "UsageElement", "ownedRelatedElement": package} 675 | package = { 676 | "name": "PackageMember", 677 | "ownedRelatedElement": package, 678 | "prefix": None, 679 | } 680 | 681 | return package 682 | 683 | def _get_definition(self, child=None): 684 | package = self.usage_dump(child) 685 | 686 | if child is None: 687 | package = { 688 | "name": "PackageBodyElement", 689 | "ownedRelationship": [package], 690 | "prefix": None, 691 | } 692 | 693 | # Add the typed by definition to the package output 694 | if self.typedby is not None: 695 | if child is None: 696 | package["ownedRelationship"].insert( 697 | 0, self.typedby._get_definition(child="PackageBody") 698 | ) 699 | elif child == "PackageBody": 700 | package = [self.typedby._get_definition(child="PackageBody"), package] 701 | else: 702 | package["ownedRelationship"].insert( 703 | 0, self.typedby._get_definition(child=child)["ownedRelationship"][0] 704 | ) 705 | 706 | return package 707 | 708 | # def dump(self, child=None): 709 | # package = self.usage_dump(child) 710 | 711 | # if child is None: 712 | # package = { 713 | # "name": "PackageBodyElement", 714 | # "ownedRelationship": [package], 715 | # "prefix": None, 716 | # } 717 | 718 | # # Add the typed by definition to the package output 719 | # if self.typedby is not None: 720 | # if child is None: 721 | # package["ownedRelationship"].insert( 722 | # 0, self.typedby.dump(child="PackageBody") 723 | # ) 724 | # elif child == "PackageBody": 725 | # package = [self.typedby.dump(child="PackageBody"), package] 726 | # else: 727 | # package["ownedRelationship"].insert( 728 | # 0, self.typedby.dump(child=child)["ownedRelationship"][0] 729 | # ) 730 | 731 | # return package 732 | -------------------------------------------------------------------------------- /tests/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Westfall-io/sysml2py/b1e59714c239394cacd8542e8b4ae343aa15e843/tests/.DS_Store -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Westfall-io/sysml2py/b1e59714c239394cacd8542e8b4ae343aa15e843/tests/__init__.py -------------------------------------------------------------------------------- /tests/class_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Tue Jul 11 16:46:28 2023 5 | 6 | @author: christophercox 7 | """ 8 | 9 | import pytest 10 | 11 | from sysml2py.formatting import classtree 12 | from sysml2py import Package, Item, Model, Attribute, Part, Port 13 | from sysml2py import load_grammar as loads 14 | 15 | 16 | def test_package(): 17 | p = classtree(Package()._get_definition()).dump() 18 | 19 | text = """package ;""" 20 | q = classtree(loads(text)).dump() 21 | 22 | assert p == q 23 | 24 | 25 | def test_package_name(): 26 | name = "Rocket" 27 | p = classtree(Package()._set_name(name)._get_definition()).dump() 28 | 29 | text = "package " + name + ";" 30 | q = classtree(loads(text)).dump() 31 | 32 | assert p == q 33 | 34 | 35 | def test_package_shortname(): 36 | name = "'3.1'" 37 | p = classtree(Package()._set_name(name, short=True)._get_definition()).dump() 38 | 39 | text = "package <" + name + ">;" 40 | q = classtree(loads(text)).dump() 41 | 42 | assert p == q 43 | 44 | 45 | def test_package_setbothnames(): 46 | name = "Rocket" 47 | shortname = "'3.1'" 48 | p = classtree( 49 | Package()._set_name(name)._set_name(shortname, short=True)._get_definition() 50 | ).dump() 51 | 52 | text = "package <" + shortname + "> " + name + ";" 53 | q = classtree(loads(text)).dump() 54 | 55 | assert p == q 56 | 57 | 58 | def test_package_getname(): 59 | name = "Rocket" 60 | p = Package()._set_name(name) 61 | assert p._get_name() == name 62 | 63 | 64 | def test_package_addchild(): 65 | p1 = Package()._set_name("Rocket") 66 | p2 = Package()._set_name("Engine") 67 | p1._set_child(p2) 68 | p = classtree(p1._get_definition()).dump() 69 | 70 | text = """package Rocket { 71 | package Engine; 72 | }""" 73 | 74 | q = classtree(loads(text)).dump() 75 | 76 | assert p == q 77 | 78 | 79 | def test_package_get_child(): 80 | p1 = Package()._set_name("Rocket") 81 | p2 = Package()._set_name("Engine") 82 | p1._set_child(p2) 83 | p = classtree(p1._get_child("Rocket.Engine")._get_definition()).dump() 84 | 85 | text = """package Engine;""" 86 | 87 | q = classtree(loads(text)).dump() 88 | 89 | assert p == q 90 | 91 | 92 | def test_package_get_child_method2(): 93 | p1 = Package()._set_name("Rocket") 94 | p2 = Package()._set_name("Engine") 95 | p1._set_child(p2) 96 | p = classtree(p1._get_child("Engine")._get_definition()).dump() 97 | 98 | text = """package Engine;""" 99 | 100 | q = classtree(loads(text)).dump() 101 | 102 | assert p == q 103 | 104 | 105 | def test_package_typed_child(): 106 | p1 = Package()._set_name("Rocket") 107 | i1 = Item(definition=True)._set_name("Fuel") 108 | i2 = Item()._set_name("Hydrogen") 109 | p1._set_child(i2) 110 | i2._set_typed_by(i1) 111 | p = classtree(p1._get_definition()).dump() 112 | 113 | text = """package Rocket { 114 | item def Fuel ; 115 | item Hydrogen : Fuel; 116 | }""" 117 | 118 | q = classtree(loads(text)).dump() 119 | 120 | assert p == q 121 | 122 | 123 | def test_package_load_grammar(): 124 | p = Package() 125 | 126 | text = """package Rocket { 127 | item def Fuel ; 128 | item Hydrogen : Fuel; 129 | }""" 130 | q = Model().load(text) 131 | p.load_from_grammar(q._get_child("Rocket")._get_grammar()) 132 | 133 | assert p.dump() == q.dump() 134 | 135 | 136 | def test_model_cannot_dump_error(): 137 | m = Model() 138 | with pytest.raises(ValueError, match="Base Model has no elements."): 139 | m.dump() 140 | 141 | 142 | def test_model_load_error_not_package_def(): 143 | text = """item def Fuel ;""" 144 | with pytest.raises( 145 | ValueError, match="Base Model must be encapsulated by a package." 146 | ): 147 | Model().load(text) 148 | 149 | 150 | def test_model_load_error_not_package_usage(): 151 | text = """item Fuel ;""" 152 | with pytest.raises( 153 | ValueError, match="Base Model must be encapsulated by a package." 154 | ): 155 | Model().load(text) 156 | 157 | 158 | def test_model_add_child(): 159 | m = Model() 160 | p1 = Package()._set_name("Rocket") 161 | p2 = Package()._set_name("Payload") 162 | m._set_child(p1) 163 | m._set_child(p2) 164 | 165 | text = """package Rocket; 166 | package Payload;""" 167 | q = classtree(loads(text)) 168 | assert m.dump() == q.dump() 169 | 170 | 171 | def test_model_get_child(): 172 | m = Model() 173 | p1 = Package()._set_name("Rocket") 174 | p2 = Package()._set_name("Payload") 175 | m._set_child(p1) 176 | m._set_child(p2) 177 | m2 = m._get_child("Rocket") 178 | 179 | text = """package Rocket;""" 180 | q = classtree(loads(text)) 181 | assert m2.dump() == q.dump() 182 | 183 | 184 | def test_model_load(): 185 | p1 = Package()._set_name("Rocket") 186 | i1 = Item(definition=True)._set_name("Fuel") 187 | i2 = Item()._set_name("Hydrogen") 188 | p1._set_child(i2) 189 | i2._set_typed_by(i1) 190 | p = classtree(p1._get_definition()) 191 | 192 | text = """package Rocket { 193 | item def Fuel ; 194 | item Hydrogen : Fuel; 195 | }""" 196 | 197 | q = Model().load(text) 198 | 199 | assert p.dump() == q.dump() 200 | 201 | 202 | def test_item(): 203 | i1 = Item() 204 | text = """item;""" 205 | i2 = classtree(loads(text)) 206 | 207 | assert i1.dump() == i2.dump() 208 | 209 | 210 | def test_item_def(): 211 | i1 = Item(definition=True) 212 | text = """item def;""" 213 | i2 = classtree(loads(text)) 214 | 215 | assert i1.dump() == i2.dump() 216 | 217 | 218 | def test_item_name(): 219 | i1 = Item()._set_name("Fuel") 220 | text = """item Fuel;""" 221 | i2 = classtree(loads(text)) 222 | 223 | assert i1.dump() == i2.dump() 224 | 225 | 226 | def test_item_shortname(): 227 | i1 = Item()._set_name("'3.1'", short=True) 228 | text = """item <'3.1'>;""" 229 | i2 = classtree(loads(text)) 230 | 231 | assert i1.dump() == i2.dump() 232 | 233 | 234 | def test_item_getname(): 235 | name = "Fuel" 236 | i1 = Item()._set_name(name) 237 | 238 | assert i1._get_name() == name 239 | 240 | 241 | def test_item_setchild(): 242 | i1 = Item()._set_name("Fuel") 243 | ic1 = Item() 244 | i1._set_child(ic1) 245 | text = """item Fuel { 246 | item; 247 | }""" 248 | i2 = classtree(loads(text)) 249 | 250 | assert i1.dump() == i2.dump() 251 | 252 | 253 | def test_item_getchild(): 254 | i1 = Item()._set_name("Fuel") 255 | ic1 = Item()._set_name("Fuel_child") 256 | i1._set_child(ic1) 257 | text = """item Fuel_child;""" 258 | i2 = classtree(loads(text)) 259 | 260 | assert i1._get_child("Fuel.Fuel_child").dump() == i2.dump() 261 | 262 | 263 | def test_item_getchild_skipelement(): 264 | i1 = Item()._set_name("Fuel") 265 | ic1 = Item()._set_name("Fuel_child") 266 | i1._set_child(ic1) 267 | text = """item Fuel_child;""" 268 | i2 = classtree(loads(text)) 269 | 270 | assert i1._get_child("Fuel_child").dump() == i2.dump() 271 | 272 | 273 | def test_item_getchild_threelevel(): 274 | i1 = Item()._set_name("Fuel") 275 | ic1 = Item()._set_name("child") 276 | ic2 = Item()._set_name("subchild") 277 | i1._set_child(ic1) 278 | ic1._set_child(ic2) 279 | text = """item subchild;""" 280 | i2 = classtree(loads(text)) 281 | 282 | assert i1._get_child("Fuel.child.subchild").dump() == i2.dump() 283 | 284 | 285 | def test_item_getchild_error_int(): 286 | i1 = Item()._set_name("Fuel") 287 | ic1 = Item()._set_name("Fuel_child") 288 | i1._set_child(ic1) 289 | with pytest.raises(TypeError): 290 | i1._get_child(1) 291 | 292 | 293 | def test_item_getchild_error_str(): 294 | i1 = Item()._set_name("Fuel") 295 | ic1 = Item()._set_name("Fuel_child") 296 | i1._set_child(ic1) 297 | assert i1._get_child("Fuel.error") == None 298 | 299 | 300 | def test_item_typedby(): 301 | p1 = Package()._set_name("Store") 302 | i1 = Item()._set_name("apple") 303 | i2 = Item(definition=True)._set_name("Fruit") 304 | p1._set_child(i1) 305 | i1._set_typed_by(i2) 306 | 307 | text = """package Store { 308 | item def Fruit ; 309 | item apple : Fruit; 310 | }""" 311 | p2 = classtree(loads(text)) 312 | 313 | assert p1.dump() == p2.dump() 314 | 315 | 316 | def test_item_typedby_invalidusage_twousage(): 317 | i1 = Item()._set_name("apple") 318 | i2 = Item()._set_name("Fruit") 319 | with pytest.raises(ValueError): 320 | i1._set_typed_by(i2) 321 | 322 | 323 | def test_item_typedby_invalidusage_twodef(): 324 | i1 = Item(definition=True)._set_name("apple") 325 | i2 = Item(definition=True)._set_name("Fruit") 326 | with pytest.raises(ValueError): 327 | i1._set_typed_by(i2) 328 | 329 | 330 | def test_part_load_grammar(): 331 | p = Part() 332 | 333 | text = """package Rocket { 334 | package EngineAssembly; 335 | part Tank { 336 | item def Fuel ; 337 | item Hydrogen : Fuel; 338 | } 339 | }""" 340 | q = Model().load(text)._get_child("Rocket.Tank") 341 | p.load_from_grammar(q._get_grammar()) 342 | 343 | assert p.dump() == q.dump() 344 | 345 | 346 | def test_part(): 347 | i1 = Part() 348 | text = """part;""" 349 | i2 = classtree(loads(text)) 350 | 351 | assert i1.dump() == i2.dump() 352 | 353 | 354 | def test_part_def(): 355 | i1 = Part(definition=True) 356 | text = """part def;""" 357 | i2 = classtree(loads(text)) 358 | 359 | assert i1.dump() == i2.dump() 360 | 361 | 362 | def test_part_name(): 363 | i1 = Part()._set_name("Fuel") 364 | text = """part Fuel;""" 365 | i2 = classtree(loads(text)) 366 | 367 | assert i1.dump() == i2.dump() 368 | 369 | 370 | def test_part_shortname(): 371 | i1 = Part()._set_name("'3.1'", short=True) 372 | text = """part <'3.1'>;""" 373 | i2 = classtree(loads(text)) 374 | 375 | assert i1.dump() == i2.dump() 376 | 377 | 378 | def test_part_getname(): 379 | name = "Fuel" 380 | i1 = Part()._set_name(name) 381 | 382 | assert i1._get_name() == name 383 | 384 | 385 | def test_part_setchild(): 386 | i1 = Part()._set_name("Fuel") 387 | ic1 = Part() 388 | i1._set_child(ic1) 389 | text = """part Fuel { 390 | part; 391 | }""" 392 | i2 = classtree(loads(text)) 393 | 394 | assert i1.dump() == i2.dump() 395 | 396 | 397 | def test_part_getchild(): 398 | i1 = Part()._set_name("Fuel") 399 | ic1 = Part()._set_name("Fuel_child") 400 | i1._set_child(ic1) 401 | text = """part Fuel_child;""" 402 | i2 = classtree(loads(text)) 403 | 404 | assert i1._get_child("Fuel.Fuel_child").dump() == i2.dump() 405 | 406 | 407 | def test_part_getchild_error_int(): 408 | i1 = Part()._set_name("Fuel") 409 | ic1 = Part()._set_name("Fuel_child") 410 | i1._set_child(ic1) 411 | with pytest.raises(TypeError): 412 | i1._get_child(1) 413 | 414 | 415 | def test_part_getchild_error_str(): 416 | i1 = Part()._set_name("Fuel") 417 | ic1 = Part()._set_name("Fuel_child") 418 | i1._set_child(ic1) 419 | assert i1._get_child("Fuel.error") == None 420 | 421 | 422 | def test_part_typedby(): 423 | p1 = Package()._set_name("Store") 424 | i1 = Part()._set_name("apple") 425 | i2 = Part(definition=True)._set_name("Fruit") 426 | p1._set_child(i1) 427 | i1._set_typed_by(i2) 428 | 429 | text = """package Store { 430 | part def Fruit ; 431 | part apple : Fruit; 432 | }""" 433 | p2 = classtree(loads(text)) 434 | 435 | assert p1.dump() == p2.dump() 436 | 437 | 438 | def test_part_typedby_invalidusage_twousage(): 439 | i1 = Part()._set_name("apple") 440 | i2 = Part()._set_name("Fruit") 441 | with pytest.raises(ValueError): 442 | i1._set_typed_by(i2) 443 | 444 | 445 | def test_part_typedby_invalidusage_twodef(): 446 | i1 = Part(definition=True)._set_name("apple") 447 | i2 = Part(definition=True)._set_name("Fruit") 448 | with pytest.raises(ValueError): 449 | i1._set_typed_by(i2) 450 | 451 | 452 | def test_port(): 453 | o1 = Port() 454 | text = """port;""" 455 | o2 = classtree(loads(text)) 456 | 457 | assert o1.dump() == o2.dump() 458 | 459 | 460 | def test_port_def(): 461 | o1 = Port(definition=True) 462 | text = """port def;""" 463 | o2 = classtree(loads(text)) 464 | 465 | assert o1.dump() == o2.dump() 466 | 467 | 468 | def test_port_directed_in(): 469 | o1 = Port()._set_name("FuelHose") 470 | o1.add_directed_feature("in", "Fuel") 471 | text = """port FuelHose { 472 | in Fuel ; 473 | }""" 474 | o2 = classtree(loads(text)) 475 | assert o1.dump() == o2.dump() 476 | 477 | 478 | def test_port_directed_out(): 479 | o1 = Port()._set_name("FuelHose") 480 | o1.add_directed_feature("out", "Fuel") 481 | text = """port FuelHose { 482 | out Fuel ; 483 | }""" 484 | o2 = classtree(loads(text)) 485 | assert o1.dump() == o2.dump() 486 | 487 | 488 | def test_port_directed_inout(): 489 | o1 = Port()._set_name("FuelHose") 490 | o1.add_directed_feature("inout", "Fuel") 491 | text = """port FuelHose { 492 | inout Fuel ; 493 | }""" 494 | o2 = classtree(loads(text)) 495 | assert o1.dump() == o2.dump() 496 | 497 | 498 | def test_port_directed_error(): 499 | o1 = Port() 500 | with pytest.raises(ValueError): 501 | o1.add_directed_feature("error", "Fuel") 502 | 503 | 504 | # This test doesn't work right now 505 | # def test_item_def_subchild(): 506 | # i = Item(definition=True)._set_name("Engine") 507 | # import astropy.units as u 508 | 509 | # a = Attribute()._set_name("mass") 510 | # a.set_value(100 * u.kg) 511 | # i._set_child(a) 512 | 513 | # text = """item Engine { 514 | # attribute mass= 100.0 [kg]; 515 | # }""" 516 | 517 | # q = classtree(loads(text)) 518 | 519 | # assert i.dump() == q.dump() 520 | 521 | 522 | def test_attribute_definition(): 523 | import astropy.units as u 524 | 525 | a = Attribute(definition=True)._set_name("mass") 526 | 527 | text = """attribute def mass;""" 528 | 529 | q = classtree(loads(text)) 530 | 531 | assert a.dump() == q.dump() 532 | 533 | 534 | def test_attribute_units(): 535 | import astropy.units as u 536 | 537 | a = Attribute()._set_name("mass") 538 | a.set_value(100 * u.kg) 539 | 540 | text = """attribute mass= 100.0 [kg];""" 541 | 542 | q = classtree(loads(text)) 543 | 544 | assert a.dump() == q.dump() 545 | 546 | 547 | def test_attribute_getunits(): 548 | import astropy.units as u 549 | 550 | value = 100 * u.kg 551 | 552 | a = Attribute()._set_name("mass") 553 | a.set_value(value) 554 | 555 | assert value == a.get_value() 556 | 557 | 558 | def test_attribute_nounits(): 559 | a = Attribute()._set_name("mass") 560 | a.set_value(100) 561 | 562 | text = """attribute mass= 100.0;""" 563 | 564 | q = classtree(loads(text)) 565 | 566 | assert a.dump() == q.dump() 567 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Tue Jul 11 22:49:00 2023 5 | 6 | @author: christophercox 7 | """ 8 | 9 | import pytest 10 | 11 | 12 | @pytest.fixture 13 | def single_package(): 14 | return """package;""" 15 | -------------------------------------------------------------------------------- /tests/functions.py: -------------------------------------------------------------------------------- 1 | import re 2 | import string 3 | 4 | 5 | def remove_comments(string): 6 | pattern = r"(\".*?\"|\'.*?\')|(//[^\r\n]*$)" 7 | # first group captures quoted strings (double or single) 8 | # second group captures comments (//single-line or /* multi-line */) 9 | regex = re.compile(pattern, re.MULTILINE | re.DOTALL) 10 | 11 | def _replacer(match): 12 | # if the 2nd group (capturing comments) is not None, 13 | # it means we have captured a non-quoted (real) comment string. 14 | if match.group(2) is not None: 15 | return "" # so we will return empty to remove the comment 16 | else: # otherwise, we will return the 1st group 17 | return match.group(1) # captured quoted-string 18 | 19 | return regex.sub(_replacer, string) 20 | 21 | 22 | def strip_ws(text): 23 | text = remove_comments(text) 24 | text = text.replace("specializes", ":>") 25 | text = text.replace("subsets", ":>") 26 | text = text.replace("redefines", ":>>") 27 | return text.translate(str.maketrans("", "", string.whitespace)) 28 | -------------------------------------------------------------------------------- /tests/main_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Mon May 29 23:20:18 2023 5 | 6 | @author: christophercox 7 | """ 8 | import pytest 9 | 10 | from sysml2py import load, loads, load_grammar 11 | from sysml2py.formatting import classtree 12 | 13 | from textx import TextXSyntaxError 14 | 15 | from .functions import strip_ws 16 | 17 | 18 | def test_grammar_load_fromfile(single_package): 19 | with open("temp.txt", "w") as f: 20 | f.write(single_package) 21 | f.close() 22 | 23 | f = open("temp.txt", "r") 24 | grammar = load_grammar(f) 25 | assert strip_ws(classtree(grammar).dump()) == strip_ws(single_package) 26 | 27 | 28 | def test_grammar_invalid_input(): 29 | with pytest.raises(TypeError): 30 | load_grammar({}) 31 | 32 | 33 | def test_load_fromfile(single_package): 34 | with open("temp.txt", "w") as f: 35 | f.write(single_package) 36 | f.close() 37 | 38 | f = open("temp.txt", "r") 39 | model = load(f) 40 | assert strip_ws(model.dump()) == strip_ws(single_package) 41 | 42 | 43 | def test_load_fromfile_error(single_package): 44 | with pytest.raises(TypeError): 45 | load("string") 46 | 47 | 48 | def test_load_fromstr(single_package): 49 | model = loads(single_package) 50 | assert strip_ws(model.dump()) == strip_ws(single_package) 51 | 52 | 53 | def test_load_fromstr_error(single_package): 54 | with pytest.raises(TypeError): 55 | loads({}) 56 | 57 | 58 | def test_invalid_sysml(): 59 | with pytest.raises(TextXSyntaxError): 60 | loads("error") 61 | --------------------------------------------------------------------------------