Skip to content

Commit a6784ed

Browse files
committed
dev: Begin a script help the refactor
1 parent 587495c commit a6784ed

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
#! /usr/bin/env python3
2+
# Refactor headers according to
3+
# https://github.com/stack-of-tasks/pinocchio/pull/2572
4+
# Run test with python -m doctest -v refactor_headers.py
5+
6+
import re
7+
import argparse
8+
9+
# Walk in a directory
10+
# Find all xxx.hpp
11+
# Rename it into xxx-def.hxx
12+
# Update guards
13+
# Remove includes
14+
# Add clangd_hack
15+
# if xxx.hxx associated
16+
# Rename into xxx-decl.hxx
17+
# Update guards
18+
# Remove includes
19+
# Add clangd_hack
20+
# if xxx.txx associated
21+
# Rename into xxx-tpl.hxx
22+
# Update guards
23+
# Remove includes
24+
# Add clangd_hack
25+
# Create xxx.hpp
26+
# Add guards
27+
# Add includes form def, decl and tpl
28+
# include def, decl and tpl
29+
30+
GUARD_PATTERN = re.compile("^#ifndef __(.*)__$", re.MULTILINE)
31+
INCLUDE_PATTERN = re.compile(r"^#include ([\"<].*[\">])\n", re.MULTILINE)
32+
33+
TEST_CPP_CONTENT_GOOD_GUARD = """//
34+
// Copyright (c) 2015-2024 CNRS INRIA
35+
// Copyright (c) 2016 Wandercraft, 86 rue de Paris 91400 Orsay, France.
36+
//
37+
38+
#ifndef __pinocchio_python_spatial_se3_hpp__
39+
#define __pinocchio_python_spatial_se3_hpp__
40+
41+
#include <eigenpy/eigenpy.hpp>
42+
#include <boost/python/tuple.hpp>
43+
44+
#include "pinocchio/spatial/se3.hpp"
45+
#include "pinocchio/spatial/explog.hpp"
46+
// ...
47+
#endif // ifndef __pinocchio_python_spatial_se3_hpp__"""
48+
49+
TEST_CPP_CONTENT_BAD_GUARD = """//
50+
// Copyright (c) 2015-2024 CNRS INRIA
51+
// Copyright (c) 2016 Wandercraft, 86 rue de Paris 91400 Orsay, France.
52+
//
53+
54+
#ifndef _pinocchio_python_spatial_se3_hpp__
55+
#define _pinocchio_python_spatial_se3_hpp__
56+
// ...
57+
#endif // ifndef _pinocchio_python_spatial_se3i_hpp__"""
58+
59+
HPP_MODULE = """//
60+
// Copyright (c) 2025 INRIA
61+
//
62+
63+
#ifndef {guard}
64+
#define {guard}
65+
66+
// Module dependencies
67+
{dep_includes}
68+
69+
// Module headers
70+
{module_includes}
71+
72+
#endif // ifndef {guard}
73+
"""
74+
75+
LSP_GUARD = """#ifdef PINOCCHIO_LSP
76+
#include "{module_hpp}"
77+
#endif // PINOCCHIO_LSP
78+
"""
79+
80+
81+
def find_guard(content: str) -> None | str:
82+
"""Find guard in a C++ header file.
83+
:ivar content: File content to parse.
84+
:return: Guard name if found (without __), None if no guard is found.
85+
>>> find_guard(TEST_CPP_CONTENT_GOOD_GUARD)
86+
'pinocchio_python_spatial_se3_hpp'
87+
>>> find_guard(TEST_CPP_CONTENT_BAD_GUARD)
88+
"""
89+
match = GUARD_PATTERN.search(content)
90+
if match:
91+
return match.group(1)
92+
return None
93+
94+
95+
def update_guard(content: str, old_guard_name, new_guard_name: str) -> None | str:
96+
"""Replace guards in a C++ header file.
97+
:ivar content: File content to parse.
98+
:ivar old_guard_name: Guard to replace.
99+
:ivar new_guard_name: New guard name.
100+
:return: New content if the 3 guards are changed, None otherwise.
101+
>>> res = update_guard(TEST_CPP_CONTENT_GOOD_GUARD, "pinocchio_python_spatial_se3_hpp", "pinocchio_python_spatial_se3_def_hpp")
102+
>>> print(res)
103+
//
104+
// Copyright (c) 2015-2024 CNRS INRIA
105+
// Copyright (c) 2016 Wandercraft, 86 rue de Paris 91400 Orsay, France.
106+
//
107+
<BLANKLINE>
108+
#ifndef __pinocchio_python_spatial_se3_def_hpp__
109+
#define __pinocchio_python_spatial_se3_def_hpp__
110+
<BLANKLINE>
111+
#include <eigenpy/eigenpy.hpp>
112+
#include <boost/python/tuple.hpp>
113+
<BLANKLINE>
114+
#include "pinocchio/spatial/se3.hpp"
115+
#include "pinocchio/spatial/explog.hpp"
116+
// ...
117+
#endif // ifndef __pinocchio_python_spatial_se3_def_hpp__
118+
>>> update_guard(TEST_CPP_CONTENT_BAD_GUARD, "pinocchio_python_spatial_se3_hpp", "pinocchio_python_spatial_se3_def_hpp")
119+
"""
120+
(new_content, nr_sub) = re.subn(f"{old_guard_name}", new_guard_name, content)
121+
if nr_sub == 3:
122+
return new_content
123+
return None
124+
125+
126+
def remove_includes(content: str, module_header: str) -> (str, list[str]):
127+
"""Remove includes, add LSP guard instead and return them.
128+
:ivar content: File content to parse.
129+
:ivar module_header: Module header path (without < or ")
130+
:return: New content and list of removed includes (path with < or ")
131+
>>> res = remove_includes(TEST_CPP_CONTENT_GOOD_GUARD, "pinocchio/bindings/python/spatial/se3.hpp")
132+
>>> print(res[0])
133+
//
134+
// Copyright (c) 2015-2024 CNRS INRIA
135+
// Copyright (c) 2016 Wandercraft, 86 rue de Paris 91400 Orsay, France.
136+
//
137+
<BLANKLINE>
138+
#ifndef __pinocchio_python_spatial_se3_hpp__
139+
#define __pinocchio_python_spatial_se3_hpp__
140+
<BLANKLINE>
141+
<BLANKLINE>
142+
#ifdef PINOCCHIO_LSP
143+
#include "pinocchio/bindings/python/spatial/se3.hpp"
144+
#endif // PINOCCHIO_LSP
145+
// ...
146+
#endif // ifndef __pinocchio_python_spatial_se3_hpp__
147+
>>> print(res[1])
148+
['<eigenpy/eigenpy.hpp>', '<boost/python/tuple.hpp>', '"pinocchio/spatial/se3.hpp"', '"pinocchio/spatial/explog.hpp"']
149+
"""
150+
# TODO: warning if 0 includes, LSP_GUARD will not be added
151+
includes = INCLUDE_PATTERN.findall(content)
152+
new_content = INCLUDE_PATTERN.sub("", content, count=len(includes) - 1)
153+
new_content2 = INCLUDE_PATTERN.sub(
154+
LSP_GUARD.format(module_hpp=module_header), new_content
155+
)
156+
# (new_content2, _) = INCLUDE_PATTERN.subn("", new_content)
157+
return new_content2, includes
158+
159+
160+
def create_hpp_module(
161+
guard: str, dependencies_includes: list[str], module_includes: list[str]
162+
) -> str:
163+
"""Create a module content.
164+
:ivar guard: Guard name.
165+
:ivar dependencies_includes: Module dependencies include paths (path with < or ").
166+
:ivar module_includes: Module internal include paths (path with < or ").
167+
:return: Module content.
168+
>>> res = create_hpp_module("__pinocchio_python_spatial_se3_hpp__",\
169+
['<eigenpy/eigenpy.hpp>', '<boost/python/tuple.hpp>', '"pinocchio/spatial/se3.hpp"', '"pinocchio/spatial/explog.hpp"'],\
170+
['"pinocchio/bindings/python/spatial/se3_decl.hxx"', '"pinocchio/bindings/python/spatial/se3_def.hxx"'])
171+
>>> print(res)
172+
//
173+
// Copyright (c) 2025 INRIA
174+
//
175+
<BLANKLINE>
176+
#ifndef __pinocchio_python_spatial_se3_hpp__
177+
#define __pinocchio_python_spatial_se3_hpp__
178+
<BLANKLINE>
179+
// Module dependencies
180+
#include <eigenpy/eigenpy.hpp>
181+
#include <boost/python/tuple.hpp>
182+
#include "pinocchio/spatial/se3.hpp"
183+
#include "pinocchio/spatial/explog.hpp"
184+
<BLANKLINE>
185+
// Module headers
186+
#include "pinocchio/bindings/python/spatial/se3_decl.hxx"
187+
#include "pinocchio/bindings/python/spatial/se3_def.hxx"
188+
<BLANKLINE>
189+
#endif // ifndef __pinocchio_python_spatial_se3_hpp__
190+
<BLANKLINE>
191+
"""
192+
deps = "\n".join([f"#include {d}" for d in dependencies_includes])
193+
modules = "\n".join([f"#include {d}" for d in module_includes])
194+
return HPP_MODULE.format(guard=guard, dep_includes=deps, module_includes=modules)
195+
196+
197+
def argument_parser() -> argparse.ArgumentParser:
198+
parser = argparse.ArgumentParser(
199+
description="Refactor headers in a Pinocchio subdirectory"
200+
)
201+
202+
return parser
203+
204+
205+
def main(args: list[str]):
206+
pass
207+
208+
209+
if __name__ == "__main__":
210+
main()

0 commit comments

Comments
 (0)