UNPKG

@abaplint/core

Version:
339 lines • 10 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.seq = seq; exports.alt = alt; exports.beginEnd = beginEnd; exports.opt = opt; exports.star = star; exports.sta = sta; exports.sub = sub; const nodes_1 = require("../../nodes"); const _statement_1 = require("../../2_statements/statements/_statement"); class Sequence { constructor(list) { if (list.length < 2) { throw new Error("Sequence, length error"); } this.list = list; } toRailroad() { const children = this.list.map((e) => { return e.toRailroad(); }); return "Railroad.Sequence(" + children.join() + ")"; } getUsing() { return this.list.reduce((a, c) => { return a.concat(c.getUsing()); }, []); } first() { return this.list[0].first(); } run(statements, parent) { let inn = statements; let out = []; for (const i of this.list) { const match = i.run(inn, parent); if (match.error) { return { matched: [], unmatched: statements, error: true, errorDescription: match.errorDescription, errorMatched: out.length, }; } if (match.matched.length < 100) { out.push(...match.matched); } else { // avoid using the spread operator, it might trigger "Maximum call stack size exceeded" // when the number of matched elements is very large out = out.concat(match.matched); } inn = match.unmatched; } return { matched: out, unmatched: inn, error: false, errorDescription: "", errorMatched: 0, }; } } // Note that the Alternative does not nessesarily return the first in the alternative // as a map is used for better performance class Alternative { constructor(list) { if (list.length < 2) { throw new Error("Alternative, length error"); } this.list = list; } setupMap() { // dont call from constructor, it will cause infinite loop if (this.map === undefined) { this.map = {}; for (const i of this.list) { for (const first of i.first()) { if (this.map[first]) { this.map[first].push(i); } else { this.map[first] = [i]; } } } } } first() { return [""]; } toRailroad() { const children = this.list.map((e) => { return e.toRailroad(); }); return "Railroad.Choice(0, " + children.join() + ")"; } getUsing() { return this.list.reduce((a, c) => { return a.concat(c.getUsing()); }, []); } run(statements, parent) { this.setupMap(); let count = 0; let countError = ""; if (statements.length === 0) { return { matched: [], unmatched: statements, error: true, errorDescription: countError, errorMatched: count, }; } const token = statements[0].getFirstToken().getStr().toUpperCase(); for (const i of this.map[token] || []) { const match = i.run(statements, parent); if (match.error === false) { return match; } if (match.errorMatched > count) { countError = match.errorDescription; count = match.errorMatched; } } for (const i of this.map[""] || []) { const match = i.run(statements, parent); if (match.error === false) { return match; } if (match.errorMatched > count) { countError = match.errorDescription; count = match.errorMatched; } } if (count === 0) { return { matched: [], unmatched: statements, error: true, errorDescription: "Unexpected code structure", errorMatched: count, }; } else { return { matched: [], unmatched: statements, error: true, errorDescription: countError, errorMatched: count, }; } } } class Optional { constructor(obj) { this.obj = obj; } toRailroad() { return "Railroad.Optional(" + this.obj.toRailroad() + ")"; } getUsing() { return this.obj.getUsing(); } run(statements, parent) { const ret = this.obj.run(statements, parent); ret.error = false; return ret; } first() { return [""]; } } class Star { constructor(obj) { this.obj = obj; } toRailroad() { return "Railroad.ZeroOrMore(" + this.obj.toRailroad() + ")"; } getUsing() { return this.obj.getUsing(); } run(statements, parent) { let inn = statements; let out = []; while (true) { if (inn.length === 0) { return { matched: out, unmatched: inn, error: false, errorDescription: "", errorMatched: 0, }; } const match = this.obj.run(inn, parent); if (match.error === true) { if (match.errorMatched > 0) { return { matched: out, unmatched: inn, error: true, errorDescription: match.errorDescription, errorMatched: match.errorMatched, }; } else { return { matched: out, unmatched: inn, error: false, errorDescription: "", errorMatched: 0, }; } } if (match.matched.length < 100) { out.push(...match.matched); } else { // avoid using the spread operator, it might trigger "Maximum call stack size exceeded" // when the number of matched elements is very large out = out.concat(match.matched); } inn = match.unmatched; } } first() { return [""]; } } class SubStructure { constructor(s) { this.s = s; } toRailroad() { return "Railroad.NonTerminal('" + this.s.constructor.name + "', {href: '#/structure/" + this.s.constructor.name + "'})"; } getUsing() { return ["structure/" + this.s.constructor.name]; } first() { this.setupMatcher(); return this.matcher.first(); } setupMatcher() { if (this.matcher === undefined) { // SubStructures are singletons, so the getMatcher can be saved, its expensive to create // dont move this to the constructor, as it might trigger infinite recursion this.matcher = this.s.getMatcher(); } } run(statements, parent) { const nparent = new nodes_1.StructureNode(this.s); this.setupMatcher(); const ret = this.matcher.run(statements, nparent); if (ret.matched.length === 0) { ret.error = true; } else { parent.addChild(nparent); } return ret; } } class SubStatement { constructor(obj) { this.obj = obj; } first() { const o = new this.obj(); if (o instanceof _statement_1.MacroCall || o instanceof _statement_1.NativeSQL) { return [""]; } return o.getMatcher().first(); } toRailroad() { return "Railroad.Terminal('" + this.className() + "', {href: '#/statement/" + this.className() + "'})"; } getUsing() { return ["statement/" + this.className()]; } className() { return this.obj.name; } run(statements, parent) { if (statements.length === 0) { return { matched: [], unmatched: [], error: true, errorDescription: "Expected " + this.className().toUpperCase(), errorMatched: 0, }; } else if (statements[0].get() instanceof this.obj) { parent.addChild(statements[0]); return { matched: [statements[0]], unmatched: statements.splice(1), error: false, errorDescription: "", errorMatched: 0, }; } else { return { matched: [], unmatched: statements, error: true, errorDescription: "Expected " + this.className().toUpperCase(), errorMatched: 0, }; } } } function seq(first, ...rest) { return new Sequence([first].concat(rest)); } function alt(first, ...rest) { return new Alternative([first].concat(rest)); } function beginEnd(begin, body, end) { return new Sequence([begin, body, end]); } function opt(o) { return new Optional(o); } function star(s) { return new Star(s); } function sta(s) { return new SubStatement(s); } const singletons = {}; function sub(s) { if (singletons[s.name] === undefined) { singletons[s.name] = new SubStructure(new s()); } return singletons[s.name]; } //# sourceMappingURL=_combi.js.map