Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Arist
firmware
Commits
9d94f87e
Commit
9d94f87e
authored
Jun 16, 2019
by
ch3
Browse files
refact(genapi): Try to increase readability
parent
cbb0f31e
Changes
1
Hide whitespace changes
Inline
Side-by-side
hw-tests/api-demo/genapi.py
View file @
9d94f87e
...
...
@@ -4,6 +4,155 @@ import os
import
re
import
subprocess
api_src_fmt
=
"""
\
#define API(id, def) __GENERATE_API $ __GEN_ID_##id $ def $
#include "{header}"
"""
"""Generated Client file"""
api_func_start_fmt
=
"""
\
/* Autogenerated stub for {id} */
void {cdecl}({cargs})
{{
const int size = {total_size};
void*buffer;
buffer = api_call_start({id}, size);
/* TODO: Check if buffer is no NULL */
"""
serialise_arg_fmt
=
""" *({type}*)(buffer + {offset}) = {arg};"""
bother_dispatcher_fmt
=
"""
printf("Sending call {id}
\\
nBUF: ");
for (int i = 0; i < size; i++) {{
printf("0x%02x ", ((char*)buffer)[i]);
}}
printf("
\\
n");
api_call_bother_dispatcher(buffer);
}}
"""
"""Generated Service file"""
api_dispatch_call_start
=
"""
\
void __api_dispatch_call(uint32_t id, void*buffer)
{
switch (id) {"""
dispatch_case_fmt
=
"""
\
case {id}:
{cdecl}("""
deserialise_arg_fmt
=
"""
\
*({type}*)(buffer + {offset})"""
insert_switch_case_break_str
=
"""
);
break;"""
switch_add_default_fmt
=
"""
\
default:
printf("Error: API function %x is unknown!!
\\
n", {id});
break;
}}
}}"""
def
api_func_iter
(
header
:
str
):
# Parse the header for API definitions
matcher
=
re
.
compile
(
r
"__GENERATE_API \$ __GEN_ID_(?P<id>\w+) \$ void (?P<decl>.+?)\((?P<args>.*?)\) \$"
,
re
.
DOTALL
|
re
.
MULTILINE
,
)
# 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
# an alternative definition of the `API` macro that marks definitions in
# a way we can find later on.
api_src
=
api_src_fmt
.
format
(
header
=
os
.
path
.
relpath
(
header
)
)
# Evaluate the preprocessor
source
=
subprocess
.
check_output
(
[
"gcc"
,
"-E"
,
"-"
],
input
=
api_src
.
encode
()
).
decode
()
return
matcher
.
finditer
(
source
)
def
include_header
(
header
:
str
,
file
):
print
(
'#include "{}"
\n
'
.
format
(
os
.
path
.
basename
(
header
)
),
file
=
file
)
def
destructure_args
(
api_args
:
str
):
api_args_names
=
[]
api_args_types
=
[]
api_args_sizes
=
[]
args_matcher
=
re
.
compile
(
r
"(?P<type>\w+(?:\*+|\s+))(?P<name>\w+),"
)
# Destructure args
for
arg
in
args_matcher
.
finditer
(
api_args
+
","
):
arg_type
=
arg
.
group
(
"type"
).
strip
()
arg_name
=
arg
.
group
(
"name"
)
api_args_names
.
append
(
arg_name
)
api_args_types
.
append
(
arg_type
)
api_args_sizes
.
append
(
"sizeof({})"
.
format
(
arg_type
))
return
(
api_args_names
,
api_args_types
,
api_args_sizes
)
def
serialise_arg
(
ty
:
str
,
api_args_sizes
:
list
,
arg_idx
:
int
,
arg
:
str
,
file
):
print
(
serialise_arg_fmt
.
format
(
type
=
ty
,
offset
=
" + "
.
join
(
api_args_sizes
[:
arg_idx
])
if
arg_idx
>
0
else
"0"
,
arg
=
arg
,
),
file
=
file
,
)
def
deserialise_arg
(
ty
:
str
,
api_args_sizes
:
list
,
arg_idx
:
int
,
file
):
if
arg_idx
!=
0
:
print
(
","
,
file
=
file
)
print
(
deserialise_arg_fmt
.
format
(
type
=
ty
,
offset
=
" + "
.
join
(
api_args_sizes
[:
arg_idx
])
if
arg_idx
>
0
else
"0"
,
),
file
=
file
,
end
=
""
,
)
def
insert_switch_case_break
(
file
):
print
(
insert_switch_case_break_str
,
file
=
file
,
)
def
bother_dispatcher
(
api_id
:
str
,
file
):
print
(
bother_dispatcher_fmt
.
format
(
id
=
api_id
),
file
=
file
,
)
def
switch_add_default
(
api_id
:
str
,
file
):
print
(
switch_add_default_fmt
.
format
(
id
=
api_id
,
),
file
=
file
)
def
main
():
parser
=
argparse
.
ArgumentParser
(
...
...
@@ -20,148 +169,45 @@ def main():
)
args
=
parser
.
parse_args
()
with
contextlib
.
ExitStack
()
as
cx
:
# 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
# an alternative definition of the `API` macro that marks definitions in
# a way we can find later on.
api_src
=
"""
\
#define API(id, def) __GENERATE_API $ __GEN_ID_##id $ def $
#include "{header}"
"""
.
format
(
header
=
os
.
path
.
relpath
(
args
.
header
)
)
# Open output files
cx
=
contextlib
.
ExitStack
()
f_client
=
cx
.
enter_context
(
open
(
args
.
client
,
"w"
))
f_server
=
cx
.
enter_context
(
open
(
args
.
server
,
"w"
))
# Evaluate the preprocessor
source
=
subprocess
.
check_output
(
[
"gcc"
,
"-E"
,
"-"
],
input
=
api_src
.
encode
()
).
decode
()
include_header
(
args
.
header
,
f_client
)
include_header
(
args
.
header
,
f_server
)
# Parse the header for API definitions
matcher
=
re
.
compile
(
r
"__GENERATE_API \$ __GEN_ID_(?P<id>\w+) \$ void (?P<decl>.+?)\((?P<args>.*?)\) \$"
,
re
.
DOTALL
|
re
.
MULTILINE
,
)
print
(
api_dispatch_call_start
,
file
=
f_server
)
args_matcher
=
re
.
compile
(
r
"(?P<type>\w+(?:\*+|\s+))(?P<name>\w+),"
)
for
api_func
in
api_func_iter
(
args
.
header
):
api_id
=
api_func
.
group
(
"id"
)
api_decl
=
api_func
.
group
(
"decl"
)
api_args
=
api_func
.
group
(
"args"
)
# Open output files
f_client
=
cx
.
enter_context
(
open
(
args
.
client
,
"w"
))
f_server
=
cx
.
enter_context
(
open
(
args
.
server
,
"w"
))
(
api_args_names
,
api_args_types
,
api_args_sizes
)
=
\
destructure_args
(
api_args
)
print
(
'#include "{}"
\n
'
.
format
(
os
.
path
.
basename
(
args
.
header
)
),
file
=
f_client
)
print
(
api_func_start_fmt
.
format
(
id
=
api_id
,
cdecl
=
api_decl
,
cargs
=
api_args
,
total_size
=
" + "
.
join
(
api_args_sizes
),
),
file
=
f_client
,
)
print
(
"""
\
#include "{}"
print
(
dispatch_case_fmt
.
format
(
id
=
api_id
,
cdecl
=
api_decl
),
file
=
f_server
,
)
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_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} */
void {cdecl}({cargs})
{{
const int size = {total_size};
void*buffer;
for
i
,
(
arg
,
ty
)
in
enumerate
(
zip
(
api_args_names
,
api_args_types
)):
serialise_arg
(
ty
,
api_args_sizes
,
i
,
arg
,
f_client
)
deserialise_arg
(
ty
,
api_args_sizes
,
i
,
f_server
)
buffer = api_call_start({id}, size);
/* TODO: Check if buffer is no NULL */
"""
.
format
(
id
=
api_id
,
cdecl
=
api_decl
,
cargs
=
api_args
,
total_size
=
" + "
.
join
(
api_args_sizes
),
),
file
=
f_client
,
)
print
(
"""
\
case {id}:
{cdecl}("""
.
format
(
id
=
api_id
,
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
:
print
(
","
,
file
=
f_server
)
print
(
"""
\
*({type}*)(buffer + {offset})"""
.
format
(
type
=
ty
,
offset
=
" + "
.
join
(
api_args_sizes
[:
i
])
if
i
>
0
else
"0"
,
),
file
=
f_server
,
end
=
""
,
)
print
(
"""
);
break;"""
.
format
(
cdecl
=
api_decl
,
args
=
", "
.
join
(
api_args_names
),
),
file
=
f_server
,
)
print
(
"""
printf("Sending call {id}
\\
nBUF: ");
for (int i = 0; i < size; i++) {{
printf("0x%02x ", ((char*)buffer)[i]);
}}
printf("
\\
n");
insert_switch_case_break
(
f_server
)
bother_dispatcher
(
api_id
,
f_client
)
api_call_bother_dispatcher(buffer);
}}
"""
.
format
(
id
=
api_id
),
file
=
f_client
,
)
print
(
"""
\
default:
printf("Error: API function %x is unknown!!
\\
n", {id});
break;
}}
}}"""
.
format
(
id
=
api_id
,
),
file
=
f_server
)
switch_add_default
(
api_id
,
f_server
)
if
__name__
==
"__main__"
:
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment