#include #include #include #include #include #include #include #include #include #include #include #include namespace saw { namespace binding { /** * The synchronous simple interface */ struct SyncC {}; } /** * Helper to determine if we are dealing with primitive types */ template struct c_is_primitive { static constexpr bool value = false; }; template struct c_is_primitive> { static constexpr bool value = true; }; template struct c_primitive_string { static_assert(always_false, "Not supported"); }; template<> struct c_primitive_string { static constexpr string_literal name = "int8"; static constexpr string_literal value = "int8_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "int16"; static constexpr string_literal value = "int16_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "int32"; static constexpr string_literal value = "int32_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "int64"; static constexpr string_literal value = "int64_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "uint8"; static constexpr string_literal value = "uint8_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "uint16"; static constexpr string_literal value = "uint16_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "uint32"; static constexpr string_literal value = "uint32_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "uint64"; static constexpr string_literal value = "uint64_t"; }; template<> struct c_primitive_string { static constexpr string_literal name = "float32"; static constexpr string_literal value = "float"; }; template<> struct c_primitive_string { static constexpr string_literal name = "float64"; static constexpr string_literal value = "double"; }; struct language_binding_config { std::string prefix; }; namespace impl { template struct lang_bind { static_assert(always_false, "Not supported"); }; struct language_binding_state { struct info { std::string type; }; std::map hashes; struct transpiled_element { uint32_t crc32; std::string header; std::string source; }; std::vector tp_elements; error_or find_id_by_crc32(uint32_t hash){ for(uint64_t iter = 0; iter < tp_elements.size(); ++iter){ if(tp_elements.at(iter).crc32 == hash){ return iter; } } return make_error(); } error_or add_tp_element(uint32_t hash){ uint64_t id{}; try{ language_binding_state::transpiled_element ele; ele.crc32 = hash; id = tp_elements.size(); tp_elements.emplace_back(std::move(ele)); }catch(const std::exception&){ return make_error(); } return id; } }; struct lang_bind_helper { static error_or append_string(std::string& buff, const std::string_view& str){ try { buff += str; }catch(const std::exception&){ return make_error(); } return void_t{}; } template static error_or append_translation_func(std::string& buff, const std::string_view& prefix, bool c_to_cpp, bool with_return_type = true){ constexpr uint32_t hash = schema_hash::apply(); if(with_return_type) { auto eov = lang_bind_helper::append_string(buff, "saw::error_or "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(buff, prefix, hash); if(eov.is_error()){ return eov; } } { std::string_view trans = c_to_cpp ? "_translate_c_to_cpp" : "_translate_cpp_to_c"; auto eov = lang_bind_helper::append_string(buff, trans); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "( const "); if(eov.is_error()){ return eov; } } std::string hash_type_str = std::string{prefix} + "_" + std::to_string(hash) + "_t"; /** * Lambdas */ auto c_val = [&]() -> error_or{ { auto eov = lang_bind_helper::append_string(buff, hash_type_str); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "* c_val"); if(eov.is_error()){ return eov; } } return void_t{}; }; auto cpp_val = [&]() -> error_or { { auto eov = lang_bind_helper::append_string(buff, "saw::data<"); if(eov.is_error()){ return eov; } } { std::stringstream ss; try{ { schema_stringify::apply(ss); auto eov = lang_bind_helper::append_string(buff, ss.str()); if(eov.is_error()){ return eov; } } }catch(const std::exception&){ return make_error(); } } { auto eov = lang_bind_helper::append_string(buff, ">& cpp_val"); if(eov.is_error()){ return eov; } } return void_t{}; }; if(c_to_cpp){ { auto eov = c_val(); if(eov.is_error()){ return eov; } } }else{ { auto eov = cpp_val(); if(eov.is_error()){ return eov; } } } { auto eov = lang_bind_helper::append_string(buff, ", "); if(eov.is_error()){ return eov; } } if(!c_to_cpp){ { auto eov = c_val(); if(eov.is_error()){ return eov; } } }else{ { auto eov = cpp_val(); if(eov.is_error()){ return eov; } } } { auto eov = lang_bind_helper::append_string(buff, " )"); if(eov.is_error()){ return eov; } } return void_t{}; } static error_or append_hashed_type(std::string& buff, const std::string_view& prefix, uint32_t hash){ { auto eov = append_string(buff, prefix); if(eov.is_error()){ return eov; } } { auto eov = append_string(buff, "_"); if(eov.is_error()){ return eov; } } { auto eov = append_string(buff, std::to_string(hash)); if(eov.is_error()){ return eov; } } { auto eov = append_string(buff, "_t"); if(eov.is_error()){ return eov; } } return void_t{}; } }; template struct lang_bind, binding::SyncC> { using Schema = schema::Primitive; /* static error_or generate_c_to_cpp(const language_binding_config& cfg, language_binding_state& state, const std::string_view& cpp_name, const std::string_view& c_name ){ return void_t{}; { auto eov = lang_bind_helper::append_string(src, "\t"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(src, cpp_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(src, ".set(*"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(src, c_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(src, ");\n"); if(eov.is_error()){ return eov; } } return void_t{}; } static error_or generate_cpp_to_c(buffer& src, const language_binding_config& cfg, language_binding_state& state, const std::string_view& cpp_name, const std::string_view& c_name ){ { auto eov = lang_bind_helper::append_string(src, "\t*"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(src, c_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(src, " = "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(src, cpp_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(src, ".get();\n"); if(eov.is_error()){ return eov; } } return void_t{}; } */ static error_or generate(const language_binding_config& cfg, language_binding_state& state){ constexpr uint32_t hash = schema_hash::apply(); { std::string hash_type_str = cfg.prefix + "_" + std::to_string(hash) + "_t"; auto emp = state.hashes.emplace(std::make_pair(hash, language_binding_state::info{hash_type_str})); if(emp.second) { /** * We want this id to access the vector */ auto& tpe = state.tp_elements; uint64_t id; { auto eoid = state.add_tp_element(hash); if(eoid.is_error()){ return std::move(eoid.get_error()); } id = eoid.get_value(); } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, "typedef "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, c_primitive_string::value.view()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, " "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, hash_type_str); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, ";\n"); if(eov.is_error()){ return eov; } } /** * Translation in source */ { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "namespace {\n"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_translation_func(tpe.at(id).source, cfg.prefix, true); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, " {\n\tcpp_output.set(*c_input);\n"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "\treturn void_t{};\n}\n"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_translation_func(tpe.at(id).source, cfg.prefix, false); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, " {\n\t*c_output = cpp_output.get();\n\treturn void_t{};\n}\n}"); if(eov.is_error()){ return eov; } } } } return void_t{}; } }; template struct lang_bind...>, binding::SyncC> { using Schema = schema::Struct...>; template static error_or generate_translation_func(const language_binding_config& cfg, language_binding_state& state, bool c_to_cpp, uint64_t id){ using MT = typename parameter_pack_type::type; static constexpr string_literal Lit = parameter_key_pack_type::literal; constexpr uint32_t hash = schema_hash::apply(); auto& tpe = state.tp_elements; if constexpr (i == 0){ auto eov = lang_bind_helper::append_translation_func(tpe.at(id).source, cfg.prefix, c_to_cpp); if(eov.is_error()){ return eov; } } if constexpr (i == 0) { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "{\n\t"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "{\n\t\tauto eov = "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(tpe.at(id).source, cfg.prefix, hash); if(eov.is_error()){ return eov; } } { std::string_view trans = c_to_cpp ? "_translate_c_to_cpp (" : "_translate_cpp_to_c ("; auto eov = lang_bind_helper::append_string(tpe.at(id).source, trans); if(eov.is_error()){ return eov; } } if(c_to_cpp){ auto eov = lang_bind_helper::append_string(tpe.at(id).source, "&((*c_val)."); if(eov.is_error()){ return eov; } } if(c_to_cpp){ auto eov = lang_bind_helper::append_string(tpe.at(id).source, std::string{Lit.view()}); if(eov.is_error()){ return eov; } } if(c_to_cpp){ auto eov = lang_bind_helper::append_string(tpe.at(id).source, "), cpp_val.template get<\""); if(eov.is_error()){ return eov; } } if(c_to_cpp){ auto eov = lang_bind_helper::append_string(tpe.at(id).source, std::string{Lit.view()}); if(eov.is_error()){ return eov; } } if(c_to_cpp){ auto eov = lang_bind_helper::append_string(tpe.at(id).source, "\">()"); if(eov.is_error()){ return eov; } } if(!c_to_cpp){ auto eov = lang_bind_helper::append_string(tpe.at(id).source, " cpp_val.template get<\""); if(eov.is_error()){ return eov; } } if(!c_to_cpp){ auto eov = lang_bind_helper::append_string(tpe.at(id).source, std::string{Lit.view()}); if(eov.is_error()){ return eov; } } if(!c_to_cpp){ auto eov = lang_bind_helper::append_string(tpe.at(id).source, "\">(), &((*c_val)."); if(eov.is_error()){ return eov; } } if(!c_to_cpp){ auto eov = lang_bind_helper::append_string(tpe.at(id).source, std::string{Lit.view()}); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, ") );\n\t\t");//cpp_output.set(*c_input);\n"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "if(eov.is_error()) return eov.get_error();\n\t}\n\t");//cpp_output.set(*c_input);\n"); if(eov.is_error()){ return eov; } } if constexpr ( (i+1) < sizeof...(V) ){ return generate_translation_func(cfg, state, c_to_cpp, id); } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "return void_t{};\n}\n"); if(eov.is_error()){ return eov; } } return void_t{}; } template static error_or generate_ele(const language_binding_config& cfg, language_binding_state& state, uint64_t id){ using MT = typename parameter_pack_type::type; static constexpr string_literal Lit = parameter_key_pack_type::literal; constexpr uint32_t hash = schema_hash::apply(); /** * Generate struct member definition. */ auto& tpe = state.tp_elements; { auto eov = lang_bind_helper::append_string(tpe.at(id).header, "\t"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(tpe.at(id).header, cfg.prefix, hash); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, " "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, Lit.view()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, ";\n"); if(eov.is_error()){ return eov; } } /** * Generate translation element */ { } /** * Ensure generation of dependent types */ { auto eov = lang_bind::generate(cfg, state); if(eov.is_error()){ return eov; } } if constexpr ( (i+1) < sizeof...(V) ){ return generate_ele(cfg, state, id); } return void_t{}; } static error_or generate(const language_binding_config& cfg, language_binding_state& state){ constexpr uint64_t hash = schema_hash::apply(); std::string hash_type_str = cfg.prefix + "_" + std::to_string(hash) + "_t"; auto emp = state.hashes.emplace(std::make_pair(hash, language_binding_state::info{hash_type_str})); /** * If successful insertion did happen that means we have no struct def yet. */ if(emp.second){ /** * Generate struct type */ auto& tpe = state.tp_elements; uint64_t id; { auto eoid = state.add_tp_element(hash); if(eoid.is_error()){ return std::move(eoid.get_error()); } id = eoid.get_value(); } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, "struct "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(tpe.at(id).header, cfg.prefix, hash); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, " {\n"); if(eov.is_error()){ return eov; } } /** * Generate translation element */ { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "namespace {\n"); if(eov.is_error()){ return eov; } } if constexpr ( sizeof...(V) > 0 ) { auto eov = generate_translation_func<0>(cfg, state, true, id); if(eov.is_error()){ return eov; } } if constexpr ( sizeof...(V) > 0 ) { auto eov = generate_translation_func<0>(cfg, state, false, id); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "}\n"); if(eov.is_error()){ return eov; } } if constexpr ( sizeof...(V) > 0 ) { auto eov = generate_ele<0>(cfg, state, id); } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, "};\n"); if(eov.is_error()){ return eov; } } } return void_t{}; } }; template struct lang_bind, binding::SyncC> { using Schema = schema::Array; static_assert(is_primitive::value, "Currently only primitive type arrays are supported"); static error_or generate(const language_binding_config& cfg, language_binding_state& state){ constexpr uint32_t hash = schema_hash::apply(); std::string hash_type_str = cfg.prefix + "_" + std::to_string(hash) + "_t"; auto emp = state.hashes.emplace(std::make_pair(hash, language_binding_state::info{hash_type_str})); if(emp.second){ auto& tpe = state.tp_elements; uint64_t id; { auto eoid = state.add_tp_element(hash); if(eoid.is_error()){ return std::move(eoid.get_error()); } id = eoid.get_value(); } /** * Generate struct type */ { auto eov = lang_bind_helper::append_string(tpe.at(id).header, "struct "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(tpe.at(id).header, cfg.prefix, hash); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, " {\n\t"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(tpe.at(id).header, cfg.prefix, schema_hash::apply()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, "* data;\n\t"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(tpe.at(id).header, cfg.prefix, schema_hash::apply()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, " length;\n};\n"); if(eov.is_error()){ return eov; } } /** * Guarante existance of length type */ { auto eov = lang_bind::generate(cfg, state); if(eov.is_error()){ return eov; } } /** * Guarante existance of inner type */ { auto eov = lang_bind::generate(cfg, state); if(eov.is_error()){ return eov; } } /** * Source */ { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "namespace {\n"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_translation_func(tpe.at(id).source, cfg.prefix, true); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, " {\n\ttry{\n\t\tcpp_val = {c_val->length};\n\t}catch(const std::exception&){return saw::make_error();}\n\n\tfor(uint64_t i = 0u; i < cpp_val.size(); ++i){\n\t\tcpp_val.at(i).set(c_val[i]);\n\t}\n\n\treturn void_t{};\n}\n"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_translation_func(tpe.at(id).source, cfg.prefix, false); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, " {\n\treturn saw::make_error();\n}\n"); } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "\n}\n"); if(eov.is_error()){ return eov; } } } return void_t{}; } }; /** * Generates the Function bindings to C */ template struct lang_bind, binding::SyncC> { using Schema = schema::Function; /** * Appends the function declaration e.g. 'int foo(const int* a, int* b)' */ static error_or append_function_def(std::string& buff, const language_binding_config& cfg, language_binding_state& state, const std::string_view& f_name){ /** * Generate the base function declaration */ { auto eov = lang_bind_helper::append_string(buff, "int "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, " ( "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_context* ctx, const "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_input_t* input, "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(buff, "_output_t* output )"); if(eov.is_error()){ return eov; } } return void_t{}; } static error_or guarantee(const language_binding_config& cfg, language_binding_state& state){ /** * Ensure existence of input and output types. * Order is not important since moving to multiple strings which get concat'ed. */ { auto eov = lang_bind::generate(cfg, state); if(eov.is_error()){ return eov; } } { auto eov = lang_bind::generate(cfg, state); if(eov.is_error()){ return eov; } } return void_t{}; } /** * Hook for the interface lang_bind class. * It's the only class which is out of place with its generate function. * The issue being that it's deeply entrenched into the function names from the * interface level. * On one hand the Interface shouldn't generate the functions themselves. * On the other hand the Functions need Interface information */ static error_or generate(const language_binding_config& cfg, language_binding_state& state, const std::string_view& f_name, const uint64_t& f_id){ constexpr uint64_t output_hash = schema_hash::apply(); auto& tpe = state.tp_elements; /** * Source */ { auto eov = append_function_def(tpe.at(f_id).source, cfg, state, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "{\n\tif(!ctx || !(ctx->ctx)) return -1;\n\tif(!input) return -1;\n\tif(!output) return -1;\n"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "\n\tauto& iface = "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "_get_cpp_interface_priv(*ctx);\n\t"); if(eov.is_error()){ return eov; } } /** * Check declarations and definitions. * Translate input. */ { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "saw::data<"); if(eov.is_error()){ return eov; } } { std::stringstream ss; try{ { schema_stringify::apply(ss); auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, ss.str()); if(eov.is_error()){ return eov; } } }catch(const std::exception&){ return make_error(); } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "> cpp_input_root;\n"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "\t{\n\t\tauto eov = "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(tpe.at(f_id).source, cfg.prefix, schema_hash::apply()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "_translate_c_to_cpp(c_input, cpp_input_root);\n\t\tif(eov.is_error()) return eov.get_error().get_code();\n\t}\n"); if(eov.is_error()){ return eov; } } /** * Call the c++ implementation */ { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "\n\tauto eoc = iface.template call<\""); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "\">(std::move(cpp_input_root));\n"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "\tif(eoc.is_error()){\n\t\tauto& err = eoc.get_error();\n\t\treturn err.get_code();\n\t}\n\tauto& cpp_output_root = eoc.get_value();\n\n"); if(eov.is_error()){ return eov; } } /** * Translate back to C */ { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "\t{\n\t\tauto eov = "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(tpe.at(f_id).source, cfg.prefix, schema_hash::apply()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "_translate_cpp_to_c(cpp_output_root, output);\n\t\tif(eov.is_error()) return eov.get_error().get_code();\n\t}\n"); if(eov.is_error()){ return eov; } } /** * End source declaration */ { auto eov = lang_bind_helper::append_string(tpe.at(f_id).source, "\treturn 0;\n}\n\n"); if(eov.is_error()){ return eov; } } /** * Header */ { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, "typedef "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(tpe.at(f_id).header, cfg.prefix, schema_hash::apply()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, " "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, "_"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, "_input_t;\n"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, "typedef "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_hashed_type(tpe.at(f_id).header, cfg.prefix, schema_hash::apply()); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, " "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, "_"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, "_output_t;\n"); if(eov.is_error()){ return eov; } } /** * Function generations */ { auto eov = append_function_def(tpe.at(f_id).header, cfg, state, f_name); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(f_id).header, ";\n\n"); if(eov.is_error()){ return eov; } } return void_t{}; } }; template struct lang_bind, binding::SyncC> { using Schema = schema::Interface; template static error_or guarantee_element(const language_binding_config& cfg, language_binding_state& state){ using Member = typename parameter_pack_type::type; using MValue = typename Member::ValueType; /** * Guarantee */ { auto eov = lang_bind::guarantee(cfg, state); if(eov.is_error()){ return eov; } } if constexpr ( (i+1u) < sizeof...(M) ){ return guarantee_element(cfg, state); } return void_t{}; } template static error_or generate_element(const language_binding_config& cfg, language_binding_state& state){ using Member = typename parameter_pack_type::type; using MValue = typename Member::ValueType; static constexpr string_literal MKey = Member::KeyLiteral; constexpr uint64_t hash = schema_hash::apply(); std::string hash_type_str = cfg.prefix + "_" + std::to_string(hash) + "_t"; auto emp = state.hashes.emplace(std::make_pair(hash, language_binding_state::info{hash_type_str})); if(!emp.second){ return make_error("Function should be guaranteed to be unique"); } /** * Adding Function to def */ uint64_t f_id; { auto eoid = state.add_tp_element(hash); if(eoid.is_error()){ return std::move(eoid.get_error()); } f_id = eoid.get_value(); } { auto eov = lang_bind::generate(cfg, state, MKey.view(), f_id); if(eov.is_error()){ return eov; } } if constexpr ((i+1) < sizeof...(M) ){ return generate_element(cfg, state); } return void_t{}; } static error_or generate(buffer& head, buffer& src, const language_binding_config& cfg){ if(cfg.prefix.size() == 0){ return make_error("C interfaces need a prefix."); } constexpr uint64_t hash = schema_hash::apply(); language_binding_state state; if constexpr (sizeof...(M) > 0){ { auto eov = generate_element<0>(cfg, state); if(eov.is_error()){ return eov; } } { auto eov = guarantee_element<0>(cfg, state); if(eov.is_error()){ return eov; } } } /** * Setup context creation to bind interface to a context */ auto& tpe = state.tp_elements; uint64_t id; { auto eoid = state.add_tp_element(hash); if(eoid.is_error()){ return std::move(eoid.get_error()); } id = eoid.get_value(); } /** * Interface type helper */ { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "namespace {\nnamespace schema {\n"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "using InterfaceType = "); if(eov.is_error()){ return eov; } } { std::stringstream ss; schema_stringify>::apply(ss); try { auto eov = lang_bind_helper::append_string(tpe.at(id).source, ss.str()); if(eov.is_error()){ return eov; } }catch(const std::exception&){ return make_error("No memory after stringification"); } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, ";\n}\n}\n\n"); if(eov.is_error()){ return eov; } } /** * Context definition */ /// @todo Add Macro which reduces typing time ? Not really that much shorter :/ // SAW_CALL_AND_RETURN_ON_ERROR(lang_bind_helper::append_string(head, "struct ")); { auto eov = lang_bind_helper::append_string(tpe.at(id).header, "struct "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, "_context {\n\tvoid* ctx;\n};\n\n"); if(eov.is_error()){ return eov; } } /** * Create and destroy declaration */ auto ctx_func = [&](std::string_view str) -> error_or{ { auto eov = lang_bind_helper::append_string(tpe.at(id).header, "int "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, "_context_"); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, str); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, " ( "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).header, "_context* ctx );\n\n"); if(eov.is_error()){ return eov; } } return void_t{}; }; { auto eov = ctx_func("create"); if(eov.is_error()){ return eov; } } { auto eov = ctx_func("destroy"); if(eov.is_error()){ return eov; } } /** * Create a casting helper in sources for the interface type */ { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "saw::interface& "); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "_get_cpp_interface_priv("); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, cfg.prefix); if(eov.is_error()){ return eov; } } { auto eov = lang_bind_helper::append_string(tpe.at(id).source, "& ctx){\n\treturn *reinterpret_cast*>(ctx.ctx);\n}\n\n"); if(eov.is_error()){ return eov; } } try{ for(auto iter = state.tp_elements.rbegin(); iter != state.tp_elements.rend(); ++iter){ for(auto c : iter->source){ auto err = src.push(c); if(!err.template is_type()){ return err; } } { auto err = src.push('\n'); if(!err.template is_type()){ return err; } } for(auto c : iter->header){ auto err = head.push(c); if(!err.template is_type()){ return err; } } { auto err = head.push('\n'); if(!err.template is_type()){ return err; } } } } catch(const std::exception&){ return make_error(); } return void_t{}; } }; } template struct language_binding { static_assert(always_false, "Case not supported."); }; template struct language_binding { static error_or generate(buffer& buff, buffer& src, const language_binding_config& cfg){ return impl::lang_bind::generate(buff, src, cfg); } }; }