pocketlang/scripts/amalgamate.py

110 lines
2.7 KiB
Python
Raw Normal View History

##
## Copyright (c) 2020-2022 Thakee Nathees
## Copyright (c) 2021-2022 Pocketlang Contributors
## Distributed Under The MIT License
##
##
## USAGE: python amalgamate.py > pocketlang.h
##
import os, re, sys
from os.path import *
## Pocket lang root directory. All the listed paths bellow are relative to
## the root path.
ROOT_PATH = abspath(join(dirname(__file__), ".."))
## Filter all the files in the [path] with extension and return them.
def files(path, ext, filter_= lambda file : True):
return [
join(ROOT_PATH, path, file) for file in os.listdir(join(ROOT_PATH, path))
if file.endswith(ext) and filter_(file)
]
SOURCES = [
*files('src/core/', '.c'),
*files('src/libs/', '.c'),
]
PUBLIC_HEADER = join(ROOT_PATH, 'src/include/pocketlang.h')
HEADERS = [
*[ ## The order of the headers are important.
join(ROOT_PATH, header)
for header in [
'src/core/common.h',
'src/core/utils.h',
'src/core/internal.h',
'src/core/buffers.h',
'src/core/value.h',
'src/core/compiler.h',
'src/core/core.h',
'src/core/debug.h',
'src/core/vm.h',
'src/libs/libs.h',
]
]
]
## return include path from a linclude "statement" line.
def _get_include_path(line):
assert '#include ' in line
index = line.find('#include ')
start = line.find('"', index)
end = line.find('"', start + 1)
return line[start+1:end]
## Since the stdout is redirected to a file, stderr can be
## used for logging.
def log(*msg):
message = ' '.join(map(lambda x: str(x), msg))
sys.stderr.write(message + '\n')
def parse(path):
text = ""
with open(path, 'r') as fp:
for line in fp.readlines():
if "//<< AMALG_INLINE >>" in line:
path = join(dirname(path), _get_include_path(line))
path = path.replace('\\', '/') ## Aaah windows path.
text += parse(path) + '\n'
else: text += line
## Note that this comment stripping regex is dubious, and wont
## work on all cases ex:
##
## const char* s = "//";\n
##
## The above '//' considered as comment but it's inside a string.
text = re.sub('/\*.*?\*/', '', text, flags=re.S)
text = re.sub('//.*?\n', '\n', text, flags=re.S)
text = re.sub('[^\n\S]*\n', '\n', text, flags=re.S)
text = re.sub('\n\n+', '\n\n', text, flags=re.S)
return text
def generate():
gen = ''
with open(PUBLIC_HEADER, 'r') as fp:
gen = fp.read()
gen += '\n#define PK_AMALGAMATED\n'
for header in HEADERS:
gen += '// Amalgamated file: ' +\
relpath(header, ROOT_PATH).replace("\\", "/") +\
'\n'
gen += parse(header) + '\n'
gen += '#ifdef PK_IMPL\n\n'
for source in SOURCES:
gen += parse(source)
gen += '#endif // PK_IMPL\n'
return gen
if __name__ == '__main__':
print(generate())