File: /var/www/vhost/disk-apps/pwa.sports-crowd.com/node_modules/chevrotain/src/generate/generate.ts
import { forEach, map } from "../utils/utils"
import {
RepetitionMandatory,
Option,
RepetitionMandatoryWithSeparator,
RepetitionWithSeparator,
Terminal,
NonTerminal,
Alternation,
Alternative,
Repetition
} from "../parse/grammar/gast/gast_public"
import { IProduction, TokenType, Rule } from "../../api"
/**
* Missing features
* 1. Rule arguments
* 2. Gates
* 3. embedded actions
*/
const NL = "\n"
export function genUmdModule(options: { name: string; rules: Rule[] }): string {
return `
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['chevrotain'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory(require('chevrotain'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.b);
}
}(typeof self !== 'undefined' ? self : this, function (chevrotain) {
${genClass(options)}
return {
${options.name}: ${options.name}
}
}));
`
}
export function genWrapperFunction(options: {
name: string
rules: Rule[]
}): string {
return `
${genClass(options)}
return new ${options.name}(tokenVocabulary, config)
`
}
export function genClass(options: { name: string; rules: Rule[] }): string {
// TODO: how to pass the token vocabulary? Constructor? other?
let result = `
function ${options.name}(tokenVocabulary, config) {
// invoke super constructor
// No support for embedded actions currently, so we can 'hardcode'
// The use of CstParser.
chevrotain.CstParser.call(this, tokenVocabulary, config)
const $ = this
${genAllRules(options.rules)}
// very important to call this after all the rules have been defined.
// otherwise the parser may not work correctly as it will lack information
// derived during the self analysis phase.
this.performSelfAnalysis(this)
}
// inheritance as implemented in javascript in the previous decade... :(
${options.name}.prototype = Object.create(chevrotain.CstParser.prototype)
${options.name}.prototype.constructor = ${options.name}
`
return result
}
export function genAllRules(rules: Rule[]): string {
let rulesText = map(rules, (currRule) => {
return genRule(currRule, 1)
})
return rulesText.join("\n")
}
export function genRule(prod: Rule, n: number): string {
let 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: Terminal, n: number): string {
const 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: NonTerminal, n: number): string {
return indent(n, `$.SUBRULE${prod.idx}($.${prod.nonTerminalName})` + NL)
}
export function genAlternation(prod: Alternation, n: number): string {
let result = indent(n, `$.OR${prod.idx}([`) + NL
const alts = map(prod.definition, (altDef) => genSingleAlt(altDef, n + 1))
result += alts.join("," + NL)
result += NL + indent(n, `])` + NL)
return result
}
export function genSingleAlt(prod: Alternative, n: number): string {
let 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: IProduction, n: number): string {
/* 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: {
definition: IProduction[]
idx: number
separator?: TokenType
},
n: number
): string {
let 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: IProduction[], n: number): string {
let def = "function() {" + NL
def += genDefinition(definition, n)
def += indent(n, `}`) + NL
return def
}
function genDefinition(def: IProduction[], n: number): string {
let result = ""
forEach(def, (prod) => {
result += genProd(prod, n + 1)
})
return result
}
function indent(howMuch: number, text: string): string {
const spaces = Array(howMuch * 4 + 1).join(" ")
return spaces + text
}