//+------------------------------------------------------------------+ //| Query.mqh | //| Copyright 2026, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MetaQuotes Ltd." #property link "https://www.mql5.com" #property strict //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "Parser.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ namespace TSN { class CSLDomQuery; //--- typedef void(*CSLQueryFunc)(CSLDomQuery* state); //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CSLDomQuery : public CSLDomQueryCompiler { private: //--- Dom CDomNodeManager* m_dom; //--- Bytecode long m_bytecode[]; int m_bytecode_s; int m_bytecode_r; //--- Funciones CSLQueryFunc m_funcs[128]; int m_funcs_size; //--- Iteracion //- iteracion de obj CHashMapFastIterator(string, CDomNodeBase*) m_stack_it_obj[TSN_DOMPATH_MAX_DEPTH_ITER]; //- iteracion de array int m_stack_it_ix[TSN_DOMPATH_MAX_DEPTH_ITER]; int m_stack_it_k[TSN_DOMPATH_MAX_DEPTH_ITER]; int m_stack_it_count[TSN_DOMPATH_MAX_DEPTH_ITER]; //- cacheables int m_stack_it_curr; //--- Registros constantes DomConstantStr m_rk_str[TSN_DOMPATH_MAX_S_RK]; DomPathV m_rk[TSN_DOMPATH_MAX_S_RK]; int m_rk_s; //--- Registros dinamicos CDomNodeBase* m_dnodes[TSN_DOMPATH_MAX_S_R]; int m_dnodes_size; string m_sreg[TSN_DOMPATH_MAX_S_R]; int m_sreg_s; DomPathV m_reg[TSN_DOMPATH_MAX_S_R]; int m_reg_s; //--- Call frame actual int m_num_args; int m_reg_start; //--- Actual ulong m_current_hash; CDomNodeBase* m_curr; bool m_last_bool_r; //CDomNodeBase* m_root; //--- int m_ip; public: CSLDomQuery(void) {} ~CSLDomQuery(void) {} bool Run(CDomNodeBase& *elemts[]); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ struct DomConstantStr { uchar arr[]; int len; bool operator=(const string& other) { const int l = StringLen(other); if(l != len) return false; int k = 0; for(int i = start; i < start + len; i++) if(arr[i] != other[k++]) return false; return true; } bool operator<(const string& other) { const int l = StringLen(other); if(l != len) return true; int k = 0; for(int i = start; i < start + len; i++) if(arr[i] < other[k++]) return true; return false; } bool operator<=(const string& other) { const int l = StringLen(other); if(l != len) return true; int k = 0; for(int i = start; i < start + len; i++) if(arr[i] <= other[k++]) return true; return false; } }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ //--- #define TSN_DOMPATH_DO_MATH_TYPED_ALL(B, C, OP) \ switch(B.tt) \ { \ case DOMPATHV_TYPE_BOL: \ B.v.bv OP= (C.tt == DOMPATHV_TYPE_FLT ? (bool)C.v.dv : C.v.bv); \ m_ip++; \ break; \ case DOMPATHV_TYPE_INT: \ B.v.iv OP= (C.tt == DOMPATHV_TYPE_FLT ? (long)C.v.dv : C.v.iv); \ m_ip++; \ break; \ case DOMPATHV_TYPE_FLT: \ B.v.dv OP= (C.tt != DOMPATHV_TYPE_FLT ? (double)C.v.lv : C.v.dv); \ m_ip++; \ break; \ default: \ m_ip = int(m_bytecode[m_ip+1] >> TSN_DOMPATH_BIT_INS_JUMP_START_MATHERR); \ break; \ } //--- #define TSN_DOMPATH_DO_MATH_TYPED_INTEGER(B, C, OP) \ switch(B.tt) \ { \ case DOMPATHV_TYPE_BOL: \ B.v.bv OP= C.v.bv; \ m_ip++; \ break; \ case DOMPATHV_TYPE_INT: \ B.v.iv OP= C.v.iv; \ m_ip++; \ break; \ default: \ m_ip = int(m_bytecode[m_ip+1] >> TSN_DOMPATH_BIT_INS_JUMP_START_MATHERR); \ break; \ } //--- #define TSN_DOMPATH_DEFINE_MATH_OP(OP, FUNC) \ const long l = m_bytecode[m_ip];\ const int b = int(l >> TSN_DOMPATH_BIT_INS_ETYPE) & TSN_DOMPATH_INS_MASK_INDEX_REG; \ switch(uchar(m_bytecode[m_ip+1]&2)) \ { \ case TSN_DOMPATH_INS_MATH_TYPE_DS: \ { \ const TSNDomPathValues c = m_rk[int(l >> TSN_DOMPATH_INS_MATH_BIT_START_REG_2)]; \ FUNC(m_reg[b], c, OP) \ break; \ } \ case TSN_DOMPATH_INS_MATH_TYPE_SD: \ { \ const TSNDomPathValues c = m_reg[int(l >> TSN_DOMPATH_INS_MATH_BIT_START_REG_2)]; \ FUNC(m_rk[b], c, OP) \ break; \ } \ case TSN_DOMPATH_INS_MATH_TYPE_DD: \ { \ const TSNDomPathValues c = m_reg[int(l >> TSN_DOMPATH_INS_MATH_BIT_START_REG_2)]; \ FUNC(m_reg[b], c, OP) \ break; \ } \ default:\ break;\ } \ //--- // string solo comparcion con srting no hay casteo implciito #define TSN_DOMPATH_DO_COMP_TYPED_ALL(B, C, OP, bstring_reg, cstring_reg) \ switch(B.tt) \ { \ case DOMPATHV_TYPE_BOL: \ res = (B.v.bv OP (C.tt == DOMPATHV_TYPE_FLT ? (bool)C.v.dv : C.v.bv)); \ break; \ case DOMPATHV_TYPE_INT: \ res = (B.v.iv OP (C.tt == DOMPATHV_TYPE_FLT ? (long)C.v.dv : C.v.iv)); \ break; \ case DOMPATHV_TYPE_FLT: \ res = (B.v.dv OP (C.tt != DOMPATHV_TYPE_FLT ? (double)C.v.lv : C.v.dv)); \ break; \ case DOMPATHV_TYPE_STR: \ {\ if(C.tt!=DOMPATHV_TYPE_STR)\ break; \ res = (bstring_reg[B.v.ix] OP cstring_reg[C.v.ix]) + 1; \ break; \ } \ default: \ break; \ } //--- #define TSN_DOMPATH_DEFINE_BOOL_OP(OP) \ bool res=false;\ const long l = m_bytecode[m_ip];\ const int b = int(l >> TSN_DOMPATH_BIT_INS_ETYPE) & TSN_DOMPATH_INS_MASK_INDEX_REG; \ switch(uchar(m_bytecode[m_ip+1]&2)) \ { \ case TSN_DOMPATH_INS_MATH_TYPE_DS: \ { \ const TSNDomPathValues c = m_rk[int(l >> TSN_DOMPATH_INS_MATH_BIT_START_REG_2)]; \ TSN_DOMPATH_DO_COMP_TYPED_ALL(m_reg[b], c, OP, m_reg_s) \ break; \ } \ case TSN_DOMPATH_INS_MATH_TYPE_SD: \ { \ const TSNDomPathValues c = m_reg[int(l >> TSN_DOMPATH_INS_MATH_BIT_START_REG_2)]; \ TSN_DOMPATH_DO_COMP_TYPED_ALL(m_rk[b], c, OP, m_rk_s) \ break; \ } \ case TSN_DOMPATH_INS_MATH_TYPE_DD: \ { \ const TSNDomPathValues c = m_reg[int(l >> TSN_DOMPATH_INS_MATH_BIT_START_REG_2)]; \ TSN_DOMPATH_DO_COMP_TYPED_ALL(m_reg[b], c, OP, m_reg_s) \ break; \ } \ default:\ break;\ } \ m_ip++;\ if(res == bool((m_bytecode[m_ip] >> TSN_DOMPATH_BIT_INS_JUMP_START_CMP_V) & 1))\ m_ip++;\ else\ m_ip = int(m_bytecode[m_ip] >> TSN_DOMPATH_BIT_INS_JUMP_START_CMPFALSE) & TSN_DOMPATH_BIT_INS_JUMP_START_MATHERR; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CSLDomQuery::Run(CDomNodeBase& *elemts[]) { //--- m_ip = 0; //--- while(m_ip < m_bytecode_s) { switch(uchar(m_bytecode[m_ip]&TSN_DOMPATH_MASK_INS_TYPE)) { //--- Acceso // Acceso normal en iteracion case DOMPATH_QUERY_INS_TYPE_ACCESO_KEY: { // accceso directo por hash 64 m_curr = m_curr.Get((ulong)m_bytecode[m_ip + 1]); if(m_curr == NULL) { // JUMP explicito a direccion especificada. break; } break; } // Acceso F case DOMPATH_QUERY_INS_TYPE_ACCESO_KEY_F: { // accceso directo por hash 64 m_curr = m_curr.Get((ulong)m_bytecode[m_ip + 1]); if(m_curr == NULL) return; // place holder.. aqui seria finalizar de una break; } case DOMPATH_QUERY_INS_TYPE_ACCESO_IDX: { m_curr = m_curr.AtSafe(m_bytecode[m_ip++] >> TSN_DOMPATH_BIT_INS_ETYPE); // Acceso if(m_curr == NULL) { // JUMP explicito a direccion especificada. break; } break; } case DOMPATH_QUERY_INS_TYPE_ACCESO_IDX_F { m_curr = m_curr.AtSafe(m_bytecode[m_ip++] >> TSN_DOMPATH_BIT_INS_ETYPE); // Acceso if(m_curr == NULL) return; // aqui seria finalizar directo.. break; } //--- Iniciar iteracion case DOMPATH_QUERY_INS_TYPE_INICIAR_ITERACION: { m_stack_it_curr++; if(m_curr.m_type == TSN_SBL_BASE_TYPE_OBJ) { m_stack_it_obj[m_stack_it_curr] = m_curr.BenginIteration(); } else { //falta } break; } case DOMPATH_QUERY_INS_TYPE_ITER_ASSING: { if(m_curr.m_type == TSN_SBL_BASE_TYPE_OBJ) { if(m_stack_it_obj[m_stack_it_curr].IsValid()) { m_current_hash = m_stack_it_obj[m_stack_it_curr].Hash(); m_curr = m_stack_it_obj[m_stack_it_curr].Val(); m_stack_it_obj[m_stack_it_curr].Next(); m_ip++; // Siguiente instrucciones } else // SI no es valido { // Saltamos a donde se diga m_ip = int(m_bytecode[m_ip] >> TSN_DOMPATH_BIT_INS_ETYPE); } } else { //falta } break; } //--- case DOMPATH_QUERY_INS_TYPE_EXIST: { // 2 slots // expectred [type=8 1 slot][hash=64] (cada [] es un slot) m_last_bool_r = (m_current_hash == (ulong)m_bytecode[m_ip + 1]); break; } //--- save basico para nativos case DOMPATH_QUERY_INS_TYPE_SAVE: { // [8type][28=k][28=jump] const int k = int(m_bytecode[m_ip] >> TSN_DOMPATH_BIT_INS_ETYPE) & TSN_DOMPATH_INS_MASK_INDEX_REG; switch(m_curr.m_type) { case TSN_SBL_BASE_TYPE_OBJ: m_reg[k].tt = DOMPATHV_TYPE_OBJ; m_reg[k].v.ix = m_dnodes_size; m_dnodes[m_dnodes_size++] = m_curr; break; case TSN_SBL_BASE_TYPE_ARR: m_reg[k].tt = DOMPATHV_TYPE_ARR; m_reg[k].v.ix = m_dnodes_size; m_dnodes[m_dnodes_size++] = m_curr; break; case TSN_SBL_BASE_TYPE_INT: m_reg[k].v.iv = m_curr.m_v.iv; m_reg[k].tt = DOMPATHV_TYPE_INT; break; case TSN_SBL_BASE_TYPE_FLT: m_reg[k].v.dv = m_curr.m_v.dv; m_reg[k].tt = DOMPATHV_TYPE_FLT; break; case TSN_SBL_BASE_TYPE_BOL: m_reg[k].v.bv = m_curr.m_v.bv; m_reg[k].tt = DOMPATHV_TYPE_BOL; break; case TSN_SBL_BASE_TYPE_STR: m_reg[k].tt = DOMPATHV_TYPE_BOL; m_reg[k].v.ix = m_sreg_s; m_reg_s[m_sreg_s++] = m_curr.m_ctx.m_string_stack[m_curr.m_v.ix]; break; default: { // Nota que solo los valores normales como string\int se guranda en reg // Los otros como arr tambien pero solo se almacnea us nodo su unica utilidad es para funciones.. // Tipo invalido null // Aqui un jump a direccion especificada break; } } break; } //--- math // math entero usa 2 slots.. para sus intrucciones // [type][28][28] | [2][28] // 8 bits type, 28 valor 1, 28 valor ahora para el siuient eslot solo es de qeu tipo es.. (sd\ds\.etc..) // 28 bits ultimso a donde salta case DOMPATH_QUERY_INS_TYPE_M_MUL: { TSN_DOMPATH_DEFINE_MATH_OP(*, TSN_DOMPATH_DO_MATH_TYPED_ALL) break; } case DOMPATH_QUERY_INS_TYPE_M_RES: { TSN_DOMPATH_DEFINE_MATH_OP(-, TSN_DOMPATH_DO_MATH_TYPED_ALL) break; } case DOMPATH_QUERY_INS_TYPE_M_DIV: { TSN_DOMPATH_DEFINE_MATH_OP( /, TSN_DOMPATH_DO_MATH_TYPED_ALL) break; } case DOMPATH_QUERY_INS_TYPE_M_SUM: { //TSN_DOMPATH_DEFINE_MATH_OP(*) break; } case DOMPATH_QUERY_INS_TYPE_M_MOD: { TSN_DOMPATH_DEFINE_MATH_OP( %, TSN_DOMPATH_DO_MATH_TYPED_INTEGER) break; } case DOMPATH_QUERY_INS_TYPE_M_BIT_OR: { TSN_DOMPATH_DEFINE_MATH_OP( |, TSN_DOMPATH_DO_MATH_TYPED_INTEGER) break; } case DOMPATH_QUERY_INS_TYPE_M_BIT_AND: { TSN_DOMPATH_DEFINE_MATH_OP(&, TSN_DOMPATH_DO_MATH_TYPED_INTEGER) break; } case DOMPATH_QUERY_INS_TYPE_M_BIT_XOR: { TSN_DOMPATH_DEFINE_MATH_OP(^, TSN_DOMPATH_DO_MATH_TYPED_INTEGER) break; } case DOMPATH_QUERY_INS_TYPE_M_BIT_DEZ_IZQ: { TSN_DOMPATH_DEFINE_MATH_OP( <<, TSN_DOMPATH_DO_MATH_TYPED_INTEGER) break; } case DOMPATH_QUERY_INS_TYPE_M_BIT_DEZ_DRC: { TSN_DOMPATH_DEFINE_MATH_OP( >> TSN_DOMPATH_DO_MATH_TYPED_INTEGER) break; } //--- Operaciones de compracion // [type][28][28] | [2][28][1] //--- Cmp (comparaciones..) case DOMPATH_QUERY_INS_TYPE_COMPARE_EQ: { TSN_DOMPATH_DEFINE_BOOL_OP( ==) break; } case DOMPATH_QUERY_INS_TYPE_COMPARE_MENOR: { TSN_DOMPATH_DEFINE_BOOL_OP( <) break; } case DOMPATH_QUERY_INS_TYPE_COMPARE_MENOR_EQ: { TSN_DOMPATH_DEFINE_BOOL_OP( <=) break; } case DOMPATH_QUERY_INS_TYPE_COMPARE_IS: { //--- [8bytes][KIndex=28][28] | [1 bit = resultado esperado] bool res = false; const int k = int(m_bytecode[m_ip] >> TSN_DOMPATH_BIT_INS_ETYPE) & TSN_DOMPATH_INS_MASK_INDEX_REG; switch(m_curr.m_type) { case TSN_SBL_BASE_TYPE_INT: res = m_reg[k].v.iv != 0; break; case TSN_SBL_BASE_TYPE_FLT: res = m_reg[k].v.dv != 0; break; case TSN_SBL_BASE_TYPE_BOL: res = m_reg[k].v.bv; break; case TSN_SBL_BASE_TYPE_STR: res = m_sreg[m_reg[k].v.ix].Length() != 0; break; default: break; } //--- m_ip++; if(res == bool(m_bytecode[m_ip])) m_ip++; // sigueinte normal else m_ip = int(m_bytecode[m_ip] >> TSN_DOMPATH_BIT_INS_JUMP_START_CMPIS_FALSE); // saltamos break; } //--- case DOMPATH_QUERY_INS_TYPE_CALL: { // [8type][28=direecion donde poner el valor final][28 numero de argumentos] // [indice de funcion] (slot completo) m_reg_start = int(m_bytecode[m_ip] >> TSN_DOMPATH_BIT_INS_ETYPE) & TSN_DOMPATH_INS_MASK_INDEX_REG; m_num_args = int(m_bytecode[m_ip] >> TSN_DOMPATH_BIT_INS_BIT_START_NARGS); m_ip++; m_funcs[m_bytecode[m_ip]](&this); // llamamos // ahora ya se sape que la funcion escrbiio un valor en dicho registro m_ip++; // Siguiente insturccion break; } //---- case DOMPATH_QUERY_INS_TYPE_LOADK: { // [8type][28dirrecion donde se copia reg][28 dirrecion src kreg] m_reg[int(m_bytecode[m_ip] >> TSN_DOMPATH_BIT_INS_ETYPE) & TSN_DOMPATH_INS_MASK_INDEX_REG] = m_rk[int(m_bytecode[m_ip] >> TSN_DOMPATH_BIT_INS_BIT_START_NARGS)]; m_ip++; break; } //--- Finaes case DOMPATH_QUERY_INS_TYPE_APPEND: { break; } case DOMPATH_QUERY_INS_TYPE_SALIDA: return true; default: return false; } } } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+