| //+------------------------------------------------------------------+
|
| //| 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.
|
| */
|
| //+------------------------------------------------------------------+
|