├── requirements.txt ├── a2lparser ├── gen │ ├── .gitignore │ └── __init__.py ├── logs │ ├── .gitignore │ └── __init__.py ├── a2l │ ├── __init__.py │ ├── ast │ │ └── __init__.py │ ├── lex │ │ ├── __init__.py │ │ ├── keywords │ │ │ ├── __init__.py │ │ │ ├── a2l_keywords_datatypes.py │ │ │ ├── a2l_keywords_enums.py │ │ │ └── a2l_keywords_sections.py │ │ ├── lexer_keywords.py │ │ └── lexer_regex.py │ └── rules │ │ └── __init__.py ├── cli │ ├── __init__.py │ └── command_prompt.py ├── converter │ ├── __init__.py │ ├── yaml_converter.py │ └── json_converter.py ├── a2lparser_exception.py └── __init__.py ├── .flake8 ├── codecov.yml ├── .github └── workflows │ ├── build.yml │ ├── flake8.yml │ ├── main.yml │ └── publish-to-pypi.yml ├── testfiles └── A2L │ ├── TEST_Nested_Includes.a2l │ ├── AMLTemplate.aml │ └── submodules │ ├── MODULE_INCLUDES.a2l │ ├── TRANSFORMERS.a2l │ └── MEASUREMENTS.a2l ├── pyproject.toml ├── tests ├── __init__.py ├── conftest.py ├── lex │ ├── test_lex_newlines.py │ ├── test_lex_keywords.py │ ├── test_lex_tags_begin_end.py │ └── test_lex_datatypes.py ├── rules │ ├── test_rules_def_characteristic.py │ ├── test_rules_a2ml_version.py │ ├── test_rules_asap2_version.py │ ├── test_rules_formula.py │ ├── test_rules_function_list.py │ ├── test_rules_header.py │ ├── test_rules_dependent_characteristic.py │ ├── test_rules_var_forbidden_comb.py │ ├── test_rules_user_rights.py │ ├── test_rules_bit_operation.py │ ├── test_rules_var_criterion.py │ ├── test_rules_ar_component.py │ ├── test_rules_compu_vtab_range.py │ ├── test_rules_var_characteristic.py │ ├── test_rules_frame.py │ ├── test_rules_virtual_characteristic.py │ ├── test_rules_memory_layout.py │ ├── test_rules_compu_tab.py │ ├── test_rules_mod_common.py │ ├── test_rules_compu_vtab.py │ ├── test_rules_typedef_blob.py │ ├── test_rules_project.py │ ├── test_rules_unit.py │ ├── test_rules_overwrite.py │ ├── test_rules_calibration_handle.py │ ├── test_rules_annotation.py │ ├── test_rules_memory_segment.py │ ├── test_rules_structure_component.py │ ├── test_rules_compu_method.py │ ├── test_rules_calibration_method.py │ ├── test_rules_typedef_structure.py │ └── test_rules_transformer.py ├── integration │ ├── test_integration_version.py │ ├── test_integration_asap2_demo_v161.py │ ├── test_integration_asap2_demo_v171.py │ └── test_integration_nested_includes.py ├── fixture_utils.py ├── ast │ └── test_ast_generator.py └── parser │ └── test_parser_find_includes.py ├── .gitignore └── setup.py /requirements.txt: -------------------------------------------------------------------------------- 1 | ply 2 | loguru 3 | alive-progress 4 | prompt-toolkit 5 | pyyaml 6 | xmltodict -------------------------------------------------------------------------------- /a2lparser/gen/.gitignore: -------------------------------------------------------------------------------- 1 | # This directory will contain the generated A2L yacc tables 2 | # Ignore everything in this directory 3 | * 4 | # Except this file 5 | !.gitignore 6 | !__init__.py -------------------------------------------------------------------------------- /a2lparser/logs/.gitignore: -------------------------------------------------------------------------------- 1 | # This directory will contain the history of the commands used with the CLI. 2 | # Ignore everything in this directory 3 | * 4 | # Except this file 5 | !.gitignore 6 | !__init__.py -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | show-source = True 3 | 4 | count = True 5 | 6 | statistics = True 7 | 8 | max-line-length = 100 9 | 10 | exclude = .tox,.venv,.env,venv,env,build,dist,doc,a2lparser/gen/ 11 | 12 | extend-ignore = E203 13 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | require_ci_to_pass: yes 3 | 4 | coverage: 5 | precision: 2 6 | round: down 7 | range: "70...100" 8 | 9 | parsers: 10 | gcov: 11 | branch_detection: 12 | conditional: yes 13 | loop: yes 14 | method: no 15 | macro: no 16 | 17 | comment: 18 | layout: "reach,diff,flags,files,footer" 19 | behavior: default 20 | require_changes: no 21 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | # Controls when the action will run. 4 | on: push 5 | 6 | jobs: 7 | build-Linux: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | # Checkout the repository under $GITHUB_WORKSPACE and install python 12 | - uses: actions/checkout@v3 13 | - name: Set up Python 14 | uses: actions/setup-python@v4 15 | with: 16 | python-version: 3.11 17 | # Set up virtual environment 18 | - name: Set up virtual environment 19 | run: | 20 | python -m pip install --upgrade pip 21 | python -m venv .venv 22 | - name: Activate virtual environment 23 | run: source .venv/bin/activate 24 | # Install build dependencies 25 | - name: Install build dependencies 26 | run: | 27 | python -m pip install setuptools wheel build 28 | # Building the package 29 | - name: Build package 30 | run: | 31 | python -m build 32 | # Installing package 33 | - name: Install package 34 | run: | 35 | pip install dist/*.whl 36 | # Running a2lparser. 37 | - name: Print package version 38 | run: | 39 | a2lparser --version || exit 1 40 | -------------------------------------------------------------------------------- /.github/workflows/flake8.yml: -------------------------------------------------------------------------------- 1 | name: flake8 2 | 3 | # Controls when the action will run. 4 | on: 5 | # Triggers the workflow on push or pull request events but only for the main branch 6 | push: 7 | branches: [ main ] 8 | pull_request: 9 | branches: [ main ] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | # Checkout the repository under $GITHUB_WORKSPACE and install python 20 | - uses: actions/checkout@v3 21 | - name: Set up Python 22 | uses: actions/setup-python@v4 23 | with: 24 | python-version: '3.11' 25 | # Set up the environment 26 | - name: Create a virtual environment 27 | run: | 28 | python -m pip install --upgrade pip 29 | python -m venv .venv 30 | - name: Activate the virtual environment 31 | run: | 32 | source .venv/bin/activate 33 | - name: Install flake8 34 | run: | 35 | pip install flake8 36 | # Performs a flake8 check on the fritzsniffer package and tests 37 | - name: Run flake8 38 | run: | 39 | flake8 a2lparser/ tests/ --config=.flake8 40 | -------------------------------------------------------------------------------- /testfiles/A2L/TEST_Nested_Includes.a2l: -------------------------------------------------------------------------------- 1 | /* ============================================================================================== */ 2 | /* */ 3 | /* Nested Includes Test File (ASAP2 V1.7.1) */ 4 | /* */ 5 | /* Note: */ 6 | /* This A2L file will include a module which itself uses the include mechanism. */ 7 | /* The values used are not meant to make sense in a practical way. */ 8 | /* Used for testing nested include mechanism. */ 9 | /* */ 10 | /* ============================================================================================== */ 11 | 12 | 13 | ASAP2_VERSION 1 71 /* Version 1.7.1 */ 14 | 15 | 16 | /begin PROJECT NESTED_INCLUDES "Tests including multiple subnested modules." 17 | 18 | /begin HEADER "Multiple Nested Includes Example File" 19 | VERSION "V1.7.1" 20 | PROJECT_NO T23_NESTED_MULTIPLE_INCLUDES 21 | /end HEADER 22 | 23 | /INCLUDE "submodules/MODULE_INCLUDES.a2l" 24 | 25 | /end PROJECT -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools", "wheel"] 3 | 4 | [project] 5 | name = "a2lparser" 6 | requires-python = ">=3.11" 7 | authors = [ 8 | { name = "mrom1", email = "mrom@linuxmail.org" } 9 | ] 10 | description="ASAP2 A2L file parsing tool." 11 | readme = "README.md" 12 | keywords = ["a2lparser", "A2L", "ASAP2", "ASAM MCD-2MC"] 13 | license = { file = "LICENSE" } 14 | dynamic = ["version"] 15 | classifiers = [ 16 | "Programming Language :: Python :: 3.11", 17 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 18 | "Operating System :: OS Independent", 19 | ] 20 | dependencies = [ 21 | "ply", 22 | "loguru", 23 | "alive-progress", 24 | "prompt-toolkit", 25 | "pyyaml", 26 | "xmltodict", 27 | ] 28 | 29 | [project.urls] 30 | "Homepage" = "https://github.com/mrom1/a2lparser" 31 | "Repository" = "https://github.com/mrom1/a2lparser.git" 32 | "Bug Reports" = "https://github.com/mrom1/a2lparser/issues" 33 | 34 | [tool.setuptools.packages.find] 35 | exclude = ["tests*"] 36 | 37 | [tool.setuptools] 38 | package-data = {"a2lparser" = ["*.cfg", "*.config"]} 39 | 40 | [project.scripts] 41 | a2lparser = "a2lparser.main:main" 42 | 43 | [tool.black] 44 | line-length = 100 45 | include = '\.pyi?$' 46 | exclude = ''' 47 | /( 48 | \.git 49 | | \.hg 50 | | \.mypy_cache 51 | | \.tox 52 | | \.venv 53 | | \.env 54 | | _build 55 | | buck-out 56 | | build 57 | | dist 58 | )/ 59 | ''' 60 | 61 | # Uncomment to always show output from tests in pytest 62 | # [tool.pytest.ini_options] 63 | # addopts = "-s" 64 | 65 | [tool.pylint.messages_control] 66 | max-line-length = 128 67 | disable="C0114, R0903, W0718, W0401, C0302" 68 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | -------------------------------------------------------------------------------- /a2lparser/a2l/__init__.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | -------------------------------------------------------------------------------- /a2lparser/cli/__init__.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | -------------------------------------------------------------------------------- /a2lparser/gen/__init__.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | -------------------------------------------------------------------------------- /a2lparser/a2l/ast/__init__.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | -------------------------------------------------------------------------------- /a2lparser/a2l/lex/__init__.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | -------------------------------------------------------------------------------- /a2lparser/logs/__init__.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | -------------------------------------------------------------------------------- /a2lparser/a2l/rules/__init__.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | -------------------------------------------------------------------------------- /a2lparser/converter/__init__.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | -------------------------------------------------------------------------------- /a2lparser/a2l/lex/keywords/__init__.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | -------------------------------------------------------------------------------- /a2lparser/a2lparser_exception.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | class A2LParserException(Exception): 23 | """ 24 | Exception thrown when encountering a fatal error during parsing. 25 | """ 26 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: a2lparser 2 | 3 | # Controls when the action will run. 4 | on: 5 | # Triggers the workflow on push or pull request events but only for the main branch 6 | push: 7 | branches: [ main ] 8 | pull_request: 9 | branches: [ main ] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | steps: 18 | # Checkout the repository under $GITHUB_WORKSPACE and install python 19 | - uses: actions/checkout@v3 20 | - name: Set up Python 21 | uses: actions/setup-python@v4 22 | with: 23 | python-version: 3.11 24 | 25 | # Set up virtual environment 26 | - name: Create virtual environment 27 | run: | 28 | python -m pip install --upgrade pip 29 | python -m venv .venv 30 | - name: Activate virtual environment 31 | run: | 32 | source .venv/bin/activate 33 | 34 | # Install a2lparser dependencies 35 | - name: Install dependencies 36 | run: | 37 | pip install coverage pytest pytest-timeout 38 | pip install -r requirements.txt 39 | 40 | # Initialize a2lparser by importing for first time 41 | - name: Initialize a2lparser 42 | run: | 43 | python -c "import a2lparser" 44 | 45 | # Run Testcases and generate report 46 | - name: Testcases 47 | run: | 48 | coverage run --omit="test_a2l_ast.py,tests/*,a2lparser/gen/*" -m pytest -v --timeout=30 49 | coverage report -m 50 | coverage xml 51 | 52 | # Upload code coverage report 53 | - name: Upload coverage report to Codecov 54 | uses: codecov/codecov-action@v3 55 | with: 56 | token: ${{ secrets.CODECOV_TOKEN }} 57 | files: ./coverage.xml 58 | env_vars: OS,PYTHON 59 | name: codecov-umbrella 60 | verbose: true 61 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | # Import fixtures to make them available across all tests. 23 | # These imports are not used directly in this file but are necessary 24 | # for pytest to recognize and use these fixtures. 25 | from .fixture_utils import create_file # noqa: F401, pylint: disable=unused-import 26 | from .fixture_utils import compare_files # noqa: F401, pylint: disable=unused-import 27 | from .fixture_utils import check_files_exist # noqa: F401, pylint: disable=unused-import 28 | -------------------------------------------------------------------------------- /tests/lex/test_lex_newlines.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_lex import A2LLex 23 | 24 | 25 | def test_lex_newlines(): 26 | """ 27 | Testing the A2L Lexer for detection of newlines. 28 | """ 29 | multliline_string = """ 30 | 31 | 3 32 | 4 33 | 34 | 6 35 | 7 36 | 8 37 | 38 | 39 | 40 | 12 41 | 42 | 14 43 | 15 44 | """ 45 | lexer = A2LLex() 46 | lexer.input(multliline_string) 47 | while True: 48 | if token := lexer.token(): 49 | assert token.value == str(lexer.get_current_line_position()) 50 | else: 51 | break 52 | -------------------------------------------------------------------------------- /tests/rules/test_rules_def_characteristic.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_def_characteristic(): 26 | """ 27 | Tests a A2L DEF_CHARACTERISTIC section. 28 | """ 29 | characteristic_block = """ 30 | /begin DEF_CHARACTERISTIC INJECTION_CURVE 31 | DELAY_FACTOR 32 | RANDOM_FACTOR 33 | /end DEF_CHARACTERISTIC 34 | """ 35 | ast = A2LYacc().generate_ast(characteristic_block) 36 | assert ast 37 | assert ast["DEF_CHARACTERISTIC"] == { 38 | "Identifier": ["INJECTION_CURVE", "DELAY_FACTOR", "RANDOM_FACTOR"] 39 | } 40 | -------------------------------------------------------------------------------- /tests/rules/test_rules_a2ml_version.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_a2ml_version(): 26 | """ 27 | Tests parsing a valid "A2ML_VERSION" type. 28 | """ 29 | a2ml_version_input = """ 30 | A2ML_VERSION 31 | 1 32 | 61 /* Version 1.6.1 */ 33 | """ 34 | parser = A2LYacc() 35 | ast = parser.generate_ast(a2ml_version_input) 36 | assert ast 37 | 38 | a2ml_version = ast["A2ML_VERSION"] 39 | assert a2ml_version 40 | assert a2ml_version["VersionNo"] == "1" 41 | assert a2ml_version["UpgradeNo"] == "61" 42 | -------------------------------------------------------------------------------- /tests/rules/test_rules_asap2_version.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_asap2_version(): 26 | """ 27 | Tests parsing a valid "ASAP2_VERSION" type. 28 | """ 29 | asap2_version_input = """ 30 | ASAP2_VERSION 31 | 4 32 | 91 /* Version 4.9.1 */ 33 | """ 34 | parser = A2LYacc() 35 | ast = parser.generate_ast(asap2_version_input) 36 | assert ast 37 | 38 | asap2_version = ast["ASAP2_VERSION"] 39 | assert asap2_version 40 | assert asap2_version["VersionNo"] == "4" 41 | assert asap2_version["UpgradeNo"] == "91" 42 | -------------------------------------------------------------------------------- /tests/rules/test_rules_formula.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_formula(): 26 | """ 27 | Tests a A2L FORMULA section. 28 | """ 29 | formula_block = """ 30 | /begin FORMULA 31 | "sqrt( 3 - 4*sin(X1) )" 32 | FORMULA_INV "asin( sqrt( (3 - X1)/4 ) )" 33 | /end FORMULA 34 | """ 35 | ast = A2LYacc().generate_ast(formula_block) 36 | assert ast 37 | 38 | formula = ast["FORMULA"] 39 | assert formula 40 | assert formula["f_x"] == '"sqrt( 3 - 4*sin(X1) )"' 41 | assert formula["FORMULA_INV"]["g_x"] == '"asin( sqrt( (3 - X1)/4 ) )"' 42 | -------------------------------------------------------------------------------- /tests/rules/test_rules_function_list.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_function_list(): 26 | """ 27 | Tests parsing a valid "FUNCTION_LIST" block. 28 | """ 29 | function_list_block = """ 30 | /begin FUNCTION_LIST 31 | ID_ADJUSTM 32 | FL_ADJUSTM 33 | SPEED_LIM 34 | /end FUNCTION_LIST 35 | """ 36 | parser = A2LYacc() 37 | ast = parser.generate_ast(function_list_block) 38 | assert ast 39 | 40 | function_list = ast["FUNCTION_LIST"] 41 | assert function_list 42 | assert function_list["Name"] == ["ID_ADJUSTM", "FL_ADJUSTM", "SPEED_LIM"] 43 | -------------------------------------------------------------------------------- /tests/rules/test_rules_header.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_header(): 26 | """ 27 | Tests parsing a A2L "HEADER" section. 28 | """ 29 | header_block = """ 30 | /begin HEADER "see also specification XYZ of 01.02.1994" 31 | VERSION "BG5.0815" 32 | PROJECT_NO M4711Z1 33 | /end HEADER 34 | """ 35 | parser = A2LYacc() 36 | ast = parser.generate_ast(header_block) 37 | assert ast 38 | 39 | header = ast["HEADER"] 40 | assert header 41 | assert header["Comment"] == '"see also specification XYZ of 01.02.1994"' 42 | assert header["PROJECT_NO"] == "M4711Z1" 43 | assert header["VERSION"] == '"BG5.0815"' 44 | -------------------------------------------------------------------------------- /tests/rules/test_rules_dependent_characteristic.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_dependent_characteristic(): 26 | """ 27 | Tests a A2L DEPENDENT_CHARACTERISTIC section. 28 | """ 29 | dependent_characteristic_block = """ 30 | /begin DEPENDENT_CHARACTERISTIC 31 | "X2-X1" 32 | ParamA /* is referenced by X1 */ 33 | ParamB /* is referenced by X2 */ 34 | /end DEPENDENT_CHARACTERISTIC 35 | """ 36 | ast = A2LYacc().generate_ast(dependent_characteristic_block) 37 | assert ast 38 | assert ast["DEPENDENT_CHARACTERISTIC"]["FORMULA"] == '"X2-X1"' 39 | assert ast["DEPENDENT_CHARACTERISTIC"]["CHARACTERISTIC"] == ["ParamA", "ParamB"] 40 | -------------------------------------------------------------------------------- /a2lparser/a2l/lex/lexer_keywords.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.lex.keywords.a2l_keywords_types import A2LKeywordsTypes 23 | from a2lparser.a2l.lex.keywords.a2l_keywords_enums import A2LKeywordsEnums 24 | from a2lparser.a2l.lex.keywords.a2l_keywords_sections import A2LKeywordsSections 25 | from a2lparser.a2l.lex.keywords.a2l_keywords_datatypes import A2LKeywordsDataTypes 26 | 27 | 28 | class LexerKeywords: 29 | """ 30 | Holds a collection of keyword tokens used in an A2L file. 31 | """ 32 | 33 | keywords_type: list = A2LKeywordsTypes.keywords 34 | keywords_enum: list = A2LKeywordsEnums.keywords 35 | keywords_section: list = A2LKeywordsSections.keywords 36 | keywords_datatypes: list = A2LKeywordsDataTypes.keywords 37 | -------------------------------------------------------------------------------- /tests/integration/test_integration_version.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import pytest 23 | from a2lparser import __version__ 24 | from a2lparser.main import main 25 | 26 | 27 | def test_integration_version_argument(monkeypatch, capsys): 28 | """ 29 | Tests the "version" parameter of the a2lparser. 30 | 31 | Calls "a2lparser --version" and checks if the output contains the expected version information. 32 | """ 33 | # Modify sys.argv to include the version argument 34 | monkeypatch.setattr("sys.argv", ["a2lparser", "--version"]) 35 | 36 | # Call main function 37 | with pytest.raises(SystemExit): 38 | main() 39 | 40 | # Capture the output 41 | captured = capsys.readouterr() 42 | 43 | # Check if the output contains the expected version information 44 | assert f"a2lparser version: {__version__}\n" == captured.out 45 | -------------------------------------------------------------------------------- /testfiles/A2L/AMLTemplate.aml: -------------------------------------------------------------------------------- 1 | /begin A2ML 2 | 3 | /* template.aml *******************************************************************/ 4 | /* */ 5 | /* */ 6 | /* Template for designing IF_DATA fields for ASAM MCD-2MC files and BLOB's */ 7 | /* for driver interface. */ 8 | /* ********************************************************************************/ 9 | block "IF_DATA" taggedunion if_data 10 | { 11 | "ASAP1B_EXAMPLE" /* The tag of ASAP1B is reserved for ASAM Interfaces */ 12 | /* EXAMPLE shall be substituted with a name of */ 13 | /* manufacturer's choice. */ 14 | 15 | taggedstruct /* optional parameters */ 16 | 17 | (block "SOURCE" struct 18 | { 19 | struct /* indispensable */ 20 | { 21 | char [101]; /* source name (string)*/ 22 | int; /* min period ( conforming together with min factor */ 23 | /* the fastest samplingrate available ). */ 24 | long; /* min factor */ 25 | }; 26 | taggedstruct /* optional parameters */ 27 | { 28 | block "QP_BLOB" struct /* QP_BLOB for driver */ 29 | { 30 | /* QP_BLOB specification */ 31 | }; 32 | }; 33 | } 34 | )*; /* multiple SOURCE may exist */ 35 | 36 | block "TP_BLOB" struct /* TP_BLOB for driver */ 37 | { 38 | /* TP_BLOB specification */ 39 | }; 40 | 41 | block "DP_BLOB" struct /* DP_BLOB for driver */ 42 | { 43 | /* DP_BLOB specification */ 44 | }; 45 | 46 | block "PA_BLOB" struct /* PA_BLOB for driver */ 47 | { 48 | /* PA_BLOB specification */ 49 | }; 50 | block "KP_BLOB" struct /* KP_BLOB for driver */ 51 | { 52 | /* KP_BLOB specification */ 53 | }; 54 | 55 | /* for MODULE may only TP_BLOB and SOURCE be specified */ 56 | /* for CHARACTERISTIC may only DP_BLOB and PA_BLOB be specified */ 57 | /* for AXIS_PTS may only DP_BLOB and PA_BLOB be specified */ 58 | /* for MEMORY_LAYOUT may only DP_BLOB and PA_BLOB be specified */ 59 | /* for MEASUREMENT may only KP_BLOB, DP_BLOB and PA_BLOB be specified */ 60 | }; 61 | 62 | /* Extra tags can be defined here */ 63 | 64 | }; 65 | 66 | /***********************************************************************/ 67 | /end A2ML -------------------------------------------------------------------------------- /.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 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 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 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Tests output 114 | testfiles/temp_dir_output_*/ 115 | 116 | # Spyder project settings 117 | .spyderproject 118 | .spyproject 119 | 120 | # Rope project settings 121 | .ropeproject 122 | 123 | # mkdocs documentation 124 | /site 125 | 126 | # mypy 127 | .mypy_cache/ 128 | .dmypy.json 129 | dmypy.json 130 | 131 | # Pyre type checker 132 | .pyre/ 133 | 134 | # Visual Studio (Code) Environment 135 | .vs/ 136 | .vscode/ -------------------------------------------------------------------------------- /tests/rules/test_rules_var_forbidden_comb.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_var_forbidden_comb(): 26 | """ 27 | Tests parsing a valid "VAR_FORBIDDEN_COMB" block. 28 | """ 29 | var_forbidden_comb_block = """ 30 | /begin VAR_FORBIDDEN_COMB 31 | Car Limousine /* variant value 'Limousine' of criterion 'Car' */ 32 | Gear Manual /* variant value 'Manual' of criterion 'Gear' */ 33 | /end VAR_FORBIDDEN_COMB 34 | """ 35 | parser = A2LYacc() 36 | ast = parser.generate_ast(var_forbidden_comb_block) 37 | assert ast 38 | 39 | var_forbidden_comb = ast["VAR_FORBIDDEN_COMB"] 40 | assert var_forbidden_comb 41 | assert var_forbidden_comb["CriterionList"][0][0] == "Car" 42 | assert var_forbidden_comb["CriterionList"][0][1] == "Limousine" 43 | assert var_forbidden_comb["CriterionList"][1][0] == "Gear" 44 | assert var_forbidden_comb["CriterionList"][1][1] == "Manual" 45 | -------------------------------------------------------------------------------- /tests/rules/test_rules_user_rights.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_user_rights(): 26 | """ 27 | Tests parsing a valid "USER_RIGHTS" block. 28 | """ 29 | user_rights_block = """ 30 | /begin USER_RIGHTS 31 | measurement_engineers 32 | /begin REF_GROUP 33 | group_1 34 | group_2 35 | group_3 36 | /end REF_GROUP 37 | READ_ONLY 38 | /end USER_RIGHTS 39 | """ 40 | parser = A2LYacc() 41 | ast = parser.generate_ast(user_rights_block) 42 | assert ast 43 | 44 | user_rights = ast["USER_RIGHTS"] 45 | assert user_rights 46 | assert user_rights["UserLevelId"] == "measurement_engineers" 47 | assert user_rights["READ_ONLY"] is True 48 | 49 | assert user_rights["REF_GROUP"]["Identifier"][0] == "group_1" 50 | assert user_rights["REF_GROUP"]["Identifier"][1] == "group_2" 51 | assert user_rights["REF_GROUP"]["Identifier"][2] == "group_3" 52 | -------------------------------------------------------------------------------- /tests/rules/test_rules_bit_operation.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_bit_operation(): 26 | """ 27 | Tests parsing a valid "BIT_OPERATION" block. 28 | """ 29 | bit_operation_block = """ 30 | /begin BIT_OPERATION 31 | RIGHT_SHIFT 4 /*4 positions*/ 32 | LEFT_SHIFT 0 33 | SIGN_EXTEND 34 | /end BIT_OPERATION 35 | /begin BIT_OPERATION 36 | RIGHT_SHIFT 1 /*4 positions*/ 37 | LEFT_SHIFT 2 38 | /end BIT_OPERATION 39 | """ 40 | parser = A2LYacc() 41 | ast = parser.generate_ast(bit_operation_block) 42 | assert ast 43 | 44 | bit_operation = ast["BIT_OPERATION"] 45 | assert bit_operation 46 | assert len(bit_operation) == 2 47 | 48 | assert bit_operation[0]["LEFT_SHIFT"]["Bitcount"] == "0" 49 | assert bit_operation[0]["RIGHT_SHIFT"]["Bitcount"] == "4" 50 | assert bit_operation[0]["SIGN_EXTEND"]["Boolean"] is True 51 | assert bit_operation[1]["LEFT_SHIFT"]["Bitcount"] == "2" 52 | assert bit_operation[1]["RIGHT_SHIFT"]["Bitcount"] == "1" 53 | -------------------------------------------------------------------------------- /tests/rules/test_rules_var_criterion.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_var_criterion(): 26 | """ 27 | Tests parsing a valid "VAR_CRITERION" block. 28 | """ 29 | var_criterion_block = """ 30 | /begin VAR_CRITERION 31 | Car 32 | "Car body" /*Enumeration of criterion values*/ 33 | Limousine Kombi Cabrio 34 | VAR_MEASUREMENT S_CAR 35 | VAR_SELECTION_CHARACTERISTIC V_CAR 36 | /end VAR_CRITERION 37 | """ 38 | parser = A2LYacc() 39 | ast = parser.generate_ast(var_criterion_block) 40 | assert ast 41 | 42 | var_criterion = ast["VAR_CRITERION"] 43 | assert var_criterion 44 | assert var_criterion["Name"] == "Car" 45 | assert var_criterion["LongIdentifier"] == '"Car body"' 46 | assert var_criterion["VALUE"][0] == "Limousine" 47 | assert var_criterion["VALUE"][1] == "Kombi" 48 | assert var_criterion["VALUE"][2] == "Cabrio" 49 | assert var_criterion["VAR_MEASUREMENT"] == "S_CAR" 50 | assert var_criterion["VAR_SELECTION_CHARACTERISTIC"] == "V_CAR" 51 | -------------------------------------------------------------------------------- /a2lparser/a2l/lex/keywords/a2l_keywords_datatypes.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | class A2LKeywordsDataTypes: 23 | """ 24 | Keywords for parsing A2L data types like "BYTE", "LONG" etc. 25 | """ 26 | 27 | keywords: list = [ 28 | # atatypes 29 | "SBYTE", 30 | "UBYTE", 31 | "UWORD", 32 | "SWORD", 33 | "ULONG", 34 | "SLONG", 35 | "A_UINT64", 36 | "A_INT64", 37 | "FLOAT16_IEEE", 38 | "FLOAT32_IEEE", 39 | "FLOAT64_IEEE", 40 | # datasizes 41 | "BYTE", 42 | "WORD", 43 | "LONG", 44 | # addrtypes 45 | "PBYTE", 46 | "PWORD", 47 | "PLONG", 48 | "PLONGLONG", 49 | "DIRECT", 50 | # byteoders 51 | "LITTLE_ENDIAN", 52 | "BIG_ENDIAN", 53 | "MSB_LAST", 54 | "MSB_FIRST", 55 | "MSB_FIRST_MSW_LAST", 56 | "MSB_LAST_MSW_FIRST", 57 | # indexorders 58 | "INDEX_INCR", 59 | "INDEX_DECR", 60 | # attributes 61 | "INTERN", 62 | "EXTERN", 63 | # encoding types 64 | "UTF8", 65 | "UTF16", 66 | "UTF32", 67 | ] 68 | -------------------------------------------------------------------------------- /tests/rules/test_rules_ar_component.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_ar_component_minimal(): 26 | """ 27 | Testing A2L AR_COMPONENT section. 28 | """ 29 | ar_component_minimal = """ 30 | /begin AR_COMPONENT 31 | "ApplicationSwComponentType" 32 | /end AR_COMPONENT 33 | """ 34 | ast = A2LYacc().generate_ast(ar_component_minimal) 35 | assert ast 36 | 37 | ar_component = ast["AR_COMPONENT"] 38 | assert ar_component 39 | assert ar_component["ComponentType"] == '"ApplicationSwComponentType"' 40 | 41 | 42 | def test_rules_ar_component_full(): 43 | """ 44 | Testing A2L AR_COMPONENT section. 45 | """ 46 | ar_component_full = """ 47 | /begin AR_COMPONENT 48 | "ApplicationSwComponentType" 49 | AR_PROTOTYPE_OF "HANDLE" 50 | /end AR_COMPONENT 51 | """ 52 | ast = A2LYacc().generate_ast(ar_component_full) 53 | assert ast 54 | 55 | ar_component = ast["AR_COMPONENT"] 56 | assert ar_component 57 | assert ar_component["ComponentType"] == '"ApplicationSwComponentType"' 58 | assert ar_component["AR_PROTOTYPE_OF"] == '"HANDLE"' 59 | -------------------------------------------------------------------------------- /testfiles/A2L/submodules/MODULE_INCLUDES.a2l: -------------------------------------------------------------------------------- 1 | /* ============================================================================================== */ 2 | /* */ 3 | /* Minimal Module using Include Mechanism */ 4 | /* */ 5 | /* ============================================================================================== */ 6 | /begin MODULE 7 | MODULE_INCLUDES 8 | "TEST_MODULE_NESTED_INCLUDES" 9 | 10 | /* ============================================================================================== */ 11 | /* */ 12 | /* Includes the A2ML section from "AMLTemplate.aml" */ 13 | /* */ 14 | /* ============================================================================================== */ 15 | /include "../AMLTemplate.aml" 16 | 17 | /* ============================================================================================== */ 18 | /* */ 19 | /* Includes Measurement sections */ 20 | /* */ 21 | /* ============================================================================================== */ 22 | /include "MEASUREMENTS.a2l" 23 | 24 | /* ============================================================================================== */ 25 | /* */ 26 | /* Includes Characteristics sections */ 27 | /* */ 28 | /* ============================================================================================== */ 29 | /include "./CHARACTERISTICS.a2l" 30 | 31 | /* ============================================================================================== */ 32 | /* */ 33 | /* Includes Transformer sections */ 34 | /* */ 35 | /* ============================================================================================== */ 36 | /include TRANSFORMERS.a2l 37 | 38 | /end MODULE -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from setuptools import setup, find_packages 23 | 24 | # When importing the a2lparser it automatically tries to generate the AST code. 25 | # This is the reason this line is in here. It is not strictly necessary anymore since 0.1.1 fixes. 26 | # In the future the whole build process should be modernized moving away from setup.py. 27 | import a2lparser 28 | 29 | setup( 30 | name=a2lparser.__package_name__, 31 | version=a2lparser.__version__, 32 | packages=find_packages(exclude=["tests*"]), 33 | install_requires=["ply", "loguru", "alive-progress", "prompt-toolkit", "pyyaml", "xmltodict"], 34 | author=a2lparser.__author__, 35 | author_email=a2lparser.__author_email__, 36 | description=a2lparser.__description__, 37 | license=a2lparser.__license__, 38 | license_files=("LICENSE",), 39 | url=a2lparser.__url__, 40 | package_data={"a2lparser": ["*.cfg", "*.config", "logs/a2lparser_history"]}, 41 | classifiers=[ 42 | "Programming Language :: Python :: 3.11", 43 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 44 | "Operating System :: OS Independent", 45 | ], 46 | entry_points={"console_scripts": ["a2lparser = a2lparser.main:main"]}, 47 | ) 48 | -------------------------------------------------------------------------------- /testfiles/A2L/submodules/TRANSFORMERS.a2l: -------------------------------------------------------------------------------- 1 | /* ============================================================================================== */ 2 | /* */ 3 | /* TRANSFORMER & BLOB (ASAP2 V1.7) */ 4 | /* */ 5 | /* The transformer uses BLOB as in- and "standard" parameter as output */ 6 | /* */ 7 | /* ============================================================================================== */ 8 | 9 | /begin TRANSFORMER TestTransformerBlob 10 | "1.1.0.0" // Version info 11 | "TransformerTestV171.dll" // Name of the 32bit DLL 12 | "" // Name of the 64bit DLL 13 | 2000 // timeout in [ms] 14 | ON_USER_REQUEST 15 | TestTransformerBlobReverse 16 | /begin TRANSFORMER_IN_OBJECTS 17 | ASAM.C.SCALAR.UINT16.IDENTICAL.TRANSFORMER_BLOB_IN_WAITTIME 18 | ASAM.C.SCALAR.UINT16.IDENTICAL.TRANSFORMER_BLOB_IN_WAITTIME_REVERSE 19 | ASAM.C.BLOB.TRANSFORMER_TEST 20 | /end TRANSFORMER_IN_OBJECTS 21 | /begin TRANSFORMER_OUT_OBJECTS 22 | ASAM.C.SCALAR.UINT16.IDENTICAL.TRANSFORMER_BLOB_OUT_WAITTIME 23 | ASAM.C.SCALAR.UINT16.IDENTICAL.TRANSFORMER_BLOB_OUT_WAITTIME_REVERSE 24 | ASAM.C.SCALAR.FLOAT32.IDENTICAL.TRANSFORMER_BLOB_OUT_1 25 | ASAM.C.SCALAR.FLOAT32.IDENTICAL.TRANSFORMER_BLOB_OUT_2 26 | ASAM.C.SCALAR.FLOAT32.IDENTICAL.TRANSFORMER_BLOB_OUT_3 27 | ASAM.C.SCALAR.FLOAT32.IDENTICAL.TRANSFORMER_BLOB_OUT_4 28 | /end TRANSFORMER_OUT_OBJECTS 29 | /end TRANSFORMER 30 | 31 | /begin TRANSFORMER TestTransformerBlobReverse 32 | "1.1.0.0" // Version info 33 | "TransformerTestV171.dll" // Name of the 32bit DLL 34 | "" // Name of the 64bit DLL 35 | 1500 // timeout in [ms] 36 | ON_CHANGE 37 | TestTransformerBlob 38 | /begin TRANSFORMER_IN_OBJECTS 39 | ASAM.C.SCALAR.UINT16.IDENTICAL.TRANSFORMER_BLOB_OUT_WAITTIME 40 | ASAM.C.SCALAR.UINT16.IDENTICAL.TRANSFORMER_BLOB_OUT_WAITTIME_REVERSE 41 | ASAM.C.SCALAR.FLOAT32.IDENTICAL.TRANSFORMER_BLOB_OUT_1 42 | ASAM.C.SCALAR.FLOAT32.IDENTICAL.TRANSFORMER_BLOB_OUT_2 43 | ASAM.C.SCALAR.FLOAT32.IDENTICAL.TRANSFORMER_BLOB_OUT_3 44 | ASAM.C.SCALAR.FLOAT32.IDENTICAL.TRANSFORMER_BLOB_OUT_4 45 | /end TRANSFORMER_IN_OBJECTS 46 | /begin TRANSFORMER_OUT_OBJECTS 47 | ASAM.C.SCALAR.UINT16.IDENTICAL.TRANSFORMER_BLOB_IN_WAITTIME 48 | ASAM.C.SCALAR.UINT16.IDENTICAL.TRANSFORMER_BLOB_IN_WAITTIME_REVERSE 49 | ASAM.C.BLOB.TRANSFORMER_TEST 50 | /end TRANSFORMER_OUT_OBJECTS 51 | /end TRANSFORMER 52 | -------------------------------------------------------------------------------- /tests/rules/test_rules_compu_vtab_range.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_compu_vtab_range(): 26 | """ 27 | Tests parsing a valid "COMPU_VTAB_RANGE" block. 28 | """ 29 | compu_vtab_range_block = """ 30 | /begin COMPU_VTAB_RANGE 31 | SAR_ASS_REQ_AX 32 | "Active assistant" 33 | 33 34 | 0 0 "IDLE" 35 | 1 1 "NDEF1" 36 | 2 2 "ACTV" 37 | 3 3 "XT_ACTV" 38 | 64 255 "not defined" 39 | DEFAULT_VALUE "SNA" 40 | /end COMPU_VTAB_RANGE 41 | """ 42 | parser = A2LYacc() 43 | ast = parser.generate_ast(compu_vtab_range_block) 44 | assert ast 45 | 46 | compu_vtab_range = ast["COMPU_VTAB_RANGE"] 47 | assert compu_vtab_range 48 | assert compu_vtab_range["Name"] == "SAR_ASS_REQ_AX" 49 | assert compu_vtab_range["LongIdentifier"] == '"Active assistant"' 50 | assert compu_vtab_range["NumberValueTriples"] == "33" 51 | assert compu_vtab_range["InVal_MinMax_OutVal"] == [ 52 | ["0", "0", '"IDLE"'], 53 | ["1", "1", '"NDEF1"'], 54 | ["2", "2", '"ACTV"'], 55 | ["3", "3", '"XT_ACTV"'], 56 | ["64", "255", '"not defined"'], 57 | ] 58 | assert compu_vtab_range["DEFAULT_VALUE"] == '"SNA"' 59 | -------------------------------------------------------------------------------- /tests/rules/test_rules_var_characteristic.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_var_characteristic(): 26 | """ 27 | Tests parsing a valid "VAR_CHARACTERISTIC" block. 28 | """ 29 | var_characteristic_block = """ 30 | /begin VAR_CHARACTERISTIC /* define NLLM as variant coded */ 31 | NLLM 32 | Gear Car /* gear box including the 2 variants "Manual" and "Automatic" */ 33 | /begin VAR_ADDRESS 34 | 0x8840 35 | 0x8858 36 | 0x8870 37 | 0x8888 38 | /end VAR_ADDRESS 39 | /end VAR_CHARACTERISTIC 40 | """ 41 | parser = A2LYacc() 42 | ast = parser.generate_ast(var_characteristic_block) 43 | assert ast 44 | 45 | var_characteristic = ast["VAR_CHARACTERISTIC"] 46 | assert var_characteristic 47 | assert var_characteristic["Name"] == "NLLM" 48 | assert var_characteristic["CriterionName"][0] == "Gear" 49 | assert var_characteristic["CriterionName"][1] == "Car" 50 | 51 | assert var_characteristic["VAR_ADDRESS"]["Address"][0] == "0x8840" 52 | assert var_characteristic["VAR_ADDRESS"]["Address"][1] == "0x8858" 53 | assert var_characteristic["VAR_ADDRESS"]["Address"][2] == "0x8870" 54 | assert var_characteristic["VAR_ADDRESS"]["Address"][3] == "0x8888" 55 | -------------------------------------------------------------------------------- /tests/rules/test_rules_frame.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_frame(): 26 | """ 27 | Tests parsing a valid "FRAME" block. 28 | """ 29 | frame_block = """ 30 | /begin FRAME ABS_ADJUSTM 31 | "function group ABS adjustment" 32 | 3 33 | 2 /* 2 msec. */ 34 | FRAME_MEASUREMENT LOOP_COUNTER TEMPORARY_1 35 | /begin IF_DATA XCP 36 | LINK_MAP ref_name 0x003432 37 | /end IF_DATA 38 | /begin IF_DATA CANAPE 39 | STATIC ref_name 0xFF 40 | /end IF_DATA 41 | /end FRAME 42 | """ 43 | parser = A2LYacc() 44 | ast = parser.generate_ast(frame_block) 45 | assert ast 46 | 47 | frame = ast["FRAME"] 48 | assert frame 49 | assert frame["Name"] == "ABS_ADJUSTM" 50 | assert frame["LongIdentifier"] == '"function group ABS adjustment"' 51 | assert frame["ScalingUnit"] == "3" 52 | assert frame["Rate"] == "2" 53 | assert frame["FRAME_MEASUREMENT"] == ["LOOP_COUNTER", "TEMPORARY_1"] 54 | assert frame["IF_DATA"][0]["Name"] == "XCP" 55 | assert frame["IF_DATA"][0]["DataParams"] == ["LINK_MAP", "ref_name", "0x003432"] 56 | assert frame["IF_DATA"][1]["Name"] == "CANAPE" 57 | assert frame["IF_DATA"][1]["DataParams"] == ["STATIC", "ref_name", "0xFF"] 58 | -------------------------------------------------------------------------------- /tests/rules/test_rules_virtual_characteristic.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_virtual_characteristic_minimal(): 26 | """ 27 | Tests parsing the VIRTUAL_CHARACTERISTIC A2L section. 28 | """ 29 | virtual_characeristic_section = """ 30 | /begin VIRTUAL_CHARACTERISTIC 31 | "f(x)=x^2 + cos(x) + c" 32 | /end VIRTUAL_CHARACTERISTIC 33 | """ 34 | parser = A2LYacc() 35 | ast = parser.generate_ast(virtual_characeristic_section) 36 | assert ast 37 | assert ast["VIRTUAL_CHARACTERISTIC"]["FORMULA"] == '"f(x)=x^2 + cos(x) + c"' 38 | 39 | 40 | def test_rules_virtual_characteristic_full(): 41 | """ 42 | Tests parsing the VIRTUAL_CHARACTERISTIC A2L section. 43 | """ 44 | virtual_characeristic_section = """ 45 | /begin VIRTUAL_CHARACTERISTIC 46 | "sin(X1)" 47 | alpha 48 | beta 49 | gamma 50 | /end VIRTUAL_CHARACTERISTIC 51 | """ 52 | parser = A2LYacc() 53 | ast = parser.generate_ast(virtual_characeristic_section) 54 | assert ast 55 | 56 | virtual_characeristic = ast["VIRTUAL_CHARACTERISTIC"] 57 | assert virtual_characeristic 58 | assert virtual_characeristic["FORMULA"] == '"sin(X1)"' 59 | assert virtual_characeristic["CHARACTERISTIC"] == ["alpha", "beta", "gamma"] 60 | -------------------------------------------------------------------------------- /tests/rules/test_rules_memory_layout.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_memory_layout(): 26 | """ 27 | Tests parsing a valid "MEMORY_LAYOUT" block. 28 | """ 29 | memory_layout_block = """ 30 | /begin MEMORY_LAYOUT 31 | PRG_RESERVED 32 | 0x0000 33 | 0x0400 34 | -1 -1 -1 -1 -1 35 | /begin IF_DATA XCP 36 | LINK_MAP ref_name 0x003432 37 | /end IF_DATA 38 | /begin IF_DATA CANAPE 39 | STATIC ref_name 0xFF 40 | /end IF_DATA 41 | /end MEMORY_LAYOUT 42 | """ 43 | parser = A2LYacc() 44 | ast = parser.generate_ast(memory_layout_block) 45 | assert ast 46 | 47 | memory_layout = ast["MEMORY_LAYOUT"] 48 | assert memory_layout 49 | assert memory_layout["PrgType"] == "PRG_RESERVED" 50 | assert memory_layout["Address"] == "0x0000" 51 | assert memory_layout["Size"] == "0x0400" 52 | assert memory_layout["Offset"] == ["-1", "-1", "-1", "-1", "-1"] 53 | assert len(memory_layout["IF_DATA"]) == 2 54 | assert memory_layout["IF_DATA"][0]["Name"] == "XCP" 55 | assert memory_layout["IF_DATA"][0]["DataParams"] == ["LINK_MAP", "ref_name", "0x003432"] 56 | assert memory_layout["IF_DATA"][1]["Name"] == "CANAPE" 57 | assert memory_layout["IF_DATA"][1]["DataParams"] == ["STATIC", "ref_name", "0xFF"] 58 | -------------------------------------------------------------------------------- /tests/rules/test_rules_compu_tab.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_compu_tab(): 26 | """ 27 | Tests parsing a valid "COMPU_TAB" block. 28 | """ 29 | compu_tab_block = """ 30 | /begin COMPU_TAB 31 | TT /* name */ 32 | "conversion table for oil temperatures" 33 | TAB_NOINTP /* convers_type */ 34 | 7 /* number_value_pairs */ 35 | 1 4.3 2 4.7 3 5.8 4 14.2 5 16.8 6 17.2 7 19.4 /* value pairs */ 36 | DEFAULT_VALUE_NUMERIC 99.0 37 | DEFAULT_VALUE "DEFAULT_VALUE_STRING" 38 | /end COMPU_TAB 39 | """ 40 | parser = A2LYacc() 41 | ast = parser.generate_ast(compu_tab_block) 42 | assert ast 43 | 44 | compu_tab = ast["COMPU_TAB"] 45 | assert compu_tab 46 | assert compu_tab["Name"] == "TT" 47 | assert compu_tab["LongIdentifier"] == '"conversion table for oil temperatures"' 48 | assert compu_tab["ConversionType"] == "TAB_NOINTP" 49 | assert compu_tab["NumberValuePairs"] == "7" 50 | assert compu_tab["Axis_Points"] == [ 51 | ["1", "4.3"], 52 | ["2", "4.7"], 53 | ["3", "5.8"], 54 | ["4", "14.2"], 55 | ["5", "16.8"], 56 | ["6", "17.2"], 57 | ["7", "19.4"], 58 | ] 59 | assert compu_tab["DEFAULT_VALUE"] == '"DEFAULT_VALUE_STRING"' 60 | assert compu_tab["DEFAULT_VALUE_NUMERIC"] == "99.0" 61 | -------------------------------------------------------------------------------- /tests/rules/test_rules_mod_common.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_mod_common(): 26 | """ 27 | Tests parsing a valid "MOD_COMMON" block. 28 | """ 29 | mod_common_block = """ 30 | /begin MOD_COMMON 31 | "COMMENT" 32 | ALIGNMENT_BYTE 1 33 | ALIGNMENT_FLOAT16_IEEE 2 34 | ALIGNMENT_FLOAT32_IEEE 4 35 | ALIGNMENT_FLOAT64_IEEE 4 36 | ALIGNMENT_INT64 8 37 | ALIGNMENT_LONG 4 38 | ALIGNMENT_WORD 2 39 | BYTE_ORDER MSB_FIRST 40 | DEPOSIT ABSOLUTE 41 | DATA_SIZE 16 42 | /end MOD_COMMON 43 | """ 44 | parser = A2LYacc() 45 | ast = parser.generate_ast(mod_common_block) 46 | assert ast 47 | 48 | mod_common = ast["MOD_COMMON"] 49 | assert mod_common 50 | assert mod_common["Comment"] == '"COMMENT"' 51 | assert mod_common["ALIGNMENT_BYTE"] == "1" 52 | assert mod_common["ALIGNMENT_FLOAT16_IEEE"] == "2" 53 | assert mod_common["ALIGNMENT_FLOAT32_IEEE"] == "4" 54 | assert mod_common["ALIGNMENT_FLOAT64_IEEE"] == "4" 55 | assert mod_common["ALIGNMENT_INT64"] == "8" 56 | assert mod_common["ALIGNMENT_LONG"] == "4" 57 | assert mod_common["ALIGNMENT_WORD"] == "2" 58 | assert mod_common["BYTE_ORDER"] == "MSB_FIRST" 59 | assert mod_common["DATA_SIZE"] == "16" 60 | assert mod_common["DEPOSIT"] == "ABSOLUTE" 61 | -------------------------------------------------------------------------------- /tests/rules/test_rules_compu_vtab.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_compu_vtab(): 26 | """ 27 | Tests parsing a valid "COMPU_VTAB" block. 28 | """ 29 | compu_vtab_block = """ 30 | /begin COMPU_VTAB CM_BuiltInDTypeId "LONG" TAB_VERB 9 31 | 0 "SS_DOUBLE" 32 | 1 "SS_SINGLE" 33 | 2 "SS_INT8" 34 | 3 "SS_UINT8" 35 | 4 "SS_INT16" 36 | 5 "SS_UINT16" 37 | 6 "SS_INT32" 38 | 7 "SS_UINT32" 39 | 8 "SS_BOOLEAN" 40 | DEFAULT_VALUE "DEFAULT_VALUE" 41 | /end COMPU_VTAB 42 | """ 43 | parser = A2LYacc() 44 | ast = parser.generate_ast(compu_vtab_block) 45 | assert ast 46 | 47 | compu_vtab = ast["COMPU_VTAB"] 48 | assert compu_vtab 49 | assert compu_vtab["Name"] == "CM_BuiltInDTypeId" 50 | assert compu_vtab["LongIdentifier"] == '"LONG"' 51 | assert compu_vtab["ConversionType"] == "TAB_VERB" 52 | assert compu_vtab["NumberValuePairs"] == "9" 53 | assert compu_vtab["InVal_OutVal"] == [ 54 | ["0", '"SS_DOUBLE"'], 55 | ["1", '"SS_SINGLE"'], 56 | ["2", '"SS_INT8"'], 57 | ["3", '"SS_UINT8"'], 58 | ["4", '"SS_INT16"'], 59 | ["5", '"SS_UINT16"'], 60 | ["6", '"SS_INT32"'], 61 | ["7", '"SS_UINT32"'], 62 | ["8", '"SS_BOOLEAN"'], 63 | ] 64 | assert compu_vtab["DEFAULT_VALUE"] == '"DEFAULT_VALUE"' 65 | -------------------------------------------------------------------------------- /tests/rules/test_rules_typedef_blob.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_typedef_blob_minimal(): 26 | """ 27 | Test A2L TYPEDEF_BLOB section. 28 | """ 29 | typedef_blob_minimal = """ 30 | /begin TYPEDEF_BLOB 31 | T_BLOB // type name 32 | "binary blob" // description 33 | 1024 // number of bytes in blob 34 | /end TYPEDEF_BLOB 35 | """ 36 | ast = A2LYacc().generate_ast(typedef_blob_minimal) 37 | assert ast 38 | 39 | typedef_blob = ast["TYPEDEF_BLOB"] 40 | assert typedef_blob 41 | assert typedef_blob["Name"] == "T_BLOB" 42 | assert typedef_blob["LongIdentifier"] == '"binary blob"' 43 | assert typedef_blob["Size"] == "1024" 44 | 45 | 46 | def test_rules_typedef_blob_full(): 47 | """ 48 | Test A2L TYPEDEF_BLOB section. 49 | """ 50 | typedef_blob_full = """ 51 | /begin TYPEDEF_BLOB 52 | T_BLOB // type name 53 | "binary blob" // description 54 | 1024 // number of bytes in blob 55 | ADDRESS_TYPE PWORD 56 | /end TYPEDEF_BLOB 57 | """ 58 | ast = A2LYacc().generate_ast(typedef_blob_full) 59 | assert ast 60 | 61 | typedef_blob = ast["TYPEDEF_BLOB"] 62 | assert typedef_blob 63 | assert typedef_blob["Name"] == "T_BLOB" 64 | assert typedef_blob["LongIdentifier"] == '"binary blob"' 65 | assert typedef_blob["Size"] == "1024" 66 | assert typedef_blob["ADDRESS_TYPE"] == "PWORD" 67 | -------------------------------------------------------------------------------- /tests/rules/test_rules_project.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_project_two_modules_minimal(): 26 | """ 27 | Tests a A2L "PROJECT" section. 28 | """ 29 | project_content = """ 30 | ASAP2_VERSION 1 71 31 | /begin PROJECT Example_Project "ProjectBackupModule" 32 | /begin HEADER 33 | "Tests a Project with two modules" 34 | /end HEADER 35 | 36 | /begin MODULE Module_x1 37 | "First Module Identifier" 38 | /end MODULE 39 | 40 | /begin MODULE Module_x2 41 | "Second Module Identifier" 42 | /end MODULE 43 | /end PROJECT 44 | """ 45 | ast = A2LYacc().generate_ast(project_content) 46 | assert ast 47 | assert ast["ASAP2_VERSION"] == {"VersionNo": "1", "UpgradeNo": "71"} 48 | 49 | project = ast["PROJECT"] 50 | assert project["Name"] == "Example_Project" 51 | assert project["LongIdentifier"] == '"ProjectBackupModule"' 52 | assert project["HEADER"]["Comment"] == '"Tests a Project with two modules"' 53 | 54 | assert len(project["MODULE"]) == 2 55 | 56 | module_x1 = project["MODULE"][0] 57 | assert module_x1 58 | assert module_x1["Name"] == "Module_x1" 59 | assert module_x1["LongIdentifier"] == '"First Module Identifier"' 60 | 61 | module_x2 = project["MODULE"][1] 62 | assert module_x2 63 | assert module_x2["Name"] == "Module_x2" 64 | assert module_x2["LongIdentifier"] == '"Second Module Identifier"' 65 | -------------------------------------------------------------------------------- /tests/fixture_utils.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import os 23 | import pytest 24 | 25 | 26 | @pytest.fixture 27 | def create_file(): 28 | """ 29 | Fixture for creating a file inside a temporary directory for testing. 30 | """ 31 | 32 | def _create_file(tempdir, filename, content): 33 | file_path = os.path.join(tempdir, filename) 34 | with open(file_path, "w", encoding="utf-8") as file: 35 | file.write(content) 36 | return file_path 37 | 38 | return _create_file 39 | 40 | 41 | @pytest.fixture 42 | def check_files_exist(): 43 | """ 44 | Fixture for checking if files exist. 45 | """ 46 | 47 | def _check_files_exist(*file_paths): 48 | missing_files = [file_path for file_path in file_paths if not os.path.exists(file_path)] 49 | assert not missing_files, f"The following files are missing: {missing_files}" 50 | 51 | return _check_files_exist 52 | 53 | 54 | @pytest.fixture 55 | def compare_files(): 56 | """ 57 | Fixture for comparing two files for equality. 58 | """ 59 | 60 | def _normalize_lines(lines): 61 | return [line.strip() for line in lines] 62 | 63 | def _compare_files(file1, file2): 64 | with open(file1, "r", encoding="utf-8") as f1, open(file2, "r", encoding="utf-8") as f2: 65 | lines1 = _normalize_lines(f1.readlines()) 66 | lines2 = _normalize_lines(f2.readlines()) 67 | assert lines1 == lines2, f"Files {file1} and {file2} do not match." 68 | 69 | return _compare_files 70 | -------------------------------------------------------------------------------- /tests/rules/test_rules_unit.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_unit(): 26 | """ 27 | Tests parsing a valid "UNIT" block. 28 | """ 29 | unit_block = """ 30 | /begin UNIT kms_per_hour 31 | "derived unit for velocity: kilometres per hour" 32 | "[km/h]" 33 | DERIVED 34 | REF_UNIT metres_per_second 35 | UNIT_CONVERSION 3.6 0.0 /* y [km/h] = (60*60/1000) * x [m/s] + 0.0 */ 36 | SI_EXPONENTS 1 2 -2 4 3 -4 -5 /*[N] = [m]*[kg]*[s]-2 */ 37 | /end UNIT 38 | """ 39 | parser = A2LYacc() 40 | ast = parser.generate_ast(unit_block) 41 | assert ast 42 | 43 | unit = ast["UNIT"] 44 | assert unit 45 | assert unit["Name"] == "kms_per_hour" 46 | assert unit["LongIdentifier"] == '"derived unit for velocity: kilometres per hour"' 47 | assert unit["Display"] == '"[km/h]"' 48 | assert unit["Type"] == "DERIVED" 49 | assert unit["REF_UNIT"] == "metres_per_second" 50 | 51 | assert unit["SI_EXPONENTS"]["Length"] == "1" 52 | assert unit["SI_EXPONENTS"]["Mass"] == "2" 53 | assert unit["SI_EXPONENTS"]["Time"] == "-2" 54 | assert unit["SI_EXPONENTS"]["ElectricCurrent"] == "4" 55 | assert unit["SI_EXPONENTS"]["Temperature"] == "3" 56 | assert unit["SI_EXPONENTS"]["AmountOfSubstance"] == "-4" 57 | assert unit["SI_EXPONENTS"]["LuminousIntensity"] == "-5" 58 | 59 | assert unit["UNIT_CONVERSION"]["Gradient"] == "3.6" 60 | assert unit["UNIT_CONVERSION"]["Offset"] == "0.0" 61 | -------------------------------------------------------------------------------- /tests/ast/test_ast_generator.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import os 23 | import tempfile 24 | import importlib.util 25 | from a2lparser import A2L_PACKAGE_DIR 26 | from a2lparser import A2L_CONFIGS_DIR 27 | from a2lparser import A2L_DEFAULT_CONFIG_NAME 28 | from a2lparser.a2l.ast.ast_generator import ASTGenerator 29 | 30 | 31 | def test_ast_generator(): 32 | """ 33 | Attempts to create the python file containing the AST node classes. 34 | """ 35 | temp_test_output_path = A2L_PACKAGE_DIR / "../testfiles" 36 | temp_test_dir_prefix = "temp_dir_output_" 37 | 38 | with tempfile.TemporaryDirectory( 39 | dir=temp_test_output_path, prefix=temp_test_dir_prefix 40 | ) as tempdir: 41 | config_file = A2L_CONFIGS_DIR / A2L_DEFAULT_CONFIG_NAME 42 | ast_python_file = os.path.join(tempdir, "test_a2l_ast.py") 43 | ast_generator = ASTGenerator(cfg_filename=str(config_file), out_filename=ast_python_file) 44 | ast_generator.generate(use_clean_names=True) 45 | 46 | # Load the module from the generated file 47 | spec = importlib.util.spec_from_file_location("test_a2l_ast", ast_python_file) 48 | assert spec is not None 49 | assert spec.loader is not None 50 | a2l_ast = importlib.util.module_from_spec(spec) # type: ignore 51 | spec.loader.exec_module(a2l_ast) 52 | 53 | # Instantiate the A2ml_Version class 54 | a2ml_version = a2l_ast.A2ml_Version("1", "2") 55 | assert a2ml_version.VersionNo == "1" 56 | assert a2ml_version.UpgradeNo == "2" 57 | -------------------------------------------------------------------------------- /tests/rules/test_rules_overwrite.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_overwrite_minimal(): 26 | """ 27 | Test A2L OVERWRITE section. 28 | """ 29 | overwrite_minimal = """ 30 | /begin OVERWRITE 31 | MyMap 1 // overruling the X axis of 32 | /end OVERWRITE 33 | """ 34 | ast = A2LYacc().generate_ast(overwrite_minimal) 35 | assert ast 36 | 37 | overwrite = ast["OVERWRITE"] 38 | assert overwrite["Name"] == "MyMap" 39 | assert overwrite["AxisNumber"] == "1" 40 | 41 | 42 | def test_rules_overwrite_full(): 43 | """ 44 | Test A2L OVERWRITE section. 45 | """ 46 | overwrite_full = """ 47 | /begin OVERWRITE 48 | XcpInstance 3 49 | CONVERSION ConversionMethod1 50 | EXTENDED_LIMITS 0 200 51 | FORMAT "%.2f" 52 | INPUT_QUANTITY Speed2 53 | LIMITS 0 160 54 | MONOTONY STRICT_DECREASE 55 | PHYS_UNIT "km/h" 56 | /end OVERWRITE 57 | """ 58 | ast = A2LYacc().generate_ast(overwrite_full) 59 | assert ast 60 | 61 | overwrite = ast["OVERWRITE"] 62 | assert overwrite["Name"] == "XcpInstance" 63 | assert overwrite["AxisNumber"] == "3" 64 | assert overwrite["CONVERSION"] == "ConversionMethod1" 65 | assert overwrite["EXTENDED_LIMITS"] == {"LowerLimit": "0", "UpperLimit": "200"} 66 | assert overwrite["FORMAT"] == '"%.2f"' 67 | assert overwrite["INPUT_QUANTITY"] == "Speed2" 68 | assert overwrite["LIMITS"] == {"LowerLimit": "0", "UpperLimit": "160"} 69 | assert overwrite["MONOTONY"] == "STRICT_DECREASE" 70 | assert overwrite["PHYS_UNIT"] == '"km/h"' 71 | -------------------------------------------------------------------------------- /tests/rules/test_rules_calibration_handle.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_calibration_handle(): 26 | """ 27 | Tests parsing a valid "CALIBRATION_HANDLE" block. 28 | """ 29 | calibration_handle_block = """ 30 | /begin CALIBRATION_HANDLE 31 | 0x10000 /* start address of pointer table */ 32 | 0x200 /* length of pointer table */ 33 | 0x4 /* size of one pointer table entry */ 34 | 0x30000 /* start address of flash section */ 35 | 0x20000 /* length of flash section */ 36 | CALIBRATION_HANDLE_TEXT "12345" 37 | /end CALIBRATION_HANDLE 38 | /begin CALIBRATION_HANDLE 39 | 0x40000 /* start address of pointer table */ 40 | 0x800 /* length of pointer table */ 41 | 0x2 /* size of one pointer table entry */ 42 | 0xFF000 /* start address of flash section */ 43 | 0xCC000 /* length of flash section */ 44 | CALIBRATION_HANDLE_TEXT "description" 45 | /end CALIBRATION_HANDLE 46 | """ 47 | parser = A2LYacc() 48 | ast = parser.generate_ast(calibration_handle_block) 49 | assert ast 50 | 51 | calibration_handle = ast["CALIBRATION_HANDLE"] 52 | assert len(calibration_handle) == 2 53 | assert calibration_handle[0]["Handle"] == ["0x10000", "0x200", "0x4", "0x30000", "0x20000"] 54 | assert calibration_handle[0]["CALIBRATION_HANDLE_TEXT"].Text == '"12345"' 55 | assert calibration_handle[1]["Handle"] == ["0x40000", "0x800", "0x2", "0xFF000", "0xCC000"] 56 | assert calibration_handle[1]["CALIBRATION_HANDLE_TEXT"].Text == '"description"' 57 | -------------------------------------------------------------------------------- /tests/rules/test_rules_annotation.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_annotation(): # sourcery skip: extract-duplicate-method 26 | """ 27 | Tests parsing a valid "ANNOTATION" block. 28 | """ 29 | annotation_block = """ 30 | /begin ANNOTATION 31 | ANNOTATION_LABEL "valid_section_1" 32 | /begin ANNOTATION_TEXT 33 | "string_literal_1" 34 | "STRING_LITERAL_2" 35 | "STRING LITERAL 3" 36 | /end ANNOTATION_TEXT 37 | ANNOTATION_ORIGIN "first block origin" 38 | /end ANNOTATION 39 | /begin ANNOTATION 40 | ANNOTATION_ORIGIN "SECOND_ORIGIN" 41 | /begin ANNOTATION_TEXT 42 | "SOME_CONSTANT = 0xC48800FF" 43 | /end ANNOTATION_TEXT 44 | ANNOTATION_LABEL "valid_section_2" 45 | /end ANNOTATION 46 | """ 47 | parser = A2LYacc() 48 | ast = parser.generate_ast(annotation_block) 49 | assert ast 50 | 51 | annotation = ast["ANNOTATION"] 52 | assert len(annotation) == 2 53 | 54 | annotation_1 = annotation[0] 55 | assert annotation_1["ANNOTATION_LABEL"] == '"valid_section_1"' 56 | assert annotation_1["ANNOTATION_ORIGIN"] == '"first block origin"' 57 | assert annotation_1["ANNOTATION_TEXT"] == [ 58 | '"string_literal_1"', 59 | '"STRING_LITERAL_2"', 60 | '"STRING LITERAL 3"', 61 | ] 62 | 63 | annotation_2 = annotation[1] 64 | assert annotation_2["ANNOTATION_LABEL"] == '"valid_section_2"' 65 | assert annotation_2["ANNOTATION_ORIGIN"] == '"SECOND_ORIGIN"' 66 | assert annotation_2["ANNOTATION_TEXT"] == ['"SOME_CONSTANT = 0xC48800FF"'] 67 | -------------------------------------------------------------------------------- /tests/rules/test_rules_memory_segment.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_memory_segment(): 26 | """ 27 | Tests parsing a valid "MEMORY_SEGMENT" block. 28 | """ 29 | memory_segment_block = """ 30 | /begin MEMORY_SEGMENT 31 | Data2 32 | "Data external Flash" 33 | DATA 34 | FLASH 35 | EXTERN 36 | 0x7000 37 | 0x2000 38 | -1 -1 -1 -1 -1 39 | /begin IF_DATA XCP 40 | LINK_MAP ref_name 0x003432 41 | /end IF_DATA 42 | /begin IF_DATA CANAPE 43 | STATIC ref_name 0xFF 44 | /end IF_DATA 45 | /end MEMORY_SEGMENT 46 | """ 47 | parser = A2LYacc() 48 | ast = parser.generate_ast(memory_segment_block) 49 | assert ast 50 | 51 | memory_segment = ast["MEMORY_SEGMENT"] 52 | assert memory_segment 53 | assert memory_segment["Name"] == "Data2" 54 | assert memory_segment["LongIdentifier"] == '"Data external Flash"' 55 | assert memory_segment["PrgType"] == "DATA" 56 | assert memory_segment["MemoryType"] == "FLASH" 57 | assert memory_segment["Attribute"] == "EXTERN" 58 | assert memory_segment["Address"] == "0x7000" 59 | assert memory_segment["Size"] == "0x2000" 60 | assert memory_segment["Offset"] == ["-1", "-1", "-1", "-1", "-1"] 61 | assert len(memory_segment["IF_DATA"]) == 2 62 | assert memory_segment["IF_DATA"][0]["Name"] == "XCP" 63 | assert memory_segment["IF_DATA"][0]["DataParams"] == ["LINK_MAP", "ref_name", "0x003432"] 64 | assert memory_segment["IF_DATA"][1]["Name"] == "CANAPE" 65 | assert memory_segment["IF_DATA"][1]["DataParams"] == ["STATIC", "ref_name", "0xFF"] 66 | -------------------------------------------------------------------------------- /tests/lex/test_lex_keywords.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import pytest 23 | from a2lparser.a2l.a2l_lex import A2LLex 24 | from a2lparser.a2l.lex.lexer_keywords import LexerKeywords 25 | 26 | 27 | @pytest.mark.parametrize("keyword_section", LexerKeywords.keywords_section) 28 | def test_lex_keywords_sections(keyword_section): 29 | """ 30 | Test the correct interpretation of the tags in a A2L file defining a section. 31 | A section is defined by being encloused with a "BEGIN" and an "END" tag. 32 | 33 | Example: 34 | /begin MEASUREMENT 35 | /end MEASUREMENT 36 | """ 37 | lexer = A2LLex() 38 | lexer.input(keyword_section) 39 | token = lexer.token() 40 | assert token 41 | assert token.type == keyword_section 42 | 43 | 44 | @pytest.mark.parametrize("keyword_type", LexerKeywords.keywords_type) 45 | def test_lex_keywords_types(keyword_type): 46 | """ 47 | Test the correct interpretation of keyword tags defining types in an A2L file. 48 | """ 49 | lexer = A2LLex() 50 | lexer.input(keyword_type) 51 | token = lexer.token() 52 | assert token 53 | assert token.type == keyword_type 54 | 55 | 56 | @pytest.mark.parametrize("keyword_enum", LexerKeywords.keywords_enum) 57 | def test_lex_keywords_enums(keyword_enum): 58 | """ 59 | Test the correct interpretation of enum types in an A2L file. 60 | """ 61 | lexer = A2LLex() 62 | lexer.input(keyword_enum) 63 | token = lexer.token() 64 | assert token 65 | 66 | 67 | @pytest.mark.parametrize("keyword_datatype", LexerKeywords.keywords_datatypes) 68 | def test_lex_keywords_datatypes(keyword_datatype): 69 | """ 70 | Test the correct interpretation of data types in an A2L file. 71 | """ 72 | lexer = A2LLex() 73 | lexer.input(keyword_datatype) 74 | token = lexer.token() 75 | assert token 76 | -------------------------------------------------------------------------------- /tests/rules/test_rules_structure_component.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_structure_component_minimal(): 26 | """ 27 | Test A2L STRUCTURE_COMPONENT section. 28 | """ 29 | structure_component_minimal = """ 30 | /begin STRUCTURE_COMPONENT 31 | XX MyUnsignedLongType 32 | 0 // address offset 33 | /end STRUCTURE_COMPONENT 34 | """ 35 | ast = A2LYacc().generate_ast(structure_component_minimal) 36 | assert ast 37 | 38 | structure_component = ast["STRUCTURE_COMPONENT"] 39 | assert structure_component["Name"] == "XX" 40 | assert structure_component["TypedefName"] == "MyUnsignedLongType" 41 | assert structure_component["AddressOffset"] == "0" 42 | 43 | 44 | def test_rules_structure_component_full(): 45 | """ 46 | Test A2L STRUCTURE_COMPONENT section. 47 | """ 48 | structure_component_full = """ 49 | /begin STRUCTURE_COMPONENT 50 | BXB MyComplexComponent 51 | 34 // address offset 52 | 53 | MATRIX_DIM 10 54 | SYMBOL_TYPE_LINK "__MyComplexComponent.pdb" 55 | ADDRESS_TYPE PLONGLONG 56 | LAYOUT ALTERNATE_CURVES 57 | /end STRUCTURE_COMPONENT 58 | """ 59 | ast = A2LYacc().generate_ast(structure_component_full) 60 | assert ast 61 | 62 | structure_component = ast["STRUCTURE_COMPONENT"] 63 | assert structure_component 64 | assert structure_component["Name"] == "BXB" 65 | assert structure_component["TypedefName"] == "MyComplexComponent" 66 | assert structure_component["AddressOffset"] == "34" 67 | assert structure_component["MATRIX_DIM"] == ["10"] 68 | assert structure_component["SYMBOL_TYPE_LINK"] == '"__MyComplexComponent.pdb"' 69 | assert structure_component["ADDRESS_TYPE"] == "PLONGLONG" 70 | assert structure_component["LAYOUT"] == "ALTERNATE_CURVES" 71 | -------------------------------------------------------------------------------- /tests/rules/test_rules_compu_method.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_compu_method(): 26 | """ 27 | Tests parsing a valid "COMPU_METHOD" block. 28 | """ 29 | compu_method_block = """ 30 | /begin COMPU_METHOD CM_FIXED_SB_06 "LongIdentifier" 31 | TAB_INTP "%4.3" "UNIT_STRING" 32 | COEFFS 0 4 8 3 2 5 33 | COEFFS_LINEAR 1.25 -2.0 34 | COMPU_TAB_REF TEMP_TAB 35 | /begin FORMULA 36 | "sqrt( 3 - 4*sin(X1) )" 37 | FORMULA_INV "asin( sqrt( (3 - X1)/4 ) )" 38 | /end FORMULA 39 | REF_UNIT kms_per_hour 40 | STATUS_STRING_REF CT_SensorStatus 41 | /end COMPU_METHOD 42 | """ 43 | parser = A2LYacc() 44 | ast = parser.generate_ast(compu_method_block) 45 | assert ast 46 | 47 | compu_method = ast["COMPU_METHOD"] 48 | assert compu_method 49 | assert compu_method["Name"] == "CM_FIXED_SB_06" 50 | assert compu_method["LongIdentifier"] == '"LongIdentifier"' 51 | assert compu_method["ConversionType"] == "TAB_INTP" 52 | assert compu_method["FORMAT"] == '"%4.3"' 53 | assert compu_method["UNIT"] == '"UNIT_STRING"' 54 | assert compu_method["COMPU_TAB_REF"] == "TEMP_TAB" 55 | assert compu_method["REF_UNIT"] == "kms_per_hour" 56 | assert compu_method["STATUS_STRING_REF"] == "CT_SensorStatus" 57 | assert compu_method["COEFFS"]["a"] == "0" 58 | assert compu_method["COEFFS"]["b"] == "4" 59 | assert compu_method["COEFFS"]["c"] == "8" 60 | assert compu_method["COEFFS"]["d"] == "3" 61 | assert compu_method["COEFFS"]["e"] == "2" 62 | assert compu_method["COEFFS"]["f"] == "5" 63 | assert compu_method["COEFFS_LINEAR"]["a"] == "1.25" 64 | assert compu_method["COEFFS_LINEAR"]["b"] == "-2.0" 65 | assert compu_method["FORMULA"]["f_x"] == '"sqrt( 3 - 4*sin(X1) )"' 66 | assert compu_method["FORMULA"]["FORMULA_INV"]["g_x"] == '"asin( sqrt( (3 - X1)/4 ) )"' 67 | -------------------------------------------------------------------------------- /tests/parser/test_parser_find_includes.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import pytest 23 | from a2lparser.a2lparser import A2LParser 24 | 25 | 26 | @pytest.mark.parametrize( 27 | "matching_includes, expected_filename", 28 | [ 29 | (r'/include "C:\DATA\ECU.A2L"', r"C:\DATA\ECU.A2L"), 30 | (r'/INCLUDE "..\includes\CANAPE_OET.A2L"', r"..\includes\CANAPE_OET.A2L"), 31 | ( 32 | r'/INCLUDE "\\server1\documents\templates\template.aml"', 33 | r"\\server1\documents\templates\template.aml", 34 | ), 35 | (r"/Include ECU_DATA.a2l", r"ECU_DATA.a2l"), 36 | (r'/include "AML Template.aml"', r"AML Template.aml"), 37 | (r'/include "/home/user/A2L\ Files/ECU_1221.A2L"', r"/home/user/A2L\ Files/ECU_1221.A2L"), 38 | (r'/include "../../../blobs/TP_BLOB.a2l"', r"../../../blobs/TP_BLOB.a2l"), 39 | ( 40 | r'/begin A2ML /include "/home/user/IF_DATA/XCP.txt" STV_N /* name */ /end A2ML', 41 | r"/home/user/IF_DATA/XCP.txt", 42 | ), 43 | ( 44 | r'/begin MODULE /Include My_Module.A2L UNIT 2 "" "" DERIVED /end MODULE', 45 | r"My_Module.A2L", 46 | ), 47 | ( 48 | r'/begin PROJECT /include "\\Z:\tmp\ecu project.a2l" /* EOF */ /end PROJECT', 49 | r"\\Z:\tmp\ecu project.a2l", 50 | ), 51 | ( 52 | ( 53 | r'/begin PROJECT /include "/home/ecu/header/my_header.a2l" ' 54 | r"/include my_module.a2l /end PROJECT" 55 | ), 56 | [r"/home/ecu/header/my_header.a2l", r"my_module.a2l"], 57 | ), 58 | (r"/begin MODULE /begin MEASUREMENT /end MEASUREMENT /end MODULE", None), 59 | ], 60 | ) 61 | def test_parser_load_file_include_mechanism(matching_includes, expected_filename): 62 | """ 63 | Tests the include mechanism of the A2L parser. 64 | """ 65 | parser = A2LParser() 66 | filename = parser._find_includes(matching_includes) 67 | assert filename == expected_filename 68 | -------------------------------------------------------------------------------- /tests/integration/test_integration_asap2_demo_v161.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import tempfile 23 | from pathlib import Path 24 | from a2lparser import A2L_PACKAGE_DIR 25 | from a2lparser.main import main 26 | # from tests.fixture_utils import compare_files, check_files_exist 27 | 28 | 29 | def test_integration_asap2_demo_v161(monkeypatch, compare_files, check_files_exist): 30 | """ 31 | Tests parsing and converting the ASAP2_Demo_V161.a2l file. 32 | """ 33 | a2l_filename = "ASAP2_Demo_V161.a2l" 34 | temp_test_output_path = A2L_PACKAGE_DIR / "../testfiles" 35 | temp_test_dir_prefix = "temp_dir_output_" 36 | 37 | with tempfile.TemporaryDirectory( 38 | dir=temp_test_output_path, prefix=temp_test_dir_prefix 39 | ) as tempdir: 40 | monkeypatch.setattr( 41 | "sys.argv", 42 | [ 43 | "a2lparser", 44 | f"testfiles/A2L/{a2l_filename}", 45 | "--json", 46 | "--xml", 47 | "--yaml", 48 | "--output-dir", 49 | f'"{Path(tempdir).resolve().as_posix()}"', 50 | ], 51 | ) 52 | main() 53 | 54 | # Check if files were generated 55 | check_files_exist( 56 | f"{Path(tempdir).as_posix()}/ASAP2_Demo_V161.xml", 57 | f"{Path(tempdir).as_posix()}/ASAP2_Demo_V161.json", 58 | f"{Path(tempdir).as_posix()}/ASAP2_Demo_V161.yml", 59 | ) 60 | 61 | # Compare files 62 | compare_files( 63 | f"{Path(tempdir).as_posix()}/ASAP2_Demo_V161.xml", 64 | f"{temp_test_output_path.as_posix()}/XML/ASAP2_Demo_V161.xml", 65 | ) 66 | compare_files( 67 | f"{Path(tempdir).as_posix()}/ASAP2_Demo_V161.json", 68 | f"{temp_test_output_path.as_posix()}/JSON/ASAP2_Demo_V161.json", 69 | ) 70 | compare_files( 71 | f"{Path(tempdir)}/ASAP2_Demo_V161.yml", 72 | f"{temp_test_output_path.as_posix()}/YAML/ASAP2_Demo_V161.yml", 73 | ) 74 | -------------------------------------------------------------------------------- /tests/integration/test_integration_asap2_demo_v171.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import tempfile 23 | from pathlib import Path 24 | from a2lparser import A2L_PACKAGE_DIR 25 | from a2lparser.main import main 26 | # from tests.fixture_utils import compare_files, check_files_exist 27 | 28 | 29 | def test_integration_asap2_demo_v171(monkeypatch, compare_files, check_files_exist): 30 | """ 31 | Tests parsing and converting the ASAP2_Demo_V161.a2l file. 32 | """ 33 | a2l_filename = "ASAP2_Demo_V171.a2l" 34 | temp_test_output_path = A2L_PACKAGE_DIR / "../testfiles" 35 | temp_test_dir_prefix = "temp_dir_output_" 36 | 37 | with tempfile.TemporaryDirectory( 38 | dir=temp_test_output_path, prefix=temp_test_dir_prefix 39 | ) as tempdir: 40 | monkeypatch.setattr( 41 | "sys.argv", 42 | [ 43 | "a2lparser", 44 | f"testfiles/A2L/{a2l_filename}", 45 | "--json", 46 | "--xml", 47 | "--yaml", 48 | "--output-dir", 49 | f'"{Path(tempdir).resolve().as_posix()}"', 50 | ], 51 | ) 52 | main() 53 | 54 | # Check if files were generated 55 | check_files_exist( 56 | f"{Path(tempdir).as_posix()}/ASAP2_Demo_V171.xml", 57 | f"{Path(tempdir).as_posix()}/ASAP2_Demo_V171.json", 58 | f"{Path(tempdir).as_posix()}/ASAP2_Demo_V171.yml", 59 | ) 60 | 61 | # Compare files 62 | compare_files( 63 | f"{Path(tempdir).as_posix()}/ASAP2_Demo_V171.xml", 64 | f"{temp_test_output_path.as_posix()}/XML/ASAP2_Demo_V171.xml", 65 | ) 66 | compare_files( 67 | f"{Path(tempdir).as_posix()}/ASAP2_Demo_V171.json", 68 | f"{temp_test_output_path.as_posix()}/JSON/ASAP2_Demo_V171.json", 69 | ) 70 | compare_files( 71 | f"{Path(tempdir)}/ASAP2_Demo_V171.yml", 72 | f"{temp_test_output_path.as_posix()}/YAML/ASAP2_Demo_V171.yml", 73 | ) 74 | -------------------------------------------------------------------------------- /tests/integration/test_integration_nested_includes.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import tempfile 23 | from pathlib import Path 24 | from a2lparser import A2L_PACKAGE_DIR 25 | from a2lparser.main import main 26 | # from tests.fixture_utils import compare_files, check_files_exist 27 | 28 | 29 | def test_integration_nested_includes(monkeypatch, compare_files, check_files_exist): 30 | """ 31 | Tests parsing and converting the NESTED_INCLUDES.a2l file. 32 | """ 33 | a2l_filename = "TEST_Nested_Includes.a2l" 34 | temp_test_output_path = A2L_PACKAGE_DIR / "../testfiles" 35 | temp_test_dir_prefix = "temp_dir_output_" 36 | 37 | with tempfile.TemporaryDirectory( 38 | dir=temp_test_output_path, prefix=temp_test_dir_prefix 39 | ) as tempdir: 40 | monkeypatch.setattr( 41 | "sys.argv", 42 | [ 43 | "a2lparser", 44 | f"testfiles/A2L/{a2l_filename}", 45 | "--json", 46 | "--xml", 47 | "--yaml", 48 | "--output-dir", 49 | f'"{Path(tempdir).resolve().as_posix()}"', 50 | ], 51 | ) 52 | main() 53 | 54 | # Check if files were generated 55 | check_files_exist( 56 | f"{Path(tempdir).as_posix()}/TEST_Nested_Includes.xml", 57 | f"{Path(tempdir).as_posix()}/TEST_Nested_Includes.json", 58 | f"{Path(tempdir).as_posix()}/TEST_Nested_Includes.yml", 59 | ) 60 | 61 | # Compare files 62 | compare_files( 63 | f"{Path(tempdir).as_posix()}/TEST_Nested_Includes.json", 64 | f"{temp_test_output_path.as_posix()}/JSON/TEST_Nested_Includes.json", 65 | ) 66 | compare_files( 67 | f"{Path(tempdir).as_posix()}/TEST_Nested_Includes.xml", 68 | f"{temp_test_output_path.as_posix()}/XML/TEST_Nested_Includes.xml", 69 | ) 70 | compare_files( 71 | f"{Path(tempdir)}/TEST_Nested_Includes.yml", 72 | f"{temp_test_output_path.as_posix()}/YAML/TEST_Nested_Includes.yml", 73 | ) 74 | -------------------------------------------------------------------------------- /.github/workflows/publish-to-pypi.yml: -------------------------------------------------------------------------------- 1 | name: pypi publish 2 | 3 | on: push 4 | 5 | jobs: 6 | build: 7 | name: Build distribution 📦 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Set up Python 13 | uses: actions/setup-python@v5 14 | with: 15 | python-version: "3.x" 16 | - name: Install pypa/build 17 | run: >- 18 | python3 -m 19 | pip install 20 | build 21 | setuptools 22 | wheel 23 | --user 24 | - name: Build a binary wheel and a source tarball 25 | run: python3 -m build 26 | - name: Store the distribution packages 27 | uses: actions/upload-artifact@v3 28 | with: 29 | name: python-package-distributions 30 | path: dist/ 31 | 32 | publish-to-pypi: 33 | name: PyPi - Publish distribution 📦 to PyPI 34 | if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes 35 | needs: 36 | - build 37 | runs-on: ubuntu-latest 38 | environment: 39 | name: pypi 40 | url: https://pypi.org/p/a2lparser 41 | permissions: 42 | id-token: write # IMPORTANT: mandatory for trusted publishing 43 | 44 | steps: 45 | - name: Download all the dists 46 | uses: actions/download-artifact@v3 47 | with: 48 | name: python-package-distributions 49 | path: dist/ 50 | - name: Publish distribution 📦 to PyPI 51 | uses: pypa/gh-action-pypi-publish@release/v1 52 | 53 | github-release: 54 | name: >- 55 | Sign the distribution 📦 with Sigstore 56 | and upload them to GitHub Release 57 | needs: 58 | - publish-to-pypi 59 | runs-on: ubuntu-latest 60 | 61 | permissions: 62 | contents: write # IMPORTANT: mandatory for making GitHub Releases 63 | id-token: write # IMPORTANT: mandatory for sigstore 64 | 65 | steps: 66 | - name: Download all the dists 67 | uses: actions/download-artifact@v3 68 | with: 69 | name: python-package-distributions 70 | path: dist/ 71 | - name: Sign the dists with Sigstore 72 | uses: sigstore/gh-action-sigstore-python@v2.1.1 73 | with: 74 | inputs: >- 75 | ./dist/*.tar.gz 76 | ./dist/*.whl 77 | - name: Create GitHub Release 78 | env: 79 | GITHUB_TOKEN: ${{ github.token }} 80 | run: >- 81 | gh release create 82 | '${{ github.ref_name }}' 83 | --repo '${{ github.repository }}' 84 | --notes "" 85 | - name: Upload artifact signatures to GitHub Release 86 | env: 87 | GITHUB_TOKEN: ${{ github.token }} 88 | # Upload to GitHub Release using the `gh` CLI. 89 | # `dist/` contains the built packages, and the 90 | # sigstore-produced signatures and certificates. 91 | run: >- 92 | gh release upload 93 | '${{ github.ref_name }}' dist/** 94 | --repo '${{ github.repository }}' 95 | 96 | publish-to-testpypi: 97 | name: TestPyPi - Publish distribution 📦 to TestPyPI 98 | needs: 99 | - build 100 | runs-on: ubuntu-latest 101 | 102 | environment: 103 | name: testpypi 104 | url: https://test.pypi.org/p/a2lparser 105 | 106 | permissions: 107 | id-token: write # IMPORTANT: mandatory for trusted publishing 108 | 109 | steps: 110 | - name: Download all the dists 111 | uses: actions/download-artifact@v3 112 | with: 113 | name: python-package-distributions 114 | path: dist/ 115 | - name: Publish distribution 📦 to TestPyPI 116 | uses: pypa/gh-action-pypi-publish@release/v1 117 | with: 118 | repository-url: https://test.pypi.org/legacy/ 119 | -------------------------------------------------------------------------------- /a2lparser/__init__.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | ################################# 23 | # A2LParser package information # 24 | ################################# 25 | from pathlib import Path 26 | 27 | __package_name__ = "a2lparser" 28 | __version__ = "0.1.1" 29 | __author__ = "mrom1" 30 | __author_email__ = "mrom@linuxmail.org" 31 | __description__ = "ASAP2 A2L file parsing tool." 32 | __license__ = "GNU General Public License v3 (GPLv3)" 33 | __url__ = "https://github.com/mrom1/a2lparser" 34 | 35 | A2L_PARSER_HEADLINE = """ 36 | ████╗ ██████╗██╗ ██████╗ ████╗ █████╗ ██████╗██████╗█████╗ 37 | ██╔═██╗╚═══██║██║ ██╔═██║██╔═██╗██╔═██╗██╔═══╝██╔═══╝██╔═██╗ 38 | ██████║██████║██║ ██████║██████║█████╔╝██████╗█████╗ █████╔╝ 39 | ██╔═██║██╔═══╝██║ ██╔═══╝██╔═██║██╔═██╗╚═══██║██╔══╝ ██╔═██╗ 40 | ██║ ██║██████╗██████╗ ██║ ██║ ██║██║ ██║██████║██████╗██║ ██║ 41 | ╚═╝ ╚═╝╚═════╝╚═════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝╚═════╝╚═╝ ╚═╝ 42 | """ 43 | A2L_PACKAGE_DIR = Path(__file__).parent 44 | A2L_GENERATED_FILES_DIR = A2L_PACKAGE_DIR / "gen" 45 | A2L_CONFIGS_DIR = A2L_PACKAGE_DIR / "configs" 46 | A2L_CLI_HISTORY_FILE = A2L_PACKAGE_DIR / "logs" / "a2lparser_history" 47 | A2L_DEFAULT_CONFIG_NAME = "ASAP2_MCD_v171.cfg" 48 | 49 | 50 | ############################# 51 | # First time initialization # 52 | ############################# 53 | try: 54 | # We try to import the AST node classes 55 | # If they can't be found it indicates a first time usage 56 | from a2lparser.gen.a2l_ast import Node 57 | 58 | Node() 59 | 60 | except ImportError: 61 | print("No AST node classes found. Generating AST nodes...") 62 | from a2lparser.a2l.ast.ast_generator import ASTGenerator 63 | 64 | # Generate the AST nodes from the standard config in configs/A2L_ASAM.cfg 65 | asam_config = A2L_CONFIGS_DIR / A2L_DEFAULT_CONFIG_NAME 66 | ast_nodes_file = A2L_GENERATED_FILES_DIR / "a2l_ast.py" 67 | 68 | # Generate the AST node containers 69 | generator = ASTGenerator(asam_config.as_posix(), ast_nodes_file.as_posix()) 70 | generator.generate() 71 | print(f"Generated AST nodes file at: {ast_nodes_file.as_posix()}") 72 | -------------------------------------------------------------------------------- /a2lparser/cli/command_prompt.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import code 23 | from pathlib import Path 24 | from prompt_toolkit import PromptSession 25 | from prompt_toolkit.history import FileHistory 26 | from prompt_toolkit.auto_suggest import AutoSuggestFromHistory 27 | from a2lparser import A2L_CLI_HISTORY_FILE 28 | 29 | 30 | class CommandPrompt: 31 | """ 32 | CommandPrompt class which lets the user evaluate any input. 33 | Used to access the generated AST dictionary. 34 | 35 | Usage: 36 | >>> parser = Parser() 37 | >>> ast = parser.parse_files("ECU_Example.a2l") 38 | >>> CommandPrompt.prompt(ast) 39 | """ 40 | 41 | _session = None 42 | # Create empty log file for command line history if it doesn't exist 43 | if not A2L_CLI_HISTORY_FILE.exists(): 44 | A2L_CLI_HISTORY_FILE.parent.mkdir(parents=True, exist_ok=True) 45 | A2L_CLI_HISTORY_FILE.write_text("") 46 | print(f"Created command line history file at: {A2L_CLI_HISTORY_FILE.as_posix()}") 47 | 48 | @staticmethod 49 | def get_session(): 50 | """ 51 | Returns the prompt session. 52 | """ 53 | if CommandPrompt._session is None: 54 | history_file: Path = A2L_CLI_HISTORY_FILE 55 | CommandPrompt._session = PromptSession( 56 | history=FileHistory(history_file), auto_suggest=AutoSuggestFromHistory() 57 | ) 58 | return CommandPrompt._session 59 | 60 | @staticmethod 61 | def cli_readfunc(prompt): 62 | """ 63 | Read function returning the session from prompt-toolkit. 64 | """ 65 | return CommandPrompt.get_session().prompt(prompt) 66 | 67 | @staticmethod 68 | def prompt(ast): 69 | """ 70 | Prompts the user for input.. 71 | """ 72 | local_vars = {"ast": ast} 73 | 74 | print("You can access the 'ast' attribute which holds the AST as a reference.\n") 75 | 76 | while True: 77 | try: 78 | code.interact(banner="", local=local_vars, readfunc=CommandPrompt.cli_readfunc) 79 | break 80 | except KeyboardInterrupt: 81 | continue 82 | -------------------------------------------------------------------------------- /testfiles/A2L/submodules/MEASUREMENTS.a2l: -------------------------------------------------------------------------------- 1 | /* ============================================================================================== */ 2 | /* */ 3 | /* Measurements (ASAP2 V1.7.1) */ 4 | /* */ 5 | /* Note: */ 6 | /* These measurements are used for testing of the a2lparser package. */ 7 | /* The values used are not meant to make sense in a practical way. */ 8 | /* */ 9 | /* ============================================================================================== */ 10 | 11 | /begin MEASUREMENT ASAM.M.SCALAR.UBYTE.FORM_X_PLUS_4 12 | "Scalar measurement" 13 | UBYTE CM.FORM.X_PLUS_4 0 0 4 259 14 | ECU_ADDRESS 0x13A00 15 | FORMAT "%5.0" /* Note: Overwrites the format stated in the computation method */ 16 | /begin IF_DATA ETK KP_BLOB 0x13A00 INTERN 1 RASTER 5 /end IF_DATA 17 | /end MEASUREMENT 18 | 19 | /begin MEASUREMENT ASAM.M.VIRTUAL.SCALAR.SWORD.PHYSICAL 20 | "Virtual measurement with 2 * ASAM.M.SCALAR.SBYTE.LINEAR_MUL_2 as input (based on the phys value of ASAM.M.SCALAR.SBYTE.LINEAR_MUL_2)" 21 | SWORD 22 | CM.VIRTUAL.EXTERNAL_VALUE 23 | 0 0 -32768 32767 24 | ECU_ADDRESS 0x0 25 | /begin VIRTUAL 26 | ASAM.M.SCALAR.SBYTE.LINEAR_MUL_2 27 | /end VIRTUAL 28 | /end MEASUREMENT 29 | 30 | /begin MEASUREMENT ASAM.M.SCALAR.UBYTE.RAT_FUNC.IDENT.STATUS_STRING 31 | "Scalar measurement with status string" 32 | UBYTE CM.RAT_FUNC.IDENT.STATUS_STRING 0 0 0 252 33 | ARRAY_SIZE 4 34 | /begin IF_DATA ETK KP_BLOB 0x13A00 INTERN 1 RASTER 2 /end IF_DATA 35 | BIT_MASK 0xFFFF 36 | /begin BIT_OPERATION 37 | RIGHT_SHIFT 4 38 | SIGN_EXTEND 39 | /end BIT_OPERATION 40 | ADDRESS_TYPE PLONGLONG 41 | BYTE_ORDER MSB_FIRST 42 | DISPLAY_IDENTIFIER load_engine.MEASUREMENT.xxx4b4b 43 | ECU_ADDRESS 0x2DDDD 44 | ECU_ADDRESS_EXTENSION 0x0 45 | FORMAT "%.3" 46 | DISCRETE 47 | /begin IF_DATA CANAPE_EXT 48 | 100 49 | LINK_MAP "xxx79c13e523bc16dfbba3285.x794ec36d9751f96100" 0x2D474 0x0 0 0x0 1 0xCF 0x0 50 | DISPLAY 0 -36044.75 36043.75 51 | /end IF_DATA 52 | /begin IF_DATA CANAPE 53 | DISPLAY 0 -36044.75 36043.75 54 | /end IF_DATA 55 | /begin ANNOTATION 56 | ANNOTATION_LABEL "ASAM ASAP2 v1.7.1" 57 | ANNOTATION_ORIGIN "Test ASAP2 ANNOTATION origin." 58 | /begin ANNOTATION_TEXT 59 | "ASAP2 annotation text list, index 0" 60 | "ASAP2 annotation text list, index 1" 61 | "ASAP2 annotation text list, index 2" 62 | "ASAP2 annotation text list, index 3" 63 | /end ANNOTATION_TEXT 64 | /end ANNOTATION 65 | ERROR_MASK 0x00000001 66 | LAYOUT ALTERNATE_WITH_Y 67 | MATRIX_DIM 2 4 3 68 | MAX_REFRESH 998 2 69 | PHYS_UNIT "Nm" 70 | READ_WRITE 71 | REF_MEMORY_SEGMENT Data1 72 | /begin FUNCTION_LIST 73 | FNC_VAL_1 74 | FNC_VAL_2 75 | FNC_VAL_3 76 | /end FUNCTION_LIST 77 | MODEL_LINK "system/measurement/ecu_x79c13.obj" 78 | /begin ANNOTATION 79 | ANNOTATION_LABEL "ASAM Workinggroup" 80 | ANNOTATION_ORIGIN "" 81 | /begin ANNOTATION_TEXT 82 | "Test the A2L annotation" 83 | /end ANNOTATION_TEXT 84 | /end ANNOTATION 85 | /begin VIRTUAL 86 | PHI_BASIS 87 | PHI_CORR 88 | /end VIRTUAL 89 | SYMBOL_LINK 90 | "_VehicleSpeed" /* Symbol name */ 91 | 0 /* Offset */ 92 | /end MEASUREMENT 93 | -------------------------------------------------------------------------------- /a2lparser/a2l/lex/keywords/a2l_keywords_enums.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | class A2LKeywordsEnums: 23 | """ 24 | Keywords for parsing A2L enums. 25 | """ 26 | 27 | keywords: list = [ 28 | # address type 29 | "ADDRESS_TYPE", 30 | # axis description enum 31 | "CURVE_AXIS", 32 | "COM_AXIS", 33 | "FIX_AXIS", 34 | "RES_AXIS", 35 | "STD_AXIS", 36 | # calibration access enum 37 | "CALIBRATION", 38 | "NO_CALIBRATION", 39 | "NOT_IN_MCD_SYSTEM", 40 | "OFFLINE_CALIBRATION", 41 | # characteristic enum 42 | "ASCII", 43 | "CURVE", 44 | "MAP", 45 | "CUBOID", 46 | "CUBE_4", 47 | "CUBE_5", 48 | "VAL_BLK", 49 | "VALUE", 50 | # conversation type enum 51 | "IDENTICAL", 52 | "FORM", 53 | "LINEAR", 54 | "RAT_FUNC", 55 | "TAB_INTP", 56 | "TAB_NOINTP", 57 | "TAB_VERB", 58 | # mode enum 59 | "ABSOLUTE", 60 | "DIFFERENCE", 61 | # index mode enum 62 | "ALTERNATE_CURVES", 63 | "ALTERNATE_WITH_X", 64 | "ALTERNATE_WITH_Y", 65 | "COLUMN_DIR", 66 | "ROW_DIR", 67 | # memory type enum 68 | "EEPROM", 69 | "EPROM", 70 | "FLASH", 71 | "RAM", 72 | "ROM", 73 | "REGISTER", 74 | "NOT_IN_ECU", 75 | # monotony enum 76 | "MON_DECREASE", 77 | "MON_INCREASE", 78 | "STRICT_DECREASE", 79 | "STRICT_INCREASE", 80 | "MONOTONOUS", 81 | "STRICT_MON", 82 | "NOT_MON", 83 | # prgtype enum 84 | "PRG_CODE", 85 | "PRG_DATA", 86 | "PRG_RESERVED", 87 | "CALIBRATION_VARIABLES", 88 | "CODE", 89 | "DATA", 90 | "EXCLUDE_FROM_FLASH", 91 | "OFFLINE_DATA", 92 | "SERAM", 93 | "VARIABLES", 94 | # unit type enum 95 | "DERIVED", 96 | "EXTENDED_SI", 97 | # tag enum 98 | "NUMERIC", 99 | "ALPHA", 100 | # Encoding used e.g. UTF8 101 | "ENCODING", 102 | # Transformer trigger enum 103 | "ON_CHANGE", 104 | "ON_USER_REQUEST" 105 | ] 106 | -------------------------------------------------------------------------------- /tests/rules/test_rules_calibration_method.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_calibration_method(): 26 | """ 27 | Tests parsing a valid "CALIBRATION_METHOD" block. 28 | """ 29 | calibration_method_block = """ 30 | /begin CALIBRATION_METHOD 31 | "FixedSizeMoveableEmuRAM" /* Method name */ 32 | 1 /* Method version */ 33 | /begin CALIBRATION_HANDLE 34 | 0 /* EmuRAM page identifier */ 35 | 0xBF000000 /* Original RAM Address */ 36 | 0x10000 /* Page size */ 37 | /end CALIBRATION_HANDLE 38 | /begin CALIBRATION_HANDLE 39 | 1 /* EmuRAM page identifier */ 40 | 0xBF010000 /* Original RAM Address */ 41 | 0x20000 /* Page size */ 42 | /end CALIBRATION_HANDLE 43 | /begin CALIBRATION_HANDLE 44 | 0x10000 /* start address of pointer table */ 45 | 0x200 /* length of pointer table */ 46 | 0x4 /* size of one pointer table entry */ 47 | 0x10000 /* start address of flash section */ 48 | 0x10000 /* length of flash section */ 49 | CALIBRATION_HANDLE_TEXT "Nmot" 50 | /end CALIBRATION_HANDLE 51 | /end CALIBRATION_METHOD 52 | """ 53 | parser = A2LYacc() 54 | ast = parser.generate_ast(calibration_method_block) 55 | assert ast 56 | 57 | calibration_method = ast["CALIBRATION_METHOD"] 58 | assert calibration_method 59 | assert calibration_method["Method"] == '"FixedSizeMoveableEmuRAM"' 60 | assert calibration_method["VERSION"] == "1" 61 | 62 | calibration_method_handle = calibration_method["CALIBRATION_HANDLE"] 63 | assert len(calibration_method_handle) == 3 64 | assert calibration_method_handle[0]["Handle"] == ["0", "0xBF000000", "0x10000"] 65 | assert calibration_method_handle[1]["Handle"] == ["1", "0xBF010000", "0x20000"] 66 | assert calibration_method_handle[2]["Handle"] == [ 67 | "0x10000", 68 | "0x200", 69 | "0x4", 70 | "0x10000", 71 | "0x10000", 72 | ] 73 | 74 | calibration_handle_text = calibration_method_handle[2]["CALIBRATION_HANDLE_TEXT"].Text 75 | assert calibration_handle_text == '"Nmot"' 76 | -------------------------------------------------------------------------------- /tests/lex/test_lex_tags_begin_end.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import pytest 23 | from a2lparser.a2l.a2l_lex import A2LLex 24 | 25 | 26 | @pytest.mark.parametrize( 27 | "begin_tag", 28 | [ 29 | "/BEGIN", 30 | "/begin", 31 | "/ BEGIN", 32 | "/ begin", 33 | "/ BEGIN", 34 | "/ begin", 35 | " /BEGIN", 36 | " /begin", 37 | " / BEGIN", 38 | " / begin", 39 | " / BEGIN ", 40 | " / begin ", 41 | ], 42 | ) 43 | def test_lex_tags_begin(begin_tag): 44 | """ 45 | Testing the A2L Lexer for detection of the A2L "BEGIN" tag with whitespaces. 46 | """ 47 | lexer = A2LLex() 48 | lexer.input(begin_tag) 49 | token = lexer.token() 50 | assert token 51 | assert token.type == "BEGIN" 52 | 53 | 54 | @pytest.mark.parametrize( 55 | "end_tag", 56 | [ 57 | "/END", 58 | "/end", 59 | "/ END", 60 | "/ end", 61 | "/ END", 62 | "/ end", 63 | " /END", 64 | " /end", 65 | " / END", 66 | " / end", 67 | " / END ", 68 | " / end ", 69 | ], 70 | ) 71 | def test_lex_tags_end(end_tag): 72 | """ 73 | Testing the A2L Lexer for detection of the A2L "END" tag with whitespaces. 74 | """ 75 | lexer = A2LLex() 76 | lexer.input(end_tag) 77 | token = lexer.token() 78 | assert token 79 | assert token.type == "END" 80 | 81 | 82 | @pytest.mark.parametrize( 83 | "begin_end_tag", 84 | [ 85 | "/BEGIN /END", 86 | "/BEGIN/END", 87 | "/begin /end", 88 | "/begin/end", 89 | "/ BEGIN / END", 90 | "/ begin / end", 91 | " /BEGIN/END", 92 | "/ begin/end", 93 | ], 94 | ) 95 | def test_lex_tags_begin_end(begin_end_tag): 96 | """ 97 | Testing the A2L Lexer for detection of A2L "BEGIN" and "END" tags. 98 | """ 99 | tokens = [] 100 | lexer = A2LLex() 101 | lexer.input(begin_end_tag) 102 | while True: 103 | if token := lexer.token(): 104 | tokens.append(token) 105 | else: 106 | break 107 | token = lexer.token() 108 | assert tokens 109 | assert len(tokens) == 2 110 | assert tokens[0].type == "BEGIN" 111 | assert tokens[1].type == "END" 112 | -------------------------------------------------------------------------------- /tests/lex/test_lex_datatypes.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import pytest 23 | from a2lparser.a2l.a2l_lex import A2LLex 24 | 25 | 26 | @pytest.mark.parametrize("decimal_constant", ["123", "-456", "0", "08001", "-01234", "+22"]) 27 | def test_lex_datatypes_decimal_constants(decimal_constant): 28 | """ 29 | Testing the A2L Lexer for detection of decimal numbers. 30 | """ 31 | lexer = A2LLex() 32 | lexer.input(decimal_constant) 33 | token = lexer.token() 34 | assert token 35 | assert token.type == "INT_CONST_DEC" 36 | assert token.value == decimal_constant 37 | 38 | 39 | @pytest.mark.parametrize("float_constant", ["3.1415", "-128.12", "0.0"]) 40 | def test_lex_datatypes_float_constants(float_constant): 41 | """ 42 | Testing the A2L Lexer for detection of float numbers. 43 | """ 44 | lexer = A2LLex() 45 | lexer.input(float_constant) 46 | token = lexer.token() 47 | assert token 48 | assert token.type == "FLOAT_CONST" 49 | assert token.value == float_constant 50 | 51 | 52 | @pytest.mark.parametrize("hex_constant", ["0x12AB", "0XFF", "0xfeed", "0xbeef1234"]) 53 | def test_lex_datatypes_hex_constants(hex_constant): 54 | """ 55 | Testing the A2L Lexer for detection of hexadecimal numbers. 56 | """ 57 | lexer = A2LLex() 58 | lexer.input(hex_constant) 59 | token = lexer.token() 60 | assert token 61 | assert token.type == "INT_CONST_HEX" 62 | assert token.value == hex_constant 63 | 64 | 65 | @pytest.mark.parametrize("exp_constant", ["1.23E-4", "2.1e+6", "-1.4e+21"]) 66 | def test_lex_datatypes_exp_constants(exp_constant): 67 | """ 68 | Testing the A2L Lexer for detection of numbers written with the exponential format. 69 | """ 70 | lexer = A2LLex() 71 | lexer.input(exp_constant) 72 | token = lexer.token() 73 | assert token 74 | assert token.type == "FLOAT_CONST" 75 | assert token.value == exp_constant 76 | 77 | 78 | @pytest.mark.parametrize( 79 | "string_literal", 80 | [ 81 | '"Some test string"', 82 | '"Some string with a weird escape character\tin it."', 83 | ], 84 | ) 85 | def test_lex_datatypes_string_literals(string_literal): 86 | """ 87 | Testing the A2L Lexer for detection of numbers written with the exponential format. 88 | """ 89 | lexer = A2LLex() 90 | lexer.input(string_literal) 91 | token = lexer.token() 92 | assert token 93 | assert token.type == "STRING_LITERAL" 94 | assert token.value == string_literal 95 | -------------------------------------------------------------------------------- /a2lparser/converter/yaml_converter.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import yaml 23 | from loguru import logger 24 | from a2lparser.converter.a2l_converter import A2LConverter 25 | 26 | 27 | class YAMLConverter(A2LConverter): 28 | """ 29 | Converter class for converting an A2L abstract syntax tree to an YAML file. 30 | 31 | Usage Example: 32 | >>> YAMLConverter().convert(ast_dict, output_dir="./yaml_files/") 33 | """ 34 | 35 | class YAMLConverterException(Exception): 36 | """ 37 | Exception raised when an error occurs while converting an AST to a YAML file. 38 | """ 39 | 40 | def convert(self, ast: dict, output_dir: str = ".", output_filename: str = None) -> None: 41 | """ 42 | Convert the given AST dictionary to YAML and write it to a file. 43 | 44 | Args: 45 | ast (dict): The AST dictionary to be converted to YAML. 46 | output_dir (str, optional): The directory to write the YAML file. 47 | output_filename (str, optional): The filename of the YAML file. 48 | """ 49 | try: 50 | logger.info("Converting AST to YAML and writing to file...") 51 | converted_tuples = self.convert_to_string(ast, output_filename) 52 | for tup in converted_tuples: 53 | filename, yaml_string = tup 54 | self.write_to_file(content=yaml_string, filename=filename, output_dir=output_dir) 55 | logger.success(f"Created YAML file: {filename}") 56 | 57 | except Exception as e: 58 | raise self.YAMLConverterException(e) from e 59 | 60 | def convert_to_string(self, ast: dict, output_filename: str = None) -> list: 61 | """ 62 | Convert the given AST dictionary to a YAML string. 63 | 64 | Args: 65 | ast (dict): The AST dictionary to be converted to YAML. 66 | output_filename (str, optional): The filename to be used. 67 | 68 | Returns: 69 | list: List of tuples (filename, yaml_string). 70 | """ 71 | try: 72 | result = [] 73 | sliced_ast = self.slice_ast(ast, file_extension="yml", filename=output_filename) 74 | for tup in sliced_ast: 75 | filename, root = tup 76 | yaml_string = yaml.dump(root) 77 | result.append((filename, yaml_string)) 78 | return result 79 | except Exception as e: 80 | raise self.YAMLConverterException(e) from e 81 | -------------------------------------------------------------------------------- /a2lparser/a2l/lex/lexer_regex.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | class LexerRegex: 23 | """ 24 | Holds a collection of regular expressions used in the lexer to identify tokens. 25 | """ 26 | 27 | ###################################### 28 | # RegEx for "BEGIN" and "END" tokens # 29 | ###################################### 30 | begin_section = r"/\s*begin|/\s*BEGIN" 31 | end_section = r"/\s*end|/\s*END" 32 | 33 | ######################################### 34 | # RegEx for parsing regular identifiers # 35 | ######################################### 36 | identifier = r"[a-zA-Z_][0-9a-zA-Z_\-.\[\]]*" 37 | 38 | ######################################## 39 | # RegEx for parsing A2ML content lines # 40 | ######################################## 41 | a2ml_content = r"/\s*begin\s+A2ML\s+([\s\S]*?)\s+/end\s+A2ML" 42 | 43 | ############################# 44 | # RegEx for parsing numbers # 45 | ############################# 46 | hex_digits = "[0-9a-fA-F]+" 47 | bin_prefix = "[+-]?0[bB]" 48 | integer_suffix_opt = r"(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?" 49 | decimal_constant = f"[+-]?([0-9]+){integer_suffix_opt}" 50 | hex_prefix = "[+-]?0[xX]" 51 | hex_constant = hex_prefix + hex_digits + integer_suffix_opt 52 | exponent_part = r"""([eE][-+]?[0-9]+)""" 53 | fractional_constant = r"""([+-]?[0-9]+\.[0-9]+)|([+-]?\.[0-9]+)|([+-]?[0-9]+\.)""" 54 | floating_constant = ( 55 | f"( ( (({fractional_constant}){exponent_part}?) | " 56 | f"([0-9]+{exponent_part}) | ([+-]?[0-9]+{exponent_part}) )[FfLl]?)" 57 | ) 58 | binary_exponent_part = r"""([pP][+-]?[0-9]+)""" 59 | hex_fractional_constant = ( 60 | f"((({hex_digits}" + r""")?\.""" + hex_digits + ")|(" + hex_digits + r"""\.))""" 61 | ) 62 | hex_floating_constant = ( 63 | f"({hex_prefix}({hex_digits}|{hex_fractional_constant}){binary_exponent_part}[FfLl]?)" 64 | ) 65 | 66 | ############################# 67 | # RegEx for parsing strings # 68 | ############################# 69 | simple_escape = r"""([a-zA-Z._~!=&\^\-\\?'"])""" 70 | decimal_escape = r"""(\d+)""" 71 | hex_escape = r"""(x[0-9a-fA-F]+)""" 72 | escape_sequence = r"""(\\(""" + simple_escape + "|" + decimal_escape + "|" + hex_escape + "))" 73 | string_char = r"""([^"\\\n]|""" + escape_sequence + ")" 74 | string_literal = r'("(\\"|[^"])*")|(\'(\\\'|[^\'])*\')' 75 | 76 | ########################################## 77 | # Regex for parsing comments and newline # 78 | ########################################## 79 | newline = r"\n+" 80 | comment_singleline = r"\/\/.*" 81 | comment_multiline = r"\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\/" 82 | -------------------------------------------------------------------------------- /a2lparser/converter/json_converter.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | import json 23 | from loguru import logger 24 | from a2lparser.converter.a2l_converter import A2LConverter 25 | 26 | 27 | class JSONConverter(A2LConverter): 28 | """ 29 | Converter class for converting an A2L abstract syntax tree to an JSON file. 30 | 31 | Usage Example: 32 | >>> JSONConverter().convert(ast_dict, output_dir="./json_files/") 33 | """ 34 | 35 | class JSONConverterException(Exception): 36 | """ 37 | Exception raised when an error occurs while converting an AST to a JSON file. 38 | """ 39 | 40 | def convert( 41 | self, ast: dict, output_dir: str = ".", output_filename: str = None, pretty: bool = True 42 | ) -> None: 43 | """ 44 | Convert the given AST dictionary to JSON and write it to a file. 45 | 46 | Args: 47 | ast (dict): The AST dictionary to be converted to JSON. 48 | output_dir (str, optional): The directory to write the JSON file. 49 | output_filename (str, optional): The filename of the JSON file. 50 | pretty (bool, optional): Whether to format the JSON file with indentation and newlines. 51 | """ 52 | try: 53 | logger.info("Converting AST to JSON and writing to file...") 54 | converted_tuples = self.convert_to_string(ast, output_filename, pretty) 55 | for tup in converted_tuples: 56 | filename, json_string = tup 57 | self.write_to_file(content=json_string, filename=filename, output_dir=output_dir) 58 | logger.success(f"Created JSON file: {filename}") 59 | 60 | except Exception as e: 61 | raise self.JSONConverterException(e) from e 62 | 63 | def convert_to_string( 64 | self, ast: dict, output_filename: str = None, pretty: bool = True 65 | ) -> list: 66 | """ 67 | Convert the given AST dictionary to a JSON string. 68 | 69 | Args: 70 | ast (dict): The AST dictionary to be converted to JSON. 71 | output_filename (str, optional): The filename to be used. 72 | pretty (bool, optional): Format the JSON string with indentation and newlines. 73 | 74 | Returns: 75 | list: List of tuples (filename, json_string). 76 | """ 77 | try: 78 | result = [] 79 | sliced_ast = self.slice_ast(ast, file_extension="json", filename=output_filename) 80 | for tup in sliced_ast: 81 | filename, root = tup 82 | json_string = json.dumps(root, indent=2) if pretty else json.dumps(root) 83 | result.append((filename, json_string)) 84 | return result 85 | except Exception as e: 86 | raise self.JSONConverterException(e) from e 87 | -------------------------------------------------------------------------------- /tests/rules/test_rules_typedef_structure.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_typedef_structure_minimal(): 26 | """ 27 | Test A2L TYPEDEF_STRUCTURE section. 28 | """ 29 | typedef_structure_minimal = """ 30 | /begin TYPEDEF_STRUCTURE 31 | MyStructure // structure name 32 | "..." // description 33 | 64 // total size of structure 34 | /end TYPEDEF_STRUCTURE 35 | """ 36 | ast = A2LYacc().generate_ast(typedef_structure_minimal) 37 | assert ast 38 | 39 | typedef_structure = ast["TYPEDEF_STRUCTURE"] 40 | assert typedef_structure 41 | assert typedef_structure["Name"] == "MyStructure" 42 | assert typedef_structure["LongIdentifier"] == '"..."' 43 | assert typedef_structure["Size"] == "64" 44 | 45 | 46 | def test_rules_typedef_structure_full(): 47 | """ 48 | Test A2L TYPEDEF_STRUCTURE section. 49 | """ 50 | typedef_structure_full = """ 51 | /begin TYPEDEF_STRUCTURE 52 | MyStructure // structure name 53 | "..." // description 54 | 64 // total size of structure 55 | 56 | /begin STRUCTURE_COMPONENT 57 | A MyUnsignedLongType 58 | 0 // address offset 59 | /end STRUCTURE_COMPONENT 60 | 61 | CONSISTENT_EXCHANGE 62 | ADDRESS_TYPE DIRECT 63 | SYMBOL_TYPE_LINK "__a" 64 | 65 | /begin STRUCTURE_COMPONENT 66 | B MyUnsignedLongType 67 | 34 // address offset 68 | MATRIX_DIM 10 69 | /end STRUCTURE_COMPONENT 70 | /end TYPEDEF_STRUCTURE 71 | """ 72 | ast = A2LYacc().generate_ast(typedef_structure_full) 73 | assert ast 74 | 75 | typedef_structure = ast["TYPEDEF_STRUCTURE"] 76 | assert typedef_structure 77 | assert typedef_structure["Name"] == "MyStructure" 78 | assert typedef_structure["LongIdentifier"] == '"..."' 79 | assert typedef_structure["Size"] == "64" 80 | assert typedef_structure["ADDRESS_TYPE"] == "DIRECT" 81 | assert typedef_structure["CONSISTENT_EXCHANGE"] is True 82 | assert typedef_structure["SYMBOL_TYPE_LINK"] == '"__a"' 83 | 84 | assert len(typedef_structure["STRUCTURE_COMPONENT"]) == 2 85 | structure_component_1 = typedef_structure["STRUCTURE_COMPONENT"][0] 86 | structure_component_2 = typedef_structure["STRUCTURE_COMPONENT"][1] 87 | 88 | assert structure_component_1 89 | assert structure_component_1["Name"] == "A" 90 | assert structure_component_1["TypedefName"] == "MyUnsignedLongType" 91 | assert structure_component_1["AddressOffset"] == "0" 92 | 93 | assert structure_component_2 94 | assert structure_component_2["Name"] == "B" 95 | assert structure_component_2["TypedefName"] == "MyUnsignedLongType" 96 | assert structure_component_2["AddressOffset"] == "34" 97 | assert structure_component_2["MATRIX_DIM"] == ["10"] 98 | -------------------------------------------------------------------------------- /tests/rules/test_rules_transformer.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | from a2lparser.a2l.a2l_yacc import A2LYacc 23 | 24 | 25 | def test_rules_transformer_minimal(): 26 | """ 27 | Test A2L TRANSFORMER section. 28 | """ 29 | transformer_minimal = """ 30 | /begin TRANSFORMER TRANSFORMER_TOOL 31 | "1.4.3.33" /* Version info */ 32 | "transformer_tool_x32.dll" /* DLL */ 33 | "" /* no 64bit DLL */ 34 | 33000 /* timeout in [ms] */ 35 | ON_USER_REQUEST 36 | TRANSFORMER_TOOL_REVERSE 37 | /end TRANSFORMER 38 | """ 39 | ast = A2LYacc().generate_ast(transformer_minimal) 40 | assert ast 41 | 42 | transformer = ast["TRANSFORMER"] 43 | assert transformer 44 | assert transformer["Name"] == "TRANSFORMER_TOOL" 45 | assert transformer["VERSION"] == '"1.4.3.33"' 46 | assert transformer["Executable32"] == '"transformer_tool_x32.dll"' 47 | assert transformer["Executable64"] == '""' 48 | assert transformer["Timeout"] == "33000" 49 | assert transformer["Trigger"] == "ON_USER_REQUEST" 50 | assert transformer["InverseTransformer"] == "TRANSFORMER_TOOL_REVERSE" 51 | 52 | 53 | def test_rules_transformer_full(): 54 | """ 55 | Test A2L TRANSFORMER section. 56 | """ 57 | transformer = """ 58 | /begin TRANSFORMER TEST_TRANSFORMER_TOOL 59 | "1.3.0.24" /* Version info */ 60 | "transformer_x32.dll" /* 32bit DLL */ 61 | "transformer_x64" /* 64bit DLL */ 62 | 5000 /* timeout in [ms] */ 63 | ON_CHANGE 64 | TRANSFORMER_TOOL_REVERSE_1 65 | /begin TRANSFORMER_IN_OBJECTS 66 | IN_CHAR_1 67 | IN_BLOB_1 68 | IN_TYPEDEF_STRUCT_x1 69 | /end TRANSFORMER_IN_OBJECTS 70 | /begin TRANSFORMER_OUT_OBJECTS 71 | OUT_ID_14 72 | OUT_STRUCT_x2 73 | OUT_BLOB_1 74 | OUT_BLOB_2 75 | /end TRANSFORMER_OUT_OBJECTS 76 | /end TRANSFORMER 77 | """ 78 | ast = A2LYacc().generate_ast(transformer) 79 | assert ast 80 | 81 | transformer = ast["TRANSFORMER"] 82 | assert transformer 83 | assert transformer["Name"] == "TEST_TRANSFORMER_TOOL" 84 | assert transformer["VERSION"] == '"1.3.0.24"' 85 | assert transformer["Executable32"] == '"transformer_x32.dll"' 86 | assert transformer["Executable64"] == '"transformer_x64"' 87 | assert transformer["Timeout"] == "5000" 88 | assert transformer["Trigger"] == "ON_CHANGE" 89 | assert transformer["InverseTransformer"] == "TRANSFORMER_TOOL_REVERSE_1" 90 | assert transformer["TRANSFORMER_IN_OBJECTS"] == [ 91 | "IN_CHAR_1", 92 | "IN_BLOB_1", 93 | "IN_TYPEDEF_STRUCT_x1", 94 | ] 95 | assert transformer["TRANSFORMER_OUT_OBJECTS"] == [ 96 | "OUT_ID_14", 97 | "OUT_STRUCT_x2", 98 | "OUT_BLOB_1", 99 | "OUT_BLOB_2", 100 | ] 101 | -------------------------------------------------------------------------------- /a2lparser/a2l/lex/keywords/a2l_keywords_sections.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # a2lparser: https://github.com/mrom1/a2lparser # 3 | # author: https://github.com/mrom1 # 4 | # # 5 | # This file is part of the a2lparser package. # 6 | # # 7 | # a2lparser is free software: you can redistribute it and/or modify it # 8 | # under the terms of the GNU General Public License as published by the # 9 | # Free Software Foundation, either version 3 of the License, or (at your option) # 10 | # any later version. # 11 | # # 12 | # a2lparser is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # 14 | # or FITNESS FOR A PARTICULAR PURPOSE. # 15 | # See the GNU General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU General Public License # 18 | # along with a2lparser. If not, see . # 19 | ####################################################################################### 20 | 21 | 22 | class A2LKeywordsSections: 23 | """ 24 | Keywords for parsing A2L sections. 25 | All section keywords are enclosed by an 26 | interpreted "/begin" and an "/end" token. 27 | 28 | Example Section: 29 | /begin VAR_ADDRESS 30 | 0x8840 31 | 0x8858 32 | 0x8870 33 | 0x8888 34 | /end VAR_ADDRESS 35 | """ 36 | 37 | keywords: list = [ 38 | # A2ML format keyword 39 | "A2ML", 40 | # Annotation 41 | "ANNOTATION", 42 | "ANNOTATION_TEXT", 43 | # AR_Component 44 | "AR_COMPONENT", 45 | # Axis description and points 46 | "AXIS_DESCR", 47 | "AXIS_PTS", 48 | # BLOB 49 | "BLOB", 50 | # Calibartion 51 | "CALIBRATION_HANDLE", 52 | "CALIBRATION_METHOD", 53 | # Characteristic section 54 | "CHARACTERISTIC", 55 | # Computation 56 | "COMPU_METHOD", 57 | "COMPU_TAB", 58 | "COMPU_VTAB", 59 | "COMPU_VTAB_RANGE", 60 | # Dependent characteristic 61 | "DEPENDENT_CHARACTERISTIC", 62 | # Fix axis par 63 | "FIX_AXIS_PAR_LIST", 64 | # Formula 65 | "FORMULA", 66 | # Frame 67 | "FRAME", 68 | # Function 69 | "FUNCTION", 70 | "FUNCTION_LIST", 71 | # Group 72 | "GROUP", 73 | # Header 74 | "HEADER", 75 | # Interface data 76 | "IF_DATA", 77 | "IN_MEASUREMENT", 78 | "LOC_MEASUREMENT", 79 | "INSTANCE", 80 | "MEASUREMENT", 81 | # MAP_LIST 82 | "MAP_LIST", 83 | # MEMORY_LAYOUT 84 | "MEMORY_LAYOUT", 85 | # MEMORY_SEGMENT 86 | "MEMORY_SEGMENT", 87 | # MOD_COMMON 88 | "MOD_COMMON", 89 | # MOD_PAR 90 | "MOD_PAR", 91 | # MODULE 92 | "MODULE", 93 | # OUT_MEASUREMENT 94 | "OUT_MEASUREMENT", 95 | # OVERWRITE 96 | "OVERWRITE", 97 | # PROJECT 98 | "PROJECT", 99 | # RECORD_LAYOUT 100 | "RECORD_LAYOUT", 101 | # REFS 102 | "REF_CHARACTERISTIC", 103 | "REF_GROUP", 104 | "REF_MEASUREMENT", 105 | "STRUCTURE_COMPONENT", 106 | "SUB_FUNCTION", 107 | "SUB_GROUP", 108 | "TRANSFORMER", 109 | # TYPE DEFS 110 | "TYPEDEF_AXIS", 111 | "TYPEDEF_BLOB", 112 | "TYPEDEF_CHARACTERISTIC", 113 | "TYPEDEF_MEASUREMENT", 114 | "TYPEDEF_STRUCTURE", 115 | # UNIT 116 | "UNIT", 117 | # USER_RIGHTS 118 | "USER_RIGHTS", 119 | # Variant sections 120 | "VAR_ADDRESS", 121 | "VAR_CHARACTERISTIC", 122 | "VAR_CRITERION", 123 | "VAR_FORBIDDEN_COMB", 124 | "VARIANT_CODING", 125 | # Virtual 126 | "VIRTUAL", 127 | "VIRTUAL_CHARACTERISTIC", 128 | ] 129 | --------------------------------------------------------------------------------