//+------------------------------------------------------------------+ //| JsonAsm.mqh | //| Copyright 2026, Niquel Mendoza. | //| https://www.mql5.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Niquel Mendoza." #property link "https://www.mql5.com/" #property strict #ifndef JSONPARSERBYLEO_SRC_JSONASM_MQH #define JSONPARSERBYLEO_SRC_JSONASM_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "JsonParser.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ namespace TSN { //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CJsonParser::ToJsonAsm(uchar& text[]) const { //--- int p = 0; // Lectura de cinta int w = 0; // Escritura en text //--- ArrayResize(text, (m_len << 1)); //--- Pila de posiciones de "muerte" (en slots de cinta) de cada ARR/OBJ abierto int end_stack[512]; int stack_curr = -1; //--- while(p < m_cinta_pos) { //--- const ENUM_JSON_VTYPE tipo = ENUM_JSON_VTYPE(m_cinta[p] & 0xF); //--- switch(tipo) { //--- case JSON_VTYPE_KEY: { // KEY 1 slot: [tipo(4)|len(28low)|start(32high)] (igual que STRING) const int s = int(m_cinta[p] >> TSN_SBL_BIT_STR_START); const int slen = int((m_cinta[p] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); text[w++] = 'K'; text[w++] = ' '; text[w++] = '"'; w += ArrayCopy(text, m_raw, w, s, slen); text[w++] = '"'; text[w++] = '\n'; break; } //--- case JSON_VTYPE_OBJ: case JSON_VTYPE_ARR: { text[w++] = tipo == JSON_VTYPE_ARR ? 'A' : 'O'; text[w++] = ' '; text[w++] = '\n'; //--- num_c = slots de cinta que ocupa este contenedor completo (incluyéndose a sí mismo) const int num_c = int(m_cinta[p] >> TSN_SBL_BIT_START_NUM_C); //--- Apilamos dónde "muere" este nivel, no cuántos elementos le faltan stack_curr++; end_stack[stack_curr] = p + num_c; break; } case JSON_VTYPE_INTEGER: { text[w++] = 'R'; text[w++] = ' '; long num = m_cinta[p + 1]; if(num == 0) { text[w++] = '0'; } else { w += StringToCharArray(string(num), text, w, WHOLE_ARRAY, CP_UTF8) - 1; } //--- text[w++] = '\n'; text[w++] = '-'; text[w++] = '\n'; break; } //--- case JSON_VTYPE_REAL: { //--- static BitInterpreter bit; bit.long_value = m_cinta[p + 1]; double num = bit.double_value; //--- text[w++] = 'R'; text[w++] = ' '; w += StringToCharArray(string(num), text, w, WHOLE_ARRAY, CP_UTF8) - 1; //--- text[w++] = '\n'; text[w++] = '-'; text[w++] = '\n'; break; } //-- case JSON_VTYPE_BOOLEAN: { text[w++] = bool((m_cinta[p] >> TSN_SBL_BIT_START_ENDTYPE) & 1) ? 'T' : 'F'; text[w++] = '\n'; text[w++] = '-'; text[w++] = '\n'; break; } //--- case JSON_VTYPE_STRING: { const int s = int(m_cinta[p] >> TSN_SBL_BIT_STR_START); const int slen = int((m_cinta[p] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); //--- text[w++] = 'S'; text[w++] = ' '; text[w++] = '"'; w += ArrayCopy(text, m_raw, w, s, slen); text[w++] = '"'; text[w++] = '\n'; text[w++] = '-'; text[w++] = '\n'; break; } //--- case JSON_VTYPE_NULL: { text[w++] = 'N'; text[w++] = '\n'; text[w++] = '-'; text[w++] = '\n'; break; } } //--- p += GetStepPure(p); //--- Cerramos en cascada todos los niveles cuya posición de muerte ya alcanzamos. // Esto reemplaza tanto el manejo de "vacío" como la cascada de pops: ya no hace // falta tocar nada dentro de cada case. while(stack_curr >= 0 && p == end_stack[stack_curr]) { text[w++] = 'P'; text[w++] = ' '; text[w++] = '\n'; //--- stack_curr--; //--- if(stack_curr >= 0) { text[w++] = '-'; text[w++] = ' '; text[w++] = '\n'; } } } //--- return ArrayResize(text, w); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CJsonParser::ParseAssembly(void) { //--- Variables init m_cinta_pos = 0; m_pos = m_offset; m_last_err = TSN_JSON_NOT_ERR; m_next = TSN_JSON_TOKEN_ASM_ITER; m_stak_curr = -1; //--- while(true) { switch(m_next) { //--- case JSON_VTYPE_KEY: { //--- m_pos += 2; //--- const int start = ++m_pos; //--- #ifndef JSONPARSERBYLEO_ACTIVE_SWAR_KEYS //--- Pase inicial 8 en 8 while(true) { // "asdasdasd".........." // PrintFormat("Analizando: '%s'", CharArrayToString(m_raw, m_pos, 8)); const ulong chunk = (ulong)m_raw[m_pos] | (ulong)m_raw[m_pos + 1] << 8 | (ulong)m_raw[m_pos + 2] << 16 | (ulong)m_raw[m_pos + 3] << 24 | (ulong)m_raw[m_pos + 4] << 32 | (ulong)m_raw[m_pos + 5] << 40 | (ulong)m_raw[m_pos + 6] << 48 | (ulong)m_raw[m_pos + 7] << 56; //--- #ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS const ulong x_bs = chunk ^ TSNTABLES_SWAR_MASK_BACK_SLASH; ulong has_bs = TSNTABLES_SWAR_HAS(x_bs); #endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS const ulong x_qt = chunk ^ TSNTABLES_SWAR_MASK_COMILLA; const ulong has_qt = TSNTABLES_SWAR_HAS(x_qt); //--- #ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS if((has_bs | has_qt) == 0) // Caso comun. .. ninguno de los dos.. continuamos.. { m_pos += 8; if((m_pos + 7) >= m_len) // Ultimas 8 posicinoes son " " asi que seria invalido ya.. { m_last_err = TSN_JSON_ERR_KEY_NOT_CLOSED; return false; } continue; } #else // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS if(has_qt == 0) // Caso comun. .. ninguno de los dos.. continuamos.. { m_pos += 8; if((m_pos + 7) >= m_len) // Ultimas 8 posicinoes son " " asi que seria invalido ya.. { m_last_err = TSN_JSON_ERR_KEY_NOT_CLOSED; return false; } continue; } #endif //--- #ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS if(has_bs == 0) // Si not iene bs (pero confirmamos que no es 0) // Entonces no tirne bs pero si qt salimos de una.. { #endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS const ulong flag_real = TSNTABLES_SWAR_64_DEJAR_SOLO_MINUS_SIG_BYTE(has_qt); //--- m_pos += TSNTABLES_SWAR_64_GET_BYTE(flag_real); m_cinta[m_cinta_pos++] = JSON_VTYPE_KEY | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; m_pos++; // Luego del " break; #ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS } //--- Hay bs si o si pero tambien puede haber " const uchar compacted_bs = TSNTABLES_COMPACT_UL(has_bs); // Aislamos los bits donde empeizan las rachas de \ const uchar starts = compacted_bs & ~(compacted_bs << 1); // sumas especiifca para impar const ushort sum_impar_wide = (ushort)compacted_bs + ushort(starts & TSNTABLES_MASK_IMPARES); // Obtenemos finales de ambos... const uchar end_par = (compacted_bs + (starts & TSNTABLES_MASK_PARES)) & ~compacted_bs; const uchar end_impar = uchar(sum_impar_wide & 0xFF) & ~compacted_bs; // Ahora ya sabemos donde esta los finaes impares.. const uchar end_final = (end_impar & TSNTABLES_MASK_PARES) | (end_par & TSNTABLES_MASK_IMPARES); const uchar compacted_qt = TSNTABLES_COMPACT_UL(has_qt); const uchar qt_final = compacted_qt & ~end_final; //Print("nada"); //--- if(qt_final != 0) // Hay un qt real de cierre { // Avanzamos y cerramos.. m_pos += g_table_i8[qt_final]; m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; m_pos++; // Luego del " break; } else { m_pos += 8; // Print(CharToString(m_raw[m_pos])); if((sum_impar_wide & 0x100) != 0) // Overflow el ultimo char es \ y el siguiente escapa { //Print("siuu"); m_pos++; // Uno mas.. luego del currend } // No hay ... o es escapado en caso exista if((m_pos + 7) >= m_len) // Ultimas 8 posicinoes son " " asi que seria invalido ya.. { m_last_err = TSN_JSON_ERR_KEY_NOT_CLOSED; return false; } } #endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS } #else // JSONPARSERBYLEO_ACTIVE_SWAR_KEYS //--- Char por char while(true) { #ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS const uchar c = m_raw[m_pos]; if(c == '\\') { m_pos += 2; continue; } if(c == '"') { m_cinta[m_cinta_pos++] = JSON_VTYPE_KEY | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; // curr_end = INT_MAX; m_pos++; break; } #else // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS if(m_raw[m_pos] == '"') { m_cinta[m_cinta_pos++] = JSON_VTYPE_KEY | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; // curr_end = INT_MAX; m_pos++; break; } #endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS //--- m_pos++; if(m_pos >= m_len) { m_last_err = TSN_JSON_ERR_KEY_NOT_CLOSED; return false; } } #endif // JSONPARSERBYLEO_ACTIVE_SWAR_KEYS //--- m_next = TSN_JSON_TOKEN_ASM_ITER; break; } //--- case JSON_VTYPE_OBJ: // OBJ [COUNT] [STEP] { //--- m_cinta[m_cinta_pos] = JSON_VTYPE_OBJ; //--- m_stak_curr++; m_stak_num[m_stak_curr] = 0; m_stak_pos[m_stak_curr] = m_cinta_pos++; //--- m_cinta[m_cinta_pos++] = m_pos++; //--- m_next = TSN_JSON_TOKEN_ASM_ITER; //--- break; } //--- case JSON_VTYPE_ARR: // ARR [COUNT] [STEP] { //--- m_cinta[m_cinta_pos] = JSON_VTYPE_ARR; //--- m_stak_curr++; m_stak_num[m_stak_curr] = 0; m_stak_pos[m_stak_curr] = m_cinta_pos++; //--- m_cinta[m_cinta_pos++] = m_pos++; //--- m_next = TSN_JSON_TOKEN_ASM_ITER; //--- break; } //--- case JSON_VTYPE_INTEGER: case JSON_VTYPE_REAL: // REAL [Valor] { //--- m_pos += 2; //--- long v = 0; //--- Validamos signo long mask = 0; uchar ch = m_raw[m_pos]; if(ch == '-') { mask = -1; m_pos++; // Ahora en numero ch = m_raw[m_pos]; } //--- ch ^= '0'; //--- while(true) { //--- v = (v << 3) + (v << 1) + ch; //--- m_pos++; //--- ch = m_raw[m_pos] ^ '0'; //--- if(ch < 10) { continue; } else if(ch == 30 || (ch | 0x20) == 117) // . { //--- double val = double(v); if(ch == 30) { m_pos++; long frac_int = 0; int fract_digits = 0; //--- while(true) { const uchar c = m_raw[m_pos] ^ '0'; if(c > 9) break; frac_int = (frac_int << 3) + (frac_int << 1) + c; fract_digits++; m_pos++; } //--- val += frac_int * g_Exp10[fract_digits]; } //--- 10e50.02500140 if((m_raw[m_pos] | 0x20) == 'e') // e or E { //--- m_pos++; bool exp_sign = true; uchar _c = m_raw[m_pos]; if(_c == '-') { exp_sign = false; m_pos++; } else if(_c == '+') { m_pos++; } //--- _c = m_raw[m_pos] ^ '0'; int exp_val = 0; //--- while(true) { exp_val = (exp_val << 3) + (exp_val << 1) + _c; //--- m_pos++; _c = m_raw[m_pos] ^ '0'; if(_c > 9) break; } //--- val *= (exp_sign) ? g_Pow10[exp_val] : g_Exp10[exp_val]; } //--- static BitInterpreter bit; bit.double_value = val; bit.long_value ^= (mask & (1LL << 63)); m_cinta[m_cinta_pos++] = JSON_VTYPE_REAL; m_cinta[m_cinta_pos++] = bit.long_value; break; } else { m_cinta[m_cinta_pos++] = JSON_VTYPE_INTEGER; m_cinta[m_cinta_pos++] = (v ^ mask) - mask; break; // Fin } } //--- m_next = TSN_JSON_TOKEN_ASM_ITER; break; } //--- case JSON_VTYPE_BOOLEAN: // TRUE (solo...) { //--- m_pos++; // 5 | 1 << TSN_SBL_BIT_START_BOOL(4) = 21 m_cinta[m_cinta_pos++] = 21; //--- m_next = TSN_JSON_TOKEN_ASM_ITER; break; } //--- case JSON_VTYPE_STRING: { //--- m_pos += 2; // S[][Aqui] //--- const int start = ++m_pos; //--- #ifndef JSONPARSERBYLEO_DESACTIVE_SWAR //--- Pase inicial 8 en 8 while(true) { // PrintFormat("Analizando: '%s'", CharArrayToString(m_raw, m_pos, 8)); const ulong chunk = (ulong)m_raw[m_pos] | (ulong)m_raw[m_pos + 1] << 8 | (ulong)m_raw[m_pos + 2] << 16 | (ulong)m_raw[m_pos + 3] << 24 | (ulong)m_raw[m_pos + 4] << 32 | (ulong)m_raw[m_pos + 5] << 40 | (ulong)m_raw[m_pos + 6] << 48 | (ulong)m_raw[m_pos + 7] << 56; //--- const ulong x_bs = chunk ^ TSNTABLES_SWAR_MASK_BACK_SLASH; ulong has_bs = TSNTABLES_SWAR_HAS(x_bs); const ulong x_qt = chunk ^ TSNTABLES_SWAR_MASK_COMILLA; const ulong has_qt = TSNTABLES_SWAR_HAS(x_qt); //--- if((has_bs | has_qt) == 0) // Caso comun. .. ninguno de los dos.. continuamos.. { m_pos += 8; if((m_pos + 7) >= m_len) // Ultimas 8 posicinoes son " " asi que seria invalido ya.. { m_last_err = TSN_JSON_ERR_STRING_NOT_CLOSED; return false; } continue; } //--- if(has_bs == 0) // Si not iene bs (pero confirmamos que no es 0) // Entonces no tirne bs pero si qt salimos de una.. { const ulong flag_real = TSNTABLES_SWAR_64_DEJAR_SOLO_MINUS_SIG_BYTE(has_qt); //--- m_pos += TSNTABLES_SWAR_64_GET_BYTE(flag_real); m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; m_pos++; // Luego del " break; } //--- Hay bs si o si pero tambien puede haber " const uchar compacted_bs = TSNTABLES_COMPACT_UL(has_bs); // Aislamos los bits donde empeizan las rachas de \ const uchar starts = compacted_bs & ~(compacted_bs << 1); // sumas especiifca para impar const ushort sum_impar_wide = (ushort)compacted_bs + ushort(starts & TSNTABLES_MASK_IMPARES); // Obtenemos finales de ambos... const uchar end_par = (compacted_bs + (starts & TSNTABLES_MASK_PARES)) & ~compacted_bs; const uchar end_impar = uchar(sum_impar_wide & 0xFF) & ~compacted_bs; // Ahora ya sabemos donde esta los finaes impares.. const uchar end_final = (end_impar & TSNTABLES_MASK_PARES) | (end_par & TSNTABLES_MASK_IMPARES); const uchar compacted_qt = TSNTABLES_COMPACT_UL(has_qt); const uchar qt_final = compacted_qt & ~end_final; //Print("nada"); //--- if(qt_final != 0) // Hay un qt real de cierre { // Avanzamos y cerramos.. m_pos += g_table_i8[qt_final]; m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; m_pos++; // Luego del " break; } else { m_pos += 8; // Print(CharToString(m_raw[m_pos])); if((sum_impar_wide & 0x100) != 0) // Overflow el ultimo char es \ y el siguiente escapa { //Print("siuu"); m_pos++; // Uno mas.. luego del currend } // No hay ... o es escapado en caso exista if((m_pos + 7) >= m_len) // Ultimas 8 posicinoes son " " asi que seria invalido ya.. { m_last_err = TSN_JSON_ERR_STRING_NOT_CLOSED; return false; } } } #else //--- Char por char do { const uchar c = m_raw[m_pos]; //--- if(c == '\\') { m_pos += 2; continue; } if(c == '"') { // STRING 1 slot: [tipo(4)|len(28low)|start(32high)] m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; // curr_end = INT_MAX; m_pos++; break; } //--- m_pos++; } while(m_pos < m_len); #endif // JSONPARSERBYLEO_DESACTIVE_SWAR //--- m_next = TSN_JSON_TOKEN_ASM_ITER; break; } //--- case JSON_VTYPE_NULL: { m_cinta[m_cinta_pos++] = JSON_VTYPE_NULL; m_pos++; m_next = TSN_JSON_TOKEN_ASM_ITER; break; } //--- case TSN_JSON_TOKEN_ASM_BOOL_FALSE: // FALSE [value=1\0] { //--- m_pos++; m_cinta[m_cinta_pos++] = JSON_VTYPE_BOOLEAN; //--- m_next = TSN_JSON_TOKEN_ASM_ITER; break; } //--- case TSN_JSON_TOKEN_ASM_INVALID: // { //Print("Err: ", m_next, " Pos: ", m_raw[m_pos]); m_last_err = TSN_JSON_ERR_MALFORDMED_JSON; return false; } //--- case TSN_JSON_TOKEN_ASM_POP: { //--- const int lp = m_stak_pos[m_stak_curr]; m_cinta[lp] |= long(m_stak_num[m_stak_curr]) << TSN_SBL_BIT_START_NUM_EL | long(m_cinta_pos - lp) << TSN_SBL_BIT_START_NUM_C; m_cinta[lp + 1] |= long(m_pos) << TSN_JSON_BIT_END_T; //--- //PrintFormat("Stack curr %d | Size = %d | Num %d | LP %d - Cinta pos %d", m_stak_curr, m_stak_size, m_stak_num[m_stak_curr], lp, m_cinta_pos); //--- m_stak_curr--; m_pos++; // Luego del P //--- if(m_stak_curr < 0) { return true; } //--- m_next = TSN_JSON_TOKEN_ASM_ITER; break; } //--- case TSN_JSON_TOKEN_ASM_ADD_EL: { m_stak_num[m_stak_curr]++; m_pos++; m_next = TSN_JSON_TOKEN_ASM_ITER; break; } //--- case TSN_JSON_TOKEN_ASM_ITER: { // JUSTO luego del \n //--- while(true) { //--- const uchar c = m_raw[m_pos]; if(c < 33) { m_pos++; if(m_pos >= m_len) { m_last_err = TSN_JSON_ERR_MALFOMED_LEN_SUPERADO; return false; } continue; } //--- m_next = g_tsn_jsonasm_char_to_token[c]; break; } //--- break; } //--- case TSN_JSON_TOKEN_ASM_SALTAR_NL: { //--- #ifdef JSONPARSERBYLEO_ACTIVE_SWAR_IN_FIND_NL //--- int curr_end = m_pos + 8; while(curr_end <= m_len) { const ulong chunk = (ulong)m_raw[m_pos] | (ulong)m_raw[m_pos + 1] << 8 | (ulong)m_raw[m_pos + 2] << 16 | (ulong)m_raw[m_pos + 3] << 24 | (ulong)m_raw[m_pos + 4] << 32 | (ulong)m_raw[m_pos + 5] << 40 | (ulong)m_raw[m_pos + 6] << 48 | (ulong)m_raw[m_pos + 7] << 56; //--- const ulong x = chunk ^ TSNTABLES_SWAR_MASK_NEW_LINE; const ulong has_x = TSNTABLES_SWAR_HAS(x); //--- if(has_x == 0) { m_pos = curr_end; curr_end += 8; continue; } //--- break; } #endif // JSONPARSERBYLEO_DESACTIVE_SWAR_IN_FIND_NL do { if(m_raw[m_pos] == '\n') break; m_pos++; } while(m_pos < m_len); // En caso supere el len haciendo esto //Print("Char: ", m_raw[m_pos]); m_pos++; // Luego del \n //--- m_next = TSN_JSON_TOKEN_ASM_ITER; break; } default: { // Print("Err: " , m_next); m_last_err = TSN_JSON_ERR_MALFORDMED_JSON; return false; } } } } //---End } //+------------------------------------------------------------------+ #endif // JSONPARSERBYLEO_SRC_JSONASM_MQH