From e459df57818f729ff442daed3f69e690f455d9b2 Mon Sep 17 00:00:00 2001 From: heck Date: Fri, 29 Jan 2021 20:48:35 +0100 Subject: [PATCH] Add support for struct containing arrays --- .../ext/lib_test/lib_test/gen/config.json | 16 ++- examples/ext/lib_test/lib_test/lib_test.cc | 2 + examples/ext/lib_test/tests/test_lib_test.py | 28 +++++ pEpACIDgen/gen_backend/gen_pybind11.ysl2 | 106 +++++++++++++----- 4 files changed, 122 insertions(+), 30 deletions(-) diff --git a/examples/ext/lib_test/lib_test/gen/config.json b/examples/ext/lib_test/lib_test/gen/config.json index 264beaa..598b28f 100644 --- a/examples/ext/lib_test/lib_test/gen/config.json +++ b/examples/ext/lib_test/lib_test/gen/config.json @@ -5,6 +5,10 @@ "variables": [ ], "functions": [ + "// func_TTAPSa_args_V", + "func_TACS_args_V" + ], + "//functions": [ "func_V_args_V", "func_Pi_args_V", "func_V_args_Pi", @@ -36,7 +40,17 @@ "func_pppTAPS_args_V", "func_V_args_pTAPS", "func_ppTAPS_args_ppTAPS", - "func_pppTAPS_args_pppTAPS" + "func_pppTAPS_args_pppTAPS", + "func_TTAPSa_args_V", + "//func_TTAPSa_args_TTAPSa", + "//func_V_args_pTTAPSa", + "//func_ppTTAPSa_args_ppTTAPSa", + "//func_pppTTAPSa_args_pppTTAPSa", + "func_TACS_args_V", + "//func_TACS_args_TACS", + "//func_V_args_pTACS", + "//func_ppTACS_args_ppTACS", + "//func_pppTACS_args_pppTACS" ], "debug_ast" : "True", "debug_acid" : "True", diff --git a/examples/ext/lib_test/lib_test/lib_test.cc b/examples/ext/lib_test/lib_test/lib_test.cc index 37eecd3..50579b5 100644 --- a/examples/ext/lib_test/lib_test/lib_test.cc +++ b/examples/ext/lib_test/lib_test/lib_test.cc @@ -1,10 +1,12 @@ #include #include +#include #include #include #include "lib_test.h" using namespace std; +namespace py = pybind11; PYBIND11_MODULE(lib_test, m) { #include "gen/py_module.pybind11" diff --git a/examples/ext/lib_test/tests/test_lib_test.py b/examples/ext/lib_test/tests/test_lib_test.py index 88c3c4e..8373859 100644 --- a/examples/ext/lib_test/tests/test_lib_test.py +++ b/examples/ext/lib_test/tests/test_lib_test.py @@ -251,6 +251,34 @@ def test_func_pppTAPS_args_pppTAPS(): assert(inout.field__P_1 == 23); assert(inout.field__P_2 == 23); +def test_struct_field_array_of_structs_immutable_len(): + a = CS() + b = PS() + assert(len(a.field_APS_1) == 3) + a.field_APS_1 = [b] + assert(len(a.field_APS_1) == 3) + a.field_APS_1 = [b,b] + assert(len(a.field_APS_1) == 3) + a.field_APS_1 = [b,b,b] + assert(len(a.field_APS_1) == 3) + a.field_APS_1 = [] + assert(len(a.field_APS_1) == 3) + +@pytest.mark.skip("throw exception instead of warnning") +def test_struct_field_array_of_structs_accept_unityped_arr_only(): + a = CS() + b = PS() + with pytest.raises(Exception): + a.field_APS_1 = [b,"invalid_type"] + +def test_struct_field_array_of_structs_of_structs_set_get(): + a = CS() + b = PS() + b.field__P_1 = 23 + b.field__P_2 = 23 + a.field_APS_1 = [b] + assert(a.field_APS_1[0].field__P_1 == 23) + assert(a.field_APS_1[0].field__P_2 == 23) def PS_to_string(ps): diff --git a/pEpACIDgen/gen_backend/gen_pybind11.ysl2 b/pEpACIDgen/gen_backend/gen_pybind11.ysl2 index 25729d7..a5f77e5 100644 --- a/pEpACIDgen/gen_backend/gen_pybind11.ysl2 +++ b/pEpACIDgen/gen_backend/gen_pybind11.ysl2 @@ -4,6 +4,8 @@ tstylesheet { template "module" { document("py_module.pybind11", "text") { || + namespace py = pybind11; + // INSERT COOL ASCII ART HERE // METHOD `` apply "method" @@ -37,19 +39,19 @@ tstylesheet { [] ( ``apply "use", mode="arg_list_from_py" - ) -> pybind11::tuple + ) -> py::tuple { ``apply "return", mode="create" ``apply "use", mode="create_args_c" `apply "return", mode="assign"`::«@name»( ``apply "use", mode="arg_list_c" ); - return pybind11::make_tuple( + return py::make_tuple( `apply "return", mode="return"``if "count(use)>0" > ,` ``apply "use", mode="return_args_as_tuple" ); }, - pybind11::return_value_policy::copy); + py::return_value_policy::copy); || } @@ -67,7 +69,7 @@ tstylesheet { const "type", "@type"; choose { when "contains($type,'void')" { - > pybind11::none() + > py::none() } otherwise { choose { when "contains($type,'*')" { @@ -174,8 +176,8 @@ tstylesheet { template "struct" { || - pybind11::class_<«@name»>(m, "«@name»") - .def(pybind11::init([]() { return «@name»(); })) + py::class_<«@name»>(m, "«@name»") + .def(py::init([]() { return «@name»(); })) || apply "field" { with "structname", "@name" @@ -185,40 +187,86 @@ tstylesheet { | } + template "field" { param "structname"; - || - .def_property("«@name»", - [](::«$structname» &obj) -> «@type» { - //cout << "«$structname» ::«@name»: getter called" << endl; - return obj.«@name»; - }, - || + param "name", "@name"; + param "type", "@type"; + const "array_type", "substring-before($type, '[')"; + const "array_len", "substring-before(substring-after($type, '['),']')"; + choose { - when "@type = 'const char *'" { - || - [](::«$structname» &obj, «@type» cstr) -> void { - //cout << "«$structname»::«@name»: setter called" << cstr << endl; - obj.«@name» = strdup(cstr); - }, - pybind11::return_value_policy::copy) - || + when "string-length($array_len) > 0" { + || + .def_property("«$name»", + [](::«$structname» &obj) -> py::list { + //cout << "«$structname»::«$name»: getter called" << endl; + py::list l; + for(int i=0; i < «$array_len»; ++i) { + l.append(obj.«$name»[i]); + } + return l; + }, + [](::«$structname» &obj, py::list val) -> void { + // cout << "«$structname»::«$name»: getter called" << endl; + if(val.size() <= 0) { + // empty array given, doing nothing (static c array cant be cleared) + } else { + int cpy_amt = std::min(static_cast(val.size()), «$array_len»); + bool isUnitypedArrayOf = true; + for(int i=0; i < cpy_amt; ++i) { + if (!py::isinstance<«$array_type»>(val[i])) { + isUnitypedArrayOf = false; + break; + } + } + if(!isUnitypedArrayOf) { + cout << "«$structname»::«$name» - setter error: is not a unityped array of type «$array_type»" << std::endl; + } else { + for(int i=0; i < cpy_amt; ++i) { + obj.«$name»[i] = val[i].cast<«$array_type»>(); + } + } + } + }, + py::return_value_policy::copy) + + || } otherwise { - || - [](::«$structname» &obj, «@type» val) -> void { - //cout << "«$structname»::«@name»: setter called" << endl; - obj.«@name» = val; - }, - pybind11::return_value_policy::copy) + || + .def_property("«@name»", + [](::«$structname» &obj) -> «$type» { + //cout << "«$structname» ::«@name»: getter called" << endl; + return obj.«@name»; + }, + || + choose { + when "$type = 'const char *'" { + || + [](::«$structname» &obj, «$type» cstr) -> void { + //cout << "«$structname»::«@name»: setter called" << cstr << endl; + obj.«@name» = strdup(cstr); + }, + py::return_value_policy::copy) + || + } otherwise { + || + [](::«$structname» &obj, «$type» val) -> void { + //cout << "«$structname»::«@name»: setter called" << endl; + obj.«@name» = val; + }, + py::return_value_policy::copy) - || + || + } + } } } } template "enum" { || - pybind11::enum_<::«@name»>(m, "«@name»") + py::enum_<::«@name»>(m, "«@name»") ``apply item ;