idl-parser 0.2.2__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {idl_parser-0.2.2 → idl_parser-0.3.2}/.github/workflows/test.yml +26 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/.gitignore +2 -0
- idl_parser-0.3.2/.vscode/extensions.json +6 -0
- idl_parser-0.3.2/.vscode/launch.json +21 -0
- idl_parser-0.3.2/.vscode/settings.json +23 -0
- {idl_parser-0.2.2/idl_parser.egg-info → idl_parser-0.3.2}/PKG-INFO +11 -3
- {idl_parser-0.2.2 → idl_parser-0.3.2}/README.md +6 -1
- {idl_parser-0.2.2 → idl_parser-0.3.2}/README.rst +10 -2
- idl_parser-0.3.2/examples/argument_direction_example.py +75 -0
- idl_parser-0.3.2/examples/enum_example.py +68 -0
- idl_parser-0.3.2/examples/example.py +37 -0
- idl_parser-0.3.2/examples/scoped_name_example.py +121 -0
- idl_parser-0.3.2/examples/struct_example.py +72 -0
- idl_parser-0.3.2/idl_parser/__init__.py +18 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/bitmask.py +26 -1
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/bitset.py +27 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/const.py +24 -1
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/enum.py +40 -1
- idl_parser-0.3.2/idl_parser/exception.py +80 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/interface.py +68 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/module.py +213 -31
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/node.py +79 -7
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/parser.py +80 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/pragma.py +3 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/struct.py +70 -10
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/token_buffer.py +9 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/type.py +103 -2
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/typedef.py +39 -1
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser/union.py +61 -4
- {idl_parser-0.2.2 → idl_parser-0.3.2/idl_parser.egg-info}/PKG-INFO +11 -3
- idl_parser-0.3.2/idl_parser.egg-info/SOURCES.txt +128 -0
- idl_parser-0.3.2/idl_parser.egg-info/scm_file_list.json +126 -0
- idl_parser-0.3.2/idl_parser.egg-info/scm_version.json +8 -0
- idl_parser-0.3.2/tests/README.md +67 -0
- idl_parser-0.3.2/tests/__init__.py +0 -0
- idl_parser-0.3.2/tests/annotation/__init__.py +0 -0
- {idl_parser-0.2.2/tests → idl_parser-0.3.2/tests/annotation}/annotation_test.py +58 -0
- idl_parser-0.3.2/tests/annotation/bit_bound_scope_test.py +45 -0
- idl_parser-0.3.2/tests/annotation/string_argument_test.py +39 -0
- idl_parser-0.3.2/tests/bitmask_bitset/__init__.py +0 -0
- {idl_parser-0.2.2/tests → idl_parser-0.3.2/tests/bitmask_bitset}/bitmask_bitset_test.py +59 -17
- idl_parser-0.3.2/tests/examples/__init__.py +0 -0
- idl_parser-0.3.2/tests/examples/examples_test.py +402 -0
- idl_parser-0.3.2/tests/forward_declaration/__init__.py +0 -0
- idl_parser-0.3.2/tests/forward_declaration/element_type_forward_test.py +64 -0
- idl_parser-0.2.2/tests/forward_declaration_test.py → idl_parser-0.3.2/tests/forward_declaration/interface_forward_test.py +85 -3
- idl_parser-0.2.2/tests/issue57_test.py → idl_parser-0.3.2/tests/forward_declaration/struct_union_forward_test.py +83 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/invalid_idl.idl +1 -1
- idl_parser-0.3.2/tests/include/__init__.py +0 -0
- idl_parser-0.2.2/tests/include_test.py → idl_parser-0.3.2/tests/include/circular_include_test.py +20 -2
- idl_parser-0.3.2/tests/include/include_dirs_test.py +46 -0
- idl_parser-0.2.2/tests/issue12_test.py → idl_parser-0.3.2/tests/include/subpath_include_test.py +20 -4
- idl_parser-0.3.2/tests/interface/__init__.py +0 -0
- idl_parser-0.3.2/tests/interface/argument_direction_test.py +77 -0
- idl_parser-0.3.2/tests/interface/basic_module_test.py +63 -0
- idl_parser-0.2.2/tests/generalization_test.py → idl_parser-0.3.2/tests/interface/inheritance_test.py +112 -66
- idl_parser-0.2.2/tests/issue45_test.py → idl_parser-0.3.2/tests/interface/raises_context_test.py +70 -0
- idl_parser-0.3.2/tests/lexing/__init__.py +0 -0
- idl_parser-0.3.2/tests/lexing/basic_module_test.py +55 -0
- idl_parser-0.2.2/tests/issue53_test.py → idl_parser-0.3.2/tests/lexing/bracket_spacing_test.py +80 -0
- idl_parser-0.3.2/tests/lexing/error_line_number_test.py +33 -0
- idl_parser-0.3.2/tests/lexing/exception_message_test.py +113 -0
- idl_parser-0.2.2/tests/issue9_test.py → idl_parser-0.3.2/tests/lexing/opensplice_idl_test.py +19 -1
- idl_parser-0.2.2/tests/issue50_test.py → idl_parser-0.3.2/tests/lexing/string_literal_comment_test.py +39 -1
- idl_parser-0.3.2/tests/lexing/token_split_test.py +51 -0
- idl_parser-0.3.2/tests/output/__init__.py +0 -0
- idl_parser-0.2.2/tests/issue43_test.py → idl_parser-0.3.2/tests/output/constructor_python_test.py +17 -0
- idl_parser-0.3.2/tests/output/simple_dic_enum_test.py +101 -0
- idl_parser-0.3.2/tests/output/simple_dic_inherits_test.py +101 -0
- idl_parser-0.2.2/tests/simple_dic_test.py → idl_parser-0.3.2/tests/output/simple_dic_member_only_test.py +14 -4
- idl_parser-0.2.2/tests/issue30_test.py → idl_parser-0.3.2/tests/output/simple_dic_member_type_test.py +30 -1
- idl_parser-0.3.2/tests/pragma_key/__init__.py +0 -0
- {idl_parser-0.2.2/tests → idl_parser-0.3.2/tests/pragma_key}/key_annotation_test.py +58 -0
- idl_parser-0.3.2/tests/pragma_key/keylist_validation_test.py +135 -0
- {idl_parser-0.2.2/tests → idl_parser-0.3.2/tests/pragma_key}/pragma_test.py +72 -82
- idl_parser-0.3.2/tests/primitive_const/__init__.py +0 -0
- idl_parser-0.3.2/tests/primitive_const/basic_module_test.py +86 -0
- idl_parser-0.2.2/tests/issue52_test.py → idl_parser-0.3.2/tests/primitive_const/const_test.py +56 -42
- idl_parser-0.2.2/tests/issue18_test.py → idl_parser-0.3.2/tests/primitive_const/int_types_test.py +27 -1
- idl_parser-0.3.2/tests/scope/__init__.py +0 -0
- idl_parser-0.3.2/tests/scope/basename_test.py +38 -0
- idl_parser-0.3.2/tests/scope/basic_module_test.py +39 -0
- idl_parser-0.3.2/tests/scope/leading_scope_test.py +115 -0
- idl_parser-0.2.2/tests/multimodule_test.py → idl_parser-0.3.2/tests/scope/multi_module_test.py +19 -30
- idl_parser-0.3.2/tests/scope/same_name_resolution_test.py +204 -0
- idl_parser-0.3.2/tests/scope/unknown_word_test.py +165 -0
- idl_parser-0.2.2/tests/issue39_test.py → idl_parser-0.3.2/tests/scope/unsupported_block_scope_test.py +17 -0
- idl_parser-0.3.2/tests/sequence_array/__init__.py +0 -0
- idl_parser-0.3.2/tests/sequence_array/basic_module_test.py +111 -0
- idl_parser-0.3.2/tests/sequence_array/element_type_test.py +164 -0
- idl_parser-0.2.2/tests/issue31_test.py → idl_parser-0.3.2/tests/sequence_array/nested_bounded_sequence_test.py +49 -0
- idl_parser-0.3.2/tests/sequence_array/syntax_error_test.py +29 -0
- idl_parser-0.3.2/tests/struct_enum_union/__init__.py +0 -0
- idl_parser-0.3.2/tests/struct_enum_union/basic_module_test.py +126 -0
- {idl_parser-0.2.2/tests → idl_parser-0.3.2/tests/struct_enum_union}/syntax_error_test.py +10 -8
- idl_parser-0.2.2/tests/issue49_test.py → idl_parser-0.3.2/tests/struct_enum_union/union_char_label_test.py +25 -0
- idl_parser-0.2.2/tests/issue48_test.py → idl_parser-0.3.2/tests/struct_enum_union/union_default_label_test.py +70 -0
- idl_parser-0.3.2/tests/support.py +6 -0
- idl_parser-0.2.2/examples/example.py +0 -101
- idl_parser-0.2.2/idl_parser/__init__.py +0 -7
- idl_parser-0.2.2/idl_parser/exception.py +0 -37
- idl_parser-0.2.2/idl_parser.egg-info/SOURCES.txt +0 -85
- idl_parser-0.2.2/idl_parser.egg-info/scm_file_list.json +0 -83
- idl_parser-0.2.2/idl_parser.egg-info/scm_version.json +0 -8
- idl_parser-0.2.2/tests/__init__.py +0 -1
- idl_parser-0.2.2/tests/examples_test.py +0 -178
- idl_parser-0.2.2/tests/invalid_idl_test.py +0 -35
- idl_parser-0.2.2/tests/module_test.py +0 -301
- {idl_parser-0.2.2 → idl_parser-0.3.2}/.github/workflows/release.yml +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/.readthedocs.yaml +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/LICENSE +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/docs/api/index.rst +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/docs/conf.py +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/docs/index.rst +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/docs/requirements.txt +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/examples/_path.py +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/examples/annotation_example.py +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/examples/union_example.py +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser.egg-info/dependency_links.txt +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/idl_parser.egg-info/top_level.txt +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/pyproject.toml +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/setup.cfg +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/basic_module_test.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/circular/circular_a.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/circular/circular_b.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/circular/diamond.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/forward_declaration.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/generalization.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/generalization_extended.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/included_idl.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/including_idl.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/issue12_subpath/relative_include.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/issue12_subpath/sensor_msgs/msg/Imu.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/issue12_subpath/std/msg/Header.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/issue18_idl42_int_types.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/issue28_pragma_keylist.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/issue9_const_pragma.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/issue9_tabs_bounded_string.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/issue9_whitespace_variants.idl +0 -0
- {idl_parser-0.2.2 → idl_parser-0.3.2}/tests/idls/multi_module_test.idl +0 -0
|
@@ -33,6 +33,32 @@ jobs:
|
|
|
33
33
|
- name: Run tests
|
|
34
34
|
run: python -m unittest discover --start-directory tests --pattern '*_test.py' --top-level-directory . --verbose
|
|
35
35
|
|
|
36
|
+
coverage:
|
|
37
|
+
name: Coverage
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v5
|
|
41
|
+
|
|
42
|
+
- uses: actions/setup-python@v6
|
|
43
|
+
with:
|
|
44
|
+
python-version: "3.12"
|
|
45
|
+
|
|
46
|
+
- name: Run tests with coverage
|
|
47
|
+
run: |
|
|
48
|
+
python -m pip install coverage
|
|
49
|
+
python -m coverage run --branch --source=idl_parser -m unittest discover --start-directory tests --pattern '*_test.py' --top-level-directory .
|
|
50
|
+
python -m coverage report
|
|
51
|
+
python -m coverage xml
|
|
52
|
+
|
|
53
|
+
# Uploads coverage.xml to Codecov, which serves the README badge.
|
|
54
|
+
# Without the CODECOV_TOKEN secret the upload may be rejected; that
|
|
55
|
+
# must not fail the tests, so errors are not fatal.
|
|
56
|
+
- uses: codecov/codecov-action@v5
|
|
57
|
+
with:
|
|
58
|
+
files: coverage.xml
|
|
59
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
60
|
+
fail_ci_if_error: false
|
|
61
|
+
|
|
36
62
|
lint:
|
|
37
63
|
name: Check undefined names
|
|
38
64
|
runs-on: ubuntu-latest
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2.0",
|
|
3
|
+
"configurations": [
|
|
4
|
+
{
|
|
5
|
+
"name": "Python: unittest discover",
|
|
6
|
+
"type": "python",
|
|
7
|
+
"request": "launch",
|
|
8
|
+
"module": "unittest",
|
|
9
|
+
"args": [
|
|
10
|
+
"discover",
|
|
11
|
+
"-s",
|
|
12
|
+
"tests",
|
|
13
|
+
"-p",
|
|
14
|
+
"*_test.py",
|
|
15
|
+
"-v"
|
|
16
|
+
],
|
|
17
|
+
"cwd": "${workspaceFolder}",
|
|
18
|
+
"justMyCode": true
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"python.testing.unittestEnabled": true,
|
|
3
|
+
"python.testing.pytestEnabled": false,
|
|
4
|
+
"python.testing.unittestArgs": [
|
|
5
|
+
"-v",
|
|
6
|
+
"-s",
|
|
7
|
+
"${workspaceFolder}/tests",
|
|
8
|
+
"-p",
|
|
9
|
+
"*_test.py"
|
|
10
|
+
],
|
|
11
|
+
"python.testing.cwd": "${workspaceFolder}",
|
|
12
|
+
"python.analysis.typeCheckingMode": "basic",
|
|
13
|
+
"python.analysis.autoImportCompletions": true,
|
|
14
|
+
"python.analysis.diagnosticMode": "workspace",
|
|
15
|
+
"files.trimTrailingWhitespace": true,
|
|
16
|
+
"editor.formatOnSave": true,
|
|
17
|
+
"editor.rulers": [
|
|
18
|
+
88
|
|
19
|
+
],
|
|
20
|
+
"terminal.integrated.env.osx": {
|
|
21
|
+
"PYTHONPATH": "${workspaceFolder}${pathSeparator}${env:PYTHONPATH}"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: idl_parser
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Very simple OMG IDL (Interface Definition Language) parser. This parses IDL files and outputs intermediate class objects.
|
|
5
5
|
Author-email: ysuga <ysuga@ysuga.net>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -24,7 +24,7 @@ Dynamic: license-file
|
|
|
24
24
|
idl_parser
|
|
25
25
|
============
|
|
26
26
|
|
|
27
|
-
|Test Status| |Docs Status|
|
|
27
|
+
|Test Status| |Coverage| |Docs Status|
|
|
28
28
|
|
|
29
29
|
Description
|
|
30
30
|
-----------
|
|
@@ -99,9 +99,13 @@ Example
|
|
|
99
99
|
|
|
100
100
|
More examples are in the ``examples`` folder of the repository:
|
|
101
101
|
|
|
102
|
-
- ``example.py``:
|
|
102
|
+
- ``example.py``: the smallest example: a module and an interface
|
|
103
|
+
- ``argument_direction_example.py``: directions of method arguments (``in``, ``out`` and ``inout``)
|
|
104
|
+
- ``struct_example.py``: structs and their member types
|
|
105
|
+
- ``enum_example.py``: enums and their values
|
|
103
106
|
- ``union_example.py``: unions (discriminator kinds, case and ``default`` labels, member types)
|
|
104
107
|
- ``annotation_example.py``: IDL 4 annotations (``@key``, ``@range``, ...) and struct keys
|
|
108
|
+
- ``scoped_name_example.py``: same-named types in several modules (relative ``X``, ``C::X`` and absolute ``::B::X`` names)
|
|
105
109
|
|
|
106
110
|
https://github.com/sugarsweetrobotics/idl_parser/tree/main/examples
|
|
107
111
|
|
|
@@ -128,3 +132,7 @@ Copyright
|
|
|
128
132
|
.. |Docs Status| image:: https://readthedocs.org/projects/idl-parser/badge/?version=latest
|
|
129
133
|
:target: https://idl-parser.readthedocs.io/en/latest/
|
|
130
134
|
:alt: Documentation Status
|
|
135
|
+
|
|
136
|
+
.. |Coverage| image:: https://codecov.io/gh/sugarsweetrobotics/idl_parser/branch/main/graph/badge.svg
|
|
137
|
+
:target: https://codecov.io/gh/sugarsweetrobotics/idl_parser
|
|
138
|
+
:alt: Coverage
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/sugarsweetrobotics/idl_parser/actions/workflows/test.yml)
|
|
4
4
|
[](https://idl-parser.readthedocs.io/en/latest/)
|
|
5
|
+
[](https://codecov.io/gh/sugarsweetrobotics/idl_parser)
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
## Description
|
|
@@ -74,9 +75,13 @@ More examples are in the [examples](examples/) folder:
|
|
|
74
75
|
|
|
75
76
|
| File | Shows |
|
|
76
77
|
|---|---|
|
|
77
|
-
| [`example.py`](examples/example.py) |
|
|
78
|
+
| [`example.py`](examples/example.py) | the smallest example: a module and an interface |
|
|
79
|
+
| [`argument_direction_example.py`](examples/argument_direction_example.py) | directions of method arguments: `in`, `out` and `inout` |
|
|
80
|
+
| [`struct_example.py`](examples/struct_example.py) | structs and their member types |
|
|
81
|
+
| [`enum_example.py`](examples/enum_example.py) | enums and their values |
|
|
78
82
|
| [`union_example.py`](examples/union_example.py) | unions: discriminator kinds, case and `default` labels, member types |
|
|
79
83
|
| [`annotation_example.py`](examples/annotation_example.py) | IDL 4 annotations (`@key`, `@range`, ...) and struct keys |
|
|
84
|
+
| [`scoped_name_example.py`](examples/scoped_name_example.py) | same-named types in several modules: relative (`X`, `C::X`) and absolute (`::B::X`) names |
|
|
80
85
|
|
|
81
86
|
Run them with e.g. `python examples/union_example.py` (in a source checkout no install is needed).
|
|
82
87
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
idl_parser
|
|
2
2
|
============
|
|
3
3
|
|
|
4
|
-
|Test Status| |Docs Status|
|
|
4
|
+
|Test Status| |Coverage| |Docs Status|
|
|
5
5
|
|
|
6
6
|
Description
|
|
7
7
|
-----------
|
|
@@ -76,9 +76,13 @@ Example
|
|
|
76
76
|
|
|
77
77
|
More examples are in the ``examples`` folder of the repository:
|
|
78
78
|
|
|
79
|
-
- ``example.py``:
|
|
79
|
+
- ``example.py``: the smallest example: a module and an interface
|
|
80
|
+
- ``argument_direction_example.py``: directions of method arguments (``in``, ``out`` and ``inout``)
|
|
81
|
+
- ``struct_example.py``: structs and their member types
|
|
82
|
+
- ``enum_example.py``: enums and their values
|
|
80
83
|
- ``union_example.py``: unions (discriminator kinds, case and ``default`` labels, member types)
|
|
81
84
|
- ``annotation_example.py``: IDL 4 annotations (``@key``, ``@range``, ...) and struct keys
|
|
85
|
+
- ``scoped_name_example.py``: same-named types in several modules (relative ``X``, ``C::X`` and absolute ``::B::X`` names)
|
|
82
86
|
|
|
83
87
|
https://github.com/sugarsweetrobotics/idl_parser/tree/main/examples
|
|
84
88
|
|
|
@@ -105,3 +109,7 @@ Copyright
|
|
|
105
109
|
.. |Docs Status| image:: https://readthedocs.org/projects/idl-parser/badge/?version=latest
|
|
106
110
|
:target: https://idl-parser.readthedocs.io/en/latest/
|
|
107
111
|
:alt: Documentation Status
|
|
112
|
+
|
|
113
|
+
.. |Coverage| image:: https://codecov.io/gh/sugarsweetrobotics/idl_parser/branch/main/graph/badge.svg
|
|
114
|
+
:target: https://codecov.io/gh/sugarsweetrobotics/idl_parser
|
|
115
|
+
:alt: Coverage
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Example: read the direction of interface method arguments (in / out / inout).
|
|
2
|
+
|
|
3
|
+
In IDL each argument of a method has a direction:
|
|
4
|
+
|
|
5
|
+
- ``in``: the caller passes a value to the method,
|
|
6
|
+
- ``out``: the method returns a value to the caller through the argument,
|
|
7
|
+
- ``inout``: the caller passes a value and the method may change it.
|
|
8
|
+
|
|
9
|
+
Shows how to
|
|
10
|
+
- read each argument's direction (``direction``),
|
|
11
|
+
- pick the arguments the caller sends and the ones it receives,
|
|
12
|
+
- build a simple call signature from the directions.
|
|
13
|
+
|
|
14
|
+
Run::
|
|
15
|
+
|
|
16
|
+
python examples/argument_direction_example.py
|
|
17
|
+
"""
|
|
18
|
+
import _path # noqa: F401 (use the idl_parser of this checkout)
|
|
19
|
+
|
|
20
|
+
from idl_parser import parser
|
|
21
|
+
|
|
22
|
+
IDL = '''
|
|
23
|
+
module my_module {
|
|
24
|
+
interface Counter {
|
|
25
|
+
// in: the value is only passed to the method
|
|
26
|
+
void set(in long value);
|
|
27
|
+
|
|
28
|
+
// out: the value is only returned from the method
|
|
29
|
+
void get(out long value);
|
|
30
|
+
|
|
31
|
+
// inout: the value is passed, changed and returned
|
|
32
|
+
void increment(inout long value);
|
|
33
|
+
|
|
34
|
+
// directions can be mixed in one method
|
|
35
|
+
boolean divide(in double a, in double b, out double quotient, inout long count);
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
'''
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def main():
|
|
42
|
+
global_module = parser.IDLParser().load(IDL)
|
|
43
|
+
counter = global_module.module_by_name('my_module').interface_by_name('Counter')
|
|
44
|
+
|
|
45
|
+
print('== Direction of each argument')
|
|
46
|
+
for m in counter.methods:
|
|
47
|
+
for a in m.arguments:
|
|
48
|
+
print(' %-10s %-9s %-6s %s' % (m.name, a.name, a.direction, a.type.name))
|
|
49
|
+
print()
|
|
50
|
+
|
|
51
|
+
# in and inout arguments are sent by the caller,
|
|
52
|
+
# out and inout arguments (and the return value) come back to the caller.
|
|
53
|
+
print('== What the caller sends and receives')
|
|
54
|
+
for m in counter.methods:
|
|
55
|
+
sends = [a.name for a in m.arguments if a.direction in ('in', 'inout')]
|
|
56
|
+
receives = [a.name for a in m.arguments if a.direction in ('out', 'inout')]
|
|
57
|
+
if m.returns.name != 'void':
|
|
58
|
+
receives.insert(0, '(return %s)' % m.returns.name)
|
|
59
|
+
print(' %-10s sends: %-14s receives: %s' % (m.name, ', '.join(sends) or '-', ', '.join(receives) or '-'))
|
|
60
|
+
print()
|
|
61
|
+
|
|
62
|
+
# For example, a Python-like signature: in/inout become parameters,
|
|
63
|
+
# out/inout and the return value become results.
|
|
64
|
+
print('== Python-like signatures')
|
|
65
|
+
for m in counter.methods:
|
|
66
|
+
params = [a.name for a in m.arguments if a.direction in ('in', 'inout')]
|
|
67
|
+
results = [a.name for a in m.arguments if a.direction in ('out', 'inout')]
|
|
68
|
+
if m.returns.name != 'void':
|
|
69
|
+
results.insert(0, 'result')
|
|
70
|
+
call = '%s(%s)' % (m.name, ', '.join(params))
|
|
71
|
+
print(' %s' % ('%s = %s' % (', '.join(results), call) if results else call))
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
if __name__ == '__main__':
|
|
75
|
+
main()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Example: read enums and their values.
|
|
2
|
+
|
|
3
|
+
Shows how to get
|
|
4
|
+
- the enums in a module (``enums``, ``enum_by_name``),
|
|
5
|
+
- each enumerator's name and ordinal (``values``, ``value``),
|
|
6
|
+
- an enumerator by name (``value_by_name``),
|
|
7
|
+
- an enum used as a struct member and as a method return type.
|
|
8
|
+
|
|
9
|
+
Run::
|
|
10
|
+
|
|
11
|
+
python examples/enum_example.py
|
|
12
|
+
"""
|
|
13
|
+
import _path # noqa: F401 (use the idl_parser of this checkout)
|
|
14
|
+
|
|
15
|
+
from idl_parser import parser
|
|
16
|
+
|
|
17
|
+
IDL = '''
|
|
18
|
+
module my_module {
|
|
19
|
+
enum Color {
|
|
20
|
+
RED,
|
|
21
|
+
GREEN,
|
|
22
|
+
BLUE
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
enum ReturnCode {
|
|
26
|
+
RETURN_OK,
|
|
27
|
+
RETURN_ERROR,
|
|
28
|
+
RETURN_TIMEOUT
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
struct Light {
|
|
32
|
+
Color color;
|
|
33
|
+
double brightness;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
interface LightController {
|
|
37
|
+
ReturnCode setColor(in Color color);
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
'''
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def main():
|
|
44
|
+
global_module = parser.IDLParser().load(IDL)
|
|
45
|
+
my_module = global_module.module_by_name('my_module')
|
|
46
|
+
|
|
47
|
+
print('enums in my_module:', [e.name for e in my_module.enums])
|
|
48
|
+
print()
|
|
49
|
+
|
|
50
|
+
color = my_module.enum_by_name('Color')
|
|
51
|
+
print('enum %s' % color.full_path)
|
|
52
|
+
for v in color.values:
|
|
53
|
+
print(' %s = %d' % (v.name, v.value))
|
|
54
|
+
print('BLUE is', color.value_by_name('BLUE').value)
|
|
55
|
+
print()
|
|
56
|
+
|
|
57
|
+
# A struct member whose type is an enum
|
|
58
|
+
light = my_module.struct_by_name('Light')
|
|
59
|
+
member = light.member_by_name('color')
|
|
60
|
+
print('Light.color is enum? %s (%s)' % (member.type.is_enum, member.type.full_path))
|
|
61
|
+
|
|
62
|
+
# An enum as a method return type
|
|
63
|
+
method = my_module.interface_by_name('LightController').method_by_name('setColor')
|
|
64
|
+
print('setColor returns %s' % method.returns.name)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
if __name__ == '__main__':
|
|
68
|
+
main()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Example: parse an IDL string and print the methods of an interface.
|
|
2
|
+
|
|
3
|
+
Run (no install needed in a checkout)::
|
|
4
|
+
|
|
5
|
+
python examples/example.py
|
|
6
|
+
|
|
7
|
+
See also ``struct_example.py``, ``enum_example.py``, ``union_example.py``,
|
|
8
|
+
``annotation_example.py`` and ``scoped_name_example.py`` in this folder.
|
|
9
|
+
"""
|
|
10
|
+
import _path # noqa: F401 (use the idl_parser of this checkout)
|
|
11
|
+
|
|
12
|
+
from idl_parser import parser
|
|
13
|
+
|
|
14
|
+
IDL = '''
|
|
15
|
+
module my_module {
|
|
16
|
+
interface Calculator {
|
|
17
|
+
long add(in long a, in long b);
|
|
18
|
+
void reset();
|
|
19
|
+
boolean divide(in double a, in double b, out double result);
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
'''
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main():
|
|
26
|
+
global_module = parser.IDLParser().load(IDL)
|
|
27
|
+
my_module = global_module.module_by_name('my_module')
|
|
28
|
+
calculator = my_module.interface_by_name('Calculator')
|
|
29
|
+
|
|
30
|
+
print('interface %s' % calculator.full_path)
|
|
31
|
+
for m in calculator.methods:
|
|
32
|
+
args = ', '.join('%s %s %s' % (a.direction, a.type.name, a.name) for a in m.arguments)
|
|
33
|
+
print(' %s %s(%s)' % (m.returns.name, m.name, args))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
if __name__ == '__main__':
|
|
37
|
+
main()
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Example: resolve type names across modules (relative and absolute names).
|
|
2
|
+
|
|
3
|
+
When several modules define a type with the same name, a type name is
|
|
4
|
+
resolved with the IDL scoping rules (issues #69, #72):
|
|
5
|
+
|
|
6
|
+
- a relative name (``X``, ``C::X``) is looked up from the scope where it is
|
|
7
|
+
written, innermost first, then in the outer scopes;
|
|
8
|
+
- an absolute name (``::B::X``) is looked up from the global scope only.
|
|
9
|
+
|
|
10
|
+
Shows how to get
|
|
11
|
+
- the definition a member, argument or return type refers to (``obj`` / ``type``),
|
|
12
|
+
- the name as written (``ref_name``) and the name of the definition (``name``),
|
|
13
|
+
- a typedef resolved in the scope where it is defined,
|
|
14
|
+
- ``find_types()`` with and without a scope.
|
|
15
|
+
|
|
16
|
+
Run::
|
|
17
|
+
|
|
18
|
+
python examples/scoped_name_example.py
|
|
19
|
+
"""
|
|
20
|
+
import _path # noqa: F401 (use the idl_parser of this checkout)
|
|
21
|
+
|
|
22
|
+
from idl_parser import parser
|
|
23
|
+
|
|
24
|
+
IDL = '''
|
|
25
|
+
// A global Point, and a Point in each module
|
|
26
|
+
struct Point { long id; };
|
|
27
|
+
|
|
28
|
+
module geometry {
|
|
29
|
+
struct Point { double x; double y; };
|
|
30
|
+
typedef Point Origin; // geometry::Point (the scope of the typedef)
|
|
31
|
+
|
|
32
|
+
module d3 {
|
|
33
|
+
struct Point { double x; double y; double z; };
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module robot {
|
|
38
|
+
struct Point { long joint; };
|
|
39
|
+
|
|
40
|
+
module arm {
|
|
41
|
+
struct Point { double angle; };
|
|
42
|
+
|
|
43
|
+
interface Controller {
|
|
44
|
+
// relative names: looked up from robot::arm, then robot, then global
|
|
45
|
+
Point current(); // robot::arm::Point
|
|
46
|
+
void move_joint(in robot::Point p); // robot::Point
|
|
47
|
+
void move_to(in geometry::Point p); // geometry::Point
|
|
48
|
+
void move_to_3d(in geometry::d3::Point p);
|
|
49
|
+
// absolute names: from the global scope only
|
|
50
|
+
void mark(in ::Point p); // the global Point
|
|
51
|
+
void move_arm(in ::robot::arm::Point p);
|
|
52
|
+
geometry::Origin origin(); // typedef of geometry::Point
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
struct Pose {
|
|
57
|
+
Point joint; // robot::Point
|
|
58
|
+
arm::Point arm; // relative name with a scope: robot::arm::Point
|
|
59
|
+
sequence<geometry::Point> path; // element type is resolved too
|
|
60
|
+
::Point marker; // the global Point
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
'''
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def path(node):
|
|
67
|
+
"""Full path of a definition ('' for the global scope is shown as '::')."""
|
|
68
|
+
p = node.full_path.lstrip(':')
|
|
69
|
+
return p if '::' in p else '::' + p
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def show(label, written, definition):
|
|
73
|
+
print(' %-22s %-24s -> %s' % (label, written, path(definition)))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def main():
|
|
77
|
+
global_module = parser.IDLParser().load(IDL)
|
|
78
|
+
robot = global_module.module_by_name('robot')
|
|
79
|
+
arm = robot.module_by_name('arm')
|
|
80
|
+
|
|
81
|
+
print('robot::arm::Controller (name as written -> definition)')
|
|
82
|
+
controller = arm.interface_by_name('Controller')
|
|
83
|
+
for method in controller.methods:
|
|
84
|
+
if method.returns.name != 'void':
|
|
85
|
+
show(method.name + '() returns', method.returns.ref_name, method.returns.obj)
|
|
86
|
+
for a in method.arguments:
|
|
87
|
+
show(method.name + '(' + a.name + ')', a.type.ref_name, a.type.obj)
|
|
88
|
+
print()
|
|
89
|
+
|
|
90
|
+
# For a struct member, .type is the definition itself
|
|
91
|
+
print('robot::Pose members (member -> definition)')
|
|
92
|
+
pose = robot.struct_by_name('Pose')
|
|
93
|
+
for m in pose.members:
|
|
94
|
+
t = m.type
|
|
95
|
+
if t.is_sequence:
|
|
96
|
+
print(' %-22s -> sequence of %s' % (m.name, path(t.inner_type.obj)))
|
|
97
|
+
else:
|
|
98
|
+
print(' %-22s -> %s' % (m.name, path(t)))
|
|
99
|
+
print()
|
|
100
|
+
|
|
101
|
+
# The typedef is resolved where it is defined (module geometry),
|
|
102
|
+
# not where it is used (module robot::arm).
|
|
103
|
+
typedef = controller.method_by_name('origin').returns.obj
|
|
104
|
+
print('typedef %s -> %s' % (path(typedef), path(typedef.type)))
|
|
105
|
+
print()
|
|
106
|
+
|
|
107
|
+
# type.name is the name of the definition, without its scope
|
|
108
|
+
t = controller.method_by_name('move_to').arguments[0].type
|
|
109
|
+
print('name: %s, ref_name: %s, full path: %s' % (t.name, t.ref_name, path(t.obj)))
|
|
110
|
+
print()
|
|
111
|
+
|
|
112
|
+
# find_types(): with a scope the IDL scoping rules are used;
|
|
113
|
+
# without one, every definition with that name is returned.
|
|
114
|
+
print('find_types("Point", scope=robot::arm):', [path(n) for n in global_module.find_types('Point', scope=arm)])
|
|
115
|
+
print('find_types("Point", scope=robot): ', [path(n) for n in global_module.find_types('Point', scope=robot)])
|
|
116
|
+
print('find_types("::Point"): ', [path(n) for n in global_module.find_types('::Point')])
|
|
117
|
+
print('find_types("Point") (no scope): ', sorted(path(n) for n in global_module.find_types('Point')))
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if __name__ == '__main__':
|
|
121
|
+
main()
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Example: read structs and their members.
|
|
2
|
+
|
|
3
|
+
Shows how to get
|
|
4
|
+
- the structs in a module (``structs``, ``struct_by_name``),
|
|
5
|
+
- each member's name and type (primitive, struct, sequence, array),
|
|
6
|
+
- a member by name (``member_by_name``) and a nested struct's members.
|
|
7
|
+
|
|
8
|
+
Run::
|
|
9
|
+
|
|
10
|
+
python examples/struct_example.py
|
|
11
|
+
"""
|
|
12
|
+
import _path # noqa: F401 (use the idl_parser of this checkout)
|
|
13
|
+
|
|
14
|
+
from idl_parser import parser
|
|
15
|
+
|
|
16
|
+
IDL = '''
|
|
17
|
+
module my_module {
|
|
18
|
+
struct Time {
|
|
19
|
+
long sec;
|
|
20
|
+
long nsec;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
struct Pose {
|
|
24
|
+
double position[3];
|
|
25
|
+
double orientation[4];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
struct Odometry {
|
|
29
|
+
Time stamp;
|
|
30
|
+
string frame_id;
|
|
31
|
+
Pose pose;
|
|
32
|
+
sequence<double> covariance;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
'''
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def describe_type(t):
|
|
39
|
+
"""Return a short description of a member type."""
|
|
40
|
+
if t.is_primitive:
|
|
41
|
+
return t.name
|
|
42
|
+
if t.is_sequence:
|
|
43
|
+
return 'sequence of %s' % t.inner_type.name
|
|
44
|
+
if t.is_array:
|
|
45
|
+
return 'array %s' % t.name
|
|
46
|
+
if t.is_struct:
|
|
47
|
+
return 'struct %s' % t.full_path
|
|
48
|
+
return t.name
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def main():
|
|
52
|
+
global_module = parser.IDLParser().load(IDL)
|
|
53
|
+
my_module = global_module.module_by_name('my_module')
|
|
54
|
+
|
|
55
|
+
print('structs in my_module:', [s.name for s in my_module.structs])
|
|
56
|
+
print()
|
|
57
|
+
|
|
58
|
+
for struct in my_module.structs:
|
|
59
|
+
print('struct %s' % struct.full_path)
|
|
60
|
+
for m in struct.members:
|
|
61
|
+
print(' %-12s %s' % (m.name, describe_type(m.type)))
|
|
62
|
+
print()
|
|
63
|
+
|
|
64
|
+
odometry = my_module.struct_by_name('Odometry')
|
|
65
|
+
|
|
66
|
+
# A member whose type is a struct: follow it to read its members.
|
|
67
|
+
stamp = odometry.member_by_name('stamp')
|
|
68
|
+
print('Odometry.stamp members:', [(m.name, m.type.name) for m in stamp.type.members])
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
if __name__ == '__main__':
|
|
72
|
+
main()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""OMG IDL parser.
|
|
2
|
+
|
|
3
|
+
Parse IDL files (or IDL text) into a tree of definition objects::
|
|
4
|
+
|
|
5
|
+
from idl_parser import parser
|
|
6
|
+
global_module = parser.IDLParser().load(idl_text)
|
|
7
|
+
my_module = global_module.module_by_name('my_module')
|
|
8
|
+
|
|
9
|
+
Start from :class:`idl_parser.parser.IDLParser`; the result is an
|
|
10
|
+
:class:`idl_parser.module.IDLModule` holding the global scope.
|
|
11
|
+
"""
|
|
12
|
+
#from parser import IDLParser
|
|
13
|
+
__all__=['parser', 'exception']
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
@@ -46,12 +46,15 @@ class IDLBitValue(node.IDLNode):
|
|
|
46
46
|
|
|
47
47
|
@property
|
|
48
48
|
def full_path(self):
|
|
49
|
+
"""Scoped name (``'M::Flags::FLAG_A'``)."""
|
|
49
50
|
return self.parent.full_path + sep + self.name
|
|
50
51
|
|
|
51
52
|
def to_simple_dic(self):
|
|
53
|
+
"""A compact summary: ``{name: position}``."""
|
|
52
54
|
return {self.name: self.position}
|
|
53
55
|
|
|
54
56
|
def to_dic(self):
|
|
57
|
+
"""The value as a plain dict (for JSON or YAML output)."""
|
|
55
58
|
return self._with_annotations({'name': self.name,
|
|
56
59
|
'classname': self.classname,
|
|
57
60
|
'position': self.position,
|
|
@@ -59,7 +62,15 @@ class IDLBitValue(node.IDLNode):
|
|
|
59
62
|
|
|
60
63
|
|
|
61
64
|
class IDLBitmask(node.IDLNode):
|
|
62
|
-
|
|
65
|
+
"""A ``bitmask`` and its values.
|
|
66
|
+
|
|
67
|
+
:param name: Bitmask name.
|
|
68
|
+
:param parent: Enclosing :class:`~idl_parser.module.IDLModule`.
|
|
69
|
+
:param annotations: Annotations written before the bitmask; ``@bit_bound``
|
|
70
|
+
sets :attr:`bit_bound`.
|
|
71
|
+
:raises ~idl_parser.exception.InvalidIDLSyntaxError: ``@bit_bound`` is not
|
|
72
|
+
in 1..64.
|
|
73
|
+
"""
|
|
63
74
|
def __init__(self, name, parent, annotations=None):
|
|
64
75
|
super(IDLBitmask, self).__init__('IDLBitmask', name, parent)
|
|
65
76
|
self._verbose = False
|
|
@@ -80,6 +91,7 @@ class IDLBitmask(node.IDLNode):
|
|
|
80
91
|
|
|
81
92
|
@property
|
|
82
93
|
def full_path(self):
|
|
94
|
+
"""Scoped name (``'M::Flags'``; ``'::Flags'`` at the global scope)."""
|
|
83
95
|
return self.parent.full_path + sep + self.name
|
|
84
96
|
|
|
85
97
|
@property
|
|
@@ -93,12 +105,19 @@ class IDLBitmask(node.IDLNode):
|
|
|
93
105
|
return self._values
|
|
94
106
|
|
|
95
107
|
def value_by_name(self, name):
|
|
108
|
+
"""The value named ``name`` (an :class:`IDLBitValue`), or None."""
|
|
96
109
|
for v in self._values:
|
|
97
110
|
if v.name == name:
|
|
98
111
|
return v
|
|
99
112
|
return None
|
|
100
113
|
|
|
101
114
|
def to_simple_dic(self, quiet=False, full_path=False, recursive=False, member_only=False):
|
|
115
|
+
"""A compact summary: ``{'bitmask NAME': [{name: position}, ...]}``.
|
|
116
|
+
|
|
117
|
+
:param quiet: Return only ``'bitmask NAME'``.
|
|
118
|
+
:param full_path: Use :attr:`full_path` as the name.
|
|
119
|
+
:param member_only: Return only the list of value summaries.
|
|
120
|
+
"""
|
|
102
121
|
name = self.full_path if full_path else self.name
|
|
103
122
|
if quiet:
|
|
104
123
|
return 'bitmask %s' % name
|
|
@@ -107,6 +126,7 @@ class IDLBitmask(node.IDLNode):
|
|
|
107
126
|
return {'bitmask %s' % name: [v.to_simple_dic() for v in self.values]}
|
|
108
127
|
|
|
109
128
|
def to_dic(self):
|
|
129
|
+
"""The bitmask as a plain dict (for JSON or YAML output)."""
|
|
110
130
|
return self._with_annotations({'name': self.name,
|
|
111
131
|
'filepath': self.filepath,
|
|
112
132
|
'classname': self.classname,
|
|
@@ -114,6 +134,11 @@ class IDLBitmask(node.IDLNode):
|
|
|
114
134
|
'values': [v.to_dic() for v in self.values]})
|
|
115
135
|
|
|
116
136
|
def parse_tokens(self, token_buf, filepath=None):
|
|
137
|
+
"""Parse the bitmask from ``token_buf``, starting after its name, up to ``};``.
|
|
138
|
+
|
|
139
|
+
:raises ~idl_parser.exception.InvalidIDLSyntaxError: The declaration is
|
|
140
|
+
not valid IDL, or a position is out of :attr:`bit_bound` or used twice.
|
|
141
|
+
"""
|
|
117
142
|
self._filepath = filepath
|
|
118
143
|
ln, fn, token = token_buf.pop()
|
|
119
144
|
if token != '{':
|