2020-01-04 14:21:38 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import re
|
|
|
|
import os
|
2020-01-11 21:15:24 +00:00
|
|
|
import os.path as path
|
2020-01-04 14:21:38 +00:00
|
|
|
import traceback
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_script_folder():
|
2020-01-11 21:15:24 +00:00
|
|
|
return path.dirname(path.realpath(sys.argv[0]))
|
2020-01-04 14:21:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def read_all_text_from_file(path):
|
|
|
|
print("Reading {}".format(path))
|
2020-01-12 15:37:02 +00:00
|
|
|
with open(path, 'r', encoding='utf-8') as file:
|
2020-01-11 21:15:24 +00:00
|
|
|
text = file.read()
|
2020-01-04 14:21:38 +00:00
|
|
|
return text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def make_divider(text = None, text_col = 40):
|
|
|
|
if (text is None):
|
2020-01-06 18:21:16 +00:00
|
|
|
return "//" + ('-' * 118)
|
2020-01-04 14:21:38 +00:00
|
|
|
else:
|
|
|
|
text = "//{} {} ".format('-' * (text_col - 2),text);
|
2020-01-06 18:21:16 +00:00
|
|
|
if (len(text) < 120):
|
|
|
|
return text + ('-' * (120 - len(text)))
|
2020-01-04 14:21:38 +00:00
|
|
|
else:
|
|
|
|
return text
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-01-06 18:21:16 +00:00
|
|
|
class Preprocessor:
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-06 18:21:16 +00:00
|
|
|
def __init__(self):
|
|
|
|
pass
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-06 18:21:16 +00:00
|
|
|
def preprocess(self, match):
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-06 18:21:16 +00:00
|
|
|
raw_incl = match if isinstance(match, str) else match.group(1)
|
|
|
|
incl = raw_incl.strip().lower()
|
|
|
|
if incl in self.processed_includes:
|
|
|
|
return ''
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-06 18:21:16 +00:00
|
|
|
self.processed_includes.append(incl)
|
2020-01-11 21:15:24 +00:00
|
|
|
text = read_all_text_from_file(path.join(get_script_folder(), '..', 'include', 'toml++', incl))
|
2020-01-06 18:21:16 +00:00
|
|
|
text = re.sub(r'^\s*#\s*pragma\s+once\s*$', '', text, 0, re.I | re.M)
|
|
|
|
text = re.sub(r'^\s*//\s*clang-format\s+(?:off|on)\s*$', '', text, 0, re.I | re.M)
|
|
|
|
|
|
|
|
self.current_level += 1
|
|
|
|
text = re.sub(r'^\s*#\s*include\s+"(.+?)"', lambda m : self.preprocess(m), text, 0, re.I | re.M)
|
|
|
|
self.current_level -= 1
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-06 18:21:16 +00:00
|
|
|
if (self.current_level == 1):
|
|
|
|
header_text = '↓ ' + raw_incl
|
2020-01-11 21:15:24 +00:00
|
|
|
lpad = 28 + ((25 * (self.header_indent % 4)) - int((len(header_text) + 4) / 2))
|
2020-01-06 18:21:16 +00:00
|
|
|
self.header_indent += 1
|
|
|
|
return '\n{}\n#pragma region {}\n\n{}\n\n#pragma endregion {}\n{}'.format(
|
|
|
|
make_divider(header_text, lpad), '', text, '', make_divider('↑ ' + raw_incl, lpad))
|
|
|
|
else:
|
|
|
|
return text
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-06 18:21:16 +00:00
|
|
|
def __call__(self, file):
|
|
|
|
self.processed_includes = []
|
|
|
|
self.header_indent = 0
|
|
|
|
self.current_level = 0
|
|
|
|
return self.preprocess(file)
|
2020-01-04 14:21:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
2020-01-06 18:21:16 +00:00
|
|
|
# preprocess header(s)
|
|
|
|
source_text = Preprocessor()('toml.h')
|
|
|
|
source_text = re.sub('\r\n', '\n', source_text, 0, re.I | re.M) # convert windows newlines
|
2020-01-11 21:15:24 +00:00
|
|
|
source_text = re.sub('(?:\n[ \t]*//[/#!<]+[^\n]*)+\n', '\n', source_text, 0, re.I | re.M) # remove 'magic' comment blocks
|
2020-01-22 21:29:46 +00:00
|
|
|
source_text = re.sub('(?:///[<].*?)\n', '\n', source_text, 0, re.I | re.M) # remove inline doxy briefs
|
2020-01-12 15:37:02 +00:00
|
|
|
source_text = re.sub('\n(?:[ \t]*\n[ \t]*)+\n', '\n\n', source_text, 0, re.I | re.M) # remove double newlines
|
2020-01-06 18:21:16 +00:00
|
|
|
source_text = re.sub('([^ \t])[ \t]+\n', '\\1\n', source_text, 0, re.I | re.M) # remove trailing whitespace
|
2020-02-03 09:12:43 +00:00
|
|
|
return_type_pattern \
|
|
|
|
= r'(?:' \
|
|
|
|
+ r'(?:\[\[nodiscard\]\]\s*)?' \
|
|
|
|
+ r'(?:(?:friend|explicit|virtual|inline|const|operator)\s+)*' \
|
|
|
|
+ r'(?:' \
|
|
|
|
+ r'bool|int64_t|(?:const_)?iterator|double|void' \
|
|
|
|
+ r'|node(?:_(?:view|of)<.+?>|)?|table|array|value(?:<.+?>)?' \
|
|
|
|
+ r'|T|U|parse_(?:error|result)' \
|
|
|
|
+ r')' \
|
|
|
|
+ r'(?:\s*[&*]+)?' \
|
|
|
|
+ r'(?:\s*[(]\s*[)])?' \
|
|
|
|
+ r'\s+' \
|
|
|
|
+ r')'
|
|
|
|
blank_lines_between_returns_pattern = '({}[^\n]+)\n\n([ \t]*{})'.format(return_type_pattern, return_type_pattern)
|
2020-01-12 15:37:02 +00:00
|
|
|
for i in range(0, 5): # remove blank lines between simple one-liner definitions
|
|
|
|
source_text = re.sub('(using .+?;)\n\n([ \t]*using)', '\\1\n\\2', source_text, 0, re.I | re.M)
|
|
|
|
source_text = re.sub(
|
|
|
|
'([a-zA-Z_][a-zA-Z0-9_]*[ \t]+[a-zA-Z_][a-zA-Z0-9_]*[ \t]*;)' \
|
|
|
|
+ '\n\n([ \t]*[a-zA-Z_][a-zA-Z0-9_]*[ \t]+[a-zA-Z_][a-zA-Z0-9_]*[ \t]*;)', '\\1\n\\2',
|
|
|
|
source_text, 0, re.I | re.M)
|
2020-02-03 09:12:43 +00:00
|
|
|
source_text = re.sub(blank_lines_between_returns_pattern, '\\1\n\\2', source_text, 0, re.I | re.M)
|
2020-01-06 18:21:16 +00:00
|
|
|
source_text = source_text.strip()
|
|
|
|
|
2020-01-12 15:37:02 +00:00
|
|
|
|
|
|
|
|
2020-01-06 18:21:16 +00:00
|
|
|
# extract library version
|
|
|
|
library_version = [0,0,0]
|
|
|
|
match = re.search(r'^\s*#\s*define\s+TOML_LIB_MAJOR\s+([0-9]+)\s*$', source_text, re.I | re.M)
|
|
|
|
if match is not None:
|
|
|
|
library_version[0] = match.group(1)
|
|
|
|
match = re.search(r'^\s*#\s*define\s+TOML_LIB_MINOR\s+([0-9]+)\s*$', source_text, re.I | re.M)
|
|
|
|
if match is not None:
|
|
|
|
library_version[1] = match.group(1)
|
2020-02-20 21:08:20 +00:00
|
|
|
match = re.search(r'^\s*#\s*define\s+TOML_LIB_(?:REVISION|PATCH)\s+([0-9]+)\s*$', source_text, re.I | re.M)
|
2020-01-06 18:21:16 +00:00
|
|
|
if match is not None:
|
|
|
|
library_version[2] = match.group(1)
|
|
|
|
|
2020-01-04 14:21:38 +00:00
|
|
|
# build the preamble (license etc)
|
|
|
|
preamble = []
|
2020-01-06 18:21:16 +00:00
|
|
|
preamble.append('''
|
|
|
|
toml++ v{}
|
2020-02-16 13:11:57 +00:00
|
|
|
https://github.com/marzer/tomlplusplus
|
|
|
|
SPDX-License-Identifier: MIT'''.format('.'.join(str(x) for x in library_version)))
|
2020-01-06 18:21:16 +00:00
|
|
|
preamble.append('''
|
2020-01-12 15:37:02 +00:00
|
|
|
- THIS FILE WAS ASSEMBLED FROM MULTIPLE HEADER FILES BY A SCRIPT - PLEASE DON'T EDIT IT DIRECTLY -
|
2020-01-06 18:21:16 +00:00
|
|
|
|
|
|
|
If you wish to submit a contribution to toml++, hooray and thanks! Before you crack on, please be aware that this
|
|
|
|
file was assembled from a number of smaller files by a python script, and code contributions should not be made
|
|
|
|
against it directly. You should instead make your changes in the relevant source file(s). The file names of the files
|
|
|
|
that contributed to this header can be found at the beginnings and ends of the corresponding sections of this file.''')
|
|
|
|
preamble.append('''
|
|
|
|
TOML language specification:
|
|
|
|
Latest: https://github.com/toml-lang/toml/blob/master/README.md
|
|
|
|
v0.5.0: https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md''')
|
2020-01-11 21:15:24 +00:00
|
|
|
preamble.append(read_all_text_from_file(path.join(get_script_folder(), '..', 'LICENSE')))
|
2020-02-03 09:12:43 +00:00
|
|
|
preamble.append('''
|
|
|
|
UTF-8 decoding is performed using a derivative of Bjoern Hoehrmann's 'Flexible and Economical UTF-8 Decoder'
|
|
|
|
See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
|
|
|
|
|
|
|
{}
|
|
|
|
'''.format(
|
|
|
|
read_all_text_from_file(path.join(get_script_folder(), '..', 'LICENSE-utf8-decoder'))
|
|
|
|
))
|
|
|
|
|
2020-01-04 14:21:38 +00:00
|
|
|
|
|
|
|
# write the output file
|
2020-01-11 21:15:24 +00:00
|
|
|
output_file_path = path.join(get_script_folder(), '..', 'toml.hpp')
|
2020-01-04 14:21:38 +00:00
|
|
|
print("Writing to {}".format(output_file_path))
|
2020-01-11 21:15:24 +00:00
|
|
|
with open(output_file_path,'w', encoding='utf-8', newline='\n') as output_file:
|
|
|
|
if (len(preamble) > 0):
|
|
|
|
print(make_divider(), file=output_file)
|
|
|
|
for pre in preamble:
|
|
|
|
print('//', file=output_file)
|
|
|
|
for line in pre.strip().splitlines():
|
|
|
|
print('//', file=output_file, end = '')
|
|
|
|
if (len(line) > 0):
|
|
|
|
print(' ', file=output_file, end = '')
|
|
|
|
print(line, file=output_file)
|
|
|
|
else:
|
|
|
|
print('\n', file=output_file, end = '')
|
|
|
|
print('//', file=output_file)
|
|
|
|
print(make_divider(), file=output_file)
|
|
|
|
print('''// clang-format off
|
2020-01-06 18:21:16 +00:00
|
|
|
#pragma once
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
|
|
|
#endif
|
|
|
|
''', file=output_file)
|
2020-01-11 21:15:24 +00:00
|
|
|
print(source_text, file=output_file)
|
|
|
|
print('''
|
2020-01-06 18:21:16 +00:00
|
|
|
#ifdef __GNUC__
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
#endif
|
|
|
|
// clang-format on''', file=output_file)
|
2020-01-04 14:21:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
try:
|
|
|
|
main()
|
|
|
|
except Exception as err:
|
|
|
|
print(
|
|
|
|
'Fatal error: [{}] {}'.format(
|
|
|
|
type(err).__name__,
|
|
|
|
str(err)
|
|
|
|
),
|
|
|
|
file=sys.stderr
|
|
|
|
)
|
|
|
|
traceback.print_exc(file=sys.stderr)
|
|
|
|
sys.exit(1)
|
|
|
|
sys.exit()
|