From 6943088df18f322349987f78bfc7fcd61b8d73c4 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Fri, 9 Aug 2024 11:28:44 +0800 Subject: [PATCH] fix: fix script exporter and some script for database fix --- materializer/DataTypes.hpp | 9 +- materializer/Database.cpp | 73 +++++------ materializer/ExportScript.cpp | 229 +++++++++++++++++++--------------- script/sqlite_helper.py | 139 +++++++++++++++------ 4 files changed, 269 insertions(+), 181 deletions(-) diff --git a/materializer/DataTypes.hpp b/materializer/DataTypes.hpp index 2a43207..cf7e5bb 100644 --- a/materializer/DataTypes.hpp +++ b/materializer/DataTypes.hpp @@ -102,15 +102,16 @@ namespace VSW::Materializer::DataTypes { }; struct Table_pLink { - CK_ID input; - CK_ID output; + // Basic infos CK_ID parent; - - //additional field + // Input infos + CK_ID input; CK_ID input_obj; VSW::DataTypes::ParameterLinkIOType input_type; bool input_is_bb; int input_index; + // Output infos + CK_ID output; CK_ID output_obj; VSW::DataTypes::ParameterLinkIOType output_type; bool output_is_bb; diff --git a/materializer/Database.cpp b/materializer/Database.cpp index d23691f..fecae54 100644 --- a/materializer/Database.cpp +++ b/materializer/Database.cpp @@ -37,7 +37,8 @@ sqlite3_reset(stmt); failed: throw std::runtime_error("fail to bind value for prepared statement."); #define REVEAL_ENUM(enum_val) static_cast>(enum_val) -#define REVEAL_U8STR(u8_str) YYCC::EncodingHelper::ToOrdinary(u8_str.c_str()) +#define REVEAL_U8STR(u8_str) YYCC::EncodingHelper::ToOrdinary(u8_str.c_str()), -1, SQLITE_TRANSIENT +#define REVEAL_BLOB(blob_val) (blob_val).ptr, (blob_val).length, SQLITE_TRANSIENT #pragma endregion @@ -135,7 +136,7 @@ failed: throw std::runtime_error("fail to bind value for prepared statement."); CTOR_SQL_EXEC("CREATE TABLE [pOper] ([thisobj] INTEGER, [op] TEXT, [op_guid] TEXT, [parent] INTEGER);"); CTOR_SQL_EXEC("CREATE TABLE [eLink] ([export_obj] INTEGER, [internal_obj] INTEGER, [is_in] INTEGER, [index] INTEGER, [parent] INTEGER);"); CTOR_SQL_EXEC("CREATE TABLE [pAttr] ([thisobj] INTEGER, [name] TEXT, [type] TEXT, [type_guid] TEXT);"); - CTOR_SQL_EXEC("CREATE TABLE [data] ([field] TEXT, [data] TEXT, [parent] INTEGER);"); + CTOR_SQL_EXEC("CREATE TABLE [data] ([field] TEXT, [data] BLOB, [parent] INTEGER);"); END_CTOR; } @@ -297,9 +298,9 @@ failed: throw std::runtime_error("fail to bind value for prepared statement."); } void ScriptDatabase::Write(const DataTypes::Script::Table_data& data) { BEGIN_WRITER("INSERT INTO [data] VALUES (?, ?, ?);"); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.field.c_str(), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, data.data.c_str(), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent)); +WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.field))); +WRITER_BIND(sqlite3_bind_blob(WRITER_STMT, WRITER_INDEX, REVEAL_BLOB(data.data))); +WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.parent)); END_WRITER; } @@ -329,15 +330,15 @@ failed: throw std::runtime_error("fail to bind value for prepared statement."); void DocumentDatabase::Write(const DataTypes::Document::Table_msg& data) { BEGIN_WRITER("INSERT INTO [msg] VALUES (?, ?);"); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name))); END_WRITER; } void DocumentDatabase::Write(const DataTypes::Document::Table_obj& data) { BEGIN_WRITER("INSERT INTO [obj] VALUES (?, ?, ?, ?);"); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.id)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.classid)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.classid_name), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.classid_name))); END_WRITER; } @@ -363,12 +364,12 @@ failed: throw std::runtime_error("fail to bind value for prepared statement."); void EnvironmentDatabase::Write(const DataTypes::Environment::Table_op& data) { BEGIN_WRITER("INSERT INTO [op] VALUES (?, ?, ?, ?, ?, ?, ?);"); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_ptr), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_ptr))); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.in1_guid)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.in2_guid)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.out_guid)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.op_guid)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.op_name), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.op_name))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.op_code)); END_WRITER; } @@ -377,16 +378,16 @@ failed: throw std::runtime_error("fail to bind value for prepared statement."); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.guid)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.derived_from)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.default_size)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_CreateDefault), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_Delete), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_SaveLoad), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_Check), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_Copy), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_String), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_UICreator), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.dll_name), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_CreateDefault))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_Delete))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_SaveLoad))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_Check))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_Copy))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_String))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_UICreator))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.dll_name))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.dll_index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.position_in_dll)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.flags)); @@ -398,49 +399,49 @@ failed: throw std::runtime_error("fail to bind value for prepared statement."); void EnvironmentDatabase::Write(const DataTypes::Environment::Table_attr& data) { BEGIN_WRITER("INSERT INTO [attr] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);"); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.category_index)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.category_name), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.category_name))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.flags)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.param_index)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.param_guid)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.compatible_classid)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.default_value), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.default_value))); END_WRITER; } void EnvironmentDatabase::Write(const DataTypes::Environment::Table_plugin& data) { BEGIN_WRITER("INSERT INTO [plugin] VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.category_name), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.category_name))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.category_index)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.dll_name), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.dll_name))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.dll_index)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.position_in_dll)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.index)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.guid)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.desc), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.author), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.summary), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.desc))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.author))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.summary))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.version)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.type)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_init), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_exit), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.reader_fct), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_init))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.func_exit))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.reader_fct))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.reader_opt_count)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.reader_flags)); WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.reader_setting_param_guid)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.reader_file_ext), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.reader_file_ext))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.manager_active)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.behavior_guids), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.behavior_guids))); END_WRITER; } void EnvironmentDatabase::Write(const DataTypes::Environment::Table_variable& data) { BEGIN_WRITER("INSERT INTO [variable] VALUES (?, ?, ?, ?, ?, ?);"); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.desciption), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.name))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.desciption))); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.flags)); WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.type)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.representation), -1, SQLITE_TRANSIENT)); - WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.data), -1, SQLITE_TRANSIENT)); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.representation))); + WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.data))); END_WRITER; } diff --git a/materializer/ExportScript.cpp b/materializer/ExportScript.cpp index 11e4e7b..7059e2d 100644 --- a/materializer/ExportScript.cpp +++ b/materializer/ExportScript.cpp @@ -152,7 +152,7 @@ namespace VSW::Materializer::ExportScript { #if defined(VIRTOOLS_50) || defined(VIRTOOLS_40) || defined(VIRTOOLS_35) || t == CKPGUID_SHADER || t == CKPGUID_TECHNIQUE || t == CKPGUID_PASS #endif - || true // All unknown type goes there. + || true // All unknown type goes here. ) { // Raw data is similar with string, // but we don't need do encoding convertion. @@ -172,7 +172,7 @@ namespace VSW::Materializer::ExportScript { * pAttr do not have any explicit interface to get them, so they only can be find via pLink analyse. * 2 pLink analyse funcstions will call this function to record each pAttr. * Due to this mechanism, it might cause a duplication issues, - * so we need check possible duplication in there. + * so we need check possible duplication in here. * @param[in] expctx Reference to export context. * @param[in] ckobj Pointer to CKParameter (actually is attribute parameter) for processing. */ @@ -193,7 +193,7 @@ namespace VSW::Materializer::ExportScript { /** * @brief Generate pLink and eLink from pIn * @param[in] expctx Reference to export context. - * @param[in] ckobj Pointer to CKParameterIn for analysing. + * @param[in] analysed Pointer to CKParameterIn for analysing. * @param[in] parent * @param[in] grandparent * @param[in] pin_index @@ -201,16 +201,12 @@ namespace VSW::Materializer::ExportScript { * @param[in] is_target True if this function is called from pTarget processor. */ static void Generate_pLink(ExportContext& expctx, CKParameterIn* analysed, CK_ID parent, CK_ID grandparent, int pin_index, bool executed_from_bb, bool is_target) { - CKParameter* direct_source = NULL; - CKObject* ds_Owner = NULL; - CKParameterIn* shared_source = NULL; - CKObject* ss_Owner = NULL; - - // first, we analyse eLink. - // check whether this is export parameter and write to database. - // if the behavior graph where this pIn's parent locate, also include this pIn, - // we can simply assume there is a eLink between them - if ((static_cast(expctx.ctx->GetObjectA(grandparent)))->GetInputParameterPosition(analysed) != -1) { + // First, we analyse eLink. + // Check whether this is export parameter and write to database. + // If the behavior graph where this pIn's parent locate, also include this pIn, + // we can simply assume there is an eLink between them + CKBehavior* ckobj_grandparent = static_cast(expctx.ctx->GetObjectA(grandparent)); + if (ckobj_grandparent->GetInputParameterPosition(analysed) != -1) { expctx.cache.eLink.export_obj = analysed->GetID(); expctx.cache.eLink.internal_obj = parent; expctx.cache.eLink.is_in = true; @@ -224,109 +220,127 @@ namespace VSW::Materializer::ExportScript { } // start to analyse pLink - // first, analyse direct_src - if (direct_source = analysed->GetDirectSource()) { + // first, analyse \c direct_source + CKParameter* direct_source = analysed->GetDirectSource(); + if (direct_source != nullptr) { expctx.cache.pLink.input = direct_source->GetID(); - // for almost pin, it is connected to a pLocal, so we use a if to test it first - if (direct_source->GetClassID() == CKCID_PARAMETERLOCAL || direct_source->GetClassID() == CKCID_PARAMETERVARIABLE) { - //pLocal + + // For almost pIn, they are connected to a pLocal, so we use \c if statement to test it first + CK_CLASSID direct_source_cid = direct_source->GetClassID(); + if (direct_source_cid == CKCID_PARAMETERLOCAL || direct_source_cid == CKCID_PARAMETERVARIABLE) { + // pLocal expctx.cache.pLink.input_obj = direct_source->GetID(); // the owner of pLocal is itself. expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::PLOCAL; expctx.cache.pLink.input_is_bb = false; expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; } else { - // according to Virtools SDK document, there are 4 possible value gotten by us: - // bb pOut / pOper pOut / CKObject Attribute / CKDataArray - // however, the last 2 returned values have NOT been tested perfectly. - ds_Owner = direct_source->GetOwner(); - switch (ds_Owner->GetClassID()) { + // According to Virtools SDK document, there are 4 possible value gotten by us: + // bb pOut / pOper pOut / CKObject Attribute / CKDataArray. + // However, the last 2 returned values have NOT been tested perfectly. + CKObject* ds_owner = direct_source->GetOwner(); + switch (ds_owner->GetClassID()) { case CKCID_BEHAVIOR: - expctx.cache.pLink.input_obj = ds_Owner->GetID(); + {; + CKBehavior* ds_owner_cast = static_cast(ds_owner); + CKParameterOut* direct_source_cast = static_cast(direct_source); + expctx.cache.pLink.input_obj = ds_owner->GetID(); expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::POUT; expctx.cache.pLink.input_is_bb = true; - expctx.cache.pLink.input_index = ((CKBehavior*)ds_Owner)->GetOutputParameterPosition((CKParameterOut*)direct_source); + expctx.cache.pLink.input_index = ds_owner_cast->GetOutputParameterPosition(direct_source_cast); break; + } case CKCID_PARAMETEROPERATION: - expctx.cache.pLink.input_obj = ds_Owner->GetID(); + { + expctx.cache.pLink.input_obj = ds_owner->GetID(); expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::POUT; expctx.cache.pLink.input_is_bb = false; expctx.cache.pLink.input_index = 0; // pOper only have 1 pOut break; + } case CKCID_DATAARRAY: + { // CKDataArray, see as virtual bb pLocal shortcut expctx.cache.pLink.input_obj = direct_source->GetID(); expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::PATTR; - expctx.cache.pLink.input_is_bb = false; // omit - expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // omit + expctx.cache.pLink.input_is_bb = false; // discard + expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // discard Proc_pAttr(expctx, direct_source); break; + } default: + { // CKObject, because CKDataArray also a CKObject, so we test it first. // see as virtual bb pLocal shortcut expctx.cache.pLink.input_obj = direct_source->GetID(); expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::PATTR; - expctx.cache.pLink.input_is_bb = false; // omit - expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // omit + expctx.cache.pLink.input_is_bb = false; // discard + expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // discard Proc_pAttr(expctx, direct_source); break; + } } } } - // direct_src reflect the real source of current analysed pIn, - // however direct_src do not reflect export link - // so we need to analyse shared_src now. - // - // if this pIn has established some export relation, its shared_src must be filled. - // so we can detect it here. once its shared_src is not NULL - // we should consider export link here. - // - // we do not need to analyse any export link here, we just need to export some info - // to indicate this phenomeno. - if (shared_source = analysed->GetSharedSource()) { - //pIn from BB - expctx.cache.pLink.input = shared_source->GetID(); - ss_Owner = shared_source->GetOwner(); - expctx.cache.pLink.input_obj = ss_Owner->GetID(); - switch (ss_Owner->GetClassID()) { + // \c direct_source reflect the real source of current analysed pIn, + // however \c direct_source can not reflect export link. + // So we need to analyse \c shared_source now for export link. + // + // If this pIn has established some export relation, its \c shared_source must be filled, so we can detect this in here. + // Once its \c shared_source is not nullptr, we should consider export link in here. + // + // We do not need to analyse any export link here, + // we just need to export some infos to tell that there is an export link. + CKParameterIn* shared_source = analysed->GetSharedSource(); + if (shared_source != nullptr) { + // pIn from BB + // Get the owner of shared_source + CKObject* ss_owner = shared_source->GetOwner(); + // Setup fields + expctx.cache.pLink.input = shared_source->GetID(); + expctx.cache.pLink.input_obj = ss_owner->GetID(); + + switch (ss_owner->GetClassID()) { case CKCID_BEHAVIOR: // CKBehavior { - if (((CKBehavior*)ss_Owner)->IsUsingTarget() && (((CKBehavior*)ss_Owner)->GetTargetParameter() == shared_source)) { + CKBehavior* ss_owner_cast = static_cast(ss_owner); + if (ss_owner_cast->IsUsingTarget() && (ss_owner_cast->GetTargetParameter() == shared_source)) { // pTarget - expctx.cache.pLink.input_type = DataStruct::pLinkInputOutputType_PTARGET; + expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::PTARGET; expctx.cache.pLink.input_is_bb = true; - expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // omit + expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // discard } else { // pIn - expctx.cache.pLink.input_type = DataStruct::pLinkInputOutputType_PIN; + expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::PIN; expctx.cache.pLink.input_is_bb = true; - expctx.cache.pLink.input_index = ((CKBehavior*)ss_Owner)->GetInputParameterPosition(shared_source); + expctx.cache.pLink.input_index = ((CKBehavior*)ss_owner)->GetInputParameterPosition(shared_source); } - break; } case CKCID_PARAMETEROPERATION: // CKParameterOperation { - //pOper only have pIn. - expctx.cache.pLink.input_type = DataStruct::pLinkInputOutputType_PIN; + // pOper only can have pIn (there is no possibility to have pTarget). + CKParameterOperation* ss_owner_cast = static_cast(ss_owner); + expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::PIN; expctx.cache.pLink.input_is_bb = false; - expctx.cache.pLink.input_index = ((CKParameterOperation*)ss_Owner)->GetInParameter1() == shared_source ? 0 : 1; + expctx.cache.pLink.input_index = ss_owner_cast->GetInParameter1() == shared_source ? 0 : 1; break; } default: - // the unexpected value. according to SDK manual, - // there are only 2 possible types + // The unexpected value. + // According to SDK manual, there are only 2 possible types. + throw std::runtime_error("unexpected shared_source owner class id!"); return; } } - // if the header of pLink has been analysed successfully, + // If the head of pLink has been analysed successfully, // we can add tail info and push into database - if (shared_source != NULL || direct_source != NULL) { + if (shared_source != nullptr || direct_source != nullptr) { expctx.cache.pLink.output = analysed->GetID(); expctx.cache.pLink.output_obj = parent; - expctx.cache.pLink.output_type = is_target ? DataStruct::pLinkInputOutputType_PTARGET : DataStruct::pLinkInputOutputType_PIN; + expctx.cache.pLink.output_type = is_target ? VSW::DataTypes::ParameterLinkIOType::PTARGET : VSW::DataTypes::ParameterLinkIOType::PIN; expctx.cache.pLink.output_is_bb = executed_from_bb; expctx.cache.pLink.output_index = pin_index; expctx.cache.pLink.parent = grandparent; @@ -337,17 +351,19 @@ namespace VSW::Materializer::ExportScript { /** * @brief Generate pLink and eLink from pOut - * @param expctx - * @param analysed - * @param parent - * @param grandparent - * @param pout_index - * @param executed_from_bb + * @param[in] expctx Reference to export context. + * @param[in] analysed Pointer to CKParameterIn for analysing. + * @param[in] parent + * @param[in] grandparent + * @param[in] pout_index + * @param[in] executed_from_bb True if given CKParameterIn is belong to a CKBehavior, otherwise false (CKParamterOperation). */ static void Generate_pLink(ExportContext& expctx, CKParameterOut* analysed, CK_ID parent, CK_ID grandparent, int pout_index, bool executed_from_bb) { - // check eLink first - // check whether expoer parameter and write to database - if (((CKBehavior*)ctx->GetObject(grandparent))->GetOutputParameterPosition(analysed) != -1) { + // Check eLink first + // Check whether there is an export parameter and write to database + // Same check method as another overload + CKBehavior* ckobj_grandparent = static_cast(expctx.ctx->GetObjectA(grandparent)); + if (ckobj_grandparent->GetOutputParameterPosition(analysed) != -1) { expctx.cache.eLink.export_obj = analysed->GetID(); expctx.cache.eLink.internal_obj = parent; expctx.cache.eLink.is_in = false; @@ -359,58 +375,65 @@ namespace VSW::Materializer::ExportScript { return; } - // try generate pLink - CKParameter* cache_Dest = NULL; - CKObject* cache_DestOwner = NULL; - for (int j = 0, jCount = analysed->GetDestinationCount(); j < jCount; j++) { - cache_Dest = analysed->GetDestination(j); + // Try to generate pLink + for (int j = 0, j_count = analysed->GetDestinationCount(); j < j_count; j++) { + CKParameter* dest = analysed->GetDestination(j); expctx.cache.pLink.input = analysed->GetID(); expctx.cache.pLink.input_obj = parent; - expctx.cache.pLink.input_type = DataStruct::pLinkInputOutputType_POUT; + expctx.cache.pLink.input_type = VSW::DataTypes::ParameterLinkIOType::POUT; expctx.cache.pLink.input_is_bb = executed_from_bb; expctx.cache.pLink.input_index = pout_index; - expctx.cache.pLink.output = cache_Dest->GetID(); - if (cache_Dest->GetClassID() == CKCID_PARAMETERLOCAL) { - //pLocal - expctx.cache.pLink.output_obj = cache_Dest->GetID(); - expctx.cache.pLink.output_type = DataStruct::pLinkInputOutputType_PLOCAL; - expctx.cache.pLink.output_is_bb = false; // omit - expctx.cache.pLink.output_index = -1; // omit + expctx.cache.pLink.output = dest->GetID(); + if (dest->GetClassID() == CKCID_PARAMETERLOCAL) { + // pLocal + expctx.cache.pLink.output_obj = dest->GetID(); + expctx.cache.pLink.output_type = VSW::DataTypes::ParameterLinkIOType::PLOCAL; + expctx.cache.pLink.output_is_bb = false; // discard + expctx.cache.pLink.output_index = Utilities::INVALID_INDEX; // discard } else { - //pOut, it must belong to a graph BB (pOut can not be shared, and prototype bb or pOper do not have link-able pOut). - cache_DestOwner = cache_Dest->GetOwner(); - switch (cache_DestOwner->GetClassID()) { + // pOut. It must belong to a graph BB + // (pOut can not be shared, and prototype bb or pOper do not have linkable pOut). + CKObject* dest_owner = dest->GetOwner(); + switch (dest_owner->GetClassID()) { case CKCID_BEHAVIOR: - expctx.cache.pLink.output_obj = cache_DestOwner->GetID(); - expctx.cache.pLink.output_type = DataStruct::pLinkInputOutputType_POUT; + { + CKBehavior* dest_owner_cast = static_cast(dest_owner); + CKParameterOut* dest_cast = static_cast(dest); + expctx.cache.pLink.output_obj = dest_owner->GetID(); + expctx.cache.pLink.output_type = VSW::DataTypes::ParameterLinkIOType::POUT; expctx.cache.pLink.output_is_bb = true; - expctx.cache.pLink.output_index = ((CKBehavior*)cache_DestOwner)->GetOutputParameterPosition((CKParameterOut*)cache_Dest); + expctx.cache.pLink.output_index = dest_owner_cast->GetOutputParameterPosition(dest_cast); break; + } case CKCID_DATAARRAY: - // CKDataArray, see as virtual bb pLocal shortcut - expctx.cache.pLink.output_obj = cache_Dest->GetID(); - expctx.cache.pLink.output_type = DataStruct::pLinkInputOutputType_PATTR; - expctx.cache.pLink.input_is_bb = false; // omit - expctx.cache.pLink.input_index = -1; // omit - Proc_pAttr(ctx, mDb, cache_Dest); + { + // CKDataArray, see as virtual BB pLocal shortcut + expctx.cache.pLink.output_obj = dest->GetID(); + expctx.cache.pLink.output_type = VSW::DataTypes::ParameterLinkIOType::PATTR; + expctx.cache.pLink.input_is_bb = false; // discard + expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // discard + Proc_pAttr(expctx, dest); break; + } default: - // CKObject, because CKDataArray also a CKObject, so we test it first. - // see as virtual bb pLocal shortcut - expctx.cache.pLink.output_obj = cache_Dest->GetID(); - expctx.cache.pLink.output_type = DataStruct::pLinkInputOutputType_PATTR; - expctx.cache.pLink.input_is_bb = false; // omit - expctx.cache.pLink.input_index = -1; // omit - Proc_pAttr(ctx, mDb, cache_Dest); + { + // CKObject. Because CKDataArray also a CKObject, so we test it above this case statement. + // See this as virtual BB pLocal shortcut + expctx.cache.pLink.output_obj = dest->GetID(); + expctx.cache.pLink.output_type = VSW::DataTypes::ParameterLinkIOType::PATTR; + expctx.cache.pLink.input_is_bb = false; // discard + expctx.cache.pLink.input_index = Utilities::INVALID_INDEX; // discard + Proc_pAttr(expctx, dest); break; + } } } + // setup parent and write into database expctx.cache.pLink.parent = grandparent; - expctx.db.Write(expctx.cache.pLink); } } @@ -450,7 +473,7 @@ namespace VSW::Materializer::ExportScript { expctx.cache.pOut.parent = parent; expctx.db.Write(expctx.cache.pOut); - // try generate pLink and eLink + // try to generate pLink and eLink Generate_pLink(expctx, ckobj, parent, grandparent, index, executed_from_bb); } diff --git a/script/sqlite_helper.py b/script/sqlite_helper.py index 02260b5..e7e2494 100644 --- a/script/sqlite_helper.py +++ b/script/sqlite_helper.py @@ -1,5 +1,12 @@ +import typing +import re + +class FieldDecl(): + c_EnumTuple: typing.ClassVar[tuple[str, ...]] = ( + 'VSW::DataTypes::ParameterLinkIOType', + 'VSW::DataTypes::BehaviorLinkIOType' + ) -class DeclPair(): m_DeclType: str m_DeclName: str @@ -10,11 +17,25 @@ class DeclPair(): def is_string(self): return self.m_DeclType == 'YYCC::yycc_u8string' + def is_blob(self): + return self.m_DeclType == 'BlobDescriptor' + def is_int64(self): return self.m_DeclType == 'int64_t' + + def is_enum(self): + return self.m_DeclType in FieldDecl.c_EnumTuple -def accept_input() -> tuple[DeclPair, ...]: - cache: list[DeclPair] = list() +class StructDecl(): + m_StructName: str + m_StructFields: tuple[FieldDecl, ...] + + def __init__(self, name: str, fields: tuple[FieldDecl, ...]): + self.m_StructName = name + self.m_StructFields = fields + +def accept_input() -> str: + cache: list[str] = list() blank_line: bool = False while True: @@ -27,51 +48,93 @@ def accept_input() -> tuple[DeclPair, ...]: else: # Reset blank line flag blank_line = False - # Analyze input - recv = recv.strip('\t\r\n ') + cache.append(recv) + + return '\n'.join(cache) + +def analyse_input(val: str) -> tuple[StructDecl, ...]: + # result container + ret: list[StructDecl] = list() + # regex for capturing struct declarations + struct_matcher: re.Pattern = re.compile('struct[ \t]+([a-zA-Z0-9_]+)[ \t]+{([^}]*)};') + # regex for capturing struct field declarations + field_matcher: re.Pattern = re.compile('([a-zA-Z0-9_:]+)[ \t]+([a-zA-Z0-9_]+)[ \t]*;') + + # capture struct declaration part + found_match: re.Match + for found_match in struct_matcher.finditer(val): + # get struct name + struct_name: str = found_match.group(1) + # analyse struct body + struct_body: str = found_match.group(2) + struct_fields: list[FieldDecl] = [] + for ln in struct_body.split('\n'): # Skip annotation - if recv.startswith('//'): continue - # Skip invalid decl - if not recv.endswith(';'): continue - recv = recv[:-1] - recv_parts = recv.split(' ') - if len(recv_parts) != 2: continue - # Okey, insert it - cache.append(DeclPair(recv_parts[0], recv_parts[1])) + ln = ln.strip() + if ln.startswith('//'): continue + # Check whether it is declaration + found_field_match: re.Match = field_matcher.match(ln) + if found_field_match is not None: + field_decl_type: str = found_field_match.group(1) + field_decl_name: str = found_field_match.group(2) + struct_fields.append(FieldDecl(field_decl_type, field_decl_name)) + # add into result + ret.append(StructDecl(struct_name, tuple(struct_fields))) - return tuple(cache) + return tuple(ret) -def generate_result(decls: tuple[DeclPair, ...]) -> tuple[str, str, str]: - # generate sql statement - def conv_sql(decl_pair: DeclPair) -> str: +def output_result(decls: tuple[StructDecl, ...]) -> None: + # assistant function for sql create table statement + def conv_sql_create_table(decl_pair: FieldDecl) -> str: if decl_pair.is_string(): return f'[{decl_pair.m_DeclName}] TEXT' + elif decl_pair.is_blob(): return f'[{decl_pair.m_DeclName}] BLOB' else: return f'[{decl_pair.m_DeclName}] INTEGER' - table_string: str = ', '.join(map(conv_sql, decls)) - gen_sql_create_statement: str = f'CREATE TABLE [] ({table_string});' - - # generate sql insert_statement - table_string = ', '.join(map(lambda _: '?', decls)) - gen_sql_insert_statement: str = f'INSERT INTO [] VALUES ({table_string});' - - # generate binding c++ statement - def conv_cpp(decl_pair: DeclPair) -> str: + # assistant function for sql insert statement + def conv_sql_insert(decl_pair: FieldDecl) -> str: + return '?' + # assistant function for c++ bind statement + def conv_cpp(decl_pair: FieldDecl) -> str: if decl_pair.is_string(): - return f'WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.{decl_pair.m_DeclName}), -1, SQLITE_TRANSIENT));' + return f'WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.{decl_pair.m_DeclName})));' elif decl_pair.is_int64(): return f'WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.{decl_pair.m_DeclName}));' + elif decl_pair.is_blob(): + return f'WRITER_BIND(sqlite3_bind_blob(WRITER_STMT, WRITER_INDEX, REVEAL_BLOB(data.{decl_pair.m_DeclName})));' + elif decl_pair.is_enum(): + return f'WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_ENUM(data.{decl_pair.m_DeclName})));' else: return f'WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.{decl_pair.m_DeclName}));' - gen_bind_statement: str = '\n'.join(map(conv_cpp, decls)) - return (gen_sql_create_statement, gen_sql_insert_statement, gen_bind_statement) + ret_sql_create_table: list[str] = [] + ret_sql_insert: list[str] = [] + ret_cpp_bind: list[tuple[str, str]] = [] + for struct_decl in decls: + # generate sql create table statement + table_string: str = ', '.join(map(conv_sql_create_table, struct_decl.m_StructFields)) + gen_statement: str = f'CREATE TABLE [{struct_decl.m_StructName}] ({table_string});' + ret_sql_create_table.append(gen_statement) + + # generate sql insert statement + table_string = ', '.join(map(conv_sql_insert, struct_decl.m_StructFields)) + gen_statement = f'INSERT INTO [{struct_decl.m_StructName}] VALUES ({table_string});' + ret_sql_insert.append(gen_statement) + + # generate c++ bind statement + bind_string: str = '\n'.join(map(conv_cpp, struct_decl.m_StructFields)) + ret_cpp_bind.append((struct_decl.m_StructName, bind_string)) + + print('========== SQL Create Table ==========') + for item in ret_sql_create_table: + print(item) + print('========== SQL Insert ==========') + for item in ret_sql_insert: + print(item) + print('========== C++ Bind ==========') + for name, item in ret_cpp_bind: + print(f'===== {name} =====') + print(item) if __name__ == '__main__': - while True: - decls: tuple[DeclPair, ...] = accept_input() - (sql_create, sql_insert, cpp) = generate_result(decls) - print('SQL Create Table Statement:') - print(sql_create) - print('SQL Insert Statement:') - print(sql_insert) - print('C++ Bind Value Statements:') - print(cpp) + input_str: str = accept_input() + decls: tuple[StructDecl, ...] = analyse_input(input_str) + output_result(decls)