UNPKG

jsonast

Version:

a json to ast parser which allows error recovery

251 lines 5.52 kB
"use strict"; var character_stream_1 = require('./character-stream'); /** * Parses a given string into a Json AST. * This parser does some error correction (notably missing comma in objects and arrays). * The template parameter could be used to qualify the result AST. * * @export * @param {string} text The Json text to parse * @returns {JsonObject|JsonArray} Either a Json Object or Json Array AST node */ function parse(text) { var result = undefined; var cs = new character_stream_1.CharacterStream(text); ws(cs); if (cs.ch === '{') { result = object(cs); } else if (cs.ch === '[') { result = array(cs); } ws(cs); if (!cs.eoi) { throw new Error("Unexpected character '" + cs.ch + "' at " + cs.line + ":" + cs.column + ". Expected end of input."); } return result; } Object.defineProperty(exports, "__esModule", { value: true }); exports.default = parse; function object(cs) { function members(cs1) { function pair(cs2) { ws(cs2); var key = string(cs2); ws(cs2); cs2.accept(':'); return { key: key, value: value(cs2) }; } var members = []; var next = true; while (next) { members.push(pair(cs1)); ws(cs1); if (cs1.ch === ',') { cs1.next(); } else if (cs1.ch === '"') { } else { next = false; } } return members; } var ast = { type: 'object', pos: { start: cs.pos, end: cs.pos } }; ws(cs); cs.accept('{'); ws(cs); if (cs.ch === '"') { ast.members = members(cs); } ws(cs); cs.accept('}'); ast.pos.end = cs.pos; return ast; } function array(cs) { var ast = { type: 'array', pos: { start: cs.pos, end: cs.pos } }; ws(cs); cs.accept('['); if (cs.ch !== ']') { ast.elements = []; var next = true; while (next) { ast.elements.push(value(cs)); ws(cs); if (cs.ch === ',') { cs.next(); } else if (cs.ch !== ']') { } else { next = false; } } } ws(cs); cs.accept(']'); ast.pos.end = cs.pos; return ast; } function value(cs) { ws(cs); switch (cs.ch) { case '"': return string(cs); case '{': return object(cs); case '[': return array(cs); case 't': return trueLiteral(cs); case 'f': return falseLiteral(cs); case 'n': return nullLiteral(cs); default: return number(cs); } } function string(cs) { var start = cs.pos; var value = ''; cs.accept('"'); while (cs.ch !== '"') { value += cs.ch; cs.next(); } cs.accept('"'); return { type: 'string', value: value, pos: { start: start, end: cs.pos } }; } function trueLiteral(cs) { ws(cs); var start = cs.pos; cs.accept('t'); cs.accept('r'); cs.accept('u'); cs.accept('e'); return { type: 'true', pos: { start: start, end: cs.pos } }; } function falseLiteral(cs) { ws(cs); var start = cs.pos; cs.accept('f'); cs.accept('a'); cs.accept('l'); cs.accept('s'); cs.accept('e'); return { type: 'false', pos: { start: start, end: cs.pos } }; } function nullLiteral(cs) { ws(cs); var start = cs.pos; cs.accept('n'); cs.accept('u'); cs.accept('l'); cs.accept('l'); return { type: 'null', pos: { start: start, end: cs.pos } }; } function number(cs) { function digit() { var number = ''; var ch = cs.ch; if (ch === '0' || ch === '1' || ch === '2' || ch === '3' || ch === '4' || ch === '5' || ch === '6' || ch === '7' || ch === '8' || ch === '9') { number = ch; cs.next(); } return number; } function digits() { var number = digit(); var temp = digit(); while (temp !== '') { number += temp; temp = digit(); } return number; } var start = cs.pos; var negative = cs.skip('-') ? '-' : ''; var int; if (cs.ch === '0') { int = cs.ch; cs.next(); } else { int = digits(); } var frac = ''; if (cs.ch === '.') { cs.next(); frac = '.' + digits(); } var exp = ''; if (cs.ch === 'e' || cs.ch === 'E') { cs.next(); exp = 'e'; exp += cs.skip('+') ? '+' : ''; exp += cs.skip('-') ? '-' : ''; exp += digits(); } return { type: 'number', value: parseFloat("" + negative + int + frac + exp), pos: { start: start, end: cs.pos } }; } function ws(cs) { var next = true; while (next) { next = cs.skip(' ') || cs.skip('\t') || cs.skip('\n') || cs.skip('\r'); } } //# sourceMappingURL=index.js.map