--- JSON-XS/XS.xs 2018/11/15 20:49:12 1.135 +++ JSON-XS/XS.xs 2018/11/15 22:35:35 1.136 @@ -98,6 +98,8 @@ enum { INCR_M_WS = 0, // initial whitespace skipping, must be 0 + INCR_M_TFN, // inside true/false/null + INCR_M_NUM, // inside number INCR_M_STR, // inside string INCR_M_BS, // inside backslash INCR_M_C0, // inside comment in initial whitespace sequence @@ -1845,9 +1847,17 @@ for (;;) { - //printf ("loop pod %d *p<%c><%s>, mode %d nest %d\n", p - SvPVX (self->incr_text), *p, p, self->incr_mode, self->incr_nest);//D switch (self->incr_mode) { + // reached end of a scalar, see if we are inside a nested structure or not + end_of_scalar: + self->incr_mode = INCR_M_JSON; + + if (self->incr_nest) // end of a scalar inside array, object or tag + goto incr_m_json; + else // end of scalar outside structure, json text ends here + goto interrupt; + // only used for initial whitespace skipping case INCR_M_WS: for (;;) @@ -1899,6 +1909,40 @@ break; + // inside true/false/null + case INCR_M_TFN: + incr_m_tfn: + for (;;) + switch (*p++) + { + case 'r': case 'u': case 'e': // tRUE, falsE, nUll + case 'a': case 'l': case 's': // fALSe, nuLL + // allowed + break; + + default: + --p; + goto end_of_scalar; + } + + // inside a number + case INCR_M_NUM: + incr_m_num: + for (;;) + switch (*p++) + { + case 'e': case 'E': case '.': case '+': + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + // allowed + break; + + default: + --p; + goto end_of_scalar; + } + // inside a string case INCR_M_STR: incr_m_str: @@ -1907,12 +1951,7 @@ if (*p == '"') { ++p; - self->incr_mode = INCR_M_JSON; - - if (!self->incr_nest) - goto interrupt; - - goto incr_m_json; + goto end_of_scalar; } else if (*p == '\\') { @@ -1952,6 +1991,21 @@ } break; + // the following three blocks handle scalars. this makes the parser + // more strict than required inside arrays or objects, and could + // be moved to a special case on the toplevel (except strings) + case 't': + case 'f': + case 'n': + self->incr_mode = INCR_M_TFN; + goto incr_m_tfn; + + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + self->incr_mode = INCR_M_NUM; + goto incr_m_num; + case '"': self->incr_mode = INCR_M_STR; goto incr_m_str;