Implement some of the JSON5 enhancements to string and numeric literals.
This is an incremental check-in of work in progress. FossilOrigin-Name: 9508efa9d61c0ff0eb73100dd52889dadc5fa2a2091b944a9b8a74e8a5c50e82
This commit is contained in:
parent
f14b2e35fa
commit
c5ee2d8e80
12
manifest
12
manifest
@ -1,5 +1,5 @@
|
||||
C Partial\simplementation\sof\sJSON5\snumeric\sliteral\sextensions.\s\sUse\sa\sswitch()\nstatement\sin\sthe\sparser\sfor\sbetter\sperformance.
|
||||
D 2023-04-26T17:30:28.870
|
||||
C Implement\ssome\sof\sthe\sJSON5\senhancements\sto\sstring\sand\snumeric\sliterals.\nThis\sis\san\sincremental\scheck-in\sof\swork\sin\sprogress.
|
||||
D 2023-04-26T20:26:14.388
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -592,7 +592,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
F src/hwtime.h b638809e083b601b618df877b2e89cb87c2a47a01f4def10be4c4ebb54664ac7
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c a8de1db43335fc4946370a7a7e47d89975ad678ddb15078a150e993ba2fb37d4
|
||||
F src/json.c a346dbe63628f8cb9c6bf6bbccb8fc81a49730db2311ec9b483d7fc3582da223
|
||||
F src/json.c f82b86599b220a2c60731eba883bbea92ee4d6e61aaa56740179e8aa5e6ec596
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c be5af440f3192c58681b5d43167dbca3ccbfce394d89faa22378a14264781136
|
||||
F src/main.c 09bc5191f75dc48fc4dfddda143cb864c0c3dbc3297eb9a9c8e01fea58ff847d
|
||||
@ -2063,8 +2063,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P ac411dbdcbf0b9040fb5b7de173271f383a6aa303d57f22ebd200809a5b4a6d3
|
||||
R 0e63126100fc0a5fcfa419eb4dbeae91
|
||||
P 78404dc37024cad5fe7eacf78ea85b56f08b129a1b9a046c3e1b11275068a485
|
||||
R e7aefca3f1ce2ae26f999bdfb414a2b2
|
||||
U drh
|
||||
Z 7c56c83a7327e89fcacb5797373de3a9
|
||||
Z b316d61c8d04f67716fa9ffd06cd770b
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@ -1 +1 @@
|
||||
78404dc37024cad5fe7eacf78ea85b56f08b129a1b9a046c3e1b11275068a485
|
||||
9508efa9d61c0ff0eb73100dd52889dadc5fa2a2091b944a9b8a74e8a5c50e82
|
160
src/json.c
160
src/json.c
@ -104,6 +104,7 @@ static const char * const jsonType[] = {
|
||||
#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */
|
||||
#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */
|
||||
#define JNODE_LABEL 0x40 /* Is a label of an object */
|
||||
#define JNODE_JSON5 0x80 /* Node contains JSON5 enhancements */
|
||||
|
||||
|
||||
/* A single node of parsed JSON
|
||||
@ -295,6 +296,72 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
|
||||
assert( p->nUsed<p->nAlloc );
|
||||
}
|
||||
|
||||
/*
|
||||
** The zIn[0..N] string is a JSON5 string literal. Append to p a translation
|
||||
** of the string literal that standard JSON and that omits all JSON5
|
||||
** features.
|
||||
*/
|
||||
static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){
|
||||
jsonAppendChar(p, '"');
|
||||
jsonAppendRaw(p, &zIn[1], N-2); /* TODO: translate JSON5 escapes */
|
||||
jsonAppendChar(p, '"');
|
||||
}
|
||||
|
||||
/*
|
||||
** The zIn[0..N] string is a JSON5 integer literal. Append to p a translation
|
||||
** of the string literal that standard JSON and that omits all JSON5
|
||||
** features.
|
||||
*/
|
||||
static void jsonAppendNormalizedInt(JsonString *p, const char *zIn, u32 N){
|
||||
if( zIn[0]=='+' ){
|
||||
zIn++;
|
||||
N--;
|
||||
}else if( zIn[0]=='-' ){
|
||||
jsonAppendChar(p, '-');
|
||||
zIn++;
|
||||
N--;
|
||||
}
|
||||
while( zIn[0]=='0' && N>1 ){
|
||||
zIn++;
|
||||
N--;
|
||||
}
|
||||
jsonAppendRaw(p, zIn, N);
|
||||
}
|
||||
|
||||
/*
|
||||
** The zIn[0..N] string is a JSON5 real literal. Append to p a translation
|
||||
** of the string literal that standard JSON and that omits all JSON5
|
||||
** features.
|
||||
*/
|
||||
static void jsonAppendNormalizedReal(JsonString *p, const char *zIn, u32 N){
|
||||
int i;
|
||||
if( zIn[0]=='+' ){
|
||||
zIn++;
|
||||
N--;
|
||||
}else if( zIn[0]=='-' ){
|
||||
jsonAppendChar(p, '-');
|
||||
zIn++;
|
||||
N--;
|
||||
}
|
||||
if( zIn[0]=='.' ){
|
||||
jsonAppendChar(p, '0');
|
||||
}
|
||||
for(i=0; i<N; i++){
|
||||
if( zIn[i]=='.' && (i+1==N || !sqlite3Isdigit(zIn[i+1])) ){
|
||||
jsonAppendRaw(p, zIn, i);
|
||||
zIn += i;
|
||||
N -= i;
|
||||
jsonAppendChar(p, '0');
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( N>0 ){
|
||||
jsonAppendRaw(p, zIn, N);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Append a function parameter value to the JSON string under
|
||||
** construction.
|
||||
@ -425,17 +492,32 @@ static void jsonRenderNode(
|
||||
break;
|
||||
}
|
||||
case JSON_STRING: {
|
||||
assert( pNode->eU==1 );
|
||||
if( pNode->jnFlags & JNODE_RAW ){
|
||||
assert( pNode->eU==1 );
|
||||
jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
|
||||
break;
|
||||
}else if( pNode->jnFlags & JNODE_JSON5 ){
|
||||
jsonAppendNormalizedString(pOut, pNode->u.zJContent, pNode->n);
|
||||
}else{
|
||||
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
|
||||
}
|
||||
/* no break */ deliberate_fall_through
|
||||
break;
|
||||
}
|
||||
case JSON_REAL: {
|
||||
assert( pNode->eU==1 );
|
||||
if( pNode->jnFlags & JNODE_JSON5 ){
|
||||
jsonAppendNormalizedReal(pOut, pNode->u.zJContent, pNode->n);
|
||||
}else{
|
||||
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSON_REAL:
|
||||
case JSON_INT: {
|
||||
assert( pNode->eU==1 );
|
||||
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
|
||||
if( pNode->jnFlags & JNODE_JSON5 ){
|
||||
jsonAppendNormalizedInt(pOut, pNode->u.zJContent, pNode->n);
|
||||
}else{
|
||||
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSON_ARRAY: {
|
||||
@ -615,9 +697,10 @@ static void jsonReturn(
|
||||
const char *z;
|
||||
char *zOut;
|
||||
u32 j;
|
||||
u32 nOut = n;
|
||||
assert( pNode->eU==1 );
|
||||
z = pNode->u.zJContent;
|
||||
zOut = sqlite3_malloc( n+1 );
|
||||
zOut = sqlite3_malloc( nOut+1 );
|
||||
if( zOut==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
break;
|
||||
@ -669,6 +752,15 @@ static void jsonReturn(
|
||||
c = '\r';
|
||||
}else if( c=='t' ){
|
||||
c = '\t';
|
||||
}else if( c=='v' ){
|
||||
c = '\v';
|
||||
}else if( c=='\'' ){
|
||||
c = '\'';
|
||||
}else if( c=='0' ){
|
||||
c = 0;
|
||||
}else if( c=='x' ){
|
||||
c = (jsonHexToInt(z[i+1])<<4) | jsonHexToInt(z[i+2]);
|
||||
i += 2;
|
||||
}
|
||||
zOut[j++] = c;
|
||||
}
|
||||
@ -749,13 +841,18 @@ static int jsonParseAddNode(
|
||||
return pParse->nNode++;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if z[] begins with 2 (or more) hexadecimal digits
|
||||
*/
|
||||
static int jsonIs2Hex(const char *z){
|
||||
return sqlite3Isxdigit(z[0]) && sqlite3Isxdigit(z[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if z[] begins with 4 (or more) hexadecimal digits
|
||||
*/
|
||||
static int jsonIs4Hex(const char *z){
|
||||
int i;
|
||||
for(i=0; i<4; i++) if( !sqlite3Isxdigit(z[i]) ) return 0;
|
||||
return 1;
|
||||
return jsonIs2Hex(z) && jsonIs2Hex(&z[2]);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -978,9 +1075,17 @@ json_parse_restart:
|
||||
pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
|
||||
return j+1;
|
||||
}
|
||||
case '"': {
|
||||
case '\'': {
|
||||
u8 jnFlags;
|
||||
char cDelim;
|
||||
pParse->has5 = 1;
|
||||
jnFlags = JNODE_JSON5;
|
||||
goto parse_string;
|
||||
case '"':
|
||||
/* Parse string */
|
||||
u8 jnFlags = 0;
|
||||
jnFlags = 0;
|
||||
parse_string:
|
||||
cDelim = z[i];
|
||||
j = i+1;
|
||||
for(;;){
|
||||
c = z[j];
|
||||
@ -992,12 +1097,16 @@ json_parse_restart:
|
||||
c = z[++j];
|
||||
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
|
||||
|| c=='n' || c=='r' || c=='t'
|
||||
|| (c=='u' && jsonIs4Hex(z+j+1)) ){
|
||||
jnFlags = JNODE_ESCAPE;
|
||||
|| (c=='u' && jsonIs4Hex(&z[j+1])) ){
|
||||
jnFlags |= JNODE_ESCAPE;
|
||||
}else if( c=='\'' || c=='0' || c=='v'
|
||||
|| (c=='x' && jsonIs2Hex(&z[j+1])) ){
|
||||
jnFlags |= (JNODE_ESCAPE|JNODE_JSON5);
|
||||
pParse->has5 = 1;
|
||||
}else{
|
||||
return -1;
|
||||
}
|
||||
}else if( c=='"' ){
|
||||
}else if( c==cDelim ){
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
@ -1027,9 +1136,11 @@ json_parse_restart:
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
case '+':
|
||||
case '+': {
|
||||
u8 seenDP, seenE, jnFlags;
|
||||
pParse->has5 = 1;
|
||||
/* fall through */
|
||||
jnFlags = JNODE_JSON5;
|
||||
goto parse_number;
|
||||
case '-':
|
||||
case '0':
|
||||
case '1':
|
||||
@ -1040,10 +1151,12 @@ json_parse_restart:
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9': {
|
||||
case '9':
|
||||
/* Parse number */
|
||||
u8 seenDP = 0;
|
||||
u8 seenE = 0;
|
||||
jnFlags = 0;
|
||||
parse_number:
|
||||
seenDP = 0;
|
||||
seenE = 0;
|
||||
assert( '-' < '0' );
|
||||
assert( '+' < '0' );
|
||||
assert( '.' < '0' );
|
||||
@ -1053,10 +1166,14 @@ json_parse_restart:
|
||||
if( c=='0' ){
|
||||
if( sqlite3Isdigit(z[i+1]) ){
|
||||
pParse->has5 = 1;
|
||||
jnFlags = JNODE_JSON5;
|
||||
}
|
||||
}else{
|
||||
if( !sqlite3Isdigit(z[i+1]) ) return -1;
|
||||
if( z[i+1]=='0' && sqlite3Isdigit(z[i+2]) ) pParse->has5 = 1;
|
||||
if( z[i+1]=='0' && sqlite3Isdigit(z[i+2]) ){
|
||||
pParse->has5 = 1;
|
||||
jnFlags = JNODE_JSON5;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(j=i+1;; j++){
|
||||
@ -1103,6 +1220,9 @@ json_parse_restart:
|
||||
if( z[j-1]<'0' ) return -1;
|
||||
jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
|
||||
j - i, &z[i]);
|
||||
if( jnFlags && !pParse->oom ){
|
||||
pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
case '}': {
|
||||
|
Loading…
x
Reference in New Issue
Block a user