Skip to content
Snippets Groups Projects
Verified Commit 06df747a authored by rahix's avatar rahix
Browse files

refactor(api): Restructure API generation script


Signed-off-by: default avatarRahix <rahix@rahix.de>
parent 15bb6ac6
No related branches found
No related tags found
No related merge requests found
import argparse import argparse
import contextlib
import os import os
import re import re
import subprocess import subprocess
MATCH_DECLARATION = re.compile(
r"__GENERATE_API \$ __GEN_ID_(?P<id>\w+) \$ (?P<type>\w+(?:\*+|\s+))(?P<name>.+?)\((?P<args>.*?)\) \$",
re.DOTALL | re.MULTILINE,
)
MATCH_ARGS = re.compile(r"(?P<type>\w+(?:\*+|\s+))(?P<name>\w+),")
def parse_declarations(source):
"""Parse all declarations in the given source."""
declarations = []
for decl in MATCH_DECLARATION.finditer(source):
id = decl.group("id")
return_type = decl.group("type").strip()
name = decl.group("name")
args = []
args_str = decl.group("args")
# Parse arguments
for arg in MATCH_ARGS.finditer(args_str + ","):
arg_type = arg.group("type").strip()
arg_name = arg.group("name")
args.append({
"type": arg_type,
"name": arg_name,
"sizeof": "sizeof({})".format(arg_type),
})
declarations.append({
"id": id,
"return_type": return_type,
"name": name,
"args": args,
"args_str": args_str,
})
return declarations
def sizeof(args):
"""Return a string that describes the size of a list of arguments."""
return " + ".join(a["sizeof"] for a in args) if args != [] else "0"
def main(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
...@@ -20,7 +63,6 @@ def main(): ...@@ -20,7 +63,6 @@ def main():
) )
args = parser.parse_args() args = parser.parse_args()
with contextlib.ExitStack() as cx:
# Run the preprocessor on the header file to get the API definitions. # Run the preprocessor on the header file to get the API definitions.
# #
# For this, we first need a source to include the header which contains # For this, we first need a source to include the header which contains
...@@ -38,151 +80,108 @@ def main(): ...@@ -38,151 +80,108 @@ def main():
["gcc", "-E", "-"], input=api_src.encode() ["gcc", "-E", "-"], input=api_src.encode()
).decode() ).decode()
# Parse the header for API definitions declarations = parse_declarations(source)
matcher = re.compile( fmt_header = {
r"__GENERATE_API \$ __GEN_ID_(?P<id>\w+) \$ (?P<type>\w+(?:\*+|\s+))(?P<decl>.+?)\((?P<args>.*?)\) \$", "header": os.path.basename(args.header)
re.DOTALL | re.MULTILINE, }
)
args_matcher = re.compile(r"(?P<type>(?:const )?\w+(?:\*+|\s+))(?P<name>\w+),")
# Open output files
f_client = cx.enter_context(open(args.client, "w"))
f_server = cx.enter_context(open(args.server, "w"))
print("""\ # Generate Client {{{
with open(args.client, "w") as f_client:
tmp = """\
#include <stdio.h> #include <stdio.h>
#include "{}" #include "{header}"
#include "api/caller.h" #include "api/caller.h"
""".format( """
os.path.basename(args.header) f_client.write(tmp.format(**fmt_header))
), file=f_client)
print("""\ for decl in declarations:
#include <stdio.h> decl["total_size"] = sizeof(decl["args"])
#include "{}" tmp = """\
void __api_dispatch_call(uint32_t id, void*buffer)
{{
switch (id) {{""".format(
os.path.basename(args.header)
), file=f_server)
for match in matcher.finditer(source):
api_id = match.group("id")
api_return = match.group("type").strip()
api_decl = match.group("decl")
api_args = match.group("args")
api_args_names = []
api_args_types = []
api_args_sizes = []
# Destructure args
for match in args_matcher.finditer(api_args + ","):
arg_type = match.group("type").strip()
arg_name = match.group("name")
api_args_names.append(arg_name)
api_args_types.append(arg_type)
api_args_sizes.append("sizeof({})".format(arg_type))
print(
"""\
/* Autogenerated stub for {id} */ /* Autogenerated stub for {id} */
{ret} {cdecl}({cargs}) {return_type} {name}({args_str})
{{ {{
const int size = {total_size}; const int size = {total_size};
void*buffer; void*buffer;
buffer = _api_call_start({id}, size); buffer = _api_call_start({id}, size);
/* TODO: Check if buffer is no NULL */ /* TODO: Check if buffer is not NULL */
""".format(
id=api_id,
ret=api_return,
cdecl=api_decl,
cargs=api_args,
total_size=" + ".join(api_args_sizes) if api_args_sizes != [] else "0",
),
file=f_client,
)
if api_return != "void": """
print("""\ f_client.write(tmp.format(**decl))
case {id}:
*(({ret}*)buffer) = {cdecl}(""".format(id=api_id, ret=api_return, cdecl=api_decl),
file=f_server,
)
else:
print("""\
case {id}:
{cdecl}(""".format(id=api_id, ret=api_return, cdecl=api_decl),
file=f_server,
)
for i, (arg, ty) in enumerate(zip(api_args_names, api_args_types)):
print(
""" *({type}*)(buffer + {offset}) = {arg};""".format(
type=ty,
offset=" + ".join(api_args_sizes[:i]) if i > 0 else "0",
arg=arg,
),
file=f_client,
)
if i != 0: for i, arg in enumerate(decl["args"]):
print(",", file=f_server) arg["offset"] = sizeof(decl["args"][:i])
tmp = """\
print( *({type}*)(buffer + {offset}) = {name};
"""\ """
*({type}*)(buffer + {offset})""".format( f_client.write(tmp.format(**arg))
type=ty,
offset=" + ".join(api_args_sizes[:i]) if i > 0 else "0",
),
file=f_server,
end="",
)
print(""" if decl["return_type"] == "void":
); # Don't return if return type is void
break;""".format( tmp = """\
cdecl=api_decl,
args=", ".join(api_args_names),
),
file=f_server,
)
if api_return != "void": _api_call_transact(buffer);
print( }}
""" """
return *({ret}*)_api_call_transact(buffer); f_client.write(tmp.format(**decl))
else:
tmp = """\
return *({return_type}*)_api_call_transact(buffer);
}} }}
""".format( """
id=api_id, f_client.write(tmp.format(**decl))
ret=api_return, # END: Generate Client }}}
),
file=f_client, # Generate Dispatcher {{{
) with open(args.server, "w") as f_dispatcher:
tmp = """\
#include <stdio.h>
#include "{header}"
void __api_dispatch_call(uint32_t id, void*buffer)
{{
switch (id) {{
"""
f_dispatcher.write(tmp.format(**fmt_header))
for decl in declarations:
if decl["return_type"] == "void":
tmp = """\
case {id}:
{name}("""
f_dispatcher.write(tmp.format(**decl))
else: else:
print( tmp = """\
case {id}:
*(({return_type}*)buffer) = {name}("""
f_dispatcher.write(tmp.format(**decl))
for i, arg in enumerate(decl["args"]):
arg["comma"] = "" if i == 0 else ","
arg["offset"] = sizeof(decl["args"][:i])
tmp = """{comma}
*({type}*)(buffer + {offset})"""
f_dispatcher.write(tmp.format(**arg))
tmp = """
);
break;
""" """
_api_call_transact(buffer); f_dispatcher.write(tmp.format(**decl))
}}
""".format(
id=api_id,
),
file=f_client,
)
print("""\ tmp = """\
default: default:
printf("Error: API function %x is unknown!!\\n", {id}); /* TODO: Better error handling */
printf("Error: API function %x is unknown!!\\n", id);
break; break;
}} }}
}}""".format( }}
id=api_id, """
), file=f_server) f_dispatcher.write(tmp.format(**fmt_header))
# END: Generate Dispatcher }}}
if __name__ == "__main__": if __name__ == "__main__":
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment