From 1cb2de71bd96c61eead4d01d7c704228b5542d70 Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Mon, 7 Sep 2020 11:58:38 +0300 Subject: [PATCH 1/5] Add an empty line before every C function. --- src/ustubby/__init__.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ustubby/__init__.py b/src/ustubby/__init__.py index e396a68..b5b402d 100644 --- a/src/ustubby/__init__.py +++ b/src/ustubby/__init__.py @@ -292,7 +292,7 @@ class ReturnContainer(BaseContainer): def stub_function(f): # Function implementation - stub_ret = [function_comments(f), function_init(f"{f.__module__}_{f.__name__}")] + stub_ret = ["", function_comments(f), function_init(f"{f.__module__}_{f.__name__}")] sig = inspect.signature(f) stub_ret[-1] += function_params(sig.parameters) stub_ret.extend(parse_params(f, sig.parameters)) @@ -414,11 +414,10 @@ def parse_params(f, params): def headers(): - return """// Include required definitions first. + return '''// Include required definitions first. #include "py/obj.h" #include "py/runtime.h" -#include "py/builtin.h" -""" +#include "py/builtin.h"''' def function_comments(f): From 294ee039ca3d472e27e5c3aec14009e6bc3e6c86 Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Mon, 7 Sep 2020 13:23:16 +0300 Subject: [PATCH 2/5] Fix: MP_QSTR_example changed to MP_QSTR_{mod.__name__} --- src/ustubby/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ustubby/__init__.py b/src/ustubby/__init__.py index b5b402d..324674c 100644 --- a/src/ustubby/__init__.py +++ b/src/ustubby/__init__.py @@ -320,7 +320,7 @@ def stub_module(mod): # Set up the module properties stub_ret.append("") stub_ret.append(f"STATIC const mp_rom_map_elem_t {mod.__name__}_module_globals_table[] = {{") - stub_ret.append(f"\t{{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example) }},") + stub_ret.append(f"\t{{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_{mod.__name__}) }},") stub_ret.extend( [f"\t{{ MP_ROM_QSTR(MP_QSTR_{f.__name__}), MP_ROM_PTR(&{mod.__name__}_{f.__name__}_obj) }}," for f in functions]) @@ -335,7 +335,7 @@ def stub_module(mod): # Register the module stub_ret.append("") stub_ret.append( - f"MP_REGISTER_MODULE(MP_QSTR_example, {mod.__name__}_user_cmodule, MODULE_{mod.__name__.upper()}_ENABLED);") + f"MP_REGISTER_MODULE(MP_QSTR_{mod.__name__}, {mod.__name__}_user_cmodule, MODULE_{mod.__name__.upper()}_ENABLED);") return "\n".join(stub_ret) From 74fd1509da692a380891cdfd3874da1748027efc Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Sun, 13 Sep 2020 02:57:39 +0300 Subject: [PATCH 3/5] tuple as output --- src/ustubby/__init__.py | 65 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/src/ustubby/__init__.py b/src/ustubby/__init__.py index 324674c..43e9f60 100644 --- a/src/ustubby/__init__.py +++ b/src/ustubby/__init__.py @@ -27,12 +27,26 @@ def string_handle(*args, **kwargs): "\tmp_obj_t *{0} = NULL;\n\tsize_t {0}_len = 0;\n\tmp_obj_get_array({0}_arg, &{0}_len, &{0});"), object: string_template("\tmp_obj_t {0} args[ARG_{0}].u_obj;") } +type_handler_arr = { + int: string_template("\tmp_int_t {0} = mp_obj_get_int(args[{1}]);"), + float: string_template("\tmp_float_t {0} = mp_obj_get_float(args[{1}]);"), + bool: string_template("\tbool {0} = mp_obj_is_true(args[{1}]);"), + str: string_template("\tconst char* {0} = mp_obj_str_get_str(args[{1}]);"), + tuple: string_template( + "\tmp_obj_t *{0} = NULL;\n\tsize_t {0}_len = 0;\n\tmp_obj_get_array(args[{1}], &{0}_len, &{0});"), + list: string_template( + "\tmp_obj_t *{0} = NULL;\n\tsize_t {0}_len = 0;\n\tmp_obj_get_array(args[{1}], &{0}_len, &{0});"), + set: string_template( + "\tmp_obj_t *{0} = NULL;\n\tsize_t {0}_len = 0;\n\tmp_obj_get_array(args[{1}], &{0}_len, &{0});"), + object: string_template("\tmp_obj_t {0} args[ARG_{0}].u_obj;") +} return_type_handler = { int: "\tmp_int_t ret_val;", float: "\tmp_float_t ret_val;", bool: "\tbool ret_val;", str: "", + tuple: "", # tuple: string_template( # "\tmp_obj_t *{0} = NULL;\n\tsize_t {0}_len = 0;\n\tmp_obj_get_array({0}_arg, &{0}_len, &{0});"), # list: string_template( @@ -47,6 +61,14 @@ def string_handle(*args, **kwargs): float: "\treturn mp_obj_new_float(ret_val);", bool: "\treturn mp_obj_new_bool(ret_val);", str: "\treturn mp_obj_new_str(, );", + tuple: ''' + // signature: mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items); + mp_obj_t ret_val[] = { + mp_obj_new_int(123), + mp_obj_new_float(456.789), + mp_obj_new_str("hello", 5), + }; + return mp_obj_new_tuple(3, ret_val);''', None: "\treturn mp_const_none;" } @@ -105,6 +127,7 @@ class FunctionContainer(BaseContainer): float: "mp_float_t ret_val;", bool: "bool ret_val;", str: None, + tuple: "", # tuple: string_template( # "mp_obj_t *{0} = NULL;\n\tsize_t {0}_len = 0;\n\tmp_obj_get_array({0}_arg, &{0}_len, &{0});"), # list: string_template( @@ -118,6 +141,14 @@ class FunctionContainer(BaseContainer): float: "return mp_obj_new_float(ret_val);", bool: "return mp_obj_new_bool(ret_val);", str: "return mp_obj_new_str(, );", + tuple: ''' + // signature: mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items); + mp_obj_t ret_val[] = { + mp_obj_new_int(123), + mp_obj_new_float(456.789), + mp_obj_new_str("hello", 5), + }; + return mp_obj_new_tuple(3, ret_val);''', None: "return mp_const_none;" } @@ -193,8 +224,8 @@ def to_c(self): resp += f"{self.to_c_func_def()}({self.parameters.to_c_input()}) {{\n" resp += " " + "\n ".join(self.parameters.to_c_init().splitlines()) + "\n" if self.to_c_return_val_init(): - resp += " " + self.to_c_return_val_init() - resp += f"\n\n {self.to_c_code_body()}\n\n" + resp += " " + self.to_c_return_val_init() + "\n" + resp += f"\n {self.to_c_code_body()}\n\n" resp += f" {self.to_c_return_value()}\n" resp += "}\n" resp += self.to_c_define() @@ -215,6 +246,19 @@ class ParametersContainer(BaseContainer): "mp_obj_t *{0} = NULL;\nsize_t {0}_len = 0;\nmp_obj_get_array({0}_arg, &{0}_len, &{0});"), object: string_template("\tmp_obj_t {0} args[ARG_{0}].u_obj;") } + type_handler_arr = { + int: string_template("mp_int_t {0} = mp_obj_get_int(args[{1}]);"), + float: string_template("mp_float_t {0} = mp_obj_get_float(args[{1}]);"), + bool: string_template("bool {0} = mp_obj_is_true(args[{1}]);"), + str: string_template("const char* {0} = mp_obj_str_get_str(args[{1}]);"), + tuple: string_template( + "mp_obj_t *{0} = NULL;\n\tsize_t {0}_len = 0;\n\tmp_obj_get_array(args[{1}], &{0}_len, &{0});"), + list: string_template( + "mp_obj_t *{0} = NULL;\n\tsize_t {0}_len = 0;\n\tmp_obj_get_array(args[{1}], &{0}_len, &{0});"), + set: string_template( + "mp_obj_t *{0} = NULL;\n\tsize_t {0}_len = 0;\n\tmp_obj_get_array(args[{1}], &{0}_len, &{0});"), + object: string_template("mp_obj_t {0} args[ARG_{0}].u_obj;") + } def __init__(self): self.type = "" @@ -282,6 +326,8 @@ def to_c_init(self): self.to_c_arg_array(), "", self.to_c_kw_arg_unpack()]) + elif len(self.parameters) > 3: + return "\n".join([self.type_handler_arr[value.annotation](param, index) for index, (param, value) in enumerate(self.parameters.items())]) else: return "\n".join([self.type_handler[value.annotation](param) for param, value in self.parameters.items()]) @@ -309,8 +355,16 @@ def stub_function(f): return "\n".join(expand_newlines(stub_ret)) +def module_doc(mod): + s = '''// This file was developed using uStubby. +// https://github.com/pazzarpj/micropython-ustubby +''' + if mod.__doc__ is not None: + s += '\n/*'+ mod.__doc__ + '*/\n' + return s + def stub_module(mod): - stub_ret = [headers()] + stub_ret = [module_doc(mod), headers()] classes = [o[1] for o in inspect.getmembers(mod) if inspect.isclass(o[1])] functions = [o[1] for cls in classes for o in inspect.getmembers(cls) if inspect.isfunction(o[1])] functions.extend([o[1] for o in inspect.getmembers(mod) if inspect.isfunction(o[1])]) @@ -348,12 +402,13 @@ def ret_val_init(ret_type): def ret_val_return(ret_type): + print('ret_type', ret_type) return return_handler[ret_type] def function_params(params): if len(params) == 0: - return "() {" + return ") {" simple = all([param.kind == param.POSITIONAL_OR_KEYWORD for param in params.values()]) if simple and len(params) < 4: params = ", ".join([f"mp_obj_t {x}_obj" for x in params]) @@ -407,6 +462,8 @@ def parse_params(f, params): :return: list of strings defining the parsed parameters in c """ simple = all([param.kind == param.POSITIONAL_OR_KEYWORD for param in params.values()]) + if simple and len(params) > 3: + return [type_handler_arr[value.annotation](param, ind) for ind, (param, value) in enumerate(params.items())] if simple: return [type_handler[value.annotation](param) for param, value in params.items()] else: From a55d596e57a4bbb539940b21c1f9c27737097a05 Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Tue, 22 Sep 2020 01:22:34 +0300 Subject: [PATCH 4/5] return list and dict from C function --- src/ustubby/__init__.py | 44 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/src/ustubby/__init__.py b/src/ustubby/__init__.py index 43e9f60..5002e4b 100644 --- a/src/ustubby/__init__.py +++ b/src/ustubby/__init__.py @@ -46,13 +46,18 @@ def string_handle(*args, **kwargs): float: "\tmp_float_t ret_val;", bool: "\tbool ret_val;", str: "", + bytes: "", tuple: "", + list: "", + dict: "", + object: "", # tuple: string_template( # "\tmp_obj_t *{0} = NULL;\n\tsize_t {0}_len = 0;\n\tmp_obj_get_array({0}_arg, &{0}_len, &{0});"), # list: string_template( # "\tmp_obj_t *{0} = NULL;\n\tsize_t {0}_len = 0;\n\tmp_obj_get_array({0}_arg, &{0}_len, &{0});"), # set: string_template( # "\tmp_obj_t *{0} = NULL;\n\tsize_t {0}_len = 0;\n\tmp_obj_get_array({0}_arg, &{0}_len, &{0});"), + inspect._empty: "", None: "" } @@ -60,15 +65,38 @@ def string_handle(*args, **kwargs): int: "\treturn mp_obj_new_int(ret_val);", float: "\treturn mp_obj_new_float(ret_val);", bool: "\treturn mp_obj_new_bool(ret_val);", - str: "\treturn mp_obj_new_str(, );", - tuple: ''' - // signature: mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items); + + str: """\t// signature: mp_obj_t mp_obj_new_bytes(const char* data, size_t len); + return mp_obj_new_str("hello", 5);""", + + tuple: '''\t// signature: mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items); mp_obj_t ret_val[] = { mp_obj_new_int(123), mp_obj_new_float(456.789), mp_obj_new_str("hello", 5), }; return mp_obj_new_tuple(3, ret_val);''', + + bytes:'''\t// signature: mp_obj_t mp_obj_new_bytes(const byte* data, size_t len); + return mp_obj_new_bytes("hello", 5);''', + + list: '''\t// signature: mp_obj_t mp_obj_new_list(size_t n, const mp_obj_t *items); + mp_obj_t ret_val[] = { + mp_obj_new_int(123), + mp_obj_new_float(456.789), + mp_obj_new_str("hello", 5), + }; + return mp_obj_new_list(3, ret_val);''', + + dict: '''\tmp_obj_t ret_val = mp_obj_dict(0); + mp_obj_dict_store(ret_val, mp_obj_new_str("element1", 8), mp_obj_new_int(123)); + mp_obj_dict_store(ret_val, mp_obj_new_str("element2", 8), mp_obj_new_float(456.789)); + mp_obj_dict_store(ret_val, mp_obj_new_str("element3", 8), mp_obj_new_str("hello", 5)); + return ret_val;''', + + object: '''\treturn mp_const_none; // TODO''', + + inspect._empty: "\treturn mp_const_none;", None: "\treturn mp_const_none;" } @@ -402,7 +430,6 @@ def ret_val_init(ret_type): def ret_val_return(ret_type): - print('ret_type', ret_type) return return_handler[ret_type] @@ -474,7 +501,14 @@ def headers(): return '''// Include required definitions first. #include "py/obj.h" #include "py/runtime.h" -#include "py/builtin.h"''' +#include "py/builtin.h" + + /* + // Example exception for any generated function + if (some_val == 0) { + mp_raise_ValueError("'some_val' can't be zero!"); + } + */''' def function_comments(f): From 57c55e203d566aaa35f07a74dc866b82f679dc2a Mon Sep 17 00:00:00 2001 From: Ihor Nehrutsa Date: Tue, 22 Sep 2020 09:38:38 +0300 Subject: [PATCH 5/5] Try to fix 'Test with pytest' error --- test/test_basic.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test_basic.py b/test/test_basic.py index 4299710..44ae32b 100644 --- a/test/test_basic.py +++ b/test/test_basic.py @@ -140,7 +140,9 @@ def readfrom_mem(addr: int = 0, memaddr: int = 0, arg: object = None, *, addrsiz assert func.to_c_func_def() == "STATIC mp_obj_t example_readfrom_mem" assert func.to_c_return_val_init() is None assert func.to_c_code_body() == "//Your code here" - assert func.to_c_return_value() == "return mp_obj_new_str(, );" +# assert func.to_c_return_value() == "return mp_obj_new_str(, );" + assert func.to_c_return_value() == """\t// signature: mp_obj_t mp_obj_new_bytes(const char* data, size_t len);\n + return mp_obj_new_str("hello", 5);""" assert func.to_c_define() == "MP_DEFINE_CONST_FUN_OBJ_KW(example_readfrom_mem_obj, 1, example_readfrom_mem);" assert func.to_c_arg_array_def() == "STATIC const mp_arg_t example_readfrom_mem_allowed_args[]"