]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/metaparse/tools/generate_all.py
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / metaparse / tools / generate_all.py
1 #!/usr/bin/python
2
3 # Copyright Abel Sinkovics (abel@sinkovics.hu) 2015.
4 # Distributed under the Boost Software License, Version 1.0.
5 # (See accompanying file LICENSE_1_0.txt or copy at
6 # http://www.boost.org/LICENSE_1_0.txt)
7
8 import sys
9 import argparse
10 import re
11 import os
12
13 def remove_last_dot(s):
14 if s.endswith('.'):
15 return s[:-1]
16 else:
17 return s
18
19 def remove_newline(s):
20 return re.sub('[\r\n]', '', s)
21
22 def is_definition(s):
23 cmd = s.strip()
24
25 def_prefixes = ['#include ', 'using ', 'struct ', 'template ']
26 return any([cmd.startswith(s) for s in def_prefixes]) or cmd.endswith(';')
27
28 def prefix_lines(prefix, s):
29 return '\n'.join(['%s%s' % (prefix, l) for l in s.split('\n')])
30
31 def protect_metashell(s):
32 if s.startswith('#include <metashell'):
33 return '#ifdef __METASHELL\n%s\n#endif' % (s)
34 else:
35 return s
36
37 def parse_md(qbk):
38 sections = []
39 defs = []
40 current_section = ''
41 in_cpp_snippet = False
42 numbered_section_header = re.compile('^\[section *([0-9.]+)')
43 metashell_command = re.compile('^> [^ ]')
44 metashell_prompt = re.compile('^(\.\.\.|)>')
45 msh_cmd = ''
46 for l in qbk:
47 if l.startswith(' '):
48 ll = l[2:]
49 if not in_cpp_snippet:
50 in_msh_cpp_snippet = True
51 if in_msh_cpp_snippet:
52 if metashell_command.match(ll) or msh_cmd != '':
53 cmd = metashell_prompt.sub('', remove_newline(ll))
54 if msh_cmd != '':
55 msh_cmd = msh_cmd + '\n'
56 msh_cmd = msh_cmd + cmd
57 if msh_cmd.endswith('\\'):
58 msh_cmd = msh_cmd[:-1].strip() + ' '
59 else:
60 if not is_definition(msh_cmd):
61 msh_cmd = '// query:\n%s' % (prefix_lines('// ', msh_cmd))
62 defs.append((current_section, protect_metashell(msh_cmd.strip())))
63 msh_cmd = ''
64 elif not in_cpp_snippet:
65 in_msh_cpp_snippet = False
66 in_cpp_snippet = True
67 else:
68 in_cpp_snippet = False
69 m = numbered_section_header.match(l)
70 if m:
71 current_section = remove_last_dot(m.group(1)).replace('.', '_')
72 sections.append(current_section)
73
74 sections.sort(key = lambda s: [int(n) for n in s.split('_')])
75 return (sections, defs)
76
77 def delete_old_headers(path):
78 for f in os.listdir(path):
79 if f.endswith('.hpp'):
80 os.remove(os.path.join(path, f))
81
82 def gen_headers(sections, defs, path):
83 files = {}
84
85 prev_section = ''
86 for s in sections:
87 prev_name = prev_section.replace('_', '.')
88 include_guard = 'BOOST_METAPARSE_GETTING_STARTED_%s_HPP' % (s)
89 if prev_section == '':
90 prev_include = ''
91 else:
92 prev_include = \
93 '// Definitions before section {0}\n'.format(prev_name) + \
94 '#include "{0}.hpp"\n'.format(prev_section) + \
95 '\n'
96
97 files[os.path.join(path, s + '.hpp')] = \
98 '#ifndef {0}\n'.format(include_guard) + \
99 '#define {0}\n'.format(include_guard) + \
100 '\n' + \
101 '// Automatically generated header file\n' + \
102 '\n' + \
103 prev_include + \
104 '// Definitions of section {0}\n'.format(prev_name) + \
105 '\n'.join( \
106 ['%s\n' % (d) for (sec, d) in defs if sec == prev_section] \
107 ) + \
108 '\n' + \
109 '#endif\n' + \
110 '\n'
111 prev_section = s
112 return files
113
114 def remove_metashell_protection(s):
115 prefix = '#ifdef __METASHELL\n'
116 suffix = '#endif'
117 return \
118 s[len(prefix):-len(suffix)] \
119 if s.startswith(prefix) and s.endswith(suffix) \
120 else s
121
122 def make_code_snippet(s):
123 return '\n'.join([' {0}'.format(l) for l in s.split('\n')])
124
125 def what_we_have_so_far_docs(doc_dir, qbk, defs, sections):
126 files = {}
127 so_far = ''
128 sections_with_definition = []
129 for s in sections:
130 if so_far != '':
131 files[os.path.join(doc_dir, 'before_{0}.qbk'.format(s))] = \
132 '[#before_{0}]\n[\'Definitions before section {1}]\n\n{2}\n'.format(
133 s,
134 s.replace('_', '.') + '.',
135 so_far
136 )
137 sections_with_definition.append(s)
138
139 so_far = so_far + '\n'.join([
140 '{0}\n'.format(make_code_snippet(remove_metashell_protection(d)))
141 for (sec, d) in defs
142 if sec == s and not d.startswith('//')
143 ])
144
145 is_section = re.compile('^\[section (([0-9]\.)+)')
146 note_prefix = \
147 '[note Note that you can find everything that has been included and' \
148 ' defined so far [link before_'
149
150 in_definitions_before_each_section = False
151
152 result = []
153 for l in qbk:
154 if in_definitions_before_each_section:
155 if l.strip() == '[endsect]':
156 in_definitions_before_each_section = False
157 result.append(l)
158 elif l.strip() == '[section Definitions before each section]':
159 in_definitions_before_each_section = True
160 result.append(l)
161 result.append('\n')
162 for s in sections_with_definition:
163 result.append('[include before_{0}.qbk]\n'.format(s))
164 result.append('\n')
165 elif not l.startswith(note_prefix):
166 result.append(l)
167 m = is_section.match(l)
168 if m:
169 section_number = m.group(1).replace('.', '_')[:-1]
170 if section_number in sections_with_definition:
171 result.append('{0}{1} here].]\n'.format(note_prefix, section_number))
172
173 return (files, result)
174
175 def strip_not_finished_line(s):
176 s = s.strip()
177 return s[:-1] if s.endswith('\\') else s
178
179 def make_copy_paste_friendly(lines):
180 result = []
181 for l in lines:
182 if l.startswith('> '):
183 result.append(l[2:])
184 elif l.startswith('...> '):
185 result[-1] = strip_not_finished_line(result[-1]) + l[5:].lstrip()
186 return result
187
188 def extract_code_snippets(qbk, fn_base):
189 code_prefix = ' '
190
191 files = {}
192
193 result = []
194 in_cpp_code = False
195 counter = 0
196 in_copy_paste_friendly_examples = False
197 skip_empty_lines = False
198 for l in qbk:
199 if l.strip() != '' or not skip_empty_lines:
200 skip_empty_lines = False
201 if in_copy_paste_friendly_examples:
202 if 'endsect' in l:
203 in_copy_paste_friendly_examples = False
204 result.append('\n')
205 result.extend([
206 '[include {0}_{1}.qbk]\n'.format(re.sub('^.*/', '', fn_base), i) \
207 for i in range(0, counter)
208 ])
209 result.append('\n')
210 result.append(l)
211 in_copy_paste_friendly_examples = False
212 elif '[section Copy-paste friendly code examples]' in l:
213 in_copy_paste_friendly_examples = True
214 result.append(l)
215 elif 'copy-paste friendly version' in l:
216 skip_empty_lines = True
217 else:
218 result.append(l)
219
220 if in_cpp_code:
221 if not l.startswith(code_prefix):
222 in_cpp_code = False
223 if len(code) > 1:
224 f = '{0}_{1}'.format(fn_base, counter)
225 basename_f = re.sub('^.*/', '', f)
226 files['{0}.qbk'.format(f)] = \
227 '[#{0}]\n\n{1}\n'.format(
228 basename_f,
229 ''.join(
230 [code_prefix + s for s in make_copy_paste_friendly(code)]
231 )
232 )
233 result.append(
234 '[link {0} copy-paste friendly version]\n'.format(basename_f)
235 )
236 result.append('\n')
237 counter = counter + 1
238 elif \
239 l.startswith(code_prefix + '> ') \
240 or l.startswith(code_prefix + '...> '):
241 code.append(l[len(code_prefix):])
242 elif l.startswith(code_prefix):
243 in_cpp_code = True
244 code = [l[len(code_prefix):]]
245
246 return (files, result)
247
248 def write_file(fn, content):
249 with open(fn, 'w') as f:
250 f.write(content)
251
252 def write_files(files):
253 for fn in files:
254 write_file(fn, files[fn])
255
256 def main():
257 desc = 'Generate headers with the definitions of a Getting Started guide'
258 parser = argparse.ArgumentParser(description=desc)
259 parser.add_argument(
260 '--src',
261 dest='src',
262 default='doc/getting_started.qbk',
263 help='The .qbk source of the Getting Started guide'
264 )
265 parser.add_argument(
266 '--dst',
267 dest='dst',
268 default='example/getting_started',
269 help='The target directory to generate into (all headers in that directory will be deleted!)'
270 )
271
272 args = parser.parse_args()
273
274 qbk = open(args.src, 'r').readlines()
275
276 delete_old_headers(args.dst)
277 doc_dir = os.path.dirname(args.src)
278
279 (sections, defs) = parse_md(qbk)
280 files1 = gen_headers(sections, defs, args.dst)
281 (files2, qbk) = what_we_have_so_far_docs(doc_dir, qbk, defs, sections)
282 (files3, qbk) = \
283 extract_code_snippets(
284 qbk,
285 args.src[:-4] if args.src.endswith('.qbk') else args.src
286 )
287
288 write_files(files1)
289 write_files(files2)
290 write_files(files3)
291 write_file(args.src, ''.join(qbk))
292
293 if __name__ == "__main__":
294 main()
295