JsonParserByLeo/Src/DLL/Parser.cpp
Nique_372 Nique_372 af09b3a2c4
2026-10-19 16:34:19 -05:00
697 lines
22 KiB
C++
//+------------------------------------------------------------------+
//| Parser.cpp |
//| Copyright 2026, Niquel Mendoza. |
//| https://www.mql5.com/ |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "Parser.hpp"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// array ya allocado tambein raw solo hace falta rellenar
using namespace TSN;
/*
* Para el tema de SP en index decididi que en las transiciones ya no se haga siempre el sp++ si no que ahora cada case lo haga sp++
*/
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
extern "C" __declspec(dllexport)
// array ya allocado tambein raw solo hace falta rellenar
bool __stdcall JsonParserResolve(
const uint8_t* __restrict m_raw, // datos de entrada
uint64_t* __restrict m_cinta, // cinta de datos
int* __restrict m_index, // array de indices structurales
const int len, // tamaño de raw
const uint64_t jit_enabled, // valor del 2do slot de los objetos (JIT habilitado o no)
//--- salida
int* __restrict out_last_err, // ultimo err
int* __restrict out_cinta_pos, // posicion actul en la cinta
int* __restrict out_pos // ultima posicion en la lecutra de raw
) // retorna true en caso de exito, false de lo contrario..
{
//--- Estado (la pila vive en la propia cinta, igual que CJsonParser::Parse)
uchar closer = 0; // cierre esperado del contenedor actual: '}' o ']'
uint32_t curr_count = 0;
uint32_t curr_padre = 0;
//--- Inicio de miembros
int m_pos = *out_pos; // posicion de lecutra
int m_cinta_pos = 0; // pocision en la cinta
uint8_t m_next = TSN_JSON_TOK_INVALID; // siguiente token
//--- Para string y structurales
ulong prev_in_string = 0ULL;
ulong prev_scape = 0ULL;
int index_s = 0;
//--- Intrisicos masks
const __m256i mask_20 = _mm256_set1_epi8(0x20);
const __m256i bs_mask = _mm256_set1_epi8('\\');
const __m256i qt_mask = _mm256_set1_epi8('"');
const __m128i all_ones = _mm_set1_epi8(0xFF);
const __m256i op_table = _mm256_setr_epi8(
//--- low
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, ':', '{',
',', '}', 0, 0,
//--- high
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, ':', '{',
',', '}', 0, 0
);
//--- Fase inicial
do
{
// carga inicial
const __m256i chunk_lo = _mm256_loadu_si256((const __m256i*)(m_raw + m_pos)); // bytes 0-31
const __m256i chunk_hi = _mm256_loadu_si256((const __m256i*)(m_raw + m_pos + 32)); // bytes 32-63
//--- Detectamos bs
const uint32_t bs_bits_lo = (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi8(chunk_lo, bs_mask));
const uint32_t bs_bits_hi = (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi8(chunk_hi, bs_mask));
//--- Detectamos qt
const uint32_t qt_bits_lo = (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi8(chunk_lo, qt_mask));
const uint32_t qt_bits_hi = (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi8(chunk_hi, qt_mask));
//---
// compactamos ambos
const ulong compacted_qt = ((ulong)qt_bits_hi << 32) | qt_bits_lo;
const ulong compacted_bs = ((ulong)bs_bits_hi << 32) | bs_bits_lo;
//---
const ulong compacted_bs_masked = compacted_bs & ~prev_scape;
const ulong prev = (((compacted_bs_masked << 1) | TSNTABLES_MASK_IMPARES_F) - compacted_bs_masked) ^ TSNTABLES_MASK_IMPARES_F;
const ulong escaped = prev ^ (compacted_bs | prev_scape);
prev_scape = (prev & compacted_bs_masked) >> 63;
//---
const ulong quoted_pos = compacted_qt & ~escaped; // Posiciones reales del "
//const ulong quoted_pos = qt_final;
//--- prefix xor (masracara de 1
const __m128i clmul = _mm_clmulepi64_si128(_mm_set_epi64x(0, quoted_pos), all_ones, 0);
const ulong qt_final = (uint64_t)_mm_cvtsi128_si64(clmul); // Tomamos los bajos
const ulong in_string = qt_final ^ prev_in_string;
//--- Ahora obtenemos los strucutrurales
// ahora lo qeu haremos sera un or entre la masra de 0x20
// La idea econ esto es que (en las siugientes) lineas hay un problema
// noramlte con shuffle si tenemos lo sigueinte {}
// se genera
// {} (tal cual bien)
// pero si tenemos
// [] se genra {} (esto es por que se genera eso en base a los bajos)
// entonces esto luego con el cmp que se hace estair ocmprand [ con { lo qeu daria 0 asi qeu se perderia
// los caracteres estrucutalres, por eso le debemos de aumenar 0x20, esto hace que [ pase a {
// con eso soluicionas dicho problema..
const __m256i op_mask_norm_lo = _mm256_or_si256(chunk_lo, mask_20);
const __m256i op_mask_norm_hi = _mm256_or_si256(chunk_hi, mask_20);
// ahora usarmeos shuffle para hacer lo sigeuinte
// : = 1010
// ] y } = 1011
// , = 1100
// Como para generar strucuturales rapdios, la idea es quedarse solo con los estrucuturales
// Aparte metemos un eq para confirmar.. pro qeu ahroa mismo la mascara previa
// peude dar falsso posiivots (dado qeu eso de 1010... puede repetirse)
const __m256i op_lo = _mm256_cmpeq_epi8(_mm256_shuffle_epi8(op_table, chunk_lo), op_mask_norm_lo);
const __m256i op_hi = _mm256_cmpeq_epi8(_mm256_shuffle_epi8(op_table, chunk_hi), op_mask_norm_hi);
// ahora lo basmoas a 1\0 no bytes.. para trabajar..
const uint32_t bits_lo = (uint32_t)_mm256_movemask_epi8(op_lo);
const uint32_t bits_hi = (uint32_t)_mm256_movemask_epi8(op_hi);
const uint64_t raw_pure_structurals = ((uint64_t)bits_hi << 32) | bits_lo; // estuructales puros
//--- overflow (cast a int64 para shift arit)
prev_in_string = uint64_t(static_cast<int64_t>(in_string) >> 63);
// La idea es quitar a todos los operadores que se encuntrane en el camino de los strigns (in string) y solo mantneer los verdares
// a esto le agregas las posiciones de los quotes
ulong structural = (raw_pure_structurals & ~in_string) | quoted_pos;
//--- Numero de unos aqui..
const int cnt = _mm_popcnt_u64(structural);
int written = 0;
//---
while(written + 4 <= cnt)
{
m_index[index_s++] = m_pos + _tzcnt_u64(structural);
structural &= structural - 1;
m_index[index_s++] = m_pos + _tzcnt_u64(structural);
structural &= structural - 1;
m_index[index_s++] = m_pos + _tzcnt_u64(structural);
structural &= structural - 1;
m_index[index_s++] = m_pos + _tzcnt_u64(structural);
structural &= structural - 1;
written += 4;
}
// Resto (0-3 elementos sobrantes), bucle normal
while(written < cnt)
{
m_index[index_s++] = m_pos + _tzcnt_u64(structural);
structural &= structural - 1;
written++;
}
m_pos += 64; // avanzamos 64 caracteres..
// Seguimos con check
} while(m_pos < len);
//--- Esto va de la mana con el padding siempre pero siempre tendremos como minomo
// un estrucutral asi que para que esto falle ltielte no dberia de haber nada como contenido real... y si alemsno hay un solo stuucta { etc.. eso..
//if(index_s < 2)
//{
// TSN_JSON_ON_FINISH_WOUT(TSN_JSON_ERR_NOT_STRUCUTURAL_CHARS_FOUND)
// return false; // esto dado que no podemos usar goto (hay aun varaibles por inciar)
//}
// Lo comento dado qe quizas no haga falta (el padding como tal mete minimo dos " y un , asi qeu tendreismo 3 estrucutrules
// Lo cual haria uqe nunca se active esto... test por ahora.
//--- Fase 2
int sp = 0; // posicion acutal en los indices
m_pos = m_index[0]; // Posicion (consumimos el primer estructural)
//--- Solo se permite { o [ como valor raiz (ahora este es la redicreccion)
const uchar __c = m_raw[m_pos];
if(__c == '{')
{
m_next = TSN_JSON_TOK_LLAVE_INI;
}
else if(__c == '[')
{
m_next = TSN_JSON_TOK_COR_INI;
}
else // Error
{
TSN_JSON_FAIL(TSN_JSON_ERR_INVALID_CHAR)
}
//--- Iteracion
json_switch_start:
{
switch(m_next)
{
case TSN_JSON_TOK_NUMBER_NEG:
{
//--- solo 3 varaibles nada mas en general (garantizado)
int64_t v = 0;
const uint start = m_pos;
uchar ch = m_raw[++m_pos] ^ '0';
//---
switch(0)
{
default: // scope con psoiblidad de break.
{
//--- primera iteracion sin cheking
DOMBASEUTIL_PARSE_NUM_U1(v)
//--- Interesante: sigue siendo cero pero me pide mas digitios ?¿
if(!v)
{
TSN_JSON_FAIL(TSN_JSON_ERR_LEADING_ZEROS)
}
//--- 19 iteraciones maximo
DOMBASEUTIL_PARSE_NUM_UNROLLED_17(v)
STRCONV_TOV_ALG(v, ch)
if((ch = m_raw[++m_pos] ^ '0') > 9)
{
if(v > 0)
break;
}
else // aun es valido asi que seguimos saltando el numero completo (parte entera) (pero ya sabmeos que es invalido)
{
DOMBASEUTIL_NUM_SKIP_NUMBER
}
//--- revismoos si es dec, si lo es saltamos la parte dec
if(STRCONV_DECX_CH_IS_DEC(ch))
break;
//--- pasamos a str y ya no caemos abajo de aqui:
JSONPARSERBYLEO_NUM_MAKE_STRING
TSN_JSON_AUMENT
JSONPARSERBYLEO_GOTO_AFTERVALUE
}
}
//--- vemos si decimal
if(STRCONV_DECX_CH_IS_DEC(ch))
{
int64_t exponente = 0; // exponente
uint digitos = m_pos - start; // digitos que se van acomulando (parte ent + dec)
if(STRCONV_DECX_CH_IS_PDEC(ch))
{
uint ds = ++m_pos; // inicio
if((ch = m_raw[m_pos] ^ '0') > 9)
{
TSN_JSON_FAIL(TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_DECIMALP)
}
while(true)
{
DOMBASEUTIL_PARSE_NUM_UNROLLED_18(v)
DOMBASEUTIL_NUM_SKIP_NUMBER
break;
}
//---
ds = (m_pos - ds); // numero de digitos de la parte decimal
digitos += ds;
exponente -= ds;
}
if(STRCONV_DECX_CH_IS_E(ch)) //
{
bool exp_positivo = true;
ch = m_raw[++m_pos] ^ '0';
if(ch > 9)
{
if(STRCONV_DECX_CH_IS_MINUS(ch))
exp_positivo = false;
if((ch = m_raw[++m_pos] ^ '0') > 9)
{
TSN_JSON_FAIL(TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_EXP)
}
}
int expo = 0;
while(true) // siguimos acomulando en v
{
DOMBASEUTIL_PARSE_NUM_U1(expo)
if(expo == 0) // leading zeros.. ahora mismo aun hay digitos pero el primero es 0..
{
DOMBASEUTIL_PARSE_SKIP_LZ
} // pos apunta al curr no cero ch ya tiene su valor en caso sea 00000x (no numero) sale..
DOMBASEUTIL_PARSE_NUM_UNROLLED_8(expo)
STRCONV_TOV_ALG(expo, ch)
if((ch = m_raw[++m_pos] ^ '0') > 9) // 10cimo digito
{
if(expo > 0) // es valido
break; // no ov
}
else // sigue saltamos todo lo que hya
{
DOMBASEUTIL_NUM_SKIP_NUMBER
}
expo = INT_MAX;
break;
}
exponente += exp_positivo ? expo : -expo;
}
//--- 1 dado que start incluye el -
if(STRCONV_DOUBLE_SAFE_DBL_P(digitos, exponente, 1))
{
TsnBitInterprete bit;
bit.double_value = -STRCONV_TO_DOUBLE_ALG(exponente, v);
m_cinta[m_cinta_pos++] = JSON_VTYPE_REAL;
m_cinta[m_cinta_pos++] = bit.ulong_value;
}
else // make_string: numero grande o que ya no se peude representar con precision (a string)
{
JSONPARSERBYLEO_NUM_MAKE_STRING
}
}
else
{
m_cinta[m_cinta_pos++] = JSON_VTYPE_INTEGER;
m_cinta[m_cinta_pos++] = (-v);
}
//---
TSN_JSON_AUMENT
JSONPARSERBYLEO_GOTO_AFTERVALUE
}
case TSN_JSON_TOK_NUMBER:
{
//---
const uint start = m_pos;
// Primer valor
const uchar fc = m_raw[start] ^ '0';
ulong v = fc; // Tal cual sin mas..
// Segundo valor
uchar ch = m_raw[++m_pos] ^ '0';
//---
switch(0)
{
default: // scope con psoiblidad de break.
{
//---
if(ch > 9) // Mayor
break;
if(!v) // LZ
{
TSN_JSON_FAIL(TSN_JSON_ERR_LEADING_ZEROS)
}
//--- 19 iteraciones maximo
DOMBASEUTIL_PARSE_NUM_UNROLLED_18(v)
STRCONV_TOV_ALG(v, ch)
if((ch = m_raw[++m_pos] ^ '0') > 9)
{
if(fc == 1 && v > (uint64_t)INT64_MAX)
break;
}
else // aun es valido asi que seguimos saltando el numero completo (parte entera) (pero ya sabmeos que es invalido)
{
DOMBASEUTIL_NUM_SKIP_NUMBER
}
//--- revismoos si es dec, si es asi lo mandamos para la funcion dec aqui solo big integer
if(STRCONV_DECX_CH_IS_DEC(ch))
break;
//--- pasamos a str y ya no caemos abajo de aqui:
JSONPARSERBYLEO_NUM_MAKE_STRING
TSN_JSON_AUMENT
JSONPARSERBYLEO_GOTO_AFTERVALUE
}
}
//--- vemos si decimal
if(STRCONV_DECX_CH_IS_DEC(ch)) // v por lo tanto llega bien aqui como entero unsigned valido
{
int64_t exponente = 0; // exponente
uint digitos = m_pos - start; // digitos que se van acomulando (parte ent + dec)
if(STRCONV_DECX_CH_IS_PDEC(ch)) // punto decimal (tomar precuacion aqui si v puede dar overflow y voltear no hay chekeo)
{
uint ds = ++m_pos;
if((ch = m_raw[m_pos] ^ '0') > 9)
{
TSN_JSON_FAIL(TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_DECIMALP)
}
while(true)
{
DOMBASEUTIL_PARSE_NUM_UNROLLED_18(v)
DOMBASEUTIL_NUM_SKIP_NUMBER
break;
}
//---
ds = (m_pos - ds); // numero de digitos de la parte decimal
digitos += ds;
exponente -= ds;
}
if(STRCONV_DECX_CH_IS_E(ch)) //
{
bool exp_positivo = true;
ch = m_raw[++m_pos] ^ '0';
if(ch > 9)
{
if(STRCONV_DECX_CH_IS_MINUS(ch))
exp_positivo = false;
if((ch = m_raw[++m_pos] ^ '0') > 9)
{
TSN_JSON_FAIL(TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_EXP)
}
}
int expo = 0;
while(true)
{
DOMBASEUTIL_PARSE_NUM_U1(expo)
if(expo == 0) // leading zeros.. ahora mismo aun hay digitos pero el primero es 0..
{
DOMBASEUTIL_PARSE_SKIP_LZ
} // pos apunta al curr no cero ch ya tiene su valor en caso sea 00000x (no numero) sale..
DOMBASEUTIL_PARSE_NUM_UNROLLED_8(expo)
STRCONV_TOV_ALG(expo, ch)
if((ch = m_raw[++m_pos] ^ '0') > 9) // 10cimo digito
{
if(expo > 0) // es valido
break; // no ov
}
else // sigue saltamos todo lo que hya
{
DOMBASEUTIL_NUM_SKIP_NUMBER
}
expo = INT_MAX;
break;
}
exponente += exp_positivo ? expo : -expo;
}
//---
if(STRCONV_DOUBLE_SAFE_DBL(digitos, exponente))
{
TsnBitInterprete bit;
bit.double_value = STRCONV_TO_DOUBLE_ALG(exponente, v);
m_cinta[m_cinta_pos++] = JSON_VTYPE_REAL;
m_cinta[m_cinta_pos++] = bit.ulong_value;
}
else
{
JSONPARSERBYLEO_NUM_MAKE_STRING
}
}
else
{
m_cinta[m_cinta_pos++] = JSON_VTYPE_UINTEGER;
m_cinta[m_cinta_pos++] = v;
}
//---
TSN_JSON_AUMENT
JSONPARSERBYLEO_GOTO_AFTERVALUE
}
case TSN_JSON_TOK_STRING:
{
//---
// NOTA: no hay veriicamos dado qeu dminimo para que sea valido {"valor":"
// el punto qeu es que el suginte si o si es el " y luego el siutine esutructa es " por lo que falla.. (no es valido)
const int start = m_index[sp++] + 1; // luego del "
//---
m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING
| uint64_t(m_index[sp] - start) << TSN_SBL_BIT_STR_LEN(TSN_SBL_SLEN_STR)
| uint64_t(start) << TSN_SBL_BIT_STR_START;
//---
sp++; // luego del
//---
TSN_JSON_AUMENT
JSONPARSERBYLEO_GOTO_AFTERVALUE
}
case TSN_JSON_TOK_BOOL_TRUE:
{
//---
JSONPARSERBYLEO_CHEK_LITERAL(TSNJSON_VAL_TRUE_F, TSN_JSON_ERR_MALFORMED_TRUE)
//---
m_cinta[m_cinta_pos++] = (JSON_VTYPE_BOOLEAN | 1ULL << TSN_SBL_BIT_START_BOOL);
m_pos += 4;
//---
TSN_JSON_AUMENT
JSONPARSERBYLEO_GOTO_AFTERVALUE
}
case TSN_JSON_TOK_BOOL_FALSE:
{
//---
m_pos++; // salta el f para que solo compare con "alse"
JSONPARSERBYLEO_CHEK_LITERAL(TSNJSON_VAL_FALSE, TSN_JSON_ERR_MALFORMED_FALSE)
//---
m_cinta[m_cinta_pos++] = JSON_VTYPE_BOOLEAN;
m_pos += 4;
//---
TSN_JSON_AUMENT
JSONPARSERBYLEO_GOTO_AFTERVALUE
}
case TSN_JSON_TOK_NULL:
{
//---
JSONPARSERBYLEO_CHEK_LITERAL(TSNJSON_VAL_NULL_F, TSN_JSON_ERR_MALFORMED_NULL)
//---
m_cinta[m_cinta_pos++] = JSON_VTYPE_NULL;
m_pos += 4;
//---
TSN_JSON_AUMENT
JSONPARSERBYLEO_GOTO_AFTERVALUE
}
case TSN_JSON_TOK_COMMA: // Solo redirigimos (lo puse para no tener "correciones")
{
TSN_JSON_FAIL(TSN_JSON_ERR_INVALID_CHAR)
}
// Nota: la coma ya no es un case, se maneja en json_after_value (mas abajo)
case TSN_JSON_TOK_LLAVE_INI:
{
//--- saltamos el estructural actual
sp++;
//--- guardar lo uqe tenaismos (numero de elementos) (+1 para contar este nuevo elemento)
m_cinta[curr_padre] = curr_count + 1;
//--- guardamos la direccion de nuesto padre y la nuestra (reemplazado luego en el cierre)
m_cinta[m_cinta_pos] = JSON_VTYPE_OBJ
| uint64_t(m_cinta_pos) << TSN_SBL_PARSE_START_CINTAPOS
| uint64_t(curr_padre) << TSN_SBL_BIT_START_NUM_C;
curr_padre = ++m_cinta_pos; // apunta al inicio + 1 (lo modificamos para count, ahora apunta aqui..)
m_cinta_pos++; // salta la posicion 1
//--- reiniciamos los estados
closer = '}';
curr_count = 0;
//---
m_pos = m_index[sp];
const uchar __c = m_raw[m_pos];
if(__c == '"') // fast path
{
sp++; // apunta ahora mismo al siguiente
const int start = m_pos + 1; // luego del "
TSN_JSON_PARSE_KEY
TSN_JSON_NEXT_VALUE_COMM_KEY
}
else if(__c == '}')
{
goto label_json_llave_end; // m_next = TSN_JSON_TOK_LLAVE_END; // el estructural } ya fue consumido
}
else
{
TSN_JSON_FAIL(TSN_JSON_ERR_MALFORDMED_JSON_AFTER_LLAVE_INI)
}
//---
TSN_JSON_IN_BEAK
}
case TSN_JSON_TOK_COR_INI:
{
//--- saltamos el estructural actual
sp++;
//--- guardar lo uqe tenaismos (numero de elementos) (+1 para contar este nuevo elemento)
m_cinta[curr_padre] = curr_count + 1;
//--- guardamos la direccion de nuesto padre y la nuestra (reemplazado luego en el cierre)
m_cinta[m_cinta_pos] = JSON_VTYPE_ARR
| uint64_t(m_cinta_pos) << TSN_SBL_PARSE_START_CINTAPOS
| uint64_t(curr_padre) << TSN_SBL_BIT_START_NUM_C;
curr_padre = ++m_cinta_pos; // apunta al inicio + 1 (lo modificamos para count, ahora apunta aqui..)
m_cinta_pos++; // salta la posicion 1
//--- reiniciamos los estados
closer = ']';
curr_count = 0;
//--- El primer elemento puede no ser estructural ([5]) asi que se mira el caracter, no el indice
m_pos++; // saltamos el [
TSN_JSON_NEXT_COR_INI
//---
TSN_JSON_IN_BEAK
}
// tema de ends ya lo saca en next el sp
case TSN_JSON_TOK_LLAVE_END:
label_json_llave_end:
{
//---
sp++; // Salta el suyo
//--- cerramos el 2do slot del objeto con el valor final del JIT
m_cinta[curr_padre] = jit_enabled;
const uint32_t idata = --curr_padre;
const uint64_t v = m_cinta[idata];
// ahora si rehacemos el valor con todo ya listo.. (curr padre apunta a la posicion correcta)
m_cinta[idata] = JSON_VTYPE_OBJ
| uint64_t(curr_count) << TSN_SBL_BIT_START_NUM_EL
| uint64_t(m_cinta_pos - ((v >> 1) & TSN_SBL_PARSE_MASK_CINTAPOS_S)) << TSN_SBL_BIT_START_NUM_C;
curr_padre = uint32_t(v >> TSN_SBL_BIT_START_NUM_C); // ahora obtenemos su padre..
//---
if(curr_padre == idata) // raiz
{
TSN_JSON_ON_FINISH_WOUT(TSN_JSON_NOT_ERR)
return true;
}
//---
curr_count = (uint32_t)m_cinta[curr_padre]; // le devolvemos..
closer = TSN_JSON_MAKE_CLOSER(m_cinta[curr_padre - 1] & TSN_SBL_PARSE_MASK_OA_T);
//---
JSONPARSERBYLEO_GOTO_AFTERVALUE
}
case TSN_JSON_TOK_COR_END:
label_json_cor_end:
{
//---
sp++; // Esto dado que luego de un valor sigue un strucutral alguien ha de consumirlo..
//---
const uint32_t idata = --curr_padre;
const uint64_t v = m_cinta[idata];
// ahora si rehacemos el valor con todo ya listo.. (curr padre apunta a la posicion correcta)
m_cinta[idata] = JSON_VTYPE_ARR
| uint64_t(curr_count) << TSN_SBL_BIT_START_NUM_EL
| uint64_t(m_cinta_pos - ((v >> 1) & TSN_SBL_PARSE_MASK_CINTAPOS_S)) << TSN_SBL_BIT_START_NUM_C;
curr_padre = uint32_t(v >> TSN_SBL_BIT_START_NUM_C); // ahora obtenemos su padre..
//---
if(curr_padre == idata) // raiz
{
TSN_JSON_ON_FINISH_WOUT(TSN_JSON_NOT_ERR)
return true;
}
//---
curr_count = (uint32_t)m_cinta[curr_padre]; // le devolvemos..
closer = TSN_JSON_MAKE_CLOSER(m_cinta[curr_padre - 1] & TSN_SBL_PARSE_MASK_OA_T);
//---
JSONPARSERBYLEO_GOTO_AFTERVALUE
}
//---
default:
json_err: // goto para ir directo
{
// Nota aqui simplemte falla no sale ni nada.. es como la version normal... de mql5.. (luego usa cath)
TSN_JSON_FINISH_B
return false;
}
}
}
//--- Luego de un valor: solo puede venir ',' o el cierre del contenedor actual
json_after_value:
{
m_pos = m_index[sp];
const uchar _c = m_raw[m_pos];
if(_c == ',') // Fastpath
{
m_pos++;
sp++;
//--- En objeto: sigue la key
if(closer == '}')
{
const int start = m_index[sp++] + 1; // ahora mismo sp apunta a "
TSN_JSON_PARSE_KEY
}
//--- Le sigue valor si o si
TSN_JSON_NEXT_VALUE_COMM_KEY
goto json_switch_start;
}
if(_c == closer)
{
if(_c == '}')
goto label_json_llave_end;
goto label_json_cor_end;
}
TSN_JSON_FAIL(TSN_JSON_ERR_MALFORDMED_JSON_AFTER_VAL)
}
}
/* Obervaciones
* Hay un tema ahora mismo luego de , en ctx obj no se valida " (esto aplica a key, string no)
* Pasa bien [abc] dado qe solo se tiene en cuenta los estrucuturales nada mas.
*/
//+------------------------------------------------------------------+