diff --git a/src/parse/grammar/lookahead.ts b/src/parse/grammar/lookahead.ts index 7edb61de5..10f4bbe83 100644 --- a/src/parse/grammar/lookahead.ts +++ b/src/parse/grammar/lookahead.ts @@ -40,7 +40,7 @@ namespace chevrotain.lookahead { checkForOrAmbiguities(alternativesTokens, orOccurrence, ruleGrammar) } - let hasLastAnEmptyAlt = utils.isEmpty(_.last(alternativesTokens)) + let hasLastAnEmptyAlt = utils.isEmpty(utils.last(alternativesTokens)) if (hasLastAnEmptyAlt) { let lastIdx = alternativesTokens.length - 1 /** diff --git a/src/parse/parser_public.ts b/src/parse/parser_public.ts index e4ee31812..bda31a1f3 100644 --- a/src/parse/parser_public.ts +++ b/src/parse/parser_public.ts @@ -1279,7 +1279,7 @@ namespace chevrotain { let key = this.getKeyForAutomaticLookahead(prodName, prodKeys, prodOccurrence) let firstAfterRepInfo = this.firstAfterRepMap.get(key) if (firstAfterRepInfo === undefined) { - let currRuleName = _.last(this.RULE_STACK) + let currRuleName = utils.last(this.RULE_STACK) let ruleGrammar = this.getGAstProductions().get(currRuleName) let walker:interp.AbstractNextTerminalAfterProductionWalker = new nextToksWalker(ruleGrammar, prodOccurrence) firstAfterRepInfo = walker.startWalking() @@ -1586,7 +1586,7 @@ namespace chevrotain { private getKeyForAutomaticLookahead(prodName:string, prodKeys:lang.HashTable[], occurrence:number):string { let occuMap = prodKeys[occurrence - 1] - let currRule = _.last(this.RULE_STACK) + let currRule = utils.last(this.RULE_STACK) let key = occuMap[currRule] if (key === undefined) { key = prodName + occurrence + IN + currRule @@ -1630,7 +1630,7 @@ namespace chevrotain { occurrence:number, laFuncBuilder:(number, any) => () => T, extraArgs:any[] = []):() => T { - let ruleName = _.last(this.RULE_STACK) + let ruleName = utils.last(this.RULE_STACK) let condition = this.classLAFuncs.get(key) if (condition === undefined) { let ruleGrammar = this.getGAstProductions().get(ruleName) @@ -1660,7 +1660,7 @@ namespace chevrotain { private raiseNoAltException(occurrence:number, errMsgTypes:string):void { let errSuffix = " but found: '" + this.NEXT_TOKEN().image + "'" if (errMsgTypes === undefined) { - let ruleName = _.last(this.RULE_STACK) + let ruleName = utils.last(this.RULE_STACK) let ruleGrammar = this.getGAstProductions().get(ruleName) let nextTokens = new interp.NextInsideOrWalker(ruleGrammar, occurrence).startWalking() let nextTokensFlat = utils.flatten(nextTokens) diff --git a/src/utils/utils.ts b/src/utils/utils.ts index e8d1d5e2b..a406efaa1 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -8,10 +8,10 @@ considering they will not be invoked in hotspots... */ -namespace utils { +namespace chevrotain.utils { export function isEmpty(arr:any[]):boolean { - return arr.length === 0 + return arr && arr.length === 0 } export function keys(obj:any):string[] { @@ -53,4 +53,9 @@ namespace utils { export function first(arr:T[]):T { return isEmpty(arr) ? undefined : arr[0] } + + export function last(arr:T[]):T { + let len = arr && arr.length + return len ? arr[len - 1] : undefined + } } diff --git a/test/utils/utils_spec.ts b/test/utils/utils_spec.ts new file mode 100644 index 000000000..6f6777958 --- /dev/null +++ b/test/utils/utils_spec.ts @@ -0,0 +1,12 @@ +namespace chevrotain.utils.spec { + + describe("The Utils functions namespace", () => { + + it("exports a last utility", () => { + expect(last([1, 2, 3])).to.equal(3) + expect(last([])).to.equal(undefined) + expect(last(null)).to.equal(undefined) + }) + }) + +}