UNPKG

chevrotain

Version:

Chevrotain is a high performance fault tolerant javascript parsing DSL for building recursive decent parsers

250 lines 11.2 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); var tokens_public_1 = require("../../scan/tokens_public"); var utils_1 = require("../../utils/utils"); var lang_extensions_1 = require("../../lang/lang_extensions"); var keys_1 = require("../grammar/keys"); var gast_public_1 = require("../grammar/gast/gast_public"); var gast_visitor_public_1 = require("../grammar/gast/gast_visitor_public"); function addTerminalToCst(node, token, tokenTypeName) { ; node.children[tokenTypeName].push(token); } exports.addTerminalToCst = addTerminalToCst; function addNoneTerminalToCst(node, ruleName, ruleResult) { ; node.children[ruleName].push(ruleResult); } exports.addNoneTerminalToCst = addNoneTerminalToCst; var NamedDSLMethodsCollectorVisitor = /** @class */ (function (_super) { __extends(NamedDSLMethodsCollectorVisitor, _super); function NamedDSLMethodsCollectorVisitor(ruleIdx) { var _this = _super.call(this) || this; _this.result = []; _this.ruleIdx = ruleIdx; return _this; } NamedDSLMethodsCollectorVisitor.prototype.collectNamedDSLMethod = function (node, newNodeConstructor, methodIdx) { // TODO: better hack to copy what we need here... if (!utils_1.isUndefined(node.name)) { // copy without name so this will indeed be processed later. var nameLessNode = void 0; if (node instanceof gast_public_1.Option || node instanceof gast_public_1.Repetition || node instanceof gast_public_1.RepetitionMandatory || node instanceof gast_public_1.Alternation) { nameLessNode = new newNodeConstructor({ definition: node.definition, idx: node.idx }); } else if (node instanceof gast_public_1.RepetitionMandatoryWithSeparator || node instanceof gast_public_1.RepetitionWithSeparator) { nameLessNode = new newNodeConstructor({ definition: node.definition, idx: node.idx, separator: node.separator }); } else { /* istanbul ignore next */ throw Error("non exhaustive match"); } var def = [nameLessNode]; var key = keys_1.getKeyForAutomaticLookahead(this.ruleIdx, methodIdx, node.idx); this.result.push({ def: def, key: key, name: node.name, orgProd: node }); } }; NamedDSLMethodsCollectorVisitor.prototype.visitOption = function (node) { this.collectNamedDSLMethod(node, gast_public_1.Option, keys_1.OPTION_IDX); }; NamedDSLMethodsCollectorVisitor.prototype.visitRepetition = function (node) { this.collectNamedDSLMethod(node, gast_public_1.Repetition, keys_1.MANY_IDX); }; NamedDSLMethodsCollectorVisitor.prototype.visitRepetitionMandatory = function (node) { this.collectNamedDSLMethod(node, gast_public_1.RepetitionMandatory, keys_1.AT_LEAST_ONE_IDX); }; NamedDSLMethodsCollectorVisitor.prototype.visitRepetitionMandatoryWithSeparator = function (node) { this.collectNamedDSLMethod(node, gast_public_1.RepetitionMandatoryWithSeparator, keys_1.AT_LEAST_ONE_SEP_IDX); }; NamedDSLMethodsCollectorVisitor.prototype.visitRepetitionWithSeparator = function (node) { this.collectNamedDSLMethod(node, gast_public_1.RepetitionWithSeparator, keys_1.MANY_SEP_IDX); }; NamedDSLMethodsCollectorVisitor.prototype.visitAlternation = function (node) { var _this = this; this.collectNamedDSLMethod(node, gast_public_1.Alternation, keys_1.OR_IDX); var hasMoreThanOneAlternative = node.definition.length > 1; utils_1.forEach(node.definition, function (currFlatAlt, altIdx) { if (!utils_1.isUndefined(currFlatAlt.name)) { var def = currFlatAlt.definition; if (hasMoreThanOneAlternative) { def = [new gast_public_1.Option({ definition: currFlatAlt.definition })]; } else { // mandatory def = currFlatAlt.definition; } var key = keys_1.getKeyForAltIndex(_this.ruleIdx, keys_1.OR_IDX, node.idx, altIdx); _this.result.push({ def: def, key: key, name: currFlatAlt.name, orgProd: currFlatAlt }); } }); }; return NamedDSLMethodsCollectorVisitor; }(gast_visitor_public_1.GAstVisitor)); exports.NamedDSLMethodsCollectorVisitor = NamedDSLMethodsCollectorVisitor; function analyzeCst(topRules, fullToShortName) { var result = { dictDef: new lang_extensions_1.HashTable(), allRuleNames: [] }; utils_1.forEach(topRules, function (currTopRule) { var currChildrenNames = buildChildDictionaryDef(currTopRule.definition); var currTopRuleShortName = fullToShortName.get(currTopRule.name); result.dictDef.put(currTopRuleShortName, buildInitDefFunc(currChildrenNames)); result.allRuleNames.push(currTopRule.name); var namedCollectorVisitor = new NamedDSLMethodsCollectorVisitor(currTopRuleShortName); currTopRule.accept(namedCollectorVisitor); utils_1.forEach(namedCollectorVisitor.result, function (_a) { var def = _a.def, key = _a.key, name = _a.name; var currNestedChildrenNames = buildChildDictionaryDef(def); result.dictDef.put(key, buildInitDefFunc(currNestedChildrenNames)); result.allRuleNames.push(currTopRule.name + name); }); }); return result; } exports.analyzeCst = analyzeCst; function buildInitDefFunc(childrenNames) { var funcString = "return {\n"; funcString += utils_1.map(childrenNames, function (currName) { return "\"" + currName + "\" : []"; }).join(",\n"); funcString += "}"; // major performance optimization, faster to create the children dictionary this way // versus iterating over the childrenNames each time. return Function(funcString); } function buildChildDictionaryDef(initialDef) { var result = []; var possiblePaths = []; possiblePaths.push({ def: initialDef }); var currDef; var currInIteration; var currInOption; var currResult; function addSingleItemToResult(itemName) { result.push(itemName); var nextPath = { def: utils_1.drop(currDef), inIteration: currInIteration, inOption: currInOption, currResult: utils_1.cloneObj(currResult) }; possiblePaths.push(nextPath); } while (!utils_1.isEmpty(possiblePaths)) { var currPath = possiblePaths.pop(); currDef = currPath.def; currInIteration = currPath.inIteration; currInOption = currPath.inOption; currResult = currPath.currResult; // For Example: an empty path could exist in a valid grammar in the case of an EMPTY_ALT if (utils_1.isEmpty(currDef)) { continue; } var prod = currDef[0]; if (prod instanceof gast_public_1.Terminal) { var terminalName = tokens_public_1.tokenName(prod.terminalType); addSingleItemToResult(terminalName); } else if (prod instanceof gast_public_1.NonTerminal) { var nonTerminalName = prod.nonTerminalName; addSingleItemToResult(nonTerminalName); } else if (prod instanceof gast_public_1.Option) { if (!utils_1.isUndefined(prod.name)) { addSingleItemToResult(prod.name); } else { var nextPathWith = { def: prod.definition.concat(utils_1.drop(currDef)) }; possiblePaths.push(nextPathWith); } } else if (prod instanceof gast_public_1.RepetitionMandatory || prod instanceof gast_public_1.Repetition) { if (!utils_1.isUndefined(prod.name)) { addSingleItemToResult(prod.name); } else { var nextDef = prod.definition.concat(utils_1.drop(currDef)); var nextPath = { def: nextDef }; possiblePaths.push(nextPath); } } else if (prod instanceof gast_public_1.RepetitionMandatoryWithSeparator || prod instanceof gast_public_1.RepetitionWithSeparator) { if (!utils_1.isUndefined(prod.name)) { addSingleItemToResult(prod.name); } else { var separatorGast = new gast_public_1.Terminal({ terminalType: prod.separator }); var secondIteration = new gast_public_1.Repetition({ definition: [separatorGast].concat(prod.definition), idx: prod.idx }); // Hack: X (, X)* --> (, X) because it is identical in terms of identifying "isCollection?" var nextDef = [secondIteration].concat(utils_1.drop(currDef)); var nextPath = { def: nextDef }; possiblePaths.push(nextPath); } } else if (prod instanceof gast_public_1.Alternation) { /* istanbul ignore else */ // IGNORE ABOVE ELSE if (!utils_1.isUndefined(prod.name)) { addSingleItemToResult(prod.name); } else { // the order of alternatives is meaningful, FILO (Last path will be traversed first). for (var i = prod.definition.length - 1; i >= 0; i--) { var currAlt = prod.definition[i]; // named alternatives if (!utils_1.isUndefined(currAlt.name)) { addSingleItemToResult(currAlt.name); } else { var newDef = currAlt.definition.concat(utils_1.drop(currDef)); var currAltPath = { def: newDef }; possiblePaths.push(currAltPath); } } } } else { /* istanbul ignore next */ throw Error("non exhaustive match"); } } return result; } exports.buildChildDictionaryDef = buildChildDictionaryDef; //# sourceMappingURL=cst.js.map