Files
Mujoco_WASM/python/mujoco/introspect/codegen/generate.py
T
Haroon Qureshi 7a00c1f3e0 Factor out AstProcessor into its own library.
PiperOrigin-RevId: 936518263
Change-Id: I597ef4382e7ddc953f8daedd4f5123d71f0e8a42
2026-06-23 02:08:57 -07:00

152 lines
4.5 KiB
Python

# Copyright 2026 DeepMind Technologies Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Generates enums.py, functions.py, and structs.py.
The JSON input can be generated via:
clang -Xclang -ast-dump=json -fsyntax-only -fparse-all-comments -x c mujoco.h
"""
import re
from typing import Sequence
from absl import app
from absl import flags
from . import ast_processor
from . import formatter
_JSON_PATH = flags.DEFINE_string(
'json_path', None,
'Path to the JSON file representing the Clang AST for mujoco.h')
_HEADER_PATHS = flags.DEFINE_string(
'header_paths', None, 'Path to all header files')
_OUT_STRUCTS = flags.DEFINE_string(
'out_structs', None, 'Path to the output structs file')
_OUT_FUNCTIONS = flags.DEFINE_string(
'out_functions', None, 'Path to the output functions file')
_OUT_ENUMS = flags.DEFINE_string(
'out_enums', None, 'Path to the output enums file')
_ANONYMOUS_KEY_PATTERN = re.compile(r'\d+:\d+(?=\))')
_EXCLUDED = [
'mjpDecoder',
'mjpDecoder_',
'mjpEncoder',
'mjpEncoder_',
'mjpPlugin',
'mjpPlugin_',
'mjpResourceProvider',
'mjpResourceProvider_',
'mjResource',
'mjResource_',
# Skip mjs_setUserValueWithCleanup as it's only useful for heap allocated
# objects and doesn't need a python wrapper.
'mjs_setUserValueWithCleanup',
]
_ARRAY_COMMENT_PATTERN = re.compile(r'(.+?)\s+\(([^\(\)]+) x ([^\(\)]+)\)\Z')
_HEADER_TEMPLATE = '''
# Copyright {year} DeepMind Technologies Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Provides information about MuJoCo API {type}.
DO NOT EDIT. THIS FILE IS AUTOMATICALLY GENERATED.
"""
'''.strip()
_ENUMS_TEMPLATE = '''
from typing import Mapping
from .ast_nodes import EnumDecl
ENUMS: Mapping[str, EnumDecl] = {enums_str}
'''
_FUNCTIONS_TEMPLATE = '''
from typing import Mapping
from .ast_nodes import ArrayType
from .ast_nodes import FunctionDecl
from .ast_nodes import FunctionParameterDecl
from .ast_nodes import PointerType
from .ast_nodes import ValueType
FUNCTIONS: Mapping[str, FunctionDecl] = {functions_str}
'''
_STRUCTS_TEMPLATE = '''
from typing import Mapping
from .ast_nodes import AnonymousStructDecl
from .ast_nodes import AnonymousUnionDecl
from .ast_nodes import ArrayType
from .ast_nodes import PointerType
from .ast_nodes import StructDecl
from .ast_nodes import StructFieldDecl
from .ast_nodes import ValueType
STRUCTS: Mapping[str, StructDecl] = {structs_str}
'''
def main(argv: Sequence[str]) -> None:
if len(argv) > 1:
raise app.UsageError('Too many command-line arguments.')
visitor = ast_processor.process(
_JSON_PATH.value,
(_HEADER_PATHS.value or '').split(),
_EXCLUDED,
)
with open(_OUT_FUNCTIONS.value, 'w') as f:
functions_str = formatter.format_as_python_code(visitor.exported_functions)
f.write(_HEADER_TEMPLATE.format(year=2022, type='functions'))
f.write(_FUNCTIONS_TEMPLATE.format(functions_str=functions_str))
with open(_OUT_ENUMS.value, 'w') as f:
enums_str = formatter.format_as_python_code(visitor.exported_enums)
f.write(_HEADER_TEMPLATE.format(year=2022, type='enums'))
f.write(_ENUMS_TEMPLATE.format(enums_str=enums_str))
with open(_OUT_STRUCTS.value, 'w') as f:
structs_str = formatter.format_as_python_code(visitor.exported_structs)
f.write(_HEADER_TEMPLATE.format(year=2023, type='structs'))
f.write(_STRUCTS_TEMPLATE.format(structs_str=structs_str))
if __name__ == '__main__':
app.run(main)