stream-json
Advanced tools
Comparing version 0.4.1 to 0.4.2
1149
AltParser.js
@@ -70,594 +70,589 @@ "use strict"; | ||
try { | ||
main: do{ | ||
if(this._literal){ | ||
switch(this._literal){ | ||
case ESCAPED_CHAR: | ||
switch(s[0]){ | ||
case "\"": case "/": case "b": case "f": | ||
case "\\": case "n": case "r": case "t": | ||
this.push({id: "escapedChars", value: "\\" + s[0], line: this._line, pos: this._pos}); | ||
++i; | ||
++this._pos; | ||
break; | ||
case "u": | ||
k = Math.min(5, n); | ||
for(j = 1, ++i; i < k; ++j, ++i){ | ||
if(!hex[s[i]]) { | ||
throw Error("While matching hexadecimals encountered '" + s[i] + "'"); | ||
} | ||
this._stash += s[i]; | ||
main: do{ | ||
if(this._literal){ | ||
switch(this._literal){ | ||
case ESCAPED_CHAR: | ||
switch(s[0]){ | ||
case "\"": case "/": case "b": case "f": | ||
case "\\": case "n": case "r": case "t": | ||
this.push({id: "escapedChars", value: "\\" + s[0], line: this._line, pos: this._pos}); | ||
++i; | ||
++this._pos; | ||
break; | ||
case "u": | ||
k = Math.min(5, n); | ||
for(j = 1, ++i; i < k; ++j, ++i){ | ||
if(!hex[s[i]]) { | ||
return callback(new Error("While matching hexadecimals encountered '" + s[i] + "'")); | ||
} | ||
if(j < 5){ | ||
this._literal = HEXADECIMALS; | ||
this._literalFrom = j; | ||
break main; | ||
} | ||
this.push({id: "escapedChars", value: "\\u" + this._stash, line: this._line, pos: this._pos}); | ||
this._stash = ""; | ||
this._pos += 5; | ||
break; | ||
default: | ||
throw Error("Wrong escaped symbol '" + c + "'"); | ||
} | ||
break; | ||
case HEXADECIMALS: | ||
k = Math.min(5 - this._literalFrom, n); | ||
for(j = this._literalFrom; i < k; ++j, ++i){ | ||
if(!hex[s[i]]) { | ||
throw Error("While matching hexadecimals encountered '" + s[i] + "'"); | ||
this._stash += s[i]; | ||
} | ||
this._stash += s[i]; | ||
} | ||
if(j < 5){ | ||
this._literalFrom = j; | ||
break main; | ||
} | ||
this.push({id: "escapedChars", value: "\\u" + this._stash, line: this._line, pos: this._pos}); | ||
this._stash = ""; | ||
this._pos += 5; | ||
break; | ||
default: | ||
k = Math.min(this._literal.length - this._literalFrom, n); | ||
for(j = this._literalFrom; i < k; ++j, ++i){ | ||
if(this._literal[j] !== s[i]) { | ||
throw Error("While matching '" + this._literal + "' encountered '" + s[j] + "' instead of '" + LITERAL_TRUE[j - i] + "'"); | ||
if(j < 5){ | ||
this._literal = HEXADECIMALS; | ||
this._literalFrom = j; | ||
break main; | ||
} | ||
this.push({id: "escapedChars", value: "\\u" + this._stash, line: this._line, pos: this._pos}); | ||
this._stash = ""; | ||
this._pos += 5; | ||
break; | ||
default: | ||
return callback(new Error("Wrong escaped symbol '" + c + "'")); | ||
} | ||
break; | ||
case HEXADECIMALS: | ||
k = Math.min(5 - this._literalFrom, n); | ||
for(j = this._literalFrom; i < k; ++j, ++i){ | ||
if(!hex[s[i]]) { | ||
return callback(new Error("While matching hexadecimals encountered '" + s[i] + "'")); | ||
} | ||
if(j < this._literal.length){ | ||
this._literalFrom = j; | ||
break main; | ||
this._stash += s[i]; | ||
} | ||
if(j < 5){ | ||
this._literalFrom = j; | ||
break main; | ||
} | ||
this.push({id: "escapedChars", value: "\\u" + this._stash, line: this._line, pos: this._pos}); | ||
this._stash = ""; | ||
this._pos += 5; | ||
break; | ||
default: | ||
k = Math.min(this._literal.length - this._literalFrom, n); | ||
for(j = this._literalFrom; i < k; ++j, ++i){ | ||
if(this._literal[j] !== s[i]) { | ||
return callback(new Error("While matching '" + this._literal + "' encountered '" + s[j] + "' instead of '" + LITERAL_TRUE[j - i] + "'")); | ||
} | ||
this.push({id: this._literal, value: this._literal, line: this._line, pos: this._pos}); | ||
this._pos += this._literal.length; | ||
// end of value | ||
switch(this._parent){ | ||
case PARSING_OBJECT: | ||
this._state = EXPECTING_OBJECT_STOP; | ||
break; | ||
case PARSING_ARRAY: | ||
this._state = EXPECTING_ARRAY_STOP; | ||
break; | ||
default: | ||
this._state = EXPECTING_NOTHING; | ||
break; | ||
} | ||
break; | ||
} | ||
this._literal = null; | ||
} | ||
if(j < this._literal.length){ | ||
this._literalFrom = j; | ||
break main; | ||
} | ||
this.push({id: this._literal, value: this._literal, line: this._line, pos: this._pos}); | ||
this._pos += this._literal.length; | ||
// end of value | ||
switch(this._parent){ | ||
case PARSING_OBJECT: | ||
this._state = EXPECTING_OBJECT_STOP; | ||
break; | ||
case PARSING_ARRAY: | ||
this._state = EXPECTING_ARRAY_STOP; | ||
break; | ||
default: | ||
this._state = EXPECTING_NOTHING; | ||
break; | ||
} | ||
break; | ||
} | ||
this._literal = null; | ||
} | ||
for(; i < n; ++i, ++this._pos){ | ||
var c = s[i]; | ||
// calculate (line, pos) | ||
switch(c){ | ||
case "\r": | ||
for(; i < n; ++i, ++this._pos){ | ||
var c = s[i]; | ||
// calculate (line, pos) | ||
switch(c){ | ||
case "\r": | ||
++this._line; | ||
this._pos = 1; | ||
break; | ||
case "\n": | ||
if(this._lastChar !== "\r"){ | ||
++this._line; | ||
this._pos = 1; | ||
break; | ||
case "\n": | ||
if(this._lastChar !== "\r"){ | ||
++this._line; | ||
} | ||
this._pos = 1; | ||
break; | ||
} | ||
this._lastChar = c; | ||
// process a character | ||
switch(this._state){ | ||
case EXPECTING_NOTHING: | ||
switch(c){ | ||
case " ": case "\t": case "\r": case "\n": // ws | ||
if(this._chunk && this._chunk.id !== "ws"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this._pos = 1; | ||
break; | ||
} | ||
this._lastChar = c; | ||
// process a character | ||
switch(this._state){ | ||
case EXPECTING_NOTHING: | ||
switch(c){ | ||
case " ": case "\t": case "\r": case "\n": // ws | ||
if(this._chunk && this._chunk.id !== "ws"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "ws", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
default: | ||
return callback(new Error("Expected whitespace")); | ||
} | ||
break; | ||
case EXPECTING_VALUE: | ||
case EXPECTING_ARRAY_FIRST: | ||
switch(c){ | ||
case "{": // object | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_KEY_FIRST; | ||
this._stack.push(this._parent); | ||
this._parent = PARSING_OBJECT; | ||
continue; | ||
case "[": // array | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_ARRAY_FIRST; | ||
this._stack.push(this._parent); | ||
this._parent = PARSING_ARRAY; | ||
continue; | ||
case "\"": // string | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_STRING_VALUE; | ||
continue; | ||
case "-": // number | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_NUMBER_START; | ||
continue; | ||
case "0": // number | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_FRACTION; | ||
continue; | ||
case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": // number | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: "nonZero", value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_NUMBER_DIGIT; | ||
continue; | ||
case "t": // true | ||
case "f": // false | ||
case "n": // null | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this._literal = LITERALS[c]; | ||
k = Math.min(this._literal.length + i, n); | ||
for(j = 1, ++i; i < k; ++j, ++i){ | ||
if(this._literal[j] !== s[i]) { | ||
return callback(new Error("While matching '" + this._literal + "' encountered '" + s[i] + "' instead of '" + this._literal[j] + "'")); | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "ws", value: i, line: this._line, pos: this._pos}; | ||
} | ||
} | ||
if(j < this._literal.length){ | ||
this._literalFrom = j; | ||
break main; | ||
} | ||
this.push({id: this._literal, value: this._literal, line: this._line, pos: this._pos}); | ||
--i; | ||
this._pos += this._literal.length - 1; | ||
this._literal = null; | ||
break; | ||
case " ": case "\t": case "\r": case "\n": // ws | ||
if(this._chunk && this._chunk.id !== "ws"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "ws", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
case "]": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(this._state !== EXPECTING_ARRAY_FIRST){ | ||
return callback(new Error("Expected a value but got ']' instead")); | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._parent = this._stack.pop(); | ||
break; | ||
default: | ||
return callback(new Error("Expected a value")); | ||
} | ||
break; | ||
case EXPECTING_KEY_FIRST: | ||
case EXPECTING_KEY: | ||
switch(c){ | ||
case "}": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(this._state !== EXPECTING_KEY_FIRST){ | ||
return callback(new Error("Expected a key value")); | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._parent = this._stack.pop(); | ||
break; | ||
case "\"": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_KEY_VALUE; | ||
continue; | ||
case " ": case "\t": case "\r": case "\n": // ws | ||
if(this._chunk && this._chunk.id !== "ws"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "ws", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
default: | ||
return callback(new Error("Expected a key")); | ||
} | ||
break; | ||
case EXPECTING_KEY_COLON: | ||
switch(c){ | ||
case ":": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_VALUE; | ||
continue; | ||
case " ": case "\t": case "\r": case "\n": // ws | ||
if(this._chunk && this._chunk.id !== "ws"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "ws", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
default: | ||
return callback(new Error("Expected ':'")); | ||
} | ||
break; | ||
case EXPECTING_OBJECT_STOP: | ||
switch(c){ | ||
case "}": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._parent = this._stack.pop(); | ||
break; | ||
case ",": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_KEY; | ||
continue; | ||
case " ": case "\t": case "\r": case "\n": // ws | ||
if(this._chunk && this._chunk.id !== "ws"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "ws", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
default: | ||
return callback(new Error("Expected ','")); | ||
} | ||
break; | ||
case EXPECTING_ARRAY_STOP: | ||
switch(c){ | ||
case "]": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._parent = this._stack.pop(); | ||
break; | ||
case ",": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_VALUE; | ||
continue; | ||
case " ": case "\t": case "\r": case "\n": // ws | ||
if(this._chunk && this._chunk.id !== "ws"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "ws", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
default: | ||
return callback(new Error("Expected ','")); | ||
} | ||
break; | ||
case EXPECTING_KEY_VALUE: | ||
case EXPECTING_STRING_VALUE: | ||
switch(c){ | ||
case "\"": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
if(this._state === EXPECTING_KEY_VALUE){ | ||
this._state = EXPECTING_KEY_COLON; | ||
continue; | ||
default: | ||
throw Error("Expected whitespace"); | ||
} | ||
break; | ||
case EXPECTING_VALUE: | ||
case EXPECTING_ARRAY_FIRST: | ||
switch(c){ | ||
case "{": // object | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_KEY_FIRST; | ||
this._stack.push(this._parent); | ||
this._parent = PARSING_OBJECT; | ||
continue; | ||
case "[": // array | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_ARRAY_FIRST; | ||
this._stack.push(this._parent); | ||
this._parent = PARSING_ARRAY; | ||
continue; | ||
case "\"": // string | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_STRING_VALUE; | ||
continue; | ||
case "-": // number | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_NUMBER_START; | ||
continue; | ||
case "0": // number | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_FRACTION; | ||
continue; | ||
case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": // number | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: "nonZero", value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_NUMBER_DIGIT; | ||
continue; | ||
case "t": // true | ||
case "f": // false | ||
case "n": // null | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this._literal = LITERALS[c]; | ||
k = Math.min(this._literal.length + i, n); | ||
for(j = 1, ++i; i < k; ++j, ++i){ | ||
if(this._literal[j] !== s[i]) { | ||
throw Error("While matching '" + this._literal + "' encountered '" + s[i] + "' instead of '" + this._literal[j] + "'"); | ||
} | ||
} | ||
if(j < this._literal.length){ | ||
this._literalFrom = j; | ||
break main; | ||
} | ||
this.push({id: this._literal, value: this._literal, line: this._line, pos: this._pos}); | ||
--i; | ||
this._pos += this._literal.length - 1; | ||
this._literal = null; | ||
break; | ||
case " ": case "\t": case "\r": case "\n": // ws | ||
if(this._chunk && this._chunk.id !== "ws"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "ws", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
case "]": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(this._state !== EXPECTING_ARRAY_FIRST){ | ||
throw Error("Expected a value but got ']' instead"); | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._parent = this._stack.pop(); | ||
break; | ||
default: | ||
throw Error("Expected a value"); | ||
} | ||
break; | ||
case EXPECTING_KEY_FIRST: | ||
case EXPECTING_KEY: | ||
switch(c){ | ||
case "}": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(this._state !== EXPECTING_KEY_FIRST){ | ||
throw Error("Expected a key value"); | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._parent = this._stack.pop(); | ||
break; | ||
case "\"": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_KEY_VALUE; | ||
continue; | ||
case " ": case "\t": case "\r": case "\n": // ws | ||
if(this._chunk && this._chunk.id !== "ws"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "ws", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
default: | ||
throw Error("Expected a key"); | ||
} | ||
break; | ||
case EXPECTING_KEY_COLON: | ||
switch(c){ | ||
case ":": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_VALUE; | ||
continue; | ||
case " ": case "\t": case "\r": case "\n": // ws | ||
if(this._chunk && this._chunk.id !== "ws"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "ws", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
default: | ||
throw Error("Expected ':'"); | ||
} | ||
break; | ||
case EXPECTING_OBJECT_STOP: | ||
switch(c){ | ||
case "}": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._parent = this._stack.pop(); | ||
break; | ||
case ",": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_KEY; | ||
continue; | ||
case " ": case "\t": case "\r": case "\n": // ws | ||
if(this._chunk && this._chunk.id !== "ws"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "ws", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
default: | ||
throw Error("Expected ','"); | ||
} | ||
break; | ||
case EXPECTING_ARRAY_STOP: | ||
switch(c){ | ||
case "]": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._parent = this._stack.pop(); | ||
break; | ||
case ",": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_VALUE; | ||
continue; | ||
case " ": case "\t": case "\r": case "\n": // ws | ||
if(this._chunk && this._chunk.id !== "ws"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "ws", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
default: | ||
throw Error("Expected ','"); | ||
} | ||
break; | ||
case EXPECTING_KEY_VALUE: | ||
case EXPECTING_STRING_VALUE: | ||
switch(c){ | ||
case "\"": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
if(this._state === EXPECTING_KEY_VALUE){ | ||
this._state = EXPECTING_KEY_COLON; | ||
continue; | ||
} | ||
break; | ||
case "\\": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(i + 1 < n){ | ||
c = s[++i]; | ||
switch(c){ | ||
case "\"": case "/": case "b": case "f": | ||
case "\\": case "n": case "r": case "t": | ||
this.push({id: "escapedChars", value: "\\" + c, line: this._line, pos: this._pos}); | ||
++this._pos; | ||
continue; | ||
case "u": | ||
k = Math.min(i + 5, n); | ||
for(j = 1, ++i; i < k; ++j, ++i){ | ||
if(!hex[s[i]]) { | ||
throw Error("While matching hexadecimals encountered '" + s[i] + "'"); | ||
} | ||
} | ||
break; | ||
case "\\": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(i + 1 < n){ | ||
c = s[++i]; | ||
switch(c){ | ||
case "\"": case "/": case "b": case "f": | ||
case "\\": case "n": case "r": case "t": | ||
this.push({id: "escapedChars", value: "\\" + c, line: this._line, pos: this._pos}); | ||
++this._pos; | ||
continue; | ||
case "u": | ||
k = Math.min(i + 5, n); | ||
for(j = 1, ++i; i < k; ++j, ++i){ | ||
if(!hex[s[i]]) { | ||
return callback(new Error("While matching hexadecimals encountered '" + s[i] + "'")); | ||
} | ||
if(j < 5){ | ||
// emit this._literal | ||
this._literal = HEXADECIMALS; | ||
this._literalFrom = j; | ||
break main; | ||
} | ||
this.push({id: "escapedChars", value: "\\u" + s.substr(i - 4, 4), | ||
line: this._line, pos: this._pos}); | ||
--i; | ||
this._pos += 5; | ||
continue; | ||
default: | ||
throw Error("Wrong escaped symbol '" + c + "'"); | ||
} | ||
} | ||
if(j < 5){ | ||
// emit this._literal | ||
this._literal = HEXADECIMALS; | ||
this._literalFrom = j; | ||
break main; | ||
} | ||
this.push({id: "escapedChars", value: "\\u" + s.substr(i - 4, 4), | ||
line: this._line, pos: this._pos}); | ||
--i; | ||
this._pos += 5; | ||
continue; | ||
default: | ||
return callback(new Error("Wrong escaped symbol '" + c + "'")); | ||
} | ||
this._literal = ESCAPED_CHAR; | ||
break main; | ||
default: | ||
if(this._chunk && this._chunk.id !== "plainChunk"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "plainChunk", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
} | ||
break; | ||
case EXPECTING_NUMBER_START: | ||
switch(c){ | ||
case "0": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_FRACTION; | ||
continue; | ||
case "1": case "2": case "3": | ||
case "4": case "5": case "6": | ||
case "7": case "8": case "9": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: "nonZero", value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_NUMBER_DIGIT; | ||
continue; | ||
default: | ||
throw Error("Expected a digit"); | ||
} | ||
break; | ||
case EXPECTING_NUMBER_DIGIT: | ||
case EXPECTING_FRACTION: | ||
case EXPECTING_FRAC_DIGIT: | ||
switch(c){ | ||
case "0": case "1": case "2": case "3": case "4": | ||
case "5": case "6": case "7": case "8": case "9": | ||
if(this._chunk && this._chunk.id !== "numericChunk"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(this._state === EXPECTING_FRACTION){ | ||
throw Error("Expected '.' or 'e'"); | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "numericChunk", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
case ".": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(this._state === EXPECTING_FRAC_DIGIT){ | ||
throw Error("Expected a digit"); | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_FRAC_START; | ||
continue; | ||
case "e": case "E": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: "exponent", value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_EXP_SIGN; | ||
continue; | ||
default: | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
--i; | ||
--this._pos; | ||
break; | ||
} | ||
break; | ||
case EXPECTING_FRAC_START: | ||
switch(c){ | ||
case "0": case "1": case "2": case "3": case "4": | ||
case "5": case "6": case "7": case "8": case "9": | ||
if(this._chunk && this._chunk.id !== "numericChunk"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "numericChunk", value: i, line: this._line, pos: this._pos}; | ||
} | ||
this._state = EXPECTING_FRAC_DIGIT; | ||
continue; | ||
default: | ||
throw Error("Expected a digit"); | ||
} | ||
break; | ||
case EXPECTING_EXP_SIGN: | ||
case EXPECTING_EXP_START: | ||
switch(c){ | ||
case "-": case "+": | ||
if(this._state === EXPECTING_EXP_START){ | ||
throw Error("Expected a digit"); | ||
} | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_EXP_START; | ||
continue; | ||
case "0": case "1": case "2": case "3": case "4": | ||
case "5": case "6": case "7": case "8": case "9": | ||
if(this._chunk && this._chunk.id !== "numericChunk"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "numericChunk", value: i, line: this._line, pos: this._pos}; | ||
} | ||
this._state = EXPECTING_EXP_DIGIT; | ||
continue; | ||
default: | ||
throw Error("Expected a digit"); | ||
} | ||
break; | ||
case EXPECTING_EXP_DIGIT: | ||
switch(c){ | ||
case "0": case "1": case "2": case "3": case "4": | ||
case "5": case "6": case "7": case "8": case "9": | ||
if(this._chunk && this._chunk.id !== "numericChunk"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "numericChunk", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
default: | ||
--i; | ||
--this._pos; | ||
break; | ||
} | ||
break; | ||
default: | ||
throw Error("Unexpected this._state: " + this._state); | ||
} | ||
// end of value | ||
switch(this._parent){ | ||
case PARSING_OBJECT: | ||
this._state = EXPECTING_OBJECT_STOP; | ||
break; | ||
case PARSING_ARRAY: | ||
this._state = EXPECTING_ARRAY_STOP; | ||
break; | ||
default: | ||
this._state = EXPECTING_NOTHING; | ||
break; | ||
} | ||
} | ||
this._literal = ESCAPED_CHAR; | ||
break main; | ||
default: | ||
if(this._chunk && this._chunk.id !== "plainChunk"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "plainChunk", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
} | ||
break; | ||
case EXPECTING_NUMBER_START: | ||
switch(c){ | ||
case "0": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_FRACTION; | ||
continue; | ||
case "1": case "2": case "3": | ||
case "4": case "5": case "6": | ||
case "7": case "8": case "9": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: "nonZero", value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_NUMBER_DIGIT; | ||
continue; | ||
default: | ||
return callback(new Error("Expected a digit")); | ||
} | ||
break; | ||
case EXPECTING_NUMBER_DIGIT: | ||
case EXPECTING_FRACTION: | ||
case EXPECTING_FRAC_DIGIT: | ||
switch(c){ | ||
case "0": case "1": case "2": case "3": case "4": | ||
case "5": case "6": case "7": case "8": case "9": | ||
if(this._chunk && this._chunk.id !== "numericChunk"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(this._state === EXPECTING_FRACTION){ | ||
return callback(new Error("Expected '.' or 'e'")); | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "numericChunk", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
case ".": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(this._state === EXPECTING_FRAC_DIGIT){ | ||
return callback(new Error("Expected a digit")); | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_FRAC_START; | ||
continue; | ||
case "e": case "E": | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: "exponent", value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_EXP_SIGN; | ||
continue; | ||
default: | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
--i; | ||
--this._pos; | ||
break; | ||
} | ||
break; | ||
case EXPECTING_FRAC_START: | ||
switch(c){ | ||
case "0": case "1": case "2": case "3": case "4": | ||
case "5": case "6": case "7": case "8": case "9": | ||
if(this._chunk && this._chunk.id !== "numericChunk"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "numericChunk", value: i, line: this._line, pos: this._pos}; | ||
} | ||
this._state = EXPECTING_FRAC_DIGIT; | ||
continue; | ||
default: | ||
return callback(new Error("Expected a digit")); | ||
} | ||
break; | ||
case EXPECTING_EXP_SIGN: | ||
case EXPECTING_EXP_START: | ||
switch(c){ | ||
case "-": case "+": | ||
if(this._state === EXPECTING_EXP_START){ | ||
return callback(new Error("Expected a digit")); | ||
} | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
this.push({id: c, value: c, line: this._line, pos: this._pos}); | ||
this._state = EXPECTING_EXP_START; | ||
continue; | ||
case "0": case "1": case "2": case "3": case "4": | ||
case "5": case "6": case "7": case "8": case "9": | ||
if(this._chunk && this._chunk.id !== "numericChunk"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "numericChunk", value: i, line: this._line, pos: this._pos}; | ||
} | ||
this._state = EXPECTING_EXP_DIGIT; | ||
continue; | ||
default: | ||
return callback(new Error("Expected a digit")); | ||
} | ||
break; | ||
case EXPECTING_EXP_DIGIT: | ||
switch(c){ | ||
case "0": case "1": case "2": case "3": case "4": | ||
case "5": case "6": case "7": case "8": case "9": | ||
if(this._chunk && this._chunk.id !== "numericChunk"){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
if(!this._chunk){ | ||
this._chunk = {id: "numericChunk", value: i, line: this._line, pos: this._pos}; | ||
} | ||
continue; | ||
default: | ||
--i; | ||
--this._pos; | ||
break; | ||
} | ||
break; | ||
default: | ||
return callback(new Error("Unexpected this._state: " + this._state)); | ||
} | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
// end of value | ||
switch(this._parent){ | ||
case PARSING_OBJECT: | ||
this._state = EXPECTING_OBJECT_STOP; | ||
break; | ||
case PARSING_ARRAY: | ||
this._state = EXPECTING_ARRAY_STOP; | ||
break; | ||
default: | ||
this._state = EXPECTING_NOTHING; | ||
break; | ||
} | ||
}while(false); | ||
}catch(err){ | ||
callback(err); | ||
return; | ||
} | ||
} | ||
if(this._chunk){ | ||
this._chunk.value = s.substring(this._chunk.value, i); | ||
this.push(this._chunk); | ||
this._chunk = null; | ||
} | ||
}while(false); | ||
callback(); | ||
@@ -664,0 +659,0 @@ }; |
717
Combo.js
@@ -79,285 +79,238 @@ "use strict"; | ||
Parser.prototype._processInput = function(callback){ | ||
try{ | ||
var match, value; | ||
main: for(;;){ | ||
switch(this._expect){ | ||
case "value1": | ||
case "value": | ||
match = value1.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
if(this._done){ | ||
throw Error("Parser cannot parse input: expected a value"); | ||
} | ||
} | ||
var match, value; | ||
main: for(;;){ | ||
switch(this._expect){ | ||
case "value1": | ||
case "value": | ||
match = value1.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
if(this._done){ | ||
throw Error("Parser has expected a value"); | ||
return callback(new Error("Parser cannot parse input: expected a value")); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
switch(value){ | ||
case "\"": | ||
this.push({name: "startString"}); | ||
this._expect = "string"; | ||
break; | ||
case "{": | ||
this.push({name: "startObject"}); | ||
this._stack.push(this._parent); | ||
this._parent = "object"; | ||
this._expect = "key1"; | ||
break; | ||
case "[": | ||
this.push({name: "startArray"}); | ||
this._stack.push(this._parent); | ||
this._parent = "array"; | ||
this._expect = "value1"; | ||
break; | ||
case "]": | ||
if(this._expect !== "value1"){ | ||
throw Error("Parser cannot parse input: unexpected token ']'"); | ||
} | ||
if(this._open_number){ | ||
this.push({name: "endNumber"}); | ||
this._open_number = false; | ||
if(this._packNumbers){ | ||
this.push({name: "numberValue", value: this._accumulator}); | ||
this._accumulator = ""; | ||
} | ||
} | ||
this.push({name: "endArray"}); | ||
this._parent = this._stack.pop(); | ||
this._expect = expected[this._parent]; | ||
break; | ||
case "-": | ||
this._open_number = true; | ||
this.push({name: "startNumber"}); | ||
this.push({name: "numberChunk", value: "-"}); | ||
if(this._packNumbers){ | ||
this._accumulator = "-"; | ||
} | ||
this._expect = "numberStart"; | ||
break; | ||
case "0": | ||
this._open_number = true; | ||
this.push({name: "startNumber"}); | ||
this.push({name: "numberChunk", value: "0"}); | ||
if(this._packNumbers){ | ||
this._accumulator = "0"; | ||
} | ||
this._expect = "numberFraction"; | ||
break; | ||
case "1": | ||
case "2": | ||
case "3": | ||
case "4": | ||
case "5": | ||
case "6": | ||
case "7": | ||
case "8": | ||
case "9": | ||
this._open_number = true; | ||
this.push({name: "startNumber"}); | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
this._accumulator = value; | ||
} | ||
this._expect = "numberDigit"; | ||
break; | ||
case "true": | ||
case "false": | ||
case "null": | ||
if(this._buffer.length === value.length && !this._done){ | ||
// wait for more input | ||
break main; | ||
} | ||
this.push({name: value + "Value", value: values[value]}); | ||
this._expect = expected[this._parent]; | ||
break; | ||
// default: // ws | ||
if(this._done){ | ||
return callback(new Error("Parser has expected a value")); | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "keyVal": | ||
case "string": | ||
match = string.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
if(this._done || this._buffer.length >= 6){ | ||
throw Error("Parser cannot parse input: escaped characters"); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
switch(value){ | ||
case "\"": | ||
this.push({name: "startString"}); | ||
this._expect = "string"; | ||
break; | ||
case "{": | ||
this.push({name: "startObject"}); | ||
this._stack.push(this._parent); | ||
this._parent = "object"; | ||
this._expect = "key1"; | ||
break; | ||
case "[": | ||
this.push({name: "startArray"}); | ||
this._stack.push(this._parent); | ||
this._parent = "array"; | ||
this._expect = "value1"; | ||
break; | ||
case "]": | ||
if(this._expect !== "value1"){ | ||
return callback(new Error("Parser cannot parse input: unexpected token ']'")); | ||
} | ||
if(this._done){ | ||
throw Error("Parser has expected a string value"); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === "\""){ | ||
if(this._expect === "keyVal"){ | ||
this.push({name: "endKey"}); | ||
if(this._packKeys){ | ||
this.push({name: "keyValue", value: this._accumulator}); | ||
if(this._open_number){ | ||
this.push({name: "endNumber"}); | ||
this._open_number = false; | ||
if(this._packNumbers){ | ||
this.push({name: "numberValue", value: this._accumulator}); | ||
this._accumulator = ""; | ||
} | ||
this._expect = "colon"; | ||
}else{ | ||
this.push({name: "endString"}); | ||
if(this._packStrings){ | ||
this.push({name: "stringValue", value: this._accumulator}); | ||
this._accumulator = ""; | ||
} | ||
this._expect = expected[this._parent]; | ||
} | ||
}else if(value.length > 1 && value.charAt(0) === "\\"){ | ||
var t = value.length == 2 ? codes[value.charAt(1)] : fromHex(value); | ||
this.push({name: "stringChunk", value: t}); | ||
if(this._expect === "keyVal" ? this._packKeys : this._packStrings){ | ||
this._accumulator += t; | ||
this.push({name: "endArray"}); | ||
this._parent = this._stack.pop(); | ||
this._expect = expected[this._parent]; | ||
break; | ||
case "-": | ||
this._open_number = true; | ||
this.push({name: "startNumber"}); | ||
this.push({name: "numberChunk", value: "-"}); | ||
if(this._packNumbers){ | ||
this._accumulator = "-"; | ||
} | ||
}else{ | ||
this.push({name: "stringChunk", value: value}); | ||
if(this._expect === "keyVal" ? this._packKeys : this._packStrings){ | ||
this._accumulator += value; | ||
this._expect = "numberStart"; | ||
break; | ||
case "0": | ||
this._open_number = true; | ||
this.push({name: "startNumber"}); | ||
this.push({name: "numberChunk", value: "0"}); | ||
if(this._packNumbers){ | ||
this._accumulator = "0"; | ||
} | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "key1": | ||
case "key": | ||
match = key1.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
throw Error("Parser cannot parse input: expected an object key"); | ||
this._expect = "numberFraction"; | ||
break; | ||
case "1": | ||
case "2": | ||
case "3": | ||
case "4": | ||
case "5": | ||
case "6": | ||
case "7": | ||
case "8": | ||
case "9": | ||
this._open_number = true; | ||
this.push({name: "startNumber"}); | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
this._accumulator = value; | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === "\""){ | ||
this.push({name: "startKey"}); | ||
this._expect = "keyVal"; | ||
}else if(value === "}"){ | ||
if(this._expect !== "key1"){ | ||
throw Error("Parser cannot parse input: unexpected token '}'"); | ||
this._expect = "numberDigit"; | ||
break; | ||
case "true": | ||
case "false": | ||
case "null": | ||
if(this._buffer.length === value.length && !this._done){ | ||
// wait for more input | ||
break main; | ||
} | ||
this.push({name: "endObject"}); | ||
this._parent = this._stack.pop(); | ||
this.push({name: value + "Value", value: values[value]}); | ||
this._expect = expected[this._parent]; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "colon": | ||
match = colon.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
throw Error("Parser cannot parse input: expected ':'"); | ||
break; | ||
// default: // ws | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "keyVal": | ||
case "string": | ||
match = string.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
if(this._done || this._buffer.length >= 6){ | ||
return callback(new Error("Parser cannot parse input: escaped characters")); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === ":"){ | ||
this._expect = "value"; | ||
if(this._done){ | ||
return callback(new Error("Parser has expected a string value")); | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "arrayStop": | ||
case "objectStop": | ||
match = comma.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
throw Error("Parser cannot parse input: expected ','"); | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === "\""){ | ||
if(this._expect === "keyVal"){ | ||
this.push({name: "endKey"}); | ||
if(this._packKeys){ | ||
this.push({name: "keyValue", value: this._accumulator}); | ||
this._accumulator = ""; | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
if(this._open_number){ | ||
this.push({name: "endNumber"}); | ||
this._open_number = false; | ||
if(this._packNumbers){ | ||
this.push({name: "numberValue", value: this._accumulator}); | ||
this._expect = "colon"; | ||
}else{ | ||
this.push({name: "endString"}); | ||
if(this._packStrings){ | ||
this.push({name: "stringValue", value: this._accumulator}); | ||
this._accumulator = ""; | ||
} | ||
} | ||
value = match[0]; | ||
if(value === ","){ | ||
this._expect = this._expect === "arrayStop" ? "value" : "key"; | ||
}else if(value === "}" || value === "]"){ | ||
this.push({name: value === "}" ? "endObject" : "endArray"}); | ||
this._parent = this._stack.pop(); | ||
this._expect = expected[this._parent]; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
// number chunks | ||
case "numberStart": // [0-9] | ||
match = numberStart.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
throw Error("Parser cannot parse input: expected a digit"); | ||
} | ||
// wait for more input | ||
break main; | ||
}else if(value.length > 1 && value.charAt(0) === "\\"){ | ||
var t = value.length == 2 ? codes[value.charAt(1)] : fromHex(value); | ||
this.push({name: "stringChunk", value: t}); | ||
if(this._expect === "keyVal" ? this._packKeys : this._packStrings){ | ||
this._accumulator += t; | ||
} | ||
value = match[0]; | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
}else{ | ||
this.push({name: "stringChunk", value: value}); | ||
if(this._expect === "keyVal" ? this._packKeys : this._packStrings){ | ||
this._accumulator += value; | ||
} | ||
this._expect = value === "0" ? "numberFraction" : "numberDigit"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberDigit": // [0-9]* | ||
match = numberDigit.exec(this._buffer); | ||
value = match[0]; | ||
if(value){ | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
this._accumulator += value; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
}else{ | ||
if(this._buffer){ | ||
this._expect = "numberFraction"; | ||
break; | ||
} | ||
if(this._done){ | ||
this._expect = expected[this._parent]; | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "key1": | ||
case "key": | ||
match = key1.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
return callback(new Error("Parser cannot parse input: expected an object key")); | ||
} | ||
break; | ||
case "numberFraction": // [\.eE]? | ||
match = numberFraction.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
this._expect = expected[this._parent]; | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === "\""){ | ||
this.push({name: "startKey"}); | ||
this._expect = "keyVal"; | ||
}else if(value === "}"){ | ||
if(this._expect !== "key1"){ | ||
return callback(new Error("Parser cannot parse input: unexpected token '}'")); | ||
} | ||
value = match[0]; | ||
this.push({name: "numberChunk", value: value}); | ||
this.push({name: "endObject"}); | ||
this._parent = this._stack.pop(); | ||
this._expect = expected[this._parent]; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "colon": | ||
match = colon.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
return callback(new Error("Parser cannot parse input: expected ':'")); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === ":"){ | ||
this._expect = "value"; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "arrayStop": | ||
case "objectStop": | ||
match = comma.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
return callback(new Error("Parser cannot parse input: expected ','")); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
if(this._open_number){ | ||
this.push({name: "endNumber"}); | ||
this._open_number = false; | ||
if(this._packNumbers){ | ||
this._accumulator += value; | ||
this.push({name: "numberValue", value: this._accumulator}); | ||
this._accumulator = ""; | ||
} | ||
this._expect = value === "." ? "numberFracStart" : "numberExpSign"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberFracStart": // [0-9] | ||
match = numberFracStart.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
throw Error("Parser cannot parse input: expected a fractional part of a number"); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === ","){ | ||
this._expect = this._expect === "arrayStop" ? "value" : "key"; | ||
}else if(value === "}" || value === "]"){ | ||
this.push({name: value === "}" ? "endObject" : "endArray"}); | ||
this._parent = this._stack.pop(); | ||
this._expect = expected[this._parent]; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
// number chunks | ||
case "numberStart": // [0-9] | ||
match = numberStart.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
return callback(new Error("Parser cannot parse input: expected a digit")); | ||
} | ||
value = match[0]; | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
this._accumulator += value; | ||
} | ||
this._expect = value === "0" ? "numberFraction" : "numberDigit"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberDigit": // [0-9]* | ||
match = numberDigit.exec(this._buffer); | ||
value = match[0]; | ||
if(value){ | ||
this.push({name: "numberChunk", value: value}); | ||
@@ -367,63 +320,55 @@ if(this._packNumbers){ | ||
} | ||
this._expect = "numberFracDigit"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberFracDigit": // [0-9]* | ||
match = numberFracDigit.exec(this._buffer); | ||
value = match[0]; | ||
if(value){ | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
this._accumulator += value; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
}else{ | ||
if(this._buffer){ | ||
this._expect = "numberExponent"; | ||
break; | ||
} | ||
if(this._done){ | ||
this._expect = expected[this._parent]; | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
}else{ | ||
if(this._buffer){ | ||
this._expect = "numberFraction"; | ||
break; | ||
} | ||
break; | ||
case "numberExponent": // [eE]? | ||
match = numberExponent.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
this._expect = expected[this._parent]; | ||
break; | ||
} | ||
if(this._done){ | ||
this._expect = "done"; | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
if(this._done){ | ||
this._expect = expected[this._parent]; | ||
break; | ||
} | ||
value = match[0]; | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
this._accumulator += value; | ||
// wait for more input | ||
break main; | ||
} | ||
break; | ||
case "numberFraction": // [\.eE]? | ||
match = numberFraction.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
this._expect = expected[this._parent]; | ||
break; | ||
} | ||
this._expect = "numberExpSign"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberExpSign": // [-+]? | ||
match = numberExpSign.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
this._expect = "numberExpStart"; | ||
break; | ||
} | ||
if(this._done){ | ||
throw Error("Parser has expected an exponent value of a number"); | ||
} | ||
// wait for more input | ||
break main; | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
this._accumulator += value; | ||
} | ||
this._expect = value === "." ? "numberFracStart" : "numberExpSign"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberFracStart": // [0-9] | ||
match = numberFracStart.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
return callback(new Error("Parser cannot parse input: expected a fractional part of a number")); | ||
} | ||
value = match[0]; | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
this._accumulator += value; | ||
} | ||
this._expect = "numberFracDigit"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberFracDigit": // [0-9]* | ||
match = numberFracDigit.exec(this._buffer); | ||
value = match[0]; | ||
if(value){ | ||
this.push({name: "numberChunk", value: value}); | ||
@@ -433,15 +378,80 @@ if(this._packNumbers){ | ||
} | ||
this._expect = "numberExpStart"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberExpStart": // [0-9] | ||
match = numberExpStart.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
throw Error("Parser cannot parse input: expected an exponent part of a number"); | ||
} | ||
// wait for more input | ||
break main; | ||
}else{ | ||
if(this._buffer){ | ||
this._expect = "numberExponent"; | ||
break; | ||
} | ||
value = match[0]; | ||
if(this._done){ | ||
this._expect = expected[this._parent]; | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
break; | ||
case "numberExponent": // [eE]? | ||
match = numberExponent.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
this._expect = expected[this._parent]; | ||
break; | ||
} | ||
if(this._done){ | ||
this._expect = "done"; | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
this._accumulator += value; | ||
} | ||
this._expect = "numberExpSign"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberExpSign": // [-+]? | ||
match = numberExpSign.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
this._expect = "numberExpStart"; | ||
break; | ||
} | ||
if(this._done){ | ||
return callback(new Error("Parser has expected an exponent value of a number")); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
this._accumulator += value; | ||
} | ||
this._expect = "numberExpStart"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberExpStart": // [0-9] | ||
match = numberExpStart.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
return callback(new Error("Parser cannot parse input: expected an exponent part of a number")); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
this._accumulator += value; | ||
} | ||
this._expect = "numberExpDigit"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberExpDigit": // [0-9]* | ||
match = numberExpDigit.exec(this._buffer); | ||
value = match[0]; | ||
if(value){ | ||
this.push({name: "numberChunk", value: value}); | ||
@@ -451,47 +461,32 @@ if(this._packNumbers){ | ||
} | ||
this._expect = "numberExpDigit"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberExpDigit": // [0-9]* | ||
match = numberExpDigit.exec(this._buffer); | ||
value = match[0]; | ||
if(value){ | ||
this.push({name: "numberChunk", value: value}); | ||
if(this._packNumbers){ | ||
this._accumulator += value; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
}else{ | ||
if(this._buffer || this._done){ | ||
this._expect = expected[this._parent]; | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
}else{ | ||
if(this._buffer || this._done){ | ||
this._expect = expected[this._parent]; | ||
break; | ||
} | ||
break; | ||
case "done": | ||
match = ws.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
throw Error("Parser cannot parse input: unexpected characters"); | ||
} | ||
// wait for more input | ||
break main; | ||
// wait for more input | ||
break main; | ||
} | ||
break; | ||
case "done": | ||
match = ws.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
return callback(new Error("Parser cannot parse input: unexpected characters")); | ||
} | ||
if(this._open_number){ | ||
this.push({name: "endNumber"}); | ||
this._open_number = false; | ||
if(this._packNumbers){ | ||
this.push({name: "numberValue", value: this._accumulator}); | ||
this._accumulator = ""; | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
if(this._open_number){ | ||
this.push({name: "endNumber"}); | ||
this._open_number = false; | ||
if(this._packNumbers){ | ||
this.push({name: "numberValue", value: this._accumulator}); | ||
this._accumulator = ""; | ||
} | ||
this._buffer = this._buffer.substring(match[0].length); | ||
break; | ||
} | ||
} | ||
this._buffer = this._buffer.substring(match[0].length); | ||
break; | ||
} | ||
}catch(err){ | ||
callback(err); | ||
return; | ||
} | ||
@@ -498,0 +493,0 @@ callback(); |
{ | ||
"name": "stream-json", | ||
"version": "0.4.1", | ||
"version": "0.4.2", | ||
"description": "stream-json is a SAX-inspired stream components with a minimal memory footprint to parse huge JSON files. Includes utilities to stream Django-like JSON database dumps.", | ||
@@ -15,3 +15,3 @@ "homepage": "http://github.com/uhop/stream-json", | ||
"devDependencies": { | ||
"heya-unit": "^0.2.0" | ||
"heya-unit": "^0.3.0" | ||
}, | ||
@@ -18,0 +18,0 @@ "scripts": { |
657
Parser.js
@@ -48,143 +48,78 @@ "use strict"; | ||
Parser.prototype._processInput = function(callback){ | ||
try{ | ||
var match, value; | ||
main: for(;;){ | ||
switch(this._expect){ | ||
case "value1": | ||
case "value": | ||
match = value1.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
if(this._done){ | ||
throw Error("Parser cannot parse input: expected a value"); | ||
} | ||
} | ||
var match, value; | ||
main: for(;;){ | ||
switch(this._expect){ | ||
case "value1": | ||
case "value": | ||
match = value1.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
if(this._done){ | ||
throw Error("Parser has expected a value"); | ||
return callback(new Error("Parser cannot parse input: expected a value")); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
switch(value){ | ||
case "\"": | ||
this.push({id: value, value: value}); | ||
this._expect = "string"; | ||
break; | ||
case "{": | ||
this.push({id: value, value: value}); | ||
this._stack.push(this._parent); | ||
this._parent = "object"; | ||
this._expect = "key1"; | ||
break; | ||
case "[": | ||
this.push({id: value, value: value}); | ||
this._stack.push(this._parent); | ||
this._parent = "array"; | ||
this._expect = "value1"; | ||
break; | ||
case "]": | ||
if(this._expect !== "value1"){ | ||
throw Error("Parser cannot parse input: unexpected token ']'"); | ||
} | ||
this.push({id: value, value: value}); | ||
this._parent = this._stack.pop(); | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
} | ||
break; | ||
case "-": | ||
this.push({id: value, value: value}); | ||
this._expect = "numberStart"; | ||
break; | ||
case "0": | ||
this.push({id: value, value: value}); | ||
this._expect = "numberFraction"; | ||
break; | ||
case "1": | ||
case "2": | ||
case "3": | ||
case "4": | ||
case "5": | ||
case "6": | ||
case "7": | ||
case "8": | ||
case "9": | ||
this.push({id: "nonZero", value: value}); | ||
this._expect = "numberDigit"; | ||
break; | ||
case "true": | ||
case "false": | ||
case "null": | ||
if(this._buffer.length === value.length && !this._done){ | ||
// wait for more input | ||
break main; | ||
} | ||
this.push({id: value, value: value}); | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
} | ||
break; | ||
// default: // ws | ||
if(this._done){ | ||
return callback(new Error("Parser has expected a value")); | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "keyVal": | ||
case "string": | ||
match = string.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
if(this._done || this._buffer.length >= 6){ | ||
throw Error("Parser cannot parse input: escaped characters"); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
switch(value){ | ||
case "\"": | ||
this.push({id: value, value: value}); | ||
this._expect = "string"; | ||
break; | ||
case "{": | ||
this.push({id: value, value: value}); | ||
this._stack.push(this._parent); | ||
this._parent = "object"; | ||
this._expect = "key1"; | ||
break; | ||
case "[": | ||
this.push({id: value, value: value}); | ||
this._stack.push(this._parent); | ||
this._parent = "array"; | ||
this._expect = "value1"; | ||
break; | ||
case "]": | ||
if(this._expect !== "value1"){ | ||
return callback(new Error("Parser cannot parse input: unexpected token ']'")); | ||
} | ||
if(this._done){ | ||
throw Error("Parser has expected a string value"); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === "\""){ | ||
this.push({id: value, value: value}); | ||
if(this._expect === "keyVal"){ | ||
this._expect = "colon"; | ||
this._parent = this._stack.pop(); | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
} | ||
this._expect = "done"; | ||
} | ||
}else if(value.length > 1 && value.charAt(0) === "\\"){ | ||
this.push({id: "escapedChars", value: value}); | ||
}else{ | ||
this.push({id: "plainChunk", value: value}); | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "key1": | ||
case "key": | ||
match = key1.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
throw Error("Parser cannot parse input: expected an object key"); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === "\""){ | ||
break; | ||
case "-": | ||
this.push({id: value, value: value}); | ||
this._expect = "keyVal"; | ||
}else if(value === "}"){ | ||
if(this._expect !== "key1"){ | ||
throw Error("Parser cannot parse input: unexpected token '}'"); | ||
this._expect = "numberStart"; | ||
break; | ||
case "0": | ||
this.push({id: value, value: value}); | ||
this._expect = "numberFraction"; | ||
break; | ||
case "1": | ||
case "2": | ||
case "3": | ||
case "4": | ||
case "5": | ||
case "6": | ||
case "7": | ||
case "8": | ||
case "9": | ||
this.push({id: "nonZero", value: value}); | ||
this._expect = "numberDigit"; | ||
break; | ||
case "true": | ||
case "false": | ||
case "null": | ||
if(this._buffer.length === value.length && !this._done){ | ||
// wait for more input | ||
break main; | ||
} | ||
this.push({id: value, value: value}); | ||
this._parent = this._stack.pop(); | ||
if(this._parent){ | ||
@@ -195,38 +130,28 @@ this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
} | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "colon": | ||
match = colon.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
throw Error("Parser cannot parse input: expected ':'"); | ||
break; | ||
// default: // ws | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "keyVal": | ||
case "string": | ||
match = string.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
if(this._done || this._buffer.length >= 6){ | ||
return callback(new Error("Parser cannot parse input: escaped characters")); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === ":"){ | ||
this.push({id: value, value: value}); | ||
this._expect = "value"; | ||
if(this._done){ | ||
return callback(new Error("Parser has expected a string value")); | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "arrayStop": | ||
case "objectStop": | ||
match = comma.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
throw Error("Parser cannot parse input: expected ','"); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === ","){ | ||
this.push({id: value, value: value}); | ||
this._expect = this._expect === "arrayStop" ? "value" : "key"; | ||
}else if(value === "}" || value === "]"){ | ||
this.push({id: value, value: value}); | ||
this._parent = this._stack.pop(); | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === "\""){ | ||
this.push({id: value, value: value}); | ||
if(this._expect === "keyVal"){ | ||
this._expect = "colon"; | ||
}else{ | ||
if(this._parent){ | ||
@@ -238,198 +163,268 @@ this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
// number chunks | ||
case "numberStart": // [0-9] | ||
match = numberStart.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
throw Error("Parser cannot parse input: expected a digit"); | ||
} | ||
// wait for more input | ||
break main; | ||
}else if(value.length > 1 && value.charAt(0) === "\\"){ | ||
this.push({id: "escapedChars", value: value}); | ||
}else{ | ||
this.push({id: "plainChunk", value: value}); | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "key1": | ||
case "key": | ||
match = key1.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
return callback(new Error("Parser cannot parse input: expected an object key")); | ||
} | ||
value = match[0]; | ||
if(value === "0"){ | ||
this.push({id: value, value: value}); | ||
this._expect = "numberFraction"; | ||
}else{ | ||
this.push({id: "nonZero", value: value}); | ||
this._expect = "numberDigit"; | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === "\""){ | ||
this.push({id: value, value: value}); | ||
this._expect = "keyVal"; | ||
}else if(value === "}"){ | ||
if(this._expect !== "key1"){ | ||
return callback(new Error("Parser cannot parse input: unexpected token '}'")); | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberDigit": // [0-9]* | ||
match = numberDigit.exec(this._buffer); | ||
value = match[0]; | ||
if(value){ | ||
this.push({id: "numericChunk", value: value}); | ||
this._buffer = this._buffer.substring(value.length); | ||
this.push({id: value, value: value}); | ||
this._parent = this._stack.pop(); | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
if(this._buffer){ | ||
this._expect = "numberFraction"; | ||
break; | ||
} | ||
if(this._done){ | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
} | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
this._expect = "done"; | ||
} | ||
break; | ||
case "numberFraction": // [\.eE]? | ||
match = numberFraction.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
} | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "colon": | ||
match = colon.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
return callback(new Error("Parser cannot parse input: expected ':'")); | ||
} | ||
value = match[0]; | ||
if(value === "."){ | ||
this.push({id: value, value: value}); | ||
this._expect = "numberFracStart"; | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === ":"){ | ||
this.push({id: value, value: value}); | ||
this._expect = "value"; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "arrayStop": | ||
case "objectStop": | ||
match = comma.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
return callback(new Error("Parser cannot parse input: expected ','")); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === ","){ | ||
this.push({id: value, value: value}); | ||
this._expect = this._expect === "arrayStop" ? "value" : "key"; | ||
}else if(value === "}" || value === "]"){ | ||
this.push({id: value, value: value}); | ||
this._parent = this._stack.pop(); | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this.push({id: "exponent", value: value}); | ||
this._expect = "numberExpSign"; | ||
this._expect = "done"; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberFracStart": // [0-9] | ||
match = numberFracStart.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
throw Error("Parser cannot parse input: expected a fractional part of a number"); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
// number chunks | ||
case "numberStart": // [0-9] | ||
match = numberStart.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
return callback(new Error("Parser cannot parse input: expected a digit")); | ||
} | ||
value = match[0]; | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === "0"){ | ||
this.push({id: value, value: value}); | ||
this._expect = "numberFraction"; | ||
}else{ | ||
this.push({id: "nonZero", value: value}); | ||
this._expect = "numberDigit"; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberDigit": // [0-9]* | ||
match = numberDigit.exec(this._buffer); | ||
value = match[0]; | ||
if(value){ | ||
this.push({id: "numericChunk", value: value}); | ||
this._expect = "numberFracDigit"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberFracDigit": // [0-9]* | ||
match = numberFracDigit.exec(this._buffer); | ||
value = match[0]; | ||
if(value){ | ||
this.push({id: "numericChunk", value: value}); | ||
this._buffer = this._buffer.substring(value.length); | ||
}else{ | ||
if(this._buffer){ | ||
this._expect = "numberExponent"; | ||
break; | ||
}else{ | ||
if(this._buffer){ | ||
this._expect = "numberFraction"; | ||
break; | ||
} | ||
if(this._done){ | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
} | ||
if(this._done){ | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
} | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
break; | ||
} | ||
break; | ||
case "numberExponent": // [eE]? | ||
match = numberExponent.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
} | ||
break; | ||
} | ||
if(this._done){ | ||
// wait for more input | ||
break main; | ||
} | ||
break; | ||
case "numberFraction": // [\.eE]? | ||
match = numberFraction.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
break; | ||
} | ||
value = match[0]; | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
if(value === "."){ | ||
this.push({id: value, value: value}); | ||
this._expect = "numberFracStart"; | ||
}else{ | ||
this.push({id: "exponent", value: value}); | ||
this._expect = "numberExpSign"; | ||
} | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberFracStart": // [0-9] | ||
match = numberFracStart.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
return callback(new Error("Parser cannot parse input: expected a fractional part of a number")); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
this.push({id: "numericChunk", value: value}); | ||
this._expect = "numberFracDigit"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberFracDigit": // [0-9]* | ||
match = numberFracDigit.exec(this._buffer); | ||
value = match[0]; | ||
if(value){ | ||
this.push({id: "numericChunk", value: value}); | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberExpSign": // [-+]? | ||
match = numberExpSign.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
this._expect = "numberExpStart"; | ||
break; | ||
}else{ | ||
if(this._buffer){ | ||
this._expect = "numberExponent"; | ||
break; | ||
} | ||
if(this._done){ | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
} | ||
if(this._done){ | ||
throw Error("Parser has expected an exponent value of a number"); | ||
} | ||
// wait for more input | ||
break main; | ||
break; | ||
} | ||
value = match[0]; | ||
this.push({id: value, value: value}); | ||
this._expect = "numberExpStart"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberExpStart": // [0-9] | ||
match = numberExpStart.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
throw Error("Parser cannot parse input: expected an exponent part of a number"); | ||
// wait for more input | ||
break main; | ||
} | ||
break; | ||
case "numberExponent": // [eE]? | ||
match = numberExponent.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
} | ||
// wait for more input | ||
break main; | ||
break; | ||
} | ||
value = match[0]; | ||
if(this._done){ | ||
this._expect = "done"; | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
this.push({id: "exponent", value: value}); | ||
this._expect = "numberExpSign"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberExpSign": // [-+]? | ||
match = numberExpSign.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
this._expect = "numberExpStart"; | ||
break; | ||
} | ||
if(this._done){ | ||
return callback(new Error("Parser has expected an exponent value of a number")); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
this.push({id: value, value: value}); | ||
this._expect = "numberExpStart"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberExpStart": // [0-9] | ||
match = numberExpStart.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer || this._done){ | ||
return callback(new Error("Parser cannot parse input: expected an exponent part of a number")); | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
value = match[0]; | ||
this.push({id: "numericChunk", value: value}); | ||
this._expect = "numberExpDigit"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberExpDigit": // [0-9]* | ||
match = numberExpDigit.exec(this._buffer); | ||
value = match[0]; | ||
if(value){ | ||
this.push({id: "numericChunk", value: value}); | ||
this._expect = "numberExpDigit"; | ||
this._buffer = this._buffer.substring(value.length); | ||
break; | ||
case "numberExpDigit": // [0-9]* | ||
match = numberExpDigit.exec(this._buffer); | ||
value = match[0]; | ||
if(value){ | ||
this.push({id: "numericChunk", value: value}); | ||
this._buffer = this._buffer.substring(value.length); | ||
}else{ | ||
if(this._buffer || this._done){ | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
} | ||
break; | ||
}else{ | ||
if(this._buffer || this._done){ | ||
if(this._parent){ | ||
this._expect = this._parent === "object" ? "objectStop" : "arrayStop"; | ||
}else{ | ||
this._expect = "done"; | ||
} | ||
// wait for more input | ||
break main; | ||
break; | ||
} | ||
break; | ||
case "done": | ||
match = ws.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
throw Error("Parser cannot parse input: unexpected characters"); | ||
} | ||
// wait for more input | ||
break main; | ||
// wait for more input | ||
break main; | ||
} | ||
break; | ||
case "done": | ||
match = ws.exec(this._buffer); | ||
if(!match){ | ||
if(this._buffer){ | ||
return callback(new Error("Parser cannot parse input: unexpected characters")); | ||
} | ||
this._buffer = this._buffer.substring(match[0].length); | ||
break; | ||
} | ||
// wait for more input | ||
break main; | ||
} | ||
this._buffer = this._buffer.substring(match[0].length); | ||
break; | ||
} | ||
}catch(err){ | ||
callback(err); | ||
return; | ||
} | ||
@@ -436,0 +431,0 @@ callback(); |
@@ -574,3 +574,3 @@ # stream-json | ||
The whole library is organized as set of small components, which can be combined to produce the most effective pipeline. All components are based on node.js [streams](http://nodejs.org/api/stream.html), and [events](http://nodejs.org/api/events.html). They implement all required standard APIs. It is easy to add your own components to solve your unique tasks. | ||
The whole library is organized as a set of small components, which can be combined to produce the most effective pipeline. All components are based on node.js [streams](http://nodejs.org/api/stream.html), and [events](http://nodejs.org/api/events.html). They implement all required standard APIs. It is easy to add your own components to solve your unique tasks. | ||
@@ -585,3 +585,3 @@ The code of all components are compact and simple. Please take a look at their source code to see how things are implemented, so you can produce your own components in no time. | ||
* a snapshot of publicly available [Japanese statistics on birth and marriage in JSON)](http://dataforjapan.org/dataset/birth-stat/resource/42799d3c-ecee-4b35-9f5a-7fec30596aa2). | ||
* a snapshot of publicly available [Japanese statistics on birth and marriage in JSON](http://dataforjapan.org/dataset/birth-stat/resource/42799d3c-ecee-4b35-9f5a-7fec30596aa2). | ||
* a snapshot of publicly available [US Department of Housing and Urban Development - HUD's published metadata catalog (Schema Version 1.1)](https://catalog.data.gov/dataset/data-catalog). | ||
@@ -630,2 +630,3 @@ * a small fake sample made up by me featuring non-ASCII keys, non-ASCII strings, and primitive data missing in other two samples. | ||
- 0.4.2 *refreshed dependencies.* | ||
- 0.4.1 *added `StreamObject` by [Sam Noedel](https://github.com/delta62)* | ||
@@ -632,0 +633,0 @@ - 0.4.0 *new high-performant Combo component, switched to the previous parser.* |
@@ -18,3 +18,3 @@ "use strict"; | ||
//stringValue: stringValue, // aliased above as _saveValue | ||
//stringValue: stringValue, // aliased below as _saveValue | ||
numberValue: function(value){ this._saveValue(parseFloat(value)); }, | ||
@@ -21,0 +21,0 @@ nullValue: function(){ this._saveValue(null); }, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
650
206438
3653