diff --git a/src/lang/lang_extensions.ts b/src/lang/lang_extensions.ts index d85585f58..4b3e502ad 100644 --- a/src/lang/lang_extensions.ts +++ b/src/lang/lang_extensions.ts @@ -41,7 +41,7 @@ namespace chevrotain.lang { } values():V[] { - return _.values(this._state) + return utils.values(this._state) } put(key:string, value:V):void { diff --git a/src/parse/grammar/checks.ts b/src/parse/grammar/checks.ts index c6bd263fa..ecb668856 100644 --- a/src/parse/grammar/checks.ts +++ b/src/parse/grammar/checks.ts @@ -5,9 +5,9 @@ namespace chevrotain.checks { import IProduction = chevrotain.gast.IProduction export function validateGrammar(topLevels:gast.Rule[]):IParserDefinitionError[] { - let duplicateErrors = _.map(topLevels, validateDuplicateProductions) - let leftRecursionErrors:any = _.map(topLevels, currTopRule => validateNoLeftRecursion(currTopRule, currTopRule)) - let emptyAltErrors = _.map(topLevels, validateEmptyOrAlternative) + let duplicateErrors = utils.map(topLevels, validateDuplicateProductions) + let leftRecursionErrors:any = utils.map(topLevels, currTopRule => validateNoLeftRecursion(currTopRule, currTopRule)) + let emptyAltErrors = utils.map(topLevels, validateEmptyOrAlternative) return _.flatten(duplicateErrors.concat(leftRecursionErrors, emptyAltErrors)) } @@ -22,7 +22,7 @@ namespace chevrotain.checks { return currGroup.length > 1 }) - let errors = _.map(duplicates, (currDuplicates:any) => { + let errors = utils.map(utils.values(duplicates), (currDuplicates:any) => { let firstProd:any = _.first(currDuplicates) let msg = createDuplicatesErrorMessage(currDuplicates, topLevelRule.name) let dslName = gast.getProductionDslName(firstProd) @@ -155,7 +155,7 @@ namespace chevrotain.checks { else { let ruleName = topRule.name let foundLeftRecursion = _.contains(nextNonTerminals, topRule) - let pathNames = _.map(path, currRule => currRule.name) + let pathNames = utils.map(path, currRule => currRule.name) let leftRecursivePath = `${ruleName} --> ${pathNames.concat([ruleName]).join(" --> ")}` if (foundLeftRecursion) { let errMsg = `Left Recursion found in grammar.\n` + @@ -173,7 +173,7 @@ namespace chevrotain.checks { // we are only looking for cyclic paths leading back to the specific topRule // other cyclic paths are ignored, we still need this difference to avoid infinite loops... let validNextSteps = _.difference(nextNonTerminals, path.concat([topRule])) - let errorsFromNextSteps = _.map(validNextSteps, (currRefRule, key, all) => { + let errorsFromNextSteps = utils.map(validNextSteps, (currRefRule) => { let newPath = _.clone(path) newPath.push(currRefRule) return validateNoLeftRecursion(topRule, currRefRule, newPath) @@ -210,7 +210,7 @@ namespace chevrotain.checks { else if (firstProd instanceof gast.Alternation) { // each sub definition in alternation is a FLAT result = _.flatten( - _.map(firstProd.definition, currSubDef => getFirstNoneTerminal((currSubDef).definition))) + utils.map(firstProd.definition, currSubDef => getFirstNoneTerminal((currSubDef).definition))) } else if (firstProd instanceof gast.Terminal) { // nothing to see, move along @@ -245,7 +245,7 @@ namespace chevrotain.checks { let errors = _.reduce(ors, (errors, currOr) => { let exceptLast = _.dropRight(currOr.definition) - let currErrors = _.map(exceptLast, (currAlternative:IProduction, currAltIdx) => { + let currErrors = utils.map(exceptLast, (currAlternative:IProduction, currAltIdx) => { if (utils.isEmpty(first.first(currAlternative))) { return { message: `Ambiguous empty alternative: <${currAltIdx + 1}>` + diff --git a/src/parse/grammar/first.ts b/src/parse/grammar/first.ts index 1bc51ff88..79928e636 100644 --- a/src/parse/grammar/first.ts +++ b/src/parse/grammar/first.ts @@ -51,7 +51,7 @@ namespace chevrotain.first { } export function firstForBranching(prod:gast.AbstractProduction):Function[] { - let allAlternativesFirsts:Function[][] = _.map(prod.definition, (innerProd) => { + let allAlternativesFirsts:Function[][] = utils.map(prod.definition, (innerProd) => { return first(innerProd) }) return _.uniq(_.flatten(allAlternativesFirsts)) diff --git a/src/parse/grammar/interpreter.ts b/src/parse/grammar/interpreter.ts index 306b7ad45..c83e319d0 100644 --- a/src/parse/grammar/interpreter.ts +++ b/src/parse/grammar/interpreter.ts @@ -221,7 +221,7 @@ namespace chevrotain.interpreter { walkOr(orProd:g.Alternation, currRest:g.IProduction[], prevRest:g.IProduction[]):void { if (orProd.occurrenceInParent === this.occurrence) { - this.result = _.map(orProd.definition, (alt) => { + this.result = utils.map(orProd.definition, (alt) => { let altWrapper = new gast.Flat([alt]) return f.first(altWrapper) }) diff --git a/src/parse/grammar/lookahead.ts b/src/parse/grammar/lookahead.ts index 59705ab6e..fb404e0a1 100644 --- a/src/parse/grammar/lookahead.ts +++ b/src/parse/grammar/lookahead.ts @@ -88,7 +88,7 @@ namespace chevrotain.lookahead { let altsAmbiguityErrors = checkAlternativesAmbiguities(alternativesTokens) if (!utils.isEmpty(altsAmbiguityErrors)) { - let errorMessages = _.map(altsAmbiguityErrors, (currAmbiguity) => { + let errorMessages = utils.map(altsAmbiguityErrors, (currAmbiguity) => { return `Ambiguous alternatives: <${currAmbiguity.alts.join(" ,")}> in inside <${ruleGrammar.name}> ` + `Rule, <${tokenName(currAmbiguity.token)}> may appears as the first Terminal in all these alternatives.\n` }) @@ -114,14 +114,14 @@ namespace chevrotain.lookahead { let allTokensFlat = _.flatten(alternativesTokens) let uniqueTokensFlat = _.uniq(allTokensFlat) - let tokensToAltsIndicesItAppearsIn = _.map(uniqueTokensFlat, (seekToken) => { + let tokensToAltsIndicesItAppearsIn = utils.map(uniqueTokensFlat, (seekToken) => { let altsCurrTokenAppearsIn = _.pick(alternativesTokens, (altToLookIn) => { return _.find(altToLookIn, (currToken) => { return currToken === seekToken }) }) - let altsIndicesTokenAppearsIn = _.map(utils.keys(altsCurrTokenAppearsIn), (index) => { + let altsIndicesTokenAppearsIn = utils.map(utils.keys(altsCurrTokenAppearsIn), (index) => { return parseInt(index, 10) + 1 }) diff --git a/src/parse/parser_public.ts b/src/parse/parser_public.ts index 7039a9f75..ce70db094 100644 --- a/src/parse/parser_public.ts +++ b/src/parse/parser_public.ts @@ -169,7 +169,7 @@ namespace chevrotain { let validationErrors = checks.validateGrammar(grammarProductions.values()) definitionErrors.push.apply(definitionErrors, validationErrors) // mutability for the win? if (!utils.isEmpty(definitionErrors) && !Parser.DEFER_DEFINITION_ERRORS_HANDLING) { - defErrorsMsgs = _.map(definitionErrors, defError => defError.message) + defErrorsMsgs = utils.map(definitionErrors, defError => defError.message) throw new Error(`Parser Definition Errors detected\n: ${defErrorsMsgs.join("\n-------------------------------\n")}`) } if (utils.isEmpty(definitionErrors)) { // this analysis may fail if the grammar is not perfectly valid @@ -180,7 +180,7 @@ namespace chevrotain { // reThrow the validation errors each time an erroneous parser is instantiated if (!utils.isEmpty(cache.CLASS_TO_DEFINITION_ERRORS.get(className)) && !Parser.DEFER_DEFINITION_ERRORS_HANDLING) { - defErrorsMsgs = _.map(cache.CLASS_TO_DEFINITION_ERRORS.get(className), defError => defError.message) + defErrorsMsgs = utils.map(cache.CLASS_TO_DEFINITION_ERRORS.get(className), defError => defError.message) throw new Error(`Parser Definition Errors detected\n: ${defErrorsMsgs.join("\n-------------------------------\n")}`) } } @@ -1233,7 +1233,7 @@ namespace chevrotain { } private buildFullFollowKeyStack():IFollowKey[] { - return _.map(this.RULE_STACK, (ruleName, idx) => { + return utils.map(this.RULE_STACK, (ruleName, idx) => { if (idx === 0) { return EOF_FOLLOW_KEY } @@ -1246,7 +1246,7 @@ namespace chevrotain { } private flattenFollowSet():Function[] { - let followStack = _.map(this.buildFullFollowKeyStack(), (currKey) => { + let followStack = utils.map(this.buildFullFollowKeyStack(), (currKey) => { return this.getFollowSetFromFollowKey(currKey) }) return _.flatten(followStack) @@ -1664,7 +1664,7 @@ namespace chevrotain { let ruleGrammar = this.getGAstProductions().get(ruleName) let nextTokens = new interp.NextInsideOrWalker(ruleGrammar, occurrence).startWalking() let nextTokensFlat = _.flatten(nextTokens) - let nextTokensNames = _.map(nextTokensFlat, (currTokenClass:Function) => tokenName(currTokenClass)) + let nextTokensNames = utils.map(nextTokensFlat, (currTokenClass:Function) => tokenName(currTokenClass)) errMsgTypes = `one of: <${nextTokensNames.join(" ,")}>` } throw this.SAVE_ERROR(new exceptions.NoViableAltException(`expecting: ${errMsgTypes} ${errSuffix}`, this.NEXT_TOKEN())) diff --git a/src/scan/lexer.ts b/src/scan/lexer.ts index 12b853666..900594104 100644 --- a/src/scan/lexer.ts +++ b/src/scan/lexer.ts @@ -21,17 +21,17 @@ namespace chevrotain { return currClass[PATTERN] === Lexer.NA }) - let allTransformedPatterns = _.map(onlyRelevantClasses, (currClass) => { + let allTransformedPatterns = utils.map(onlyRelevantClasses, (currClass) => { return addStartOfInput(currClass[PATTERN]) }) let allPatternsToClass = _.zipObject(allTransformedPatterns, onlyRelevantClasses) - let patternIdxToClass:any = _.map(allTransformedPatterns, (pattern) => { + let patternIdxToClass:any = utils.map(allTransformedPatterns, (pattern) => { return allPatternsToClass[pattern.toString()] }) - let patternIdxToGroup = _.map(onlyRelevantClasses, (clazz:any) => { + let patternIdxToGroup = utils.map(onlyRelevantClasses, (clazz:any) => { let groupName = clazz.GROUP if (groupName === Lexer.SKIPPED) { return undefined @@ -47,7 +47,7 @@ namespace chevrotain { } }) - let patternIdxToLongerAltIdx:any = _.map(onlyRelevantClasses, (clazz:any, idx) => { + let patternIdxToLongerAltIdx:any = utils.map(onlyRelevantClasses, (clazz:any) => { let longerAltClass = clazz.LONGER_ALT if (longerAltClass) { @@ -56,7 +56,7 @@ namespace chevrotain { } }) - let patternIdxToCanLineTerminator = _.map(allTransformedPatterns, (pattern:RegExp) => { + let patternIdxToCanLineTerminator = utils.map(allTransformedPatterns, (pattern:RegExp) => { // TODO: unicode escapes of line terminators too? return /\\n|\\r|\\s/g.test(pattern.source) }) @@ -106,7 +106,7 @@ namespace chevrotain { return !_.has(currClass, PATTERN) }) - let errors = _.map(tokenClassesWithMissingPattern, (currClass) => { + let errors = utils.map(tokenClassesWithMissingPattern, (currClass) => { return { message: "Token class: ->" + tokenName(currClass) + "<- missing static 'PATTERN' property", type: LexerDefinitionErrorType.MISSING_PATTERN, @@ -124,7 +124,7 @@ namespace chevrotain { return !_.isRegExp(pattern) }) - let errors = _.map(tokenClassesWithInvalidPattern, (currClass) => { + let errors = utils.map(tokenClassesWithInvalidPattern, (currClass) => { return { message: "Token class: ->" + tokenName(currClass) + "<- static 'PATTERN' can only be a RegExp", type: LexerDefinitionErrorType.INVALID_PATTERN, @@ -144,7 +144,7 @@ namespace chevrotain { return end_of_input.test(pattern.source) }) - let errors = _.map(invalidRegex, (currClass) => { + let errors = utils.map(invalidRegex, (currClass) => { return { message: "Token class: ->" + tokenName(currClass) + "<- static 'PATTERN' cannot contain end of input anchor '$'", type: LexerDefinitionErrorType.EOI_ANCHOR_FOUND, @@ -161,7 +161,7 @@ namespace chevrotain { return pattern instanceof RegExp && (pattern.multiline || pattern.global) }) - let errors = _.map(invalidFlags, (currClass) => { + let errors = utils.map(invalidFlags, (currClass) => { return { message: "Token class: ->" + tokenName(currClass) + "<- static 'PATTERN' may NOT contain global('g') or multiline('m')", @@ -177,7 +177,7 @@ namespace chevrotain { export function findDuplicatePatterns(tokenClasses:TokenConstructor[]):ILexerDefinitionError[] { let found = [] - let identicalPatterns = _.map(tokenClasses, (outerClass:any) => { + let identicalPatterns = utils.map(tokenClasses, (outerClass:any) => { return _.reduce(tokenClasses, (result, innerClass:any) => { if ((outerClass.PATTERN.source === innerClass.PATTERN.source) && !_.contains(found, innerClass) && innerClass.PATTERN !== Lexer.NA) { @@ -196,8 +196,8 @@ namespace chevrotain { return _.size(currIdenticalSet) > 1 }) - let errors = _.map(duplicatePatterns, (setOfIdentical:any) => { - let classNames = _.map(setOfIdentical, (currClass:any) => { + let errors = utils.map(duplicatePatterns, (setOfIdentical:any) => { + let classNames = utils.map(setOfIdentical, (currClass:any) => { return tokenName(currClass) }) @@ -224,7 +224,7 @@ namespace chevrotain { group !== Lexer.NA && !_.isString(group) }) - let errors = _.map(invalidTypes, (currClass) => { + let errors = utils.map(invalidTypes, (currClass) => { return { message: "Token class: ->" + tokenName(currClass) + "<- static 'GROUP' can only be Lexer.SKIPPED/Lexer.NA/A String", type: LexerDefinitionErrorType.INVALID_GROUP_TYPE_FOUND, diff --git a/src/scan/lexer_public.ts b/src/scan/lexer_public.ts index 7dafb382f..49214dbdb 100644 --- a/src/scan/lexer_public.ts +++ b/src/scan/lexer_public.ts @@ -111,7 +111,7 @@ namespace chevrotain { constructor(protected tokenClasses:TokenConstructor[], deferDefinitionErrorsHandling:boolean = false) { this.lexerDefinitionErrors = validatePatterns(tokenClasses) if (!utils.isEmpty(this.lexerDefinitionErrors) && !deferDefinitionErrorsHandling) { - let allErrMessages = _.map(this.lexerDefinitionErrors, (error) => { + let allErrMessages = utils.map(this.lexerDefinitionErrors, (error) => { return error.message }) let allErrMessagesString = allErrMessages.join("-----------------------\n") @@ -152,7 +152,7 @@ namespace chevrotain { let groups:any = _.clone(this.emptyGroups) if (!utils.isEmpty(this.lexerDefinitionErrors)) { - let allErrMessages = _.map(this.lexerDefinitionErrors, (error) => { + let allErrMessages = utils.map(this.lexerDefinitionErrors, (error) => { return error.message }) let allErrMessagesString = allErrMessages.join("-----------------------\n") diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 13f579552..ec1f49877 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -10,11 +10,28 @@ namespace utils { - export function isEmpty(arr:any[]) { + export function isEmpty(arr:any[]):boolean { return arr.length === 0 } - export function keys(obj:any) { + export function keys(obj:any):string[] { return Object.keys(obj) } + + export function values(obj:any):any[] { + let vals = [] + let keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + vals.push(obj[keys[i]]) + } + return vals + } + + export function map(arr:I[], callback:(I, idx?:number) => O):O[] { + let result:O[] = [] + for (let idx = 0; idx < arr.length; idx++) { + result.push(callback.call(null, arr[idx], idx)) + } + return result + } }