From 41abb7ad92af0210e4480f783284e9e9c8bd5fea Mon Sep 17 00:00:00 2001 From: David Majda Date: Fri, 21 May 2010 17:30:39 +0200 Subject: [PATCH] AST refactoring 4/6: Rewrite compilation to not extend the AST nodes --- lib/compiler.js | 782 ++++++++++++++++++++++++------------------------ 1 file changed, 396 insertions(+), 386 deletions(-) diff --git a/lib/compiler.js b/lib/compiler.js index c28ffff..af98494 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -47,8 +47,8 @@ PEG.ArrayUtils = { }, /* - * The code needs to be in sync with a code template in - * PEG.Grammar.Action.prototype.compile. + * The code needs to be in sync with the code template in the compilation + * function for "action" nodes. */ contains: function(array, value) { /* @@ -90,8 +90,8 @@ PEG.StringUtils = { * Surrounds the string with quotes and escapes characters inside so that the * result is a valid JavaScript string. * - * The code needs to be in sync with a code template in - * PEG.Grammar.Action.prototype.compile. + * The code needs to be in sync with th code template in the compilation + * function for "action" nodes. */ quote: function(s) { /* @@ -447,6 +447,397 @@ PEG.Compiler = { } ], + _compileFunctions: { + rule: function(node) { + var resultVar = PEG.Compiler.generateUniqueIdentifier("result"); + + if (node.displayName !== null) { + var setReportMatchFailuresCode = PEG.Compiler.formatCode( + "var savedReportMatchFailures = context.reportMatchFailures;", + "context.reportMatchFailures = false;" + ); + var restoreReportMatchFailuresCode = PEG.Compiler.formatCode( + "context.reportMatchFailures = savedReportMatchFailures;" + ); + var reportMatchFailureCode = PEG.Compiler.formatCode( + "if (context.reportMatchFailures && ${resultVar} === null) {", + " this._matchFailed(${displayName|string});", + "}", + { + displayName: node.displayName, + resultVar: resultVar + } + ); + } else { + var setReportMatchFailuresCode = ""; + var restoreReportMatchFailuresCode = ""; + var reportMatchFailureCode = ""; + } + + return PEG.Compiler.formatCode( + "_parse_${name}: function(context) {", + " var cacheKey = ${name|string} + '@' + this._pos;", + " var cachedResult = this._cache[cacheKey];", + " if (cachedResult !== undefined) {", + " this._pos = cachedResult.nextPos;", + " return cachedResult.result;", + " }", + " ", + " var pos = this._pos;", + " ", + " ${setReportMatchFailuresCode}", + " ${code}", + " ${restoreReportMatchFailuresCode}", + " ${reportMatchFailureCode}", + " ", + " this._cache[cacheKey] = {", + " nextPos: this._pos,", + " result: ${resultVar}", + " };", + " return ${resultVar};", + "},", + { + name: node.name, + setReportMatchFailuresCode: setReportMatchFailuresCode, + restoreReportMatchFailuresCode: restoreReportMatchFailuresCode, + reportMatchFailureCode: reportMatchFailureCode, + code: PEG.Compiler.compileNode(node.expression, resultVar), + resultVar: resultVar + } + ); + }, + + /* + * The contract for all code fragments generated by the following functions + * is as follows: + * + * * The code fragment should try to match a part of the input starting with + * the position indicated in |this._pos|. That position may point past the + * end of the input. + * + * * If the code fragment matches the input, it advances |this._pos| after + * the matched part of the input and sets variable with a name stored in + * |resultVar| to appropriate value, which is always non-null. + * + * * If the code fragment does not match the input, it does not change + * |this._pos| and it sets a variable with a name stored in |resultVar| to + * |null|. + */ + + choice: function(node, resultVar) { + var code = PEG.Compiler.formatCode( + "var ${resultVar} = null;", + { resultVar: resultVar } + ); + + for (var i = node.alternatives.length - 1; i >= 0; i--) { + var alternativeResultVar = PEG.Compiler.generateUniqueIdentifier("result"); + code = PEG.Compiler.formatCode( + "${alternativeCode}", + "if (${alternativeResultVar} !== null) {", + " var ${resultVar} = ${alternativeResultVar};", + "} else {", + " ${code};", + "}", + { + alternativeCode: PEG.Compiler.compileNode(node.alternatives[i], alternativeResultVar), + alternativeResultVar: alternativeResultVar, + code: code, + resultVar: resultVar + } + ); + } + + return code; + }, + + sequence: function(node, resultVar) { + var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos"); + + var elementResultVars = PEG.ArrayUtils.map(node.elements, function() { + return PEG.Compiler.generateUniqueIdentifier("result") + }); + + var code = PEG.Compiler.formatCode( + "var ${resultVar} = ${elementResultVarArray};", + { + resultVar: resultVar, + elementResultVarArray: "[" + elementResultVars.join(", ") + "]" + } + ); + + for (var i = node.elements.length - 1; i >= 0; i--) { + code = PEG.Compiler.formatCode( + "${elementCode}", + "if (${elementResultVar} !== null) {", + " ${code}", + "} else {", + " var ${resultVar} = null;", + " this._pos = ${savedPosVar};", + "}", + { + elementCode: PEG.Compiler.compileNode(node.elements[i], elementResultVars[i]), + elementResultVar: elementResultVars[i], + code: code, + savedPosVar: savedPosVar, + resultVar: resultVar + } + ); + } + + return PEG.Compiler.formatCode( + "var ${savedPosVar} = this._pos;", + "${code}", + { + code: code, + savedPosVar: savedPosVar + } + ); + }, + + and_predicate: function(node, resultVar) { + var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos"); + var savedReportMatchFailuresVar = PEG.Compiler.generateUniqueIdentifier("savedReportMatchFailuresVar"); + var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); + + return PEG.Compiler.formatCode( + "var ${savedPosVar} = this._pos;", + "var ${savedReportMatchFailuresVar} = context.reportMatchFailures;", + "context.reportMatchFailures = false;", + "${expressionCode}", + "context.reportMatchFailures = ${savedReportMatchFailuresVar};", + "if (${expressionResultVar} !== null) {", + " var ${resultVar} = '';", + " this._pos = ${savedPosVar};", + "} else {", + " var ${resultVar} = null;", + "}", + { + expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar), + expressionResultVar: expressionResultVar, + savedPosVar: savedPosVar, + savedReportMatchFailuresVar: savedReportMatchFailuresVar, + resultVar: resultVar + } + ); + }, + + not_predicate: function(node, resultVar) { + var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos"); + var savedReportMatchFailuresVar = PEG.Compiler.generateUniqueIdentifier("savedReportMatchFailuresVar"); + var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); + + return PEG.Compiler.formatCode( + "var ${savedPosVar} = this._pos;", + "var ${savedReportMatchFailuresVar} = context.reportMatchFailures;", + "context.reportMatchFailures = false;", + "${expressionCode}", + "context.reportMatchFailures = ${savedReportMatchFailuresVar};", + "if (${expressionResultVar} === null) {", + " var ${resultVar} = '';", + "} else {", + " var ${resultVar} = null;", + " this._pos = ${savedPosVar};", + "}", + { + expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar), + expressionResultVar: expressionResultVar, + savedPosVar: savedPosVar, + savedReportMatchFailuresVar: savedReportMatchFailuresVar, + resultVar: resultVar + } + ); + }, + + optional: function(node, resultVar) { + var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); + + return PEG.Compiler.formatCode( + "${expressionCode}", + "var ${resultVar} = ${expressionResultVar} !== null ? ${expressionResultVar} : '';", + { + expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar), + expressionResultVar: expressionResultVar, + resultVar: resultVar + } + ); + }, + + zero_or_more: function(node, resultVar) { + var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); + + return PEG.Compiler.formatCode( + "var ${resultVar} = [];", + "${expressionCode}", + "while (${expressionResultVar} !== null) {", + " ${resultVar}.push(${expressionResultVar});", + " ${expressionCode}", + "}", + { + expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar), + expressionResultVar: expressionResultVar, + resultVar: resultVar + } + ); + }, + + one_or_more: function(node, resultVar) { + var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); + + return PEG.Compiler.formatCode( + "${expressionCode}", + "if (${expressionResultVar} !== null) {", + " var ${resultVar} = [];", + " while (${expressionResultVar} !== null) {", + " ${resultVar}.push(${expressionResultVar});", + " ${expressionCode}", + " }", + "} else {", + " var ${resultVar} = null;", + "}", + { + expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar), + expressionResultVar: expressionResultVar, + resultVar: resultVar + } + ); + }, + + action: function(node, resultVar) { + /* + * In case of sequences, we splat their elements into function arguments + * one by one. Example: + * + * start: "a" "b" "c" { alert(arguments.length) } // => 3 + * + * This behavior is reflected in this function. + */ + + var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); + + if (node.expression instanceof PEG.Grammar.Sequence) { + var params = PEG.ArrayUtils.map( + PEG.ArrayUtils.range(1, node.expression.elements.length + 1), + function(n) { return "$" + n; } + ).join(", "); + + var invocationCode = PEG.Compiler.formatCode( + "(function(${params}) { ${action} }).apply(null, ${expressionResultVar})", + { + params: params, + action: node.action, + expressionResultVar: expressionResultVar + } + ); + } else { + var invocationCode = PEG.Compiler.formatCode( + "(function($1) { ${action} })(${expressionResultVar})", + { + action: node.action, + expressionResultVar: expressionResultVar + } + ); + } + + return PEG.Compiler.formatCode( + "${expressionCode}", + "var ${resultVar} = ${expressionResultVar} !== null", + " ? ${invocationCode}", + " : null;", + { + expressionCode: PEG.Compiler.compileNode(node.expression, expressionResultVar), + expressionResultVar: expressionResultVar, + invocationCode: invocationCode, + resultVar: resultVar + } + ); + }, + + rule_ref: function(node, resultVar) { + return PEG.Compiler.formatCode( + "var ${resultVar} = this.${ruleMethod}(context);", + { + ruleMethod: "_parse_" + node.name, + resultVar: resultVar + } + ); + }, + + literal: function(node, resultVar) { + return PEG.Compiler.formatCode( + "if (this._input.substr(this._pos, ${length}) === ${value|string}) {", + " var ${resultVar} = ${value|string};", + " this._pos += ${length};", + "} else {", + " var ${resultVar} = null;", + " if (context.reportMatchFailures) {", + " this._matchFailed(this._quoteString(${value|string}));", + " }", + "}", + { + value: node.value, + length: node.value.length, + resultVar: resultVar + } + ); + }, + + any: function(node, resultVar) { + return PEG.Compiler.formatCode( + "if (this._input.length > this._pos) {", + " var ${resultVar} = this._input.charAt(this._pos);", + " this._pos++;", + "} else {", + " var ${resultVar} = null;", + " if (context.reportMatchFailures) {", + " this._matchFailed('any character');", + " }", + "}", + { resultVar: resultVar } + ); + }, + + "class": function(node, resultVar) { + /* + * Stupid IE considers regexps /[]/ and /[^]/ syntactically invalid, so we + * translate them into euqivalents it can handle. + */ + if (node.characters === "") { + var regexp = "/^(?!)/"; + } else if (node.characters === "^") { + var regexp = "/^[\\S\\s]/"; + } else { + var regexp = "/^[" + node.characters + "]/"; + } + + return PEG.Compiler.formatCode( + "if (this._input.substr(this._pos).match(${regexp}) !== null) {", + " var ${resultVar} = this._input.charAt(this._pos);", + " this._pos++;", + "} else {", + " var ${resultVar} = null;", + " if (context.reportMatchFailures) {", + " this._matchFailed('[' + ${characters|string} + ']');", + " }", + "}", + { + characters: node.characters, + regexp: regexp, + resultVar: resultVar + } + ); + } + }, + + /* + * Compiles an AST node and returns the generated code. The |resultVar| + * parameter contains a name of variable in which the match result will be + * stored in the generated code. + */ + compileNode: function(node, resultVar) { + return this._compileFunctions[node.type](node, resultVar); + }, + /* * Generates a parser from a specified grammar AST and start rule. Throws * |PEG.Grammar.GrammarError| if the AST contains a semantic error. Note that @@ -466,7 +857,7 @@ PEG.Compiler = { var parseFunctionDefinitions = []; for (var rule in ast) { - parseFunctionDefinitions.push(ast[rule].compile()); + parseFunctionDefinitions.push(this.compileNode(ast[rule])); } var source = this.formatCode( @@ -671,385 +1062,4 @@ PEG.Compiler = { } }; -PEG.Grammar.Rule.prototype.compile = function() { - var resultVar = PEG.Compiler.generateUniqueIdentifier("result"); - - if (this.displayName !== null) { - var setReportMatchFailuresCode = PEG.Compiler.formatCode( - "var savedReportMatchFailures = context.reportMatchFailures;", - "context.reportMatchFailures = false;" - ); - var restoreReportMatchFailuresCode = PEG.Compiler.formatCode( - "context.reportMatchFailures = savedReportMatchFailures;" - ); - var reportMatchFailureCode = PEG.Compiler.formatCode( - "if (context.reportMatchFailures && ${resultVar} === null) {", - " this._matchFailed(${displayName|string});", - "}", - { - displayName: this.displayName, - resultVar: resultVar - } - ); - } else { - var setReportMatchFailuresCode = ""; - var restoreReportMatchFailuresCode = ""; - var reportMatchFailureCode = ""; - } - - return PEG.Compiler.formatCode( - "_parse_${name}: function(context) {", - " var cacheKey = ${name|string} + '@' + this._pos;", - " var cachedResult = this._cache[cacheKey];", - " if (cachedResult !== undefined) {", - " this._pos = cachedResult.nextPos;", - " return cachedResult.result;", - " }", - " ", - " var pos = this._pos;", - " ", - " ${setReportMatchFailuresCode}", - " ${code}", - " ${restoreReportMatchFailuresCode}", - " ${reportMatchFailureCode}", - " ", - " this._cache[cacheKey] = {", - " nextPos: this._pos,", - " result: ${resultVar}", - " };", - " return ${resultVar};", - "},", - { - name: this.name, - setReportMatchFailuresCode: setReportMatchFailuresCode, - restoreReportMatchFailuresCode: restoreReportMatchFailuresCode, - reportMatchFailureCode: reportMatchFailureCode, - code: this.expression.compile(resultVar), - resultVar: resultVar - } - ); -}; - -/* - * The contract for all code fragments generated by the following |compile| - * methods is as follows: - * - * * The code fragment should try to match a part of the input starting with the - * position indicated in |this._pos|. That position may point past the end of - * the input. - * - * * If the code fragment matches the input, it advances |this._pos| after the - * matched part of the input and sets variable with a name stored in - * |resultVar| to appropriate value, which is always non-null. - * - * * If the code fragment does not match the input, it does not change - * |this._pos| and it sets a variable with a name stored in |resultVar| to - * |null|. - */ - -PEG.Grammar.Choice.prototype.compile = function(resultVar) { - var code = PEG.Compiler.formatCode( - "var ${resultVar} = null;", - { resultVar: resultVar } - ); - - for (var i = this.alternatives.length - 1; i >= 0; i--) { - var alternativeResultVar = PEG.Compiler.generateUniqueIdentifier("result"); - code = PEG.Compiler.formatCode( - "${alternativeCode}", - "if (${alternativeResultVar} !== null) {", - " var ${resultVar} = ${alternativeResultVar};", - "} else {", - " ${code};", - "}", - { - alternativeCode: this.alternatives[i].compile(alternativeResultVar), - alternativeResultVar: alternativeResultVar, - code: code, - resultVar: resultVar - } - ); - } - - return code; -}; - -PEG.Grammar.Sequence.prototype.compile = function(resultVar) { - var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos"); - - var elementResultVars = PEG.ArrayUtils.map(this.elements, function() { - return PEG.Compiler.generateUniqueIdentifier("result") - }); - - var code = PEG.Compiler.formatCode( - "var ${resultVar} = ${elementResultVarArray};", - { - resultVar: resultVar, - elementResultVarArray: "[" + elementResultVars.join(", ") + "]" - } - ); - - for (var i = this.elements.length - 1; i >= 0; i--) { - code = PEG.Compiler.formatCode( - "${elementCode}", - "if (${elementResultVar} !== null) {", - " ${code}", - "} else {", - " var ${resultVar} = null;", - " this._pos = ${savedPosVar};", - "}", - { - elementCode: this.elements[i].compile(elementResultVars[i]), - elementResultVar: elementResultVars[i], - code: code, - savedPosVar: savedPosVar, - resultVar: resultVar - } - ); - } - - return PEG.Compiler.formatCode( - "var ${savedPosVar} = this._pos;", - "${code}", - { - code: code, - savedPosVar: savedPosVar - } - ); -}; - -PEG.Grammar.AndPredicate.prototype.compile = function(resultVar) { - var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos"); - var savedReportMatchFailuresVar = PEG.Compiler.generateUniqueIdentifier("savedReportMatchFailuresVar"); - var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); - - return PEG.Compiler.formatCode( - "var ${savedPosVar} = this._pos;", - "var ${savedReportMatchFailuresVar} = context.reportMatchFailures;", - "context.reportMatchFailures = false;", - "${expressionCode}", - "context.reportMatchFailures = ${savedReportMatchFailuresVar};", - "if (${expressionResultVar} !== null) {", - " var ${resultVar} = '';", - " this._pos = ${savedPosVar};", - "} else {", - " var ${resultVar} = null;", - "}", - { - expressionCode: this.expression.compile(expressionResultVar), - expressionResultVar: expressionResultVar, - savedPosVar: savedPosVar, - savedReportMatchFailuresVar: savedReportMatchFailuresVar, - resultVar: resultVar - } - ); -}; - -PEG.Grammar.NotPredicate.prototype.compile = function(resultVar) { - var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos"); - var savedReportMatchFailuresVar = PEG.Compiler.generateUniqueIdentifier("savedReportMatchFailuresVar"); - var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); - - return PEG.Compiler.formatCode( - "var ${savedPosVar} = this._pos;", - "var ${savedReportMatchFailuresVar} = context.reportMatchFailures;", - "context.reportMatchFailures = false;", - "${expressionCode}", - "context.reportMatchFailures = ${savedReportMatchFailuresVar};", - "if (${expressionResultVar} === null) {", - " var ${resultVar} = '';", - "} else {", - " var ${resultVar} = null;", - " this._pos = ${savedPosVar};", - "}", - { - expressionCode: this.expression.compile(expressionResultVar), - expressionResultVar: expressionResultVar, - savedPosVar: savedPosVar, - savedReportMatchFailuresVar: savedReportMatchFailuresVar, - resultVar: resultVar - } - ); -}; - -PEG.Grammar.Optional.prototype.compile = function(resultVar) { - var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); - - return PEG.Compiler.formatCode( - "${expressionCode}", - "var ${resultVar} = ${expressionResultVar} !== null ? ${expressionResultVar} : '';", - { - expressionCode: this.expression.compile(expressionResultVar), - expressionResultVar: expressionResultVar, - resultVar: resultVar - } - ); -}; - -PEG.Grammar.ZeroOrMore.prototype.compile = function(resultVar) { - var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); - - return PEG.Compiler.formatCode( - "var ${resultVar} = [];", - "${expressionCode}", - "while (${expressionResultVar} !== null) {", - " ${resultVar}.push(${expressionResultVar});", - " ${expressionCode}", - "}", - { - expressionCode: this.expression.compile(expressionResultVar), - expressionResultVar: expressionResultVar, - resultVar: resultVar - } - ); -}; - -PEG.Grammar.OneOrMore.prototype.compile = function(resultVar) { - var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); - - return PEG.Compiler.formatCode( - "${expressionCode}", - "if (${expressionResultVar} !== null) {", - " var ${resultVar} = [];", - " while (${expressionResultVar} !== null) {", - " ${resultVar}.push(${expressionResultVar});", - " ${expressionCode}", - " }", - "} else {", - " var ${resultVar} = null;", - "}", - { - expressionCode: this.expression.compile(expressionResultVar), - expressionResultVar: expressionResultVar, - resultVar: resultVar - } - ); -}; - -PEG.Grammar.Action.prototype.compile = function(resultVar) { - /* - * In case of sequences, we splat their elements into function arguments one - * by one. Example: - * - * start: "a" "b" "c" { alert(arguments.length) } // => 3 - * - * This behavior is reflected in this function. - */ - - var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); - - if (this.expression.type === "sequence") { - var params = PEG.ArrayUtils.map( - PEG.ArrayUtils.range(1, this.expression.elements.length + 1), - function(n) { return "$" + n; } - ).join(", "); - - var invocationCode = PEG.Compiler.formatCode( - "(function(${params}) { ${action} }).apply(null, ${expressionResultVar})", - { - params: params, - action: this.action, - expressionResultVar: expressionResultVar - } - ); - } else { - var invocationCode = PEG.Compiler.formatCode( - "(function($1) { ${action} })(${expressionResultVar})", - { - action: this.action, - expressionResultVar: expressionResultVar - } - ); - } - - return PEG.Compiler.formatCode( - "${expressionCode}", - "var ${resultVar} = ${expressionResultVar} !== null", - " ? ${invocationCode}", - " : null;", - { - expressionCode: this.expression.compile(expressionResultVar), - expressionResultVar: expressionResultVar, - invocationCode: invocationCode, - resultVar: resultVar - } - ); -}; - -PEG.Grammar.RuleRef.prototype.compile = function(resultVar) { - return PEG.Compiler.formatCode( - "var ${resultVar} = this.${ruleMethod}(context);", - { - ruleMethod: "_parse_" + this.name, - resultVar: resultVar - } - ); -}; - -PEG.Grammar.Literal.prototype.compile = function(resultVar) { - return PEG.Compiler.formatCode( - "if (this._input.substr(this._pos, ${length}) === ${value|string}) {", - " var ${resultVar} = ${value|string};", - " this._pos += ${length};", - "} else {", - " var ${resultVar} = null;", - " if (context.reportMatchFailures) {", - " this._matchFailed(this._quoteString(${value|string}));", - " }", - "}", - { - value: this.value, - length: this.value.length, - resultVar: resultVar - } - ); -}; - -PEG.Grammar.Any.prototype.compile = function(resultVar) { - return PEG.Compiler.formatCode( - "if (this._input.length > this._pos) {", - " var ${resultVar} = this._input.charAt(this._pos);", - " this._pos++;", - "} else {", - " var ${resultVar} = null;", - " if (context.reportMatchFailures) {", - " this._matchFailed('any character');", - " }", - "}", - { resultVar: resultVar } - ); -}; - - -PEG.Grammar.Class.prototype.compile = function(resultVar) { - /* - * Stupid IE considers regexps /[]/ and /[^]/ syntactically invalid, so we - * translate them into euqivalents it can handle. - */ - if (this.characters === "") { - var regexp = "/^(?!)/"; - } else if (this.characters === "^") { - var regexp = "/^[\\S\\s]/"; - } else { - var regexp = "/^[" + this.characters + "]/"; - } - - return PEG.Compiler.formatCode( - "if (this._input.substr(this._pos).match(${regexp}) !== null) {", - " var ${resultVar} = this._input.charAt(this._pos);", - " this._pos++;", - "} else {", - " var ${resultVar} = null;", - " if (context.reportMatchFailures) {", - " this._matchFailed('[' + ${characters|string} + ']');", - " }", - "}", - { - characters: this.characters, - regexp: regexp, - resultVar: resultVar - } - ); -}; - })();