chevrotain
Version:
Chevrotain is a high performance fault tolerant javascript parsing DSL for building recursive decent parsers
121 lines • 5.58 kB
JavaScript
import { forEach, map } from "../utils/utils";
import { RepetitionMandatory, Option, RepetitionMandatoryWithSeparator, RepetitionWithSeparator, Terminal, NonTerminal, Alternation, Alternative, Repetition } from "../parse/grammar/gast/gast_public";
/**
* Missing features
* 1. Rule arguments
* 2. Gates
* 3. embedded actions
*/
var NL = "\n";
export function genUmdModule(options) {
return "\n(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define(['chevrotain'], factory);\n } else if (typeof module === 'object' && module.exports) {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like environments that support module.exports,\n // like Node.\n module.exports = factory(require('chevrotain'));\n } else {\n // Browser globals (root is window)\n root.returnExports = factory(root.b);\n }\n}(typeof self !== 'undefined' ? self : this, function (chevrotain) {\n\n" + genClass(options) + "\n \nreturn {\n " + options.name + ": " + options.name + " \n}\n}));\n";
}
export function genWrapperFunction(options) {
return " \n" + genClass(options) + "\nreturn new " + options.name + "(tokenVocabulary, config) \n";
}
export function genClass(options) {
// TODO: how to pass the token vocabulary? Constructor? other?
var result = "\nfunction " + options.name + "(tokenVocabulary, config) {\n // invoke super constructor\n // No support for embedded actions currently, so we can 'hardcode'\n // The use of CstParser.\n chevrotain.CstParser.call(this, tokenVocabulary, config)\n\n const $ = this\n\n " + genAllRules(options.rules) + "\n\n // very important to call this after all the rules have been defined.\n // otherwise the parser may not work correctly as it will lack information\n // derived during the self analysis phase.\n this.performSelfAnalysis(this)\n}\n\n// inheritance as implemented in javascript in the previous decade... :(\n" + options.name + ".prototype = Object.create(chevrotain.CstParser.prototype)\n" + options.name + ".prototype.constructor = " + options.name + " \n ";
return result;
}
export function genAllRules(rules) {
var rulesText = map(rules, function (currRule) {
return genRule(currRule, 1);
});
return rulesText.join("\n");
}
export function genRule(prod, n) {
var result = indent(n, "$.RULE(\"" + prod.name + "\", function() {") + NL;
result += genDefinition(prod.definition, n + 1);
result += indent(n + 1, "})") + NL;
return result;
}
export function genTerminal(prod, n) {
var name = prod.terminalType.name;
// TODO: potential performance optimization, avoid tokenMap Dictionary access
return indent(n, "$.CONSUME" + prod.idx + "(this.tokensMap." + name + ")" + NL);
}
export function genNonTerminal(prod, n) {
return indent(n, "$.SUBRULE" + prod.idx + "($." + prod.nonTerminalName + ")" + NL);
}
export function genAlternation(prod, n) {
var result = indent(n, "$.OR" + prod.idx + "([") + NL;
var alts = map(prod.definition, function (altDef) { return genSingleAlt(altDef, n + 1); });
result += alts.join("," + NL);
result += NL + indent(n, "])" + NL);
return result;
}
export function genSingleAlt(prod, n) {
var result = indent(n, "{") + NL;
result += indent(n + 1, "ALT: function() {") + NL;
result += genDefinition(prod.definition, n + 1);
result += indent(n + 1, "}") + NL;
result += indent(n, "}");
return result;
}
function genProd(prod, n) {
/* istanbul ignore else */
if (prod instanceof NonTerminal) {
return genNonTerminal(prod, n);
}
else if (prod instanceof Option) {
return genDSLRule("OPTION", prod, n);
}
else if (prod instanceof RepetitionMandatory) {
return genDSLRule("AT_LEAST_ONE", prod, n);
}
else if (prod instanceof RepetitionMandatoryWithSeparator) {
return genDSLRule("AT_LEAST_ONE_SEP", prod, n);
}
else if (prod instanceof RepetitionWithSeparator) {
return genDSLRule("MANY_SEP", prod, n);
}
else if (prod instanceof Repetition) {
return genDSLRule("MANY", prod, n);
}
else if (prod instanceof Alternation) {
return genAlternation(prod, n);
}
else if (prod instanceof Terminal) {
return genTerminal(prod, n);
}
else if (prod instanceof Alternative) {
return genDefinition(prod.definition, n);
}
else {
throw Error("non exhaustive match");
}
}
function genDSLRule(dslName, prod, n) {
var result = indent(n, "$." + (dslName + prod.idx) + "(");
if (prod.separator) {
result += "{" + NL;
result +=
indent(n + 1, "SEP: this.tokensMap." + prod.separator.name) + "," + NL;
result += "DEF: " + genDefFunction(prod.definition, n + 2) + NL;
result += indent(n, "}") + NL;
}
else {
result += genDefFunction(prod.definition, n + 1);
}
result += indent(n, ")") + NL;
return result;
}
function genDefFunction(definition, n) {
var def = "function() {" + NL;
def += genDefinition(definition, n);
def += indent(n, "}") + NL;
return def;
}
function genDefinition(def, n) {
var result = "";
forEach(def, function (prod) {
result += genProd(prod, n + 1);
});
return result;
}
function indent(howMuch, text) {
var spaces = Array(howMuch * 4 + 1).join(" ");
return spaces + text;
}
//# sourceMappingURL=generate.js.map