UNPKG

cbon

Version:
245 lines (244 loc) 8.54 kB
import { Block, KeyVal, Arr, Key, Num, Str, Bool, Null, Docs, Comma, Split, LineComment, BlockComment } from "./ast"; import { State, Context, ReDo } from "./state_machine"; import { TEOF, TStr, TWord, TSObjStart, TSArrStart, TSComma, TSObjEnd, TSArrEnd, TSSplit, TLineComment, TBlockComment } from "./token"; import { getIterator, next_micro_tick } from "./utils"; import { _continue, _break } from "./loop"; import { AlwaysFalse } from "./canceller"; export function parser(code, config = { show_all_err: false, async: false, cancel: AlwaysFalse }) { var _a, _b, _c, _d, _e, _f; const cancel = (_b = (_a = config) === null || _a === void 0 ? void 0 : _a.cancel, (_b !== null && _b !== void 0 ? _b : AlwaysFalse)); const state = new State((_d = (_c = config) === null || _c === void 0 ? void 0 : _c.show_all_err, (_d !== null && _d !== void 0 ? _d : false))); let rootAst; state.push(root(new Context(state), (d) => { rootAst = d; })); let finish = false; const iter = getIterator(code); function* main() { if (state.queue.length != 0) { state.queue.pop()(); return _continue; } if (finish) return _break; const c = yield iter.next(); if (c.done === true) { finish = true; return _continue; } state.call(c.value); } const loop = (_f = (_e = config) === null || _e === void 0 ? void 0 : _e.async, (_f !== null && _f !== void 0 ? _f : false)) ? async function () { while (true) { if (await cancel()) break; const g = main(); let y = g.next(); if (!y.done) { y = g.next(await y.value); } const s = y.value; if (s === _continue) { await next_micro_tick(); continue; } if (s === _break) break; await next_micro_tick(); } return state.errors.length !== 0 ? { err: state.errors, val: rootAst } : { err: state.errors, val: rootAst }; } : function () { while (true) { if (cancel()) break; const g = main(); let y = g.next(); if (!y.done) { y = g.next(y.value); } const s = y.value; if (s === _continue) continue; if (s === _break) break; } return state.errors.length !== 0 ? { err: state.errors, val: rootAst } : { err: state.errors, val: rootAst }; }; return loop(); } function root(ctx, finish) { const items = []; return (t) => { if (t instanceof TEOF) { finish(new Docs(items)); } else if (t instanceof TSObjStart) { return ctx.callNoFirst(block, t, b => items.push(b)); } else if (t instanceof TSArrStart) { return ctx.callNoFirst(arr, t, a => items.push(a)); } else if (t instanceof TLineComment) { items.push(new LineComment(t.range, t.items)); } else if (t instanceof TBlockComment) { items.push(new BlockComment(t.range, t.items)); } else { ctx.error(t.range, 'File root must have no content other than a document'); } }; } function block(ctx, begin, finish) { const items = []; return (t) => { if (t instanceof TEOF) { ctx.error(t.range, 'Block is not closed'); ctx.end(); finish(new Block(begin.range, t.range, items)); return ReDo; } else if (t instanceof TSComma) { items.push(new Comma(t.range)); } else if (t instanceof TSObjEnd) { ctx.end(); finish(new Block(begin.range, t.range, items)); } else if (t instanceof TSObjStart) { ctx.error(t.range, 'Block content must start with a key'); return ctx.callNoFirst(block, t, _ => { }); } else if (t instanceof TSArrStart) { ctx.error(t.range, 'Block content must start with a key'); return ctx.callNoFirst(arr, t, _ => { }); } else if (t instanceof TStr || t instanceof TWord) { return ctx.callNoFirst(key, t, kv => items.push(kv)); } else if (t instanceof TSArrEnd) { ctx.error(t.range, 'No Array here'); } else { ctx.error(t.range, 'Block content must start with a key'); } }; } function arr(ctx, begin, finish) { const items = []; return (t) => { if (t instanceof TEOF) { ctx.error(t.range, 'Array is not closed'); ctx.end(); finish(new Arr(begin.range, t.range, items)); return ReDo; } else if (t instanceof TSComma) { items.push(new Comma(t.range)); } else if (t instanceof TSArrEnd) { ctx.end(); finish(new Arr(begin.range, t.range, items)); } else if (t instanceof TSObjEnd) { ctx.error(t.range, 'No Block here'); } else if (t instanceof TSSplit) { ctx.error(t.range, 'Array cant have key'); } else { return ctx.call(val, u => items.push(u)); } }; } function key(ctx, k, finish) { return (t) => { if (t instanceof TEOF) { ctx.error(t.range, 'There should be a key value here'); ctx.end(); return ReDo; } else if (t instanceof TSComma) { ctx.error(t.range, 'There should be a key value here'); ctx.end(); return ReDo; } else if (t instanceof TSSplit) { ctx.end(); return ctx.callNoFirst(val, u => { const sp = new Split(t.range, t.val); const kv = new KeyVal(new Key(k.range, k instanceof TStr ? new Str(k.range, k.val, k.col) : k.val), u, sp); finish(kv); }); } else { ctx.end(); return ctx.call(val, u => { const kv = new KeyVal(new Key(k.range, k instanceof TStr ? new Str(k.range, k.val, k.col) : k.val), u); finish(kv); }); } }; } function val(ctx, finish) { return (t) => { if (t instanceof TEOF) { ctx.error(t.range, 'There should be a value here'); ctx.end(); return ReDo; } else if (t instanceof TStr) { ctx.end(); finish(new Str(t.range, t.val, t.col)); } else if (t instanceof TWord) { ctx.end(); return ctx.call(word, t, u => { finish(u); }); } else if (t instanceof TSComma || t instanceof TSSplit || t instanceof TSArrEnd || t instanceof TSObjEnd) { ctx.error(t.range, 'There should be a value here'); ctx.end(); return ReDo; } else if (t instanceof TSObjStart) { ctx.end(); return ctx.callNoFirst(block, t, b => { finish(b); }); } else if (t instanceof TSArrStart) { ctx.end(); return ctx.callNoFirst(arr, t, a => { finish(a); }); } else { t; //todo ctx.end(); } }; } const reg_Num = /(0x[\da-fA-F_]+)|(([\-]?([\d\_])+)\.([\-]?([\d\_])+([eE]([\-]?)\d+)?))|(([\-]?([\d\_])+)\.([eE]([\-]?)\d+)?)|([\-]?\.(([\d\_])+([eE]([\-]?)\d+)?))|(([\-]?([\d\_])+([eE]([\-]?)\d+)?))/i; function word(ctx, w, finish) { return (t) => { ctx.end(); if (w.val === 'true') { finish(new Bool(w.range, true)); } else if (w.val === 'false') { finish(new Bool(w.range, false)); } else if (w.val === 'null') { finish(new Null(w.range)); } else if (reg_Num.test(w.val)) { finish(new Num(w.range, Number(w.val.replace('_', '')))); } else { finish(new Str(w.range, w.val, null)); } }; }