Skip to content

Instantly share code, notes, and snippets.

@berlysia
Last active March 16, 2016 19:09
Show Gist options
  • Save berlysia/03e8c3207c0db030a243 to your computer and use it in GitHub Desktop.
Save berlysia/03e8c3207c0db030a243 to your computer and use it in GitHub Desktop.
'use strict';
function parse(json) {
return _parseValue(json, 0).value;
}
module.exports = parse;
const WHITESPACE = ' \t\n\r';
const DIGIT = '0123456789';
const FRAC = 'eE';
const SIGN = '+-';
function _eatWhitespace(str, pos) {
while(~WHITESPACE.indexOf(str.charAt(pos))) ++pos;
return pos;
}
function _parseValue(str, pos) {
pos = _eatWhitespace(str, pos);
switch(str.charAt(pos)) {
case '"':
return _parseString(str, pos);
case '{':
return _parseObject(str, pos);
case '[':
return _parseArray(str, pos);
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return _parseNumber(str, pos);
case 't':
case 'f':
return _parseBoolean(str, pos);
case 'n':
return _parseNull(str, pos);
default:
throw new Error('Unknown Token');
}
}
function _parseObject(str, pos) {
const ret = {};
++pos; // '{'
pos = _eatWhitespace(str, pos);
for(;;) {
pos = _eatWhitespace(str, pos);
const keyCur = _parseString(str, pos);
const key = keyCur.value;
pos = _eatWhitespace(str, keyCur.next);
if(str.charAt(pos) === ':') ++pos;
else throw new Error('Syntax Error');
const valCur = _parseValue(str, pos);
ret[key] = valCur.value;
pos = _eatWhitespace(str, valCur.next);
if(str.charAt(pos) === ',') ++pos;
if(str.charAt(pos) === '}') {
++pos;
break;
}
}
return {
value: ret,
next: pos,
}
}
function _parseNumber(str, pos) {
const beginPos = pos;
let sign, digits, float, floatDigits, powSign, powDigits;
if(~SIGN.indexOf(str.charAt(pos))) {
++pos; // sign;
sign = str.charAt(pos) === '+';
} else {
sign = true;
}
while(~DIGIT.indexOf(str.charAt(pos))) ++pos; // digits
if(str.charAt(pos) === '.') {
++pos; // dot
while(~DIGIT.indexOf(str.charAt(pos))) ++pos; // digits
}
if(~FRAC.indexOf(str.charAt(pos))) {
++pos; // frac
if(~SIGN.indexOf(str.charAt(pos))) ++pos; // sign
while(~DIGIT.indexOf(str.charAt(pos))) ++pos; // digits
}
return {
value: Number(str.substr(beginPos, pos - beginPos)), // ;P
next: pos,
};
}
function _parseArray(str, pos) {
const ret = [];
++pos;
for(;;) {
pos = _eatWhitespace(str, pos);
const cur = _parseValue(str, pos);
ret.push(cur.value);
pos = _eatWhitespace(str, cur.next);
if(str.charAt(pos) === ',') ++pos;
if(str.charAt(pos) === ']') {
++pos;
break;
}
}
return {value: ret, next: pos};
}
function _parseBoolean(str, pos) {
const head = str.charAt(pos);
if(head === 't' && str.substr(pos, 4) === 'true') {
return {
value: true,
next: pos + 4,
}
}else if(head === 'f' && str.substr(pos, 5) === 'false'){
return {
value: false,
next: pos + 5,
}
}else{
throw new Error('Syntax Error');
}
}
function _parseNull(str, pos) {
if(str.substr(pos, 4) === 'null') {
return {
value: null,
next: pos + 4,
}
} else {
throw new Error('Syntax Error');
}
}
function _parseString(str, pos) {
const beginPos = pos + 1;/* " */
let escaped = false;
while(++pos) {
if(escaped) {
escaped = false;
continue;
}
if(str.charAt(pos) === '\\') {
escaped = true;
continue;
}
if(str.charAt(pos) === '"') {
break;
}
}
return {
value: str.substr(beginPos, pos - beginPos),
next: pos+1/* " */
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment