├── 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 |
--------------------------------------------------------------------------------