idl-parser 0.1.0__tar.gz → 0.2.0__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.
Files changed (79) hide show
  1. idl_parser-0.2.0/.github/workflows/test.yml +70 -0
  2. idl_parser-0.2.0/.gitignore +6 -0
  3. idl_parser-0.2.0/.readthedocs.yaml +22 -0
  4. {idl_parser-0.1.0/idl_parser.egg-info → idl_parser-0.2.0}/PKG-INFO +26 -16
  5. {idl_parser-0.1.0 → idl_parser-0.2.0}/README.md +18 -13
  6. {idl_parser-0.1.0 → idl_parser-0.2.0}/README.rst +24 -15
  7. idl_parser-0.2.0/docs/api/index.rst +22 -0
  8. idl_parser-0.2.0/docs/conf.py +38 -0
  9. idl_parser-0.2.0/docs/index.rst +18 -0
  10. idl_parser-0.2.0/docs/requirements.txt +2 -0
  11. {idl_parser-0.1.0 → idl_parser-0.2.0}/example.py +22 -24
  12. idl_parser-0.2.0/idl_parser/bitmask.py +175 -0
  13. idl_parser-0.2.0/idl_parser/bitset.py +245 -0
  14. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser/const.py +1 -1
  15. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser/enum.py +16 -8
  16. idl_parser-0.2.0/idl_parser/interface.py +317 -0
  17. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser/module.py +132 -2
  18. idl_parser-0.2.0/idl_parser/node.py +297 -0
  19. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser/parser.py +89 -32
  20. idl_parser-0.2.0/idl_parser/pragma.py +178 -0
  21. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser/struct.py +54 -3
  22. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser/token_buffer.py +6 -2
  23. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser/type.py +47 -5
  24. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser/typedef.py +3 -1
  25. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser/union.py +16 -10
  26. {idl_parser-0.1.0 → idl_parser-0.2.0/idl_parser.egg-info}/PKG-INFO +26 -16
  27. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser.egg-info/SOURCES.txt +30 -1
  28. idl_parser-0.2.0/idl_parser.egg-info/scm_file_list.json +68 -0
  29. idl_parser-0.2.0/idl_parser.egg-info/scm_version.json +8 -0
  30. idl_parser-0.2.0/idls/forward_declaration.idl +69 -0
  31. idl_parser-0.2.0/idls/generalization_extended.idl +67 -0
  32. idl_parser-0.2.0/idls/issue12_subpath/relative_include.idl +7 -0
  33. idl_parser-0.2.0/idls/issue12_subpath/sensor_msgs/msg/Imu.idl +8 -0
  34. idl_parser-0.2.0/idls/issue12_subpath/std/msg/Header.idl +7 -0
  35. idl_parser-0.2.0/idls/issue18_idl42_int_types.idl +29 -0
  36. idl_parser-0.2.0/idls/issue28_pragma_keylist.idl +45 -0
  37. idl_parser-0.2.0/idls/issue9_const_pragma.idl +28 -0
  38. idl_parser-0.2.0/idls/issue9_tabs_bounded_string.idl +25 -0
  39. idl_parser-0.2.0/idls/issue9_whitespace_variants.idl +20 -0
  40. {idl_parser-0.1.0 → idl_parser-0.2.0}/pyproject.toml +1 -0
  41. idl_parser-0.2.0/tests/annotation_test.py +157 -0
  42. idl_parser-0.2.0/tests/bitmask_bitset_test.py +172 -0
  43. idl_parser-0.2.0/tests/example_test.py +48 -0
  44. idl_parser-0.2.0/tests/forward_declaration_test.py +124 -0
  45. idl_parser-0.2.0/tests/generalization_test.py +217 -0
  46. idl_parser-0.2.0/tests/issue12_test.py +40 -0
  47. idl_parser-0.2.0/tests/issue18_test.py +67 -0
  48. idl_parser-0.2.0/tests/issue39_test.py +57 -0
  49. idl_parser-0.2.0/tests/issue9_test.py +92 -0
  50. idl_parser-0.2.0/tests/key_annotation_test.py +85 -0
  51. idl_parser-0.2.0/tests/pragma_test.py +109 -0
  52. idl_parser-0.2.0/tests/syntax_error_test.py +42 -0
  53. idl_parser-0.1.0/.github/workflows/test.yml +0 -35
  54. idl_parser-0.1.0/.gitignore +0 -5
  55. idl_parser-0.1.0/idl_parser/interface.py +0 -226
  56. idl_parser-0.1.0/idl_parser/node.py +0 -123
  57. idl_parser-0.1.0/idl_parser.egg-info/scm_file_list.json +0 -39
  58. idl_parser-0.1.0/idl_parser.egg-info/scm_version.json +0 -8
  59. idl_parser-0.1.0/tests/generalization_test.py +0 -37
  60. {idl_parser-0.1.0 → idl_parser-0.2.0}/.github/workflows/release.yml +0 -0
  61. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser/__init__.py +0 -0
  62. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser/exception.py +0 -0
  63. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser.egg-info/dependency_links.txt +0 -0
  64. {idl_parser-0.1.0 → idl_parser-0.2.0}/idl_parser.egg-info/top_level.txt +0 -0
  65. {idl_parser-0.1.0 → idl_parser-0.2.0}/idls/basic_module_test.idl +0 -0
  66. {idl_parser-0.1.0 → idl_parser-0.2.0}/idls/circular/circular_a.idl +0 -0
  67. {idl_parser-0.1.0 → idl_parser-0.2.0}/idls/circular/circular_b.idl +0 -0
  68. {idl_parser-0.1.0 → idl_parser-0.2.0}/idls/circular/diamond.idl +0 -0
  69. {idl_parser-0.1.0 → idl_parser-0.2.0}/idls/generalization.idl +0 -0
  70. {idl_parser-0.1.0 → idl_parser-0.2.0}/idls/included_idl.idl +0 -0
  71. {idl_parser-0.1.0 → idl_parser-0.2.0}/idls/including_idl.idl +0 -0
  72. {idl_parser-0.1.0 → idl_parser-0.2.0}/idls/invalid_idl.idl +0 -0
  73. {idl_parser-0.1.0 → idl_parser-0.2.0}/idls/multi_module_test.idl +0 -0
  74. {idl_parser-0.1.0 → idl_parser-0.2.0}/setup.cfg +0 -0
  75. {idl_parser-0.1.0 → idl_parser-0.2.0}/tests/__init__.py +0 -0
  76. {idl_parser-0.1.0 → idl_parser-0.2.0}/tests/include_test.py +0 -0
  77. {idl_parser-0.1.0 → idl_parser-0.2.0}/tests/invalid_idl_test.py +0 -0
  78. {idl_parser-0.1.0 → idl_parser-0.2.0}/tests/module_test.py +0 -0
  79. {idl_parser-0.1.0 → idl_parser-0.2.0}/tests/multimodule_test.py +0 -0
@@ -0,0 +1,70 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+ workflow_call: # reused by release.yml before building
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: ${{ github.workflow }}-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ test:
19
+ name: Python ${{ matrix.python-version }}
20
+ runs-on: ubuntu-latest
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
25
+
26
+ steps:
27
+ - uses: actions/checkout@v5
28
+
29
+ - uses: actions/setup-python@v6
30
+ with:
31
+ python-version: ${{ matrix.python-version }}
32
+
33
+ # Tests open IDL files by relative path (idls/...), so run from the repository root.
34
+ - name: Run tests
35
+ run: python -m unittest discover --start-directory tests --pattern '*_test.py' --top-level-directory . --verbose
36
+
37
+ lint:
38
+ name: Check undefined names
39
+ runs-on: ubuntu-latest
40
+ steps:
41
+ - uses: actions/checkout@v5
42
+
43
+ - uses: actions/setup-python@v6
44
+ with:
45
+ python-version: "3.12"
46
+
47
+ # Catches names that are used but never defined or imported (F821 etc.).
48
+ # Such bugs hide in error paths that the tests do not reach.
49
+ - name: Run ruff
50
+ run: |
51
+ python -m pip install ruff
52
+ ruff check --select F821,F822,F823 --output-format github idl_parser
53
+
54
+ docs:
55
+ name: Build docs
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ - uses: actions/checkout@v5
59
+ with:
60
+ fetch-depth: 0 # setuptools-scm needs tags for the version shown in the docs
61
+
62
+ - uses: actions/setup-python@v6
63
+ with:
64
+ python-version: "3.12"
65
+
66
+ # Same settings as Read the Docs (.readthedocs.yaml): warnings are errors.
67
+ - name: Build HTML docs
68
+ run: |
69
+ python -m pip install -r docs/requirements.txt .
70
+ python -m sphinx -W --keep-going -b html docs docs/_build/html
@@ -0,0 +1,6 @@
1
+ *.pyc
2
+ *~
3
+ *.egg-info
4
+ build/*
5
+ dist/*docs/_build/
6
+ docs/api/generated/
@@ -0,0 +1,22 @@
1
+ # Read the Docs configuration
2
+ # https://docs.readthedocs.io/en/stable/config-file/v2.html
3
+ version: 2
4
+
5
+ build:
6
+ os: ubuntu-24.04
7
+ tools:
8
+ python: "3.12"
9
+ jobs:
10
+ # setuptools-scm derives the version from git tags, so fetch full history/tags
11
+ post_checkout:
12
+ - git fetch --unshallow --tags || true
13
+
14
+ sphinx:
15
+ configuration: docs/conf.py
16
+ fail_on_warning: true
17
+
18
+ python:
19
+ install:
20
+ - requirements: docs/requirements.txt
21
+ - method: pip
22
+ path: .
@@ -1,9 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: idl_parser
3
- Version: 0.1.0
3
+ Version: 0.2.0
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
  Project-URL: Homepage, http://www.sugarsweetrobotics.com/
7
+ Project-URL: Documentation, https://idl-parser.readthedocs.io/
7
8
  Project-URL: Source, https://github.com/sugarsweetrobotics/idl_parser
8
9
  Project-URL: Issues, https://github.com/sugarsweetrobotics/idl_parser/issues
9
10
  Classifier: Development Status :: 5 - Production/Stable
@@ -21,13 +22,18 @@ Description-Content-Type: text/x-rst
21
22
  idl_parser
22
23
  ============
23
24
 
24
- |Test Status|
25
+ |Test Status| |Docs Status|
25
26
 
26
27
  Description
27
28
  -----------
28
29
 
29
30
  OMG IDL file parser. This library just parse IDL files, and output intermidiate type objects.
30
31
 
32
+ Documentation
33
+ -------------
34
+
35
+ API reference and usage: https://idl-parser.readthedocs.io/
36
+
31
37
  Example
32
38
  -----------
33
39
 
@@ -68,26 +74,26 @@ Example
68
74
  global_module = parser_.load(idl_str)
69
75
  my_module = global_module.module_by_name('my_module')
70
76
  dataGetter = my_module.interface_by_name('DataGetter')
71
- print 'DataGetter interface'
72
- for m in dataGetter.methods:
73
- print '- method:'
74
- print ' name:', m.name
75
- print ' returns:', m.returns.name
76
- print ' arguments:'
77
+ print('DataGetter interface')
78
+ for m in dataGetter.methods:
79
+ print('- method:')
80
+ print(' name:', m.name)
81
+ print(' returns:', m.returns.name)
82
+ print(' arguments:')
77
83
  for a in m.arguments:
78
- print ' name:', a.name
79
- print ' type:', a.type
80
- print ' direction:', a.direction
84
+ print(' name:', a.name)
85
+ print(' type:', a.type)
86
+ print(' direction:', a.direction)
81
87
 
82
88
  doubleSeq = my_module.typedef_by_name('DoubleSeq')
83
- print 'typedef %s %s' % (doubleSeq.type.name, doubleSeq.name)
89
+ print('typedef %s %s' % (doubleSeq.type.name, doubleSeq.name))
84
90
 
85
91
  timedDoubleSeq = my_module.struct_by_name('TimedDoubleSeq')
86
- print 'TimedDoubleSeq'
92
+ print('TimedDoubleSeq')
87
93
  for m in timedDoubleSeq.members:
88
- print '- member:'
89
- print ' name:', m.name
90
- print ' type:', m.type.name
94
+ print('- member:')
95
+ print(' name:', m.name)
96
+ print(' type:', m.type.name)
91
97
 
92
98
  How to install
93
99
  ---------------
@@ -108,3 +114,7 @@ Copyright
108
114
 
109
115
  .. |Test Status| image:: https://github.com/sugarsweetrobotics/idl_parser/actions/workflows/test.yml/badge.svg?branch=main
110
116
  :target: https://github.com/sugarsweetrobotics/idl_parser/actions/workflows/test.yml
117
+
118
+ .. |Docs Status| image:: https://readthedocs.org/projects/idl-parser/badge/?version=latest
119
+ :target: https://idl-parser.readthedocs.io/en/latest/
120
+ :alt: Documentation Status
@@ -1,12 +1,17 @@
1
1
  # idl_parser
2
2
 
3
3
  [![Test](https://github.com/sugarsweetrobotics/idl_parser/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/sugarsweetrobotics/idl_parser/actions/workflows/test.yml)
4
+ [![Documentation Status](https://readthedocs.org/projects/idl-parser/badge/?version=latest)](https://idl-parser.readthedocs.io/en/latest/)
4
5
 
5
6
 
6
7
  ## Description
7
8
 
8
9
  OMG IDL file parser. This library just parse IDL files, and output intermidiate type objects.
9
10
 
11
+ ## Documentation
12
+
13
+ API reference and usage: https://idl-parser.readthedocs.io/
14
+
10
15
  ## Example
11
16
  ```
12
17
  """
@@ -44,26 +49,26 @@ module my_module {
44
49
  global_module = parser_.load(idl_str)
45
50
  my_module = global_module.module_by_name('my_module')
46
51
  dataGetter = my_module.interface_by_name('DataGetter')
47
- print 'DataGetter interface'
52
+ print('DataGetter interface')
48
53
  for m in dataGetter.methods:
49
- print '- method:'
50
- print ' name:', m.name
51
- print ' returns:', m.returns.name
52
- print ' arguments:'
54
+ print('- method:')
55
+ print(' name:', m.name)
56
+ print(' returns:', m.returns.name)
57
+ print(' arguments:')
53
58
  for a in m.arguments:
54
- print ' name:', a.name
55
- print ' type:', a.type
56
- print ' direction:', a.direction
59
+ print(' name:', a.name)
60
+ print(' type:', a.type)
61
+ print(' direction:', a.direction)
57
62
 
58
63
  doubleSeq = my_module.typedef_by_name('DoubleSeq')
59
- print 'typedef %s %s' % (doubleSeq.type.name, doubleSeq.name)
64
+ print('typedef %s %s' % (doubleSeq.type.name, doubleSeq.name))
60
65
 
61
66
  timedDoubleSeq = my_module.struct_by_name('TimedDoubleSeq')
62
- print 'TimedDoubleSeq'
67
+ print('TimedDoubleSeq')
63
68
  for m in timedDoubleSeq.members:
64
- print '- member:'
65
- print ' name:', m.name
66
- print ' type:', m.type.name
69
+ print('- member:')
70
+ print(' name:', m.name)
71
+ print(' type:', m.type.name)
67
72
  ```
68
73
  ## How to install
69
74
  sudo pip install idl_parser
@@ -1,13 +1,18 @@
1
1
  idl_parser
2
2
  ============
3
3
 
4
- |Test Status|
4
+ |Test Status| |Docs Status|
5
5
 
6
6
  Description
7
7
  -----------
8
8
 
9
9
  OMG IDL file parser. This library just parse IDL files, and output intermidiate type objects.
10
10
 
11
+ Documentation
12
+ -------------
13
+
14
+ API reference and usage: https://idl-parser.readthedocs.io/
15
+
11
16
  Example
12
17
  -----------
13
18
 
@@ -48,26 +53,26 @@ Example
48
53
  global_module = parser_.load(idl_str)
49
54
  my_module = global_module.module_by_name('my_module')
50
55
  dataGetter = my_module.interface_by_name('DataGetter')
51
- print 'DataGetter interface'
52
- for m in dataGetter.methods:
53
- print '- method:'
54
- print ' name:', m.name
55
- print ' returns:', m.returns.name
56
- print ' arguments:'
56
+ print('DataGetter interface')
57
+ for m in dataGetter.methods:
58
+ print('- method:')
59
+ print(' name:', m.name)
60
+ print(' returns:', m.returns.name)
61
+ print(' arguments:')
57
62
  for a in m.arguments:
58
- print ' name:', a.name
59
- print ' type:', a.type
60
- print ' direction:', a.direction
63
+ print(' name:', a.name)
64
+ print(' type:', a.type)
65
+ print(' direction:', a.direction)
61
66
 
62
67
  doubleSeq = my_module.typedef_by_name('DoubleSeq')
63
- print 'typedef %s %s' % (doubleSeq.type.name, doubleSeq.name)
68
+ print('typedef %s %s' % (doubleSeq.type.name, doubleSeq.name))
64
69
 
65
70
  timedDoubleSeq = my_module.struct_by_name('TimedDoubleSeq')
66
- print 'TimedDoubleSeq'
71
+ print('TimedDoubleSeq')
67
72
  for m in timedDoubleSeq.members:
68
- print '- member:'
69
- print ' name:', m.name
70
- print ' type:', m.type.name
73
+ print('- member:')
74
+ print(' name:', m.name)
75
+ print(' type:', m.type.name)
71
76
 
72
77
  How to install
73
78
  ---------------
@@ -88,3 +93,7 @@ Copyright
88
93
 
89
94
  .. |Test Status| image:: https://github.com/sugarsweetrobotics/idl_parser/actions/workflows/test.yml/badge.svg?branch=main
90
95
  :target: https://github.com/sugarsweetrobotics/idl_parser/actions/workflows/test.yml
96
+
97
+ .. |Docs Status| image:: https://readthedocs.org/projects/idl-parser/badge/?version=latest
98
+ :target: https://idl-parser.readthedocs.io/en/latest/
99
+ :alt: Documentation Status
@@ -0,0 +1,22 @@
1
+ API Reference
2
+ =============
3
+
4
+ .. autosummary::
5
+ :toctree: generated
6
+ :nosignatures:
7
+
8
+ idl_parser.parser
9
+ idl_parser.module
10
+ idl_parser.interface
11
+ idl_parser.struct
12
+ idl_parser.enum
13
+ idl_parser.bitmask
14
+ idl_parser.bitset
15
+ idl_parser.union
16
+ idl_parser.typedef
17
+ idl_parser.const
18
+ idl_parser.pragma
19
+ idl_parser.type
20
+ idl_parser.node
21
+ idl_parser.token_buffer
22
+ idl_parser.exception
@@ -0,0 +1,38 @@
1
+ """Sphinx configuration for idl_parser."""
2
+
3
+ import os
4
+ import sys
5
+ from importlib.metadata import PackageNotFoundError, version as _pkg_version
6
+
7
+ # Allow building from a source checkout without installing the package.
8
+ sys.path.insert(0, os.path.abspath(".."))
9
+
10
+ project = "idl_parser"
11
+ author = "Yuki Suga"
12
+ copyright = "Yuki Suga"
13
+
14
+ try:
15
+ release = _pkg_version("idl_parser")
16
+ except PackageNotFoundError:
17
+ release = "unknown"
18
+ version = ".".join(release.split(".")[:3])
19
+
20
+ extensions = [
21
+ "sphinx.ext.autodoc",
22
+ "sphinx.ext.autosummary",
23
+ "sphinx.ext.napoleon",
24
+ "sphinx.ext.viewcode",
25
+ ]
26
+
27
+ autodoc_default_options = {
28
+ "members": True,
29
+ "undoc-members": True,
30
+ "show-inheritance": True,
31
+ "member-order": "bysource",
32
+ }
33
+ autosummary_generate = True
34
+
35
+ exclude_patterns = ["_build"]
36
+
37
+ html_theme = "furo"
38
+ html_title = f"idl_parser {version}"
@@ -0,0 +1,18 @@
1
+ .. include:: ../README.rst
2
+
3
+ API Reference
4
+ -------------
5
+
6
+ See the :doc:`API Reference <api/index>` for the classes and functions of each module.
7
+
8
+ .. toctree::
9
+ :maxdepth: 2
10
+ :caption: Contents
11
+
12
+ api/index
13
+
14
+ Indices
15
+ -------
16
+
17
+ * :ref:`genindex`
18
+ * :ref:`modindex`
@@ -0,0 +1,2 @@
1
+ sphinx>=7
2
+ furo
@@ -1,8 +1,6 @@
1
- """
1
+ """Example: parse an IDL string and print interfaces, typedefs, unions and structs."""
2
2
 
3
- """
4
-
5
- def test():
3
+ def test():
6
4
  from idl_parser import parser
7
5
  _parser = parser.IDLParser()
8
6
  idl_str = '''
@@ -57,36 +55,36 @@ module my_module {
57
55
  global_module = _parser.load(idl_str)
58
56
  my_module = global_module.module_by_name('my_module')
59
57
  dataGetter = my_module.interface_by_name('DataGetter')
60
- print 'DataGetter interface'
58
+ print('DataGetter interface')
61
59
  for m in dataGetter.methods:
62
- print '- method:'
63
- print ' name:', m.name
64
- print ' returns:', m.returns.name
65
- print ' arguments:'
66
- for a in m.arguments:
67
- print ' name:', a.name
68
- print ' type:', a.type
69
- print ' direction:', a.direction
60
+ print('- method:')
61
+ print(' name:', m.name)
62
+ print(' returns:', m.returns.name)
63
+ print(' arguments:')
64
+ for a in m.arguments:
65
+ print(' name:', a.name)
66
+ print(' type:', a.type)
67
+ print(' direction:', a.direction)
70
68
 
71
69
  doubleSeq = my_module.typedef_by_name('DoubleSeq')
72
- print 'typedef %s %s' % (doubleSeq.type.name, doubleSeq.name)
70
+ print('typedef %s %s' % (doubleSeq.type.name, doubleSeq.name))
73
71
 
74
72
  unionType = my_module.union_by_name('UnionType')
75
- print 'descriminator kind: %s' % unionType.descriminator_kind
73
+ print('descriminator kind: %s' % unionType.descriminator_kind)
76
74
  for m in unionType.members:
77
- print '- member:'
78
- print ' name:', m.name
79
- print ' type:', m.type.name
80
- print 'descriminator value associations:'
75
+ print('- member:')
76
+ print(' name:', m.name)
77
+ print(' type:', m.type.name)
78
+ print(' descriminator value associations:')
81
79
  for a in m.descriminator_value_associations:
82
- print ' %s' % a
80
+ print(' %s' % a)
83
81
 
84
82
  timedDoubleSeq = my_module.struct_by_name('TimedDoubleSeq')
85
- print 'TimedDoubleSeq'
83
+ print('TimedDoubleSeq')
86
84
  for m in timedDoubleSeq.members:
87
- print '- member:'
88
- print ' name:', m.name
89
- print ' type:', m.type.name
85
+ print('- member:')
86
+ print(' name:', m.name)
87
+ print(' type:', m.type.name)
90
88
 
91
89
 
92
90
  if __name__ == '__main__':
@@ -0,0 +1,175 @@
1
+ """IDL 4.2 bitmask type (issue #39).
2
+
3
+ ::
4
+
5
+ @bit_bound(8) bitmask Flags { FLAG_A, @position(4) FLAG_B, FLAG_C };
6
+
7
+ Each value is a single bit. Positions start at 0 and follow the previous
8
+ value unless given with ``@position(n)``. ``@bit_bound`` (default 32) is the
9
+ number of bits the bitmask can hold.
10
+ """
11
+
12
+ from . import node, exception
13
+ sep = '::'
14
+
15
+ DEFAULT_BIT_BOUND = 32
16
+ MAX_BIT_BOUND = 64
17
+
18
+
19
+ def parse_int(literal):
20
+ """Integer value of an IDL integer literal (decimal, hex 0x.., octal 0..)."""
21
+ try:
22
+ return int(literal, 0)
23
+ except (TypeError, ValueError):
24
+ try:
25
+ return int(literal, 8) # e.g. '010' (IDL octal)
26
+ except (TypeError, ValueError):
27
+ return None
28
+
29
+
30
+ class IDLBitValue(node.IDLNode):
31
+ """A value (flag) of a bitmask."""
32
+
33
+ def __init__(self, name, position, parent):
34
+ super(IDLBitValue, self).__init__('IDLBitValue', name, parent)
35
+ self._position = position
36
+
37
+ @property
38
+ def position(self):
39
+ """Bit position of this flag (0 is the least significant bit)."""
40
+ return self._position
41
+
42
+ @property
43
+ def value(self):
44
+ """Integer value of this flag (``1 << position``)."""
45
+ return 1 << self._position
46
+
47
+ @property
48
+ def full_path(self):
49
+ return self.parent.full_path + sep + self.name
50
+
51
+ def to_simple_dic(self):
52
+ return {self.name: self.position}
53
+
54
+ def to_dic(self):
55
+ return self._with_annotations({'name': self.name,
56
+ 'classname': self.classname,
57
+ 'position': self.position,
58
+ 'value': self.value})
59
+
60
+
61
+ class IDLBitmask(node.IDLNode):
62
+
63
+ def __init__(self, name, parent, annotations=None):
64
+ super(IDLBitmask, self).__init__('IDLBitmask', name, parent)
65
+ self._verbose = False
66
+ self._values = []
67
+ self._bit_bound = DEFAULT_BIT_BOUND
68
+ self._add_annotations(annotations or [])
69
+ a = self.annotation_by_name('bit_bound')
70
+ if a is not None:
71
+ self._bit_bound = self._parse_bound(a.value)
72
+
73
+ def _parse_bound(self, literal):
74
+ bound = parse_int(literal)
75
+ if bound is None or not 1 <= bound <= MAX_BIT_BOUND:
76
+ raise exception.InvalidIDLSyntaxError(
77
+ message='Invalid @bit_bound(%s) of bitmask "%s" (must be 1..%d)'
78
+ % (literal, self.name, MAX_BIT_BOUND))
79
+ return bound
80
+
81
+ @property
82
+ def full_path(self):
83
+ return self.parent.full_path + sep + self.name
84
+
85
+ @property
86
+ def bit_bound(self):
87
+ """Number of bits the bitmask can hold (``@bit_bound``, default 32)."""
88
+ return self._bit_bound
89
+
90
+ @property
91
+ def values(self):
92
+ """Flags in declaration order (list of :class:`IDLBitValue`)."""
93
+ return self._values
94
+
95
+ def value_by_name(self, name):
96
+ for v in self._values:
97
+ if v.name == name:
98
+ return v
99
+ return None
100
+
101
+ def to_simple_dic(self, quiet=False, full_path=False, recursive=False, member_only=False):
102
+ name = self.full_path if full_path else self.name
103
+ if quiet:
104
+ return 'bitmask %s' % name
105
+ if member_only:
106
+ return [v.to_simple_dic() for v in self.values]
107
+ return {'bitmask %s' % name: [v.to_simple_dic() for v in self.values]}
108
+
109
+ def to_dic(self):
110
+ return self._with_annotations({'name': self.name,
111
+ 'filepath': self.filepath,
112
+ 'classname': self.classname,
113
+ 'bit_bound': self.bit_bound,
114
+ 'values': [v.to_dic() for v in self.values]})
115
+
116
+ def parse_tokens(self, token_buf, filepath=None):
117
+ self._filepath = filepath
118
+ ln, fn, token = token_buf.pop()
119
+ if token != '{':
120
+ raise exception.InvalidIDLSyntaxError(ln, fn, 'No "{" in the declaration of bitmask "%s"' % self.name)
121
+
122
+ block = []
123
+ depth = 0 # inside the parentheses of an annotation, e.g. @foo(a, b)
124
+ while True:
125
+ ln, fn, token = token_buf.pop()
126
+ if token is None:
127
+ raise exception.InvalidIDLSyntaxError(ln, fn, 'No "}" in the declaration of bitmask "%s"' % self.name)
128
+ elif token == '}' and depth == 0:
129
+ if block:
130
+ self._parse_block(block, ln, fn)
131
+ ln, fn, token = token_buf.pop()
132
+ if token != ';':
133
+ raise exception.InvalidIDLSyntaxError(ln, fn, 'No ";" after "}" in the declaration of bitmask "%s"' % self.name)
134
+ break
135
+ elif token == ',' and depth == 0:
136
+ self._parse_block(block, ln, fn)
137
+ block = []
138
+ else:
139
+ if token == '(':
140
+ depth += 1
141
+ elif token == ')':
142
+ depth -= 1
143
+ block.append(token)
144
+
145
+ def _parse_block(self, block, ln, fn):
146
+ # block: [annotation tokens...] NAME
147
+ annotations, rest = node.parse_annotations(block)
148
+ if len(rest) != 1:
149
+ raise exception.InvalidIDLSyntaxError(ln, fn, 'Invalid value "%s" in bitmask "%s"' % (' '.join(block), self.name))
150
+
151
+ if self._values:
152
+ position = self._values[-1].position + 1
153
+ else:
154
+ position = 0
155
+ for a in annotations:
156
+ if a.name == 'position':
157
+ position = parse_int(a.value)
158
+ if position is None:
159
+ raise exception.InvalidIDLSyntaxError(ln, fn, 'Invalid %s in bitmask "%s"' % (a, self.name))
160
+
161
+ if not 0 <= position < self.bit_bound:
162
+ raise exception.InvalidIDLSyntaxError(
163
+ ln, fn, 'Position %s of "%s" is out of @bit_bound(%d) of bitmask "%s"'
164
+ % (position, rest[0], self.bit_bound, self.name))
165
+ for v in self._values:
166
+ if v.position == position:
167
+ raise exception.InvalidIDLSyntaxError(
168
+ ln, fn, 'Position %d of "%s" is already used by "%s" in bitmask "%s"'
169
+ % (position, rest[0], v.name, self.name))
170
+
171
+ v = IDLBitValue(rest[0], position, self)
172
+ v._filepath = self.filepath
173
+ v._add_annotations(annotations)
174
+ self._values.append(v)
175
+