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