Last active
March 16, 2016 19:09
-
-
Save berlysia/03e8c3207c0db030a243 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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