diff --git a/lib/compiler/js.js b/lib/compiler/js.js index 4d9ec4e..afe2ee1 100644 --- a/lib/compiler/js.js +++ b/lib/compiler/js.js @@ -12,19 +12,19 @@ let js = { // // For portability, we also escape all control and non-ASCII characters. return s - .replace(/\\/g, '\\\\') // backslash - .replace(/"/g, '\\"') // closing double quote - .replace(/\0/g, '\\0') // null - .replace(/\x08/g, '\\b') // backspace - .replace(/\t/g, '\\t') // horizontal tab - .replace(/\n/g, '\\n') // line feed - .replace(/\v/g, '\\v') // vertical tab - .replace(/\f/g, '\\f') // form feed - .replace(/\r/g, '\\r') // carriage return - .replace(/[\x00-\x0F]/g, ch => '\\x0' + hex(ch)) - .replace(/[\x10-\x1F\x7F-\xFF]/g, ch => '\\x' + hex(ch)) - .replace(/[\u0100-\u0FFF]/g, ch => '\\u0' + hex(ch)) - .replace(/[\u1000-\uFFFF]/g, ch => '\\u' + hex(ch)); + .replace(/\\/g, "\\\\") // backslash + .replace(/"/g, "\\\"") // closing double quote + .replace(/\0/g, "\\0") // null + .replace(/\x08/g, "\\b") // backspace + .replace(/\t/g, "\\t") // horizontal tab + .replace(/\n/g, "\\n") // line feed + .replace(/\v/g, "\\v") // vertical tab + .replace(/\f/g, "\\f") // form feed + .replace(/\r/g, "\\r") // carriage return + .replace(/[\x00-\x0F]/g, ch => "\\x0" + hex(ch)) + .replace(/[\x10-\x1F\x7F-\xFF]/g, ch => "\\x" + hex(ch)) + .replace(/[\u0100-\u0FFF]/g, ch => "\\u0" + hex(ch)) + .replace(/[\u1000-\uFFFF]/g, ch => "\\u" + hex(ch)); }, regexpClassEscape: function(s) { @@ -32,22 +32,22 @@ let js = { // // For portability, we also escape all control and non-ASCII characters. return s - .replace(/\\/g, '\\\\') // backslash - .replace(/\//g, '\\/') // closing slash - .replace(/\]/g, '\\]') // closing bracket - .replace(/\^/g, '\\^') // caret - .replace(/-/g, '\\-') // dash - .replace(/\0/g, '\\0') // null - .replace(/\x08/g, '\\b') // backspace - .replace(/\t/g, '\\t') // horizontal tab - .replace(/\n/g, '\\n') // line feed - .replace(/\v/g, '\\v') // vertical tab - .replace(/\f/g, '\\f') // form feed - .replace(/\r/g, '\\r') // carriage return - .replace(/[\x00-\x0F]/g, ch => '\\x0' + hex(ch)) - .replace(/[\x10-\x1F\x7F-\xFF]/g, ch => '\\x' + hex(ch)) - .replace(/[\u0100-\u0FFF]/g, ch => '\\u0' + hex(ch)) - .replace(/[\u1000-\uFFFF]/g, ch => '\\u' + hex(ch)); + .replace(/\\/g, "\\\\") // backslash + .replace(/\//g, "\\/") // closing slash + .replace(/\]/g, "\\]") // closing bracket + .replace(/\^/g, "\\^") // caret + .replace(/-/g, "\\-") // dash + .replace(/\0/g, "\\0") // null + .replace(/\x08/g, "\\b") // backspace + .replace(/\t/g, "\\t") // horizontal tab + .replace(/\n/g, "\\n") // line feed + .replace(/\v/g, "\\v") // vertical tab + .replace(/\f/g, "\\f") // form feed + .replace(/\r/g, "\\r") // carriage return + .replace(/[\x00-\x0F]/g, ch => "\\x0" + hex(ch)) + .replace(/[\x10-\x1F\x7F-\xFF]/g, ch => "\\x" + hex(ch)) + .replace(/[\u0100-\u0FFF]/g, ch => "\\u0" + hex(ch)) + .replace(/[\u1000-\uFFFF]/g, ch => "\\u" + hex(ch)); } }; diff --git a/lib/compiler/passes/generate-bytecode.js b/lib/compiler/passes/generate-bytecode.js index e84cfcc..b448164 100644 --- a/lib/compiler/passes/generate-bytecode.js +++ b/lib/compiler/passes/generate-bytecode.js @@ -304,7 +304,7 @@ function generateBytecode(ast) { named: function(node, context) { let nameIndex = addConst( - 'peg$otherExpectation("' + js.stringEscape(node.name) + '")' + "peg$otherExpectation(\"" + js.stringEscape(node.name) + "\")" ); // The code generated below is slightly suboptimal because |FAIL| pushes @@ -535,17 +535,17 @@ function generateBytecode(ast) { literal: function(node) { if (node.value.length > 0) { - let stringIndex = addConst('"' + let stringIndex = addConst("\"" + js.stringEscape( node.ignoreCase ? node.value.toLowerCase() : node.value ) - + '"' + + "\"" ); let expectedIndex = addConst( - 'peg$literalExpectation(' - + '"' + js.stringEscape(node.value) + '", ' + "peg$literalExpectation(" + + "\"" + js.stringEscape(node.value) + "\", " + node.ignoreCase - + ')' + + ")" ); // For case-sensitive strings the value must match the beginning of the @@ -561,37 +561,37 @@ function generateBytecode(ast) { [op.FAIL, expectedIndex] ); } else { - let stringIndex = addConst('""'); + let stringIndex = addConst("\"\""); return [op.PUSH, stringIndex]; } }, "class": function(node) { - let regexp = '/^[' - + (node.inverted ? '^' : '') + let regexp = "/^[" + + (node.inverted ? "^" : "") + node.parts.map(part => Array.isArray(part) ? js.regexpClassEscape(part[0]) - + '-' + + "-" + js.regexpClassEscape(part[1]) : js.regexpClassEscape(part) - ).join('') - + ']/' + (node.ignoreCase ? 'i' : ''); - let parts = '[' + ).join("") + + "]/" + (node.ignoreCase ? "i" : ""); + let parts = "[" + node.parts.map(part => Array.isArray(part) - ? '["' + js.stringEscape(part[0]) + '", "' + js.stringEscape(part[1]) + '"]' - : '"' + js.stringEscape(part) + '"' - ).join(', ') - + ']'; + ? "[\"" + js.stringEscape(part[0]) + "\", \"" + js.stringEscape(part[1]) + "\"]" + : "\"" + js.stringEscape(part) + "\"" + ).join(", ") + + "]"; let regexpIndex = addConst(regexp); let expectedIndex = addConst( - 'peg$classExpectation(' - + parts + ', ' - + node.inverted + ', ' + "peg$classExpectation(" + + parts + ", " + + node.inverted + ", " + node.ignoreCase - + ')' + + ")" ); return buildCondition( @@ -602,7 +602,7 @@ function generateBytecode(ast) { }, any: function() { - let expectedIndex = addConst('peg$anyExpectation()'); + let expectedIndex = addConst("peg$anyExpectation()"); return buildCondition( [op.MATCH_ANY], diff --git a/lib/compiler/passes/generate-js.js b/lib/compiler/passes/generate-js.js index b6d0a52..cf360f4 100644 --- a/lib/compiler/passes/generate-js.js +++ b/lib/compiler/passes/generate-js.js @@ -7,85 +7,85 @@ let js = require("../js"); // Generates parser JavaScript code. function generateJS(ast, options) { // These only indent non-empty lines to avoid trailing whitespace. - function indent2(code) { return code.replace(/^(.+)$/gm, ' $1'); } - function indent10(code) { return code.replace(/^(.+)$/gm, ' $1'); } + function indent2(code) { return code.replace(/^(.+)$/gm, " $1"); } + function indent10(code) { return code.replace(/^(.+)$/gm, " $1"); } function generateTables() { if (options.optimize === "size") { return [ - 'var peg$consts = [', - indent2(ast.consts.join(',\n')), - '];', - '', - 'var peg$bytecode = [', + "var peg$consts = [", + indent2(ast.consts.join(",\n")), + "];", + "", + "var peg$bytecode = [", indent2(ast.rules.map(rule => - 'peg$decode("' + "peg$decode(\"" + js.stringEscape(rule.bytecode.map( b => String.fromCharCode(b + 32) - ).join('')) - + '")' - ).join(',\n')), - '];' - ].join('\n'); + ).join("")) + + "\")" + ).join(",\n")), + "];" + ].join("\n"); } else { - return ast.consts.map((c, i) => 'var peg$c' + i + ' = ' + c + ';').join('\n'); + return ast.consts.map((c, i) => "var peg$c" + i + " = " + c + ";").join("\n"); } } function generateRuleHeader(ruleNameCode, ruleIndexCode) { let parts = []; - parts.push(''); + parts.push(""); if (options.trace) { parts.push([ - 'peg$tracer.trace({', - ' type: "rule.enter",', - ' rule: ' + ruleNameCode + ',', - ' location: peg$computeLocation(startPos, startPos)', - '});', - '' - ].join('\n')); + "peg$tracer.trace({", + " type: \"rule.enter\",", + " rule: " + ruleNameCode + ",", + " location: peg$computeLocation(startPos, startPos)", + "});", + "" + ].join("\n")); } if (options.cache) { parts.push([ - 'var key = peg$currPos * ' + ast.rules.length + ' + ' + ruleIndexCode + ';', - 'var cached = peg$resultsCache[key];', - '', - 'if (cached) {', - ' peg$currPos = cached.nextPos;', - '' - ].join('\n')); + "var key = peg$currPos * " + ast.rules.length + " + " + ruleIndexCode + ";", + "var cached = peg$resultsCache[key];", + "", + "if (cached) {", + " peg$currPos = cached.nextPos;", + "" + ].join("\n")); if (options.trace) { parts.push([ - 'if (cached.result !== peg$FAILED) {', - ' peg$tracer.trace({', - ' type: "rule.match",', - ' rule: ' + ruleNameCode + ',', - ' result: cached.result,', - ' location: peg$computeLocation(startPos, peg$currPos)', - ' });', - '} else {', - ' peg$tracer.trace({', - ' type: "rule.fail",', - ' rule: ' + ruleNameCode + ',', - ' location: peg$computeLocation(startPos, startPos)', - ' });', - '}', - '' - ].join('\n')); + "if (cached.result !== peg$FAILED) {", + " peg$tracer.trace({", + " type: \"rule.match\",", + " rule: " + ruleNameCode + ",", + " result: cached.result,", + " location: peg$computeLocation(startPos, peg$currPos)", + " });", + "} else {", + " peg$tracer.trace({", + " type: \"rule.fail\",", + " rule: " + ruleNameCode + ",", + " location: peg$computeLocation(startPos, startPos)", + " });", + "}", + "" + ].join("\n")); } parts.push([ - ' return cached.result;', - '}', - '' - ].join('\n')); + " return cached.result;", + "}", + "" + ].join("\n")); } - return parts.join('\n'); + return parts.join("\n"); } function generateRuleFooter(ruleNameCode, resultCode) { @@ -93,37 +93,37 @@ function generateJS(ast, options) { if (options.cache) { parts.push([ - '', - 'peg$resultsCache[key] = { nextPos: peg$currPos, result: ' + resultCode + ' };' - ].join('\n')); + "", + "peg$resultsCache[key] = { nextPos: peg$currPos, result: " + resultCode + " };" + ].join("\n")); } if (options.trace) { parts.push([ - '', - 'if (' + resultCode + ' !== peg$FAILED) {', - ' peg$tracer.trace({', - ' type: "rule.match",', - ' rule: ' + ruleNameCode + ',', - ' result: ' + resultCode + ',', - ' location: peg$computeLocation(startPos, peg$currPos)', - ' });', - '} else {', - ' peg$tracer.trace({', - ' type: "rule.fail",', - ' rule: ' + ruleNameCode + ',', - ' location: peg$computeLocation(startPos, startPos)', - ' });', - '}' - ].join('\n')); + "", + "if (" + resultCode + " !== peg$FAILED) {", + " peg$tracer.trace({", + " type: \"rule.match\",", + " rule: " + ruleNameCode + ",", + " result: " + resultCode + ",", + " location: peg$computeLocation(startPos, peg$currPos)", + " });", + "} else {", + " peg$tracer.trace({", + " type: \"rule.fail\",", + " rule: " + ruleNameCode + ",", + " location: peg$computeLocation(startPos, startPos)", + " });", + "}" + ].join("\n")); } parts.push([ - '', - 'return ' + resultCode + ';' - ].join('\n')); + "", + "return " + resultCode + ";" + ].join("\n")); - return parts.join('\n'); + return parts.join("\n"); } function generateInterpreter() { @@ -131,95 +131,95 @@ function generateJS(ast, options) { function generateCondition(cond, argsLength) { let baseLength = argsLength + 3; - let thenLengthCode = 'bc[ip + ' + (baseLength - 2) + ']'; - let elseLengthCode = 'bc[ip + ' + (baseLength - 1) + ']'; + let thenLengthCode = "bc[ip + " + (baseLength - 2) + "]"; + let elseLengthCode = "bc[ip + " + (baseLength - 1) + "]"; return [ - 'ends.push(end);', - 'ips.push(ip + ' + baseLength + ' + ' + thenLengthCode + ' + ' + elseLengthCode + ');', - '', - 'if (' + cond + ') {', - ' end = ip + ' + baseLength + ' + ' + thenLengthCode + ';', - ' ip += ' + baseLength + ';', - '} else {', - ' end = ip + ' + baseLength + ' + ' + thenLengthCode + ' + ' + elseLengthCode + ';', - ' ip += ' + baseLength + ' + ' + thenLengthCode + ';', - '}', - '', - 'break;' - ].join('\n'); + "ends.push(end);", + "ips.push(ip + " + baseLength + " + " + thenLengthCode + " + " + elseLengthCode + ");", + "", + "if (" + cond + ") {", + " end = ip + " + baseLength + " + " + thenLengthCode + ";", + " ip += " + baseLength + ";", + "} else {", + " end = ip + " + baseLength + " + " + thenLengthCode + " + " + elseLengthCode + ";", + " ip += " + baseLength + " + " + thenLengthCode + ";", + "}", + "", + "break;" + ].join("\n"); } function generateLoop(cond) { let baseLength = 2; - let bodyLengthCode = 'bc[ip + ' + (baseLength - 1) + ']'; + let bodyLengthCode = "bc[ip + " + (baseLength - 1) + "]"; return [ - 'if (' + cond + ') {', - ' ends.push(end);', - ' ips.push(ip);', - '', - ' end = ip + ' + baseLength + ' + ' + bodyLengthCode + ';', - ' ip += ' + baseLength + ';', - '} else {', - ' ip += ' + baseLength + ' + ' + bodyLengthCode + ';', - '}', - '', - 'break;' - ].join('\n'); + "if (" + cond + ") {", + " ends.push(end);", + " ips.push(ip);", + "", + " end = ip + " + baseLength + " + " + bodyLengthCode + ";", + " ip += " + baseLength + ";", + "} else {", + " ip += " + baseLength + " + " + bodyLengthCode + ";", + "}", + "", + "break;" + ].join("\n"); } function generateCall() { let baseLength = 4; - let paramsLengthCode = 'bc[ip + ' + (baseLength - 1) + ']'; + let paramsLengthCode = "bc[ip + " + (baseLength - 1) + "]"; return [ - 'params = bc.slice(ip + ' + baseLength + ', ip + ' + baseLength + ' + ' + paramsLengthCode + ')', - ' .map(function(p) { return stack[stack.length - 1 - p]; });', - '', - 'stack.splice(', - ' stack.length - bc[ip + 2],', - ' bc[ip + 2],', - ' peg$consts[bc[ip + 1]].apply(null, params)', - ');', - '', - 'ip += ' + baseLength + ' + ' + paramsLengthCode + ';', - 'break;' - ].join('\n'); + "params = bc.slice(ip + " + baseLength + ", ip + " + baseLength + " + " + paramsLengthCode + ")", + " .map(function(p) { return stack[stack.length - 1 - p]; });", + "", + "stack.splice(", + " stack.length - bc[ip + 2],", + " bc[ip + 2],", + " peg$consts[bc[ip + 1]].apply(null, params)", + ");", + "", + "ip += " + baseLength + " + " + paramsLengthCode + ";", + "break;" + ].join("\n"); } parts.push([ - 'function peg$decode(s) {', - ' return s.split("").map(function(ch) { return ch.charCodeAt(0) - 32; });', - '}', - '', - 'function peg$parseRule(index) {' - ].join('\n')); + "function peg$decode(s) {", + " return s.split(\"\").map(function(ch) { return ch.charCodeAt(0) - 32; });", + "}", + "", + "function peg$parseRule(index) {" + ].join("\n")); if (options.trace) { parts.push([ - ' var bc = peg$bytecode[index];', - ' var ip = 0;', - ' var ips = [];', - ' var end = bc.length;', - ' var ends = [];', - ' var stack = [];', - ' var startPos = peg$currPos;', - ' var params;' - ].join('\n')); + " var bc = peg$bytecode[index];", + " var ip = 0;", + " var ips = [];", + " var end = bc.length;", + " var ends = [];", + " var stack = [];", + " var startPos = peg$currPos;", + " var params;" + ].join("\n")); } else { parts.push([ - ' var bc = peg$bytecode[index];', - ' var ip = 0;', - ' var ips = [];', - ' var end = bc.length;', - ' var ends = [];', - ' var stack = [];', - ' var params;' - ].join('\n')); + " var bc = peg$bytecode[index];", + " var ip = 0;", + " var ips = [];", + " var end = bc.length;", + " var ends = [];", + " var stack = [];", + " var params;" + ].join("\n")); } - parts.push(indent2(generateRuleHeader('peg$ruleNames[index]', 'index'))); + parts.push(indent2(generateRuleHeader("peg$ruleNames[index]", "index"))); parts.push([ // The point of the outer loop and the |ips| & |ends| stacks is to avoid @@ -227,179 +227,179 @@ function generateJS(ast, options) { // implement the |interpret| operation of the abstract machine without // function calls. Such calls would likely slow the parser down and more // importantly cause stack overflows for complex grammars. - ' while (true) {', - ' while (ip < end) {', - ' switch (bc[ip]) {', - ' case ' + op.PUSH + ':', // PUSH c - ' stack.push(peg$consts[bc[ip + 1]]);', - ' ip += 2;', - ' break;', - '', - ' case ' + op.PUSH_UNDEFINED + ':', // PUSH_UNDEFINED - ' stack.push(undefined);', - ' ip++;', - ' break;', - '', - ' case ' + op.PUSH_NULL + ':', // PUSH_NULL - ' stack.push(null);', - ' ip++;', - ' break;', - '', - ' case ' + op.PUSH_FAILED + ':', // PUSH_FAILED - ' stack.push(peg$FAILED);', - ' ip++;', - ' break;', - '', - ' case ' + op.PUSH_EMPTY_ARRAY + ':', // PUSH_EMPTY_ARRAY - ' stack.push([]);', - ' ip++;', - ' break;', - '', - ' case ' + op.PUSH_CURR_POS + ':', // PUSH_CURR_POS - ' stack.push(peg$currPos);', - ' ip++;', - ' break;', - '', - ' case ' + op.POP + ':', // POP - ' stack.pop();', - ' ip++;', - ' break;', - '', - ' case ' + op.POP_CURR_POS + ':', // POP_CURR_POS - ' peg$currPos = stack.pop();', - ' ip++;', - ' break;', - '', - ' case ' + op.POP_N + ':', // POP_N n - ' stack.length -= bc[ip + 1];', - ' ip += 2;', - ' break;', - '', - ' case ' + op.NIP + ':', // NIP - ' stack.splice(-2, 1);', - ' ip++;', - ' break;', - '', - ' case ' + op.APPEND + ':', // APPEND - ' stack[stack.length - 2].push(stack.pop());', - ' ip++;', - ' break;', - '', - ' case ' + op.WRAP + ':', // WRAP n - ' stack.push(stack.splice(stack.length - bc[ip + 1], bc[ip + 1]));', - ' ip += 2;', - ' break;', - '', - ' case ' + op.TEXT + ':', // TEXT - ' stack.push(input.substring(stack.pop(), peg$currPos));', - ' ip++;', - ' break;', - '', - ' case ' + op.IF + ':', // IF t, f - indent10(generateCondition('stack[stack.length - 1]', 0)), - '', - ' case ' + op.IF_ERROR + ':', // IF_ERROR t, f + " while (true) {", + " while (ip < end) {", + " switch (bc[ip]) {", + " case " + op.PUSH + ":", // PUSH c + " stack.push(peg$consts[bc[ip + 1]]);", + " ip += 2;", + " break;", + "", + " case " + op.PUSH_UNDEFINED + ":", // PUSH_UNDEFINED + " stack.push(undefined);", + " ip++;", + " break;", + "", + " case " + op.PUSH_NULL + ":", // PUSH_NULL + " stack.push(null);", + " ip++;", + " break;", + "", + " case " + op.PUSH_FAILED + ":", // PUSH_FAILED + " stack.push(peg$FAILED);", + " ip++;", + " break;", + "", + " case " + op.PUSH_EMPTY_ARRAY + ":", // PUSH_EMPTY_ARRAY + " stack.push([]);", + " ip++;", + " break;", + "", + " case " + op.PUSH_CURR_POS + ":", // PUSH_CURR_POS + " stack.push(peg$currPos);", + " ip++;", + " break;", + "", + " case " + op.POP + ":", // POP + " stack.pop();", + " ip++;", + " break;", + "", + " case " + op.POP_CURR_POS + ":", // POP_CURR_POS + " peg$currPos = stack.pop();", + " ip++;", + " break;", + "", + " case " + op.POP_N + ":", // POP_N n + " stack.length -= bc[ip + 1];", + " ip += 2;", + " break;", + "", + " case " + op.NIP + ":", // NIP + " stack.splice(-2, 1);", + " ip++;", + " break;", + "", + " case " + op.APPEND + ":", // APPEND + " stack[stack.length - 2].push(stack.pop());", + " ip++;", + " break;", + "", + " case " + op.WRAP + ":", // WRAP n + " stack.push(stack.splice(stack.length - bc[ip + 1], bc[ip + 1]));", + " ip += 2;", + " break;", + "", + " case " + op.TEXT + ":", // TEXT + " stack.push(input.substring(stack.pop(), peg$currPos));", + " ip++;", + " break;", + "", + " case " + op.IF + ":", // IF t, f + indent10(generateCondition("stack[stack.length - 1]", 0)), + "", + " case " + op.IF_ERROR + ":", // IF_ERROR t, f indent10(generateCondition( - 'stack[stack.length - 1] === peg$FAILED', + "stack[stack.length - 1] === peg$FAILED", 0 )), - '', - ' case ' + op.IF_NOT_ERROR + ':', // IF_NOT_ERROR t, f + "", + " case " + op.IF_NOT_ERROR + ":", // IF_NOT_ERROR t, f indent10( - generateCondition('stack[stack.length - 1] !== peg$FAILED', + generateCondition("stack[stack.length - 1] !== peg$FAILED", 0 )), - '', - ' case ' + op.WHILE_NOT_ERROR + ':', // WHILE_NOT_ERROR b - indent10(generateLoop('stack[stack.length - 1] !== peg$FAILED')), - '', - ' case ' + op.MATCH_ANY + ':', // MATCH_ANY a, f, ... - indent10(generateCondition('input.length > peg$currPos', 0)), - '', - ' case ' + op.MATCH_STRING + ':', // MATCH_STRING s, a, f, ... + "", + " case " + op.WHILE_NOT_ERROR + ":", // WHILE_NOT_ERROR b + indent10(generateLoop("stack[stack.length - 1] !== peg$FAILED")), + "", + " case " + op.MATCH_ANY + ":", // MATCH_ANY a, f, ... + indent10(generateCondition("input.length > peg$currPos", 0)), + "", + " case " + op.MATCH_STRING + ":", // MATCH_STRING s, a, f, ... indent10(generateCondition( - 'input.substr(peg$currPos, peg$consts[bc[ip + 1]].length) === peg$consts[bc[ip + 1]]', + "input.substr(peg$currPos, peg$consts[bc[ip + 1]].length) === peg$consts[bc[ip + 1]]", 1 )), - '', - ' case ' + op.MATCH_STRING_IC + ':', // MATCH_STRING_IC s, a, f, ... + "", + " case " + op.MATCH_STRING_IC + ":", // MATCH_STRING_IC s, a, f, ... indent10(generateCondition( - 'input.substr(peg$currPos, peg$consts[bc[ip + 1]].length).toLowerCase() === peg$consts[bc[ip + 1]]', + "input.substr(peg$currPos, peg$consts[bc[ip + 1]].length).toLowerCase() === peg$consts[bc[ip + 1]]", 1 )), - '', - ' case ' + op.MATCH_REGEXP + ':', // MATCH_REGEXP r, a, f, ... + "", + " case " + op.MATCH_REGEXP + ":", // MATCH_REGEXP r, a, f, ... indent10(generateCondition( - 'peg$consts[bc[ip + 1]].test(input.charAt(peg$currPos))', + "peg$consts[bc[ip + 1]].test(input.charAt(peg$currPos))", 1 )), - '', - ' case ' + op.ACCEPT_N + ':', // ACCEPT_N n - ' stack.push(input.substr(peg$currPos, bc[ip + 1]));', - ' peg$currPos += bc[ip + 1];', - ' ip += 2;', - ' break;', - '', - ' case ' + op.ACCEPT_STRING + ':', // ACCEPT_STRING s - ' stack.push(peg$consts[bc[ip + 1]]);', - ' peg$currPos += peg$consts[bc[ip + 1]].length;', - ' ip += 2;', - ' break;', - '', - ' case ' + op.FAIL + ':', // FAIL e - ' stack.push(peg$FAILED);', - ' if (peg$silentFails === 0) {', - ' peg$fail(peg$consts[bc[ip + 1]]);', - ' }', - ' ip += 2;', - ' break;', - '', - ' case ' + op.LOAD_SAVED_POS + ':', // LOAD_SAVED_POS p - ' peg$savedPos = stack[stack.length - 1 - bc[ip + 1]];', - ' ip += 2;', - ' break;', - '', - ' case ' + op.UPDATE_SAVED_POS + ':', // UPDATE_SAVED_POS - ' peg$savedPos = peg$currPos;', - ' ip++;', - ' break;', - '', - ' case ' + op.CALL + ':', // CALL f, n, pc, p1, p2, ..., pN + "", + " case " + op.ACCEPT_N + ":", // ACCEPT_N n + " stack.push(input.substr(peg$currPos, bc[ip + 1]));", + " peg$currPos += bc[ip + 1];", + " ip += 2;", + " break;", + "", + " case " + op.ACCEPT_STRING + ":", // ACCEPT_STRING s + " stack.push(peg$consts[bc[ip + 1]]);", + " peg$currPos += peg$consts[bc[ip + 1]].length;", + " ip += 2;", + " break;", + "", + " case " + op.FAIL + ":", // FAIL e + " stack.push(peg$FAILED);", + " if (peg$silentFails === 0) {", + " peg$fail(peg$consts[bc[ip + 1]]);", + " }", + " ip += 2;", + " break;", + "", + " case " + op.LOAD_SAVED_POS + ":", // LOAD_SAVED_POS p + " peg$savedPos = stack[stack.length - 1 - bc[ip + 1]];", + " ip += 2;", + " break;", + "", + " case " + op.UPDATE_SAVED_POS + ":", // UPDATE_SAVED_POS + " peg$savedPos = peg$currPos;", + " ip++;", + " break;", + "", + " case " + op.CALL + ":", // CALL f, n, pc, p1, p2, ..., pN indent10(generateCall()), - '', - ' case ' + op.RULE + ':', // RULE r - ' stack.push(peg$parseRule(bc[ip + 1]));', - ' ip += 2;', - ' break;', - '', - ' case ' + op.SILENT_FAILS_ON + ':', // SILENT_FAILS_ON - ' peg$silentFails++;', - ' ip++;', - ' break;', - '', - ' case ' + op.SILENT_FAILS_OFF + ':', // SILENT_FAILS_OFF - ' peg$silentFails--;', - ' ip++;', - ' break;', - '', - ' default:', - ' throw new Error("Invalid opcode: " + bc[ip] + ".");', - ' }', - ' }', - '', - ' if (ends.length > 0) {', - ' end = ends.pop();', - ' ip = ips.pop();', - ' } else {', - ' break;', - ' }', - ' }' - ].join('\n')); - - parts.push(indent2(generateRuleFooter('peg$ruleNames[index]', 'stack[0]'))); - parts.push('}'); - - return parts.join('\n'); + "", + " case " + op.RULE + ":", // RULE r + " stack.push(peg$parseRule(bc[ip + 1]));", + " ip += 2;", + " break;", + "", + " case " + op.SILENT_FAILS_ON + ":", // SILENT_FAILS_ON + " peg$silentFails++;", + " ip++;", + " break;", + "", + " case " + op.SILENT_FAILS_OFF + ":", // SILENT_FAILS_OFF + " peg$silentFails--;", + " ip++;", + " break;", + "", + " default:", + " throw new Error(\"Invalid opcode: \" + bc[ip] + \".\");", + " }", + " }", + "", + " if (ends.length > 0) {", + " end = ends.pop();", + " ip = ips.pop();", + " } else {", + " break;", + " }", + " }" + ].join("\n")); + + parts.push(indent2(generateRuleFooter("peg$ruleNames[index]", "stack[0]"))); + parts.push("}"); + + return parts.join("\n"); } function generateRuleFunction(rule) { @@ -415,7 +415,7 @@ function generateJS(ast, options) { maxSp: -1, push: function(exprCode) { - let code = s(++this.sp) + ' = ' + exprCode + ';'; + let code = s(++this.sp) + " = " + exprCode + ";"; if (this.sp > this.maxSp) { this.maxSp = this.sp; } @@ -478,13 +478,13 @@ function generateJS(ast, options) { } } - parts.push('if (' + cond + ') {'); + parts.push("if (" + cond + ") {"); parts.push(indent2(thenCode)); if (elseLength > 0) { - parts.push('} else {'); + parts.push("} else {"); parts.push(indent2(elseCode)); } - parts.push('}'); + parts.push("}"); } function compileLoop(cond) { @@ -502,20 +502,20 @@ function generateJS(ast, options) { throw new Error("Body of a loop can't move the stack pointer."); } - parts.push('while (' + cond + ') {'); + parts.push("while (" + cond + ") {"); parts.push(indent2(bodyCode)); - parts.push('}'); + parts.push("}"); } function compileCall() { let baseLength = 4; let paramsLength = bc[ip + baseLength - 1]; - let value = c(bc[ip + 1]) + '(' + let value = c(bc[ip + 1]) + "(" + bc.slice(ip + baseLength, ip + baseLength + paramsLength).map( p => stack.index(p) - ).join(', ') - + ')'; + ).join(", ") + + ")"; stack.pop(bc[ip + 2]); parts.push(stack.push(value)); ip += baseLength + paramsLength; @@ -529,27 +529,27 @@ function generateJS(ast, options) { break; case op.PUSH_CURR_POS: // PUSH_CURR_POS - parts.push(stack.push('peg$currPos')); + parts.push(stack.push("peg$currPos")); ip++; break; case op.PUSH_UNDEFINED: // PUSH_UNDEFINED - parts.push(stack.push('undefined')); + parts.push(stack.push("undefined")); ip++; break; case op.PUSH_NULL: // PUSH_NULL - parts.push(stack.push('null')); + parts.push(stack.push("null")); ip++; break; case op.PUSH_FAILED: // PUSH_FAILED - parts.push(stack.push('peg$FAILED')); + parts.push(stack.push("peg$FAILED")); ip++; break; case op.PUSH_EMPTY_ARRAY: // PUSH_EMPTY_ARRAY - parts.push(stack.push('[]')); + parts.push(stack.push("[]")); ip++; break; @@ -559,7 +559,7 @@ function generateJS(ast, options) { break; case op.POP_CURR_POS: // POP_CURR_POS - parts.push('peg$currPos = ' + stack.pop() + ';'); + parts.push("peg$currPos = " + stack.pop() + ";"); ip++; break; @@ -577,20 +577,20 @@ function generateJS(ast, options) { case op.APPEND: // APPEND value = stack.pop(); - parts.push(stack.top() + '.push(' + value + ');'); + parts.push(stack.top() + ".push(" + value + ");"); ip++; break; case op.WRAP: // WRAP n parts.push( - stack.push('[' + stack.pop(bc[ip + 1]).join(', ') + ']') + stack.push("[" + stack.pop(bc[ip + 1]).join(", ") + "]") ); ip += 2; break; case op.TEXT: // TEXT parts.push( - stack.push('input.substring(' + stack.pop() + ', peg$currPos)') + stack.push("input.substring(" + stack.pop() + ", peg$currPos)") ); ip++; break; @@ -600,29 +600,29 @@ function generateJS(ast, options) { break; case op.IF_ERROR: // IF_ERROR t, f - compileCondition(stack.top() + ' === peg$FAILED', 0); + compileCondition(stack.top() + " === peg$FAILED", 0); break; case op.IF_NOT_ERROR: // IF_NOT_ERROR t, f - compileCondition(stack.top() + ' !== peg$FAILED', 0); + compileCondition(stack.top() + " !== peg$FAILED", 0); break; case op.WHILE_NOT_ERROR: // WHILE_NOT_ERROR b - compileLoop(stack.top() + ' !== peg$FAILED', 0); + compileLoop(stack.top() + " !== peg$FAILED", 0); break; case op.MATCH_ANY: // MATCH_ANY a, f, ... - compileCondition('input.length > peg$currPos', 0); + compileCondition("input.length > peg$currPos", 0); break; case op.MATCH_STRING: // MATCH_STRING s, a, f, ... compileCondition( eval(ast.consts[bc[ip + 1]]).length > 1 - ? 'input.substr(peg$currPos, ' + ? "input.substr(peg$currPos, " + eval(ast.consts[bc[ip + 1]]).length - + ') === ' + + ") === " + c(bc[ip + 1]) - : 'input.charCodeAt(peg$currPos) === ' + : "input.charCodeAt(peg$currPos) === " + eval(ast.consts[bc[ip + 1]]).charCodeAt(0), 1 ); @@ -630,9 +630,9 @@ function generateJS(ast, options) { case op.MATCH_STRING_IC: // MATCH_STRING_IC s, a, f, ... compileCondition( - 'input.substr(peg$currPos, ' + "input.substr(peg$currPos, " + eval(ast.consts[bc[ip + 1]]).length - + ').toLowerCase() === ' + + ").toLowerCase() === " + c(bc[ip + 1]), 1 ); @@ -640,7 +640,7 @@ function generateJS(ast, options) { case op.MATCH_REGEXP: // MATCH_REGEXP r, a, f, ... compileCondition( - c(bc[ip + 1]) + '.test(input.charAt(peg$currPos))', + c(bc[ip + 1]) + ".test(input.charAt(peg$currPos))", 1 ); break; @@ -648,13 +648,13 @@ function generateJS(ast, options) { case op.ACCEPT_N: // ACCEPT_N n parts.push(stack.push( bc[ip + 1] > 1 - ? 'input.substr(peg$currPos, ' + bc[ip + 1] + ')' - : 'input.charAt(peg$currPos)' + ? "input.substr(peg$currPos, " + bc[ip + 1] + ")" + : "input.charAt(peg$currPos)" )); parts.push( bc[ip + 1] > 1 - ? 'peg$currPos += ' + bc[ip + 1] + ';' - : 'peg$currPos++;' + ? "peg$currPos += " + bc[ip + 1] + ";" + : "peg$currPos++;" ); ip += 2; break; @@ -663,25 +663,25 @@ function generateJS(ast, options) { parts.push(stack.push(c(bc[ip + 1]))); parts.push( eval(ast.consts[bc[ip + 1]]).length > 1 - ? 'peg$currPos += ' + eval(ast.consts[bc[ip + 1]]).length + ';' - : 'peg$currPos++;' + ? "peg$currPos += " + eval(ast.consts[bc[ip + 1]]).length + ";" + : "peg$currPos++;" ); ip += 2; break; case op.FAIL: // FAIL e - parts.push(stack.push('peg$FAILED')); - parts.push('if (peg$silentFails === 0) { peg$fail(' + c(bc[ip + 1]) + '); }'); + parts.push(stack.push("peg$FAILED")); + parts.push("if (peg$silentFails === 0) { peg$fail(" + c(bc[ip + 1]) + "); }"); ip += 2; break; case op.LOAD_SAVED_POS: // LOAD_SAVED_POS p - parts.push('peg$savedPos = ' + stack.index(bc[ip + 1]) + ';'); + parts.push("peg$savedPos = " + stack.index(bc[ip + 1]) + ";"); ip += 2; break; case op.UPDATE_SAVED_POS: // UPDATE_SAVED_POS - parts.push('peg$savedPos = peg$currPos;'); + parts.push("peg$savedPos = peg$currPos;"); ip++; break; @@ -695,12 +695,12 @@ function generateJS(ast, options) { break; case op.SILENT_FAILS_ON: // SILENT_FAILS_ON - parts.push('peg$silentFails++;'); + parts.push("peg$silentFails++;"); ip++; break; case op.SILENT_FAILS_OFF: // SILENT_FAILS_OFF - parts.push('peg$silentFails--;'); + parts.push("peg$silentFails--;"); ip++; break; @@ -709,531 +709,531 @@ function generateJS(ast, options) { } } - return parts.join('\n'); + return parts.join("\n"); } code = compile(rule.bytecode); - parts.push('function peg$parse' + rule.name + '() {'); + parts.push("function peg$parse" + rule.name + "() {"); if (options.trace) { - parts.push(' var startPos = peg$currPos;'); + parts.push(" var startPos = peg$currPos;"); } for (let i = 0; i <= stack.maxSp; i++) { stackVars[i] = s(i); } - parts.push(' var ' + stackVars.join(', ') + ';'); + parts.push(" var " + stackVars.join(", ") + ";"); parts.push(indent2(generateRuleHeader( - '"' + js.stringEscape(rule.name) + '"', + "\"" + js.stringEscape(rule.name) + "\"", asts.indexOfRule(ast, rule.name) ))); parts.push(indent2(code)); parts.push(indent2(generateRuleFooter( - '"' + js.stringEscape(rule.name) + '"', + "\"" + js.stringEscape(rule.name) + "\"", s(0) ))); - parts.push('}'); + parts.push("}"); - return parts.join('\n'); + return parts.join("\n"); } function generateToplevel() { let parts = []; parts.push([ - 'function peg$subclass(child, parent) {', - ' function ctor() { this.constructor = child; }', - ' ctor.prototype = parent.prototype;', - ' child.prototype = new ctor();', - '}', - '', - 'function peg$SyntaxError(message, expected, found, location) {', - ' this.message = message;', - ' this.expected = expected;', - ' this.found = found;', - ' this.location = location;', - ' this.name = "SyntaxError";', - '', - ' if (typeof Error.captureStackTrace === "function") {', - ' Error.captureStackTrace(this, peg$SyntaxError);', - ' }', - '}', - '', - 'peg$subclass(peg$SyntaxError, Error);', - '', - 'peg$SyntaxError.buildMessage = function(expected, found) {', - ' var DESCRIBE_EXPECTATION_FNS = {', - ' literal: function(expectation) {', - ' return "\\\"" + literalEscape(expectation.text) + "\\\"";', - ' },', - '', - ' "class": function(expectation) {', - ' var escapedParts = expectation.parts.map(function(part) {', - ' return Array.isArray(part)', - ' ? classEscape(part[0]) + "-" + classEscape(part[1])', - ' : classEscape(part);', - ' });', - '', - ' return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]";', - ' },', - '', - ' any: function(expectation) {', - ' return "any character";', - ' },', - '', - ' end: function(expectation) {', - ' return "end of input";', - ' },', - '', - ' other: function(expectation) {', - ' return expectation.description;', - ' }', - ' };', - '', - ' function hex(ch) {', - ' return ch.charCodeAt(0).toString(16).toUpperCase();', - ' }', - '', - ' function literalEscape(s) {', - ' return s', - ' .replace(/\\\\/g, \'\\\\\\\\\')', // backslash - ' .replace(/"/g, \'\\\\"\')', // closing double quote - ' .replace(/\\0/g, \'\\\\0\')', // null - ' .replace(/\\t/g, \'\\\\t\')', // horizontal tab - ' .replace(/\\n/g, \'\\\\n\')', // line feed - ' .replace(/\\r/g, \'\\\\r\')', // carriage return - ' .replace(/[\\x00-\\x0F]/g, function(ch) { return \'\\\\x0\' + hex(ch); })', - ' .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) { return \'\\\\x\' + hex(ch); });', - ' }', - '', - ' function classEscape(s) {', - ' return s', - ' .replace(/\\\\/g, \'\\\\\\\\\')', // backslash - ' .replace(/\\]/g, \'\\\\]\')', // closing bracket - ' .replace(/\\^/g, \'\\\\^\')', // caret - ' .replace(/-/g, \'\\\\-\')', // dash - ' .replace(/\\0/g, \'\\\\0\')', // null - ' .replace(/\\t/g, \'\\\\t\')', // horizontal tab - ' .replace(/\\n/g, \'\\\\n\')', // line feed - ' .replace(/\\r/g, \'\\\\r\')', // carriage return - ' .replace(/[\\x00-\\x0F]/g, function(ch) { return \'\\\\x0\' + hex(ch); })', - ' .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) { return \'\\\\x\' + hex(ch); });', - ' }', - '', - ' function describeExpectation(expectation) {', - ' return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);', - ' }', - '', - ' function describeExpected(expected) {', - ' var descriptions = expected.map(describeExpectation);', - ' var i, j;', - '', - ' descriptions.sort();', - '', - ' if (descriptions.length > 0) {', - ' for (i = 1, j = 1; i < descriptions.length; i++) {', - ' if (descriptions[i - 1] !== descriptions[i]) {', - ' descriptions[j] = descriptions[i];', - ' j++;', - ' }', - ' }', - ' descriptions.length = j;', - ' }', - '', - ' switch (descriptions.length) {', - ' case 1:', - ' return descriptions[0];', - '', - ' case 2:', - ' return descriptions[0] + " or " + descriptions[1];', - '', - ' default:', - ' return descriptions.slice(0, -1).join(", ")', - ' + ", or "', - ' + descriptions[descriptions.length - 1];', - ' }', - ' }', - '', - ' function describeFound(found) {', - ' return found ? "\\"" + literalEscape(found) + "\\"" : "end of input";', - ' }', - '', - ' return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";', - '};', - '' - ].join('\n')); + "function peg$subclass(child, parent) {", + " function ctor() { this.constructor = child; }", + " ctor.prototype = parent.prototype;", + " child.prototype = new ctor();", + "}", + "", + "function peg$SyntaxError(message, expected, found, location) {", + " this.message = message;", + " this.expected = expected;", + " this.found = found;", + " this.location = location;", + " this.name = \"SyntaxError\";", + "", + " if (typeof Error.captureStackTrace === \"function\") {", + " Error.captureStackTrace(this, peg$SyntaxError);", + " }", + "}", + "", + "peg$subclass(peg$SyntaxError, Error);", + "", + "peg$SyntaxError.buildMessage = function(expected, found) {", + " var DESCRIBE_EXPECTATION_FNS = {", + " literal: function(expectation) {", + " return \"\\\"\" + literalEscape(expectation.text) + \"\\\"\";", + " },", + "", + " \"class\": function(expectation) {", + " var escapedParts = expectation.parts.map(function(part) {", + " return Array.isArray(part)", + " ? classEscape(part[0]) + \"-\" + classEscape(part[1])", + " : classEscape(part);", + " });", + "", + " return \"[\" + (expectation.inverted ? \"^\" : \"\") + escapedParts + \"]\";", + " },", + "", + " any: function(expectation) {", + " return \"any character\";", + " },", + "", + " end: function(expectation) {", + " return \"end of input\";", + " },", + "", + " other: function(expectation) {", + " return expectation.description;", + " }", + " };", + "", + " function hex(ch) {", + " return ch.charCodeAt(0).toString(16).toUpperCase();", + " }", + "", + " function literalEscape(s) {", + " return s", + " .replace(/\\\\/g, \"\\\\\\\\\")", // backslash + " .replace(/\"/g, \"\\\\\\\"\")", // closing double quote + " .replace(/\\0/g, \"\\\\0\")", // null + " .replace(/\\t/g, \"\\\\t\")", // horizontal tab + " .replace(/\\n/g, \"\\\\n\")", // line feed + " .replace(/\\r/g, \"\\\\r\")", // carriage return + " .replace(/[\\x00-\\x0F]/g, function(ch) { return \"\\\\x0\" + hex(ch); })", + " .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) { return \"\\\\x\" + hex(ch); });", + " }", + "", + " function classEscape(s) {", + " return s", + " .replace(/\\\\/g, \"\\\\\\\\\")", // backslash + " .replace(/\\]/g, \"\\\\]\")", // closing bracket + " .replace(/\\^/g, \"\\\\^\")", // caret + " .replace(/-/g, \"\\\\-\")", // dash + " .replace(/\\0/g, \"\\\\0\")", // null + " .replace(/\\t/g, \"\\\\t\")", // horizontal tab + " .replace(/\\n/g, \"\\\\n\")", // line feed + " .replace(/\\r/g, \"\\\\r\")", // carriage return + " .replace(/[\\x00-\\x0F]/g, function(ch) { return \"\\\\x0\" + hex(ch); })", + " .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, function(ch) { return \"\\\\x\" + hex(ch); });", + " }", + "", + " function describeExpectation(expectation) {", + " return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);", + " }", + "", + " function describeExpected(expected) {", + " var descriptions = expected.map(describeExpectation);", + " var i, j;", + "", + " descriptions.sort();", + "", + " if (descriptions.length > 0) {", + " for (i = 1, j = 1; i < descriptions.length; i++) {", + " if (descriptions[i - 1] !== descriptions[i]) {", + " descriptions[j] = descriptions[i];", + " j++;", + " }", + " }", + " descriptions.length = j;", + " }", + "", + " switch (descriptions.length) {", + " case 1:", + " return descriptions[0];", + "", + " case 2:", + " return descriptions[0] + \" or \" + descriptions[1];", + "", + " default:", + " return descriptions.slice(0, -1).join(\", \")", + " + \", or \"", + " + descriptions[descriptions.length - 1];", + " }", + " }", + "", + " function describeFound(found) {", + " return found ? \"\\\"\" + literalEscape(found) + \"\\\"\" : \"end of input\";", + " }", + "", + " return \"Expected \" + describeExpected(expected) + \" but \" + describeFound(found) + \" found.\";", + "};", + "" + ].join("\n")); if (options.trace) { parts.push([ - 'function peg$DefaultTracer() {', - ' this.indentLevel = 0;', - '}', - '', - 'peg$DefaultTracer.prototype.trace = function(event) {', - ' var that = this;', - '', - ' function log(event) {', - ' function repeat(string, n) {', - ' var result = "", i;', - '', - ' for (i = 0; i < n; i++) {', - ' result += string;', - ' }', - '', - ' return result;', - ' }', - '', - ' function pad(string, length) {', - ' return string + repeat(" ", length - string.length);', - ' }', - '', - ' if (typeof console === "object") {', // IE 8-10 - ' console.log(', - ' event.location.start.line + ":" + event.location.start.column + "-"', - ' + event.location.end.line + ":" + event.location.end.column + " "', - ' + pad(event.type, 10) + " "', - ' + repeat(" ", that.indentLevel) + event.rule', - ' );', - ' }', - ' }', - '', - ' switch (event.type) {', - ' case "rule.enter":', - ' log(event);', - ' this.indentLevel++;', - ' break;', - '', - ' case "rule.match":', - ' this.indentLevel--;', - ' log(event);', - ' break;', - '', - ' case "rule.fail":', - ' this.indentLevel--;', - ' log(event);', - ' break;', - '', - ' default:', - ' throw new Error("Invalid event type: " + event.type + ".");', - ' }', - '};', - '' - ].join('\n')); + "function peg$DefaultTracer() {", + " this.indentLevel = 0;", + "}", + "", + "peg$DefaultTracer.prototype.trace = function(event) {", + " var that = this;", + "", + " function log(event) {", + " function repeat(string, n) {", + " var result = \"\", i;", + "", + " for (i = 0; i < n; i++) {", + " result += string;", + " }", + "", + " return result;", + " }", + "", + " function pad(string, length) {", + " return string + repeat(\" \", length - string.length);", + " }", + "", + " if (typeof console === \"object\") {", // IE 8-10 + " console.log(", + " event.location.start.line + \":\" + event.location.start.column + \"-\"", + " + event.location.end.line + \":\" + event.location.end.column + \" \"", + " + pad(event.type, 10) + \" \"", + " + repeat(\" \", that.indentLevel) + event.rule", + " );", + " }", + " }", + "", + " switch (event.type) {", + " case \"rule.enter\":", + " log(event);", + " this.indentLevel++;", + " break;", + "", + " case \"rule.match\":", + " this.indentLevel--;", + " log(event);", + " break;", + "", + " case \"rule.fail\":", + " this.indentLevel--;", + " log(event);", + " break;", + "", + " default:", + " throw new Error(\"Invalid event type: \" + event.type + \".\");", + " }", + "};", + "" + ].join("\n")); } parts.push([ - 'function peg$parse(input, options) {', - ' options = options !== undefined ? options : {};', - '', - ' var peg$FAILED = {};', - '' - ].join('\n')); + "function peg$parse(input, options) {", + " options = options !== undefined ? options : {};", + "", + " var peg$FAILED = {};", + "" + ].join("\n")); if (options.optimize === "size") { - let startRuleIndices = '{ ' + let startRuleIndices = "{ " + options.allowedStartRules.map( - r => r + ': ' + asts.indexOfRule(ast, r) - ).join(', ') - + ' }'; + r => r + ": " + asts.indexOfRule(ast, r) + ).join(", ") + + " }"; let startRuleIndex = asts.indexOfRule(ast, options.allowedStartRules[0]); parts.push([ - ' var peg$startRuleIndices = ' + startRuleIndices + ';', - ' var peg$startRuleIndex = ' + startRuleIndex + ';' - ].join('\n')); + " var peg$startRuleIndices = " + startRuleIndices + ";", + " var peg$startRuleIndex = " + startRuleIndex + ";" + ].join("\n")); } else { - let startRuleFunctions = '{ ' + let startRuleFunctions = "{ " + options.allowedStartRules.map( - r => r + ': peg$parse' + r - ).join(', ') - + ' }'; - let startRuleFunction = 'peg$parse' + options.allowedStartRules[0]; + r => r + ": peg$parse" + r + ).join(", ") + + " }"; + let startRuleFunction = "peg$parse" + options.allowedStartRules[0]; parts.push([ - ' var peg$startRuleFunctions = ' + startRuleFunctions + ';', - ' var peg$startRuleFunction = ' + startRuleFunction + ';' - ].join('\n')); + " var peg$startRuleFunctions = " + startRuleFunctions + ";", + " var peg$startRuleFunction = " + startRuleFunction + ";" + ].join("\n")); } - parts.push(''); + parts.push(""); parts.push(indent2(generateTables())); parts.push([ - '', - ' var peg$currPos = 0;', - ' var peg$savedPos = 0;', - ' var peg$posDetailsCache = [{ line: 1, column: 1 }];', - ' var peg$maxFailPos = 0;', - ' var peg$maxFailExpected = [];', - ' var peg$silentFails = 0;', // 0 = report failures, > 0 = silence failures - '' - ].join('\n')); + "", + " var peg$currPos = 0;", + " var peg$savedPos = 0;", + " var peg$posDetailsCache = [{ line: 1, column: 1 }];", + " var peg$maxFailPos = 0;", + " var peg$maxFailExpected = [];", + " var peg$silentFails = 0;", // 0 = report failures, > 0 = silence failures + "" + ].join("\n")); if (options.cache) { parts.push([ - ' var peg$resultsCache = {};', - '' - ].join('\n')); + " var peg$resultsCache = {};", + "" + ].join("\n")); } if (options.trace) { if (options.optimize === "size") { - let ruleNames = '[' + let ruleNames = "[" + ast.rules.map( - r => '"' + js.stringEscape(r.name) + '"' - ).join(', ') - + ']'; + r => "\"" + js.stringEscape(r.name) + "\"" + ).join(", ") + + "]"; parts.push([ - ' var peg$ruleNames = ' + ruleNames + ';', - '' - ].join('\n')); + " var peg$ruleNames = " + ruleNames + ";", + "" + ].join("\n")); } parts.push([ - ' var peg$tracer = "tracer" in options ? options.tracer : new peg$DefaultTracer();', - '' - ].join('\n')); + " var peg$tracer = \"tracer\" in options ? options.tracer : new peg$DefaultTracer();", + "" + ].join("\n")); } parts.push([ - ' var peg$result;', - '' - ].join('\n')); + " var peg$result;", + "" + ].join("\n")); if (options.optimize === "size") { parts.push([ - ' if ("startRule" in options) {', - ' if (!(options.startRule in peg$startRuleIndices)) {', - ' throw new Error("Can\'t start parsing from rule \\"" + options.startRule + "\\".");', - ' }', - '', - ' peg$startRuleIndex = peg$startRuleIndices[options.startRule];', - ' }' - ].join('\n')); + " if (\"startRule\" in options) {", + " if (!(options.startRule in peg$startRuleIndices)) {", + " throw new Error(\"Can't start parsing from rule \\\"\" + options.startRule + \"\\\".\");", + " }", + "", + " peg$startRuleIndex = peg$startRuleIndices[options.startRule];", + " }" + ].join("\n")); } else { parts.push([ - ' if ("startRule" in options) {', - ' if (!(options.startRule in peg$startRuleFunctions)) {', - ' throw new Error("Can\'t start parsing from rule \\"" + options.startRule + "\\".");', - ' }', - '', - ' peg$startRuleFunction = peg$startRuleFunctions[options.startRule];', - ' }' - ].join('\n')); + " if (\"startRule\" in options) {", + " if (!(options.startRule in peg$startRuleFunctions)) {", + " throw new Error(\"Can't start parsing from rule \\\"\" + options.startRule + \"\\\".\");", + " }", + "", + " peg$startRuleFunction = peg$startRuleFunctions[options.startRule];", + " }" + ].join("\n")); } parts.push([ - '', - ' function text() {', - ' return input.substring(peg$savedPos, peg$currPos);', - ' }', - '', - ' function location() {', - ' return peg$computeLocation(peg$savedPos, peg$currPos);', - ' }', - '', - ' function expected(description, location) {', - ' location = location !== undefined ? location : peg$computeLocation(peg$savedPos, peg$currPos)', - '', - ' throw peg$buildStructuredError(', - ' [peg$otherExpectation(description)],', - ' input.substring(peg$savedPos, peg$currPos),', - ' location', - ' );', - ' }', - '', - ' function error(message, location) {', - ' location = location !== undefined ? location : peg$computeLocation(peg$savedPos, peg$currPos)', - '', - ' throw peg$buildSimpleError(message, location);', - ' }', - '', - ' function peg$literalExpectation(text, ignoreCase) {', - ' return { type: "literal", text: text, ignoreCase: ignoreCase };', - ' }', - '', - ' function peg$classExpectation(parts, inverted, ignoreCase) {', - ' return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };', - ' }', - '', - ' function peg$anyExpectation() {', - ' return { type: "any" };', - ' }', - '', - ' function peg$endExpectation() {', - ' return { type: "end" };', - ' }', - '', - ' function peg$otherExpectation(description) {', - ' return { type: "other", description: description };', - ' }', - '', - ' function peg$computePosDetails(pos) {', - ' var details = peg$posDetailsCache[pos];', - ' var p;', - '', - ' if (details) {', - ' return details;', - ' } else {', - ' p = pos - 1;', - ' while (!peg$posDetailsCache[p]) {', - ' p--;', - ' }', - '', - ' details = peg$posDetailsCache[p];', - ' details = {', - ' line: details.line,', - ' column: details.column', - ' };', - '', - ' while (p < pos) {', - ' if (input.charCodeAt(p) === 10) {', - ' details.line++;', - ' details.column = 1;', - ' } else {', - ' details.column++;', - ' }', - '', - ' p++;', - ' }', - '', - ' peg$posDetailsCache[pos] = details;', - ' return details;', - ' }', - ' }', - '', - ' function peg$computeLocation(startPos, endPos) {', - ' var startPosDetails = peg$computePosDetails(startPos);', - ' var endPosDetails = peg$computePosDetails(endPos);', - '', - ' return {', - ' start: {', - ' offset: startPos,', - ' line: startPosDetails.line,', - ' column: startPosDetails.column', - ' },', - ' end: {', - ' offset: endPos,', - ' line: endPosDetails.line,', - ' column: endPosDetails.column', - ' }', - ' };', - ' }', - '', - ' function peg$fail(expected) {', - ' if (peg$currPos < peg$maxFailPos) { return; }', - '', - ' if (peg$currPos > peg$maxFailPos) {', - ' peg$maxFailPos = peg$currPos;', - ' peg$maxFailExpected = [];', - ' }', - '', - ' peg$maxFailExpected.push(expected);', - ' }', - '', - ' function peg$buildSimpleError(message, location) {', - ' return new peg$SyntaxError(message, null, null, location);', - ' }', - '', - ' function peg$buildStructuredError(expected, found, location) {', - ' return new peg$SyntaxError(', - ' peg$SyntaxError.buildMessage(expected, found),', - ' expected,', - ' found,', - ' location', - ' );', - ' }', - '' - ].join('\n')); + "", + " function text() {", + " return input.substring(peg$savedPos, peg$currPos);", + " }", + "", + " function location() {", + " return peg$computeLocation(peg$savedPos, peg$currPos);", + " }", + "", + " function expected(description, location) {", + " location = location !== undefined ? location : peg$computeLocation(peg$savedPos, peg$currPos)", + "", + " throw peg$buildStructuredError(", + " [peg$otherExpectation(description)],", + " input.substring(peg$savedPos, peg$currPos),", + " location", + " );", + " }", + "", + " function error(message, location) {", + " location = location !== undefined ? location : peg$computeLocation(peg$savedPos, peg$currPos)", + "", + " throw peg$buildSimpleError(message, location);", + " }", + "", + " function peg$literalExpectation(text, ignoreCase) {", + " return { type: \"literal\", text: text, ignoreCase: ignoreCase };", + " }", + "", + " function peg$classExpectation(parts, inverted, ignoreCase) {", + " return { type: \"class\", parts: parts, inverted: inverted, ignoreCase: ignoreCase };", + " }", + "", + " function peg$anyExpectation() {", + " return { type: \"any\" };", + " }", + "", + " function peg$endExpectation() {", + " return { type: \"end\" };", + " }", + "", + " function peg$otherExpectation(description) {", + " return { type: \"other\", description: description };", + " }", + "", + " function peg$computePosDetails(pos) {", + " var details = peg$posDetailsCache[pos];", + " var p;", + "", + " if (details) {", + " return details;", + " } else {", + " p = pos - 1;", + " while (!peg$posDetailsCache[p]) {", + " p--;", + " }", + "", + " details = peg$posDetailsCache[p];", + " details = {", + " line: details.line,", + " column: details.column", + " };", + "", + " while (p < pos) {", + " if (input.charCodeAt(p) === 10) {", + " details.line++;", + " details.column = 1;", + " } else {", + " details.column++;", + " }", + "", + " p++;", + " }", + "", + " peg$posDetailsCache[pos] = details;", + " return details;", + " }", + " }", + "", + " function peg$computeLocation(startPos, endPos) {", + " var startPosDetails = peg$computePosDetails(startPos);", + " var endPosDetails = peg$computePosDetails(endPos);", + "", + " return {", + " start: {", + " offset: startPos,", + " line: startPosDetails.line,", + " column: startPosDetails.column", + " },", + " end: {", + " offset: endPos,", + " line: endPosDetails.line,", + " column: endPosDetails.column", + " }", + " };", + " }", + "", + " function peg$fail(expected) {", + " if (peg$currPos < peg$maxFailPos) { return; }", + "", + " if (peg$currPos > peg$maxFailPos) {", + " peg$maxFailPos = peg$currPos;", + " peg$maxFailExpected = [];", + " }", + "", + " peg$maxFailExpected.push(expected);", + " }", + "", + " function peg$buildSimpleError(message, location) {", + " return new peg$SyntaxError(message, null, null, location);", + " }", + "", + " function peg$buildStructuredError(expected, found, location) {", + " return new peg$SyntaxError(", + " peg$SyntaxError.buildMessage(expected, found),", + " expected,", + " found,", + " location", + " );", + " }", + "" + ].join("\n")); if (options.optimize === "size") { parts.push(indent2(generateInterpreter())); - parts.push(''); + parts.push(""); } else { ast.rules.forEach(rule => { parts.push(indent2(generateRuleFunction(rule))); - parts.push(''); + parts.push(""); }); } if (ast.initializer) { parts.push(indent2(ast.initializer.code)); - parts.push(''); + parts.push(""); } if (options.optimize === "size") { - parts.push(' peg$result = peg$parseRule(peg$startRuleIndex);'); + parts.push(" peg$result = peg$parseRule(peg$startRuleIndex);"); } else { - parts.push(' peg$result = peg$startRuleFunction();'); + parts.push(" peg$result = peg$startRuleFunction();"); } parts.push([ - '', - ' if (peg$result !== peg$FAILED && peg$currPos === input.length) {', - ' return peg$result;', - ' } else {', - ' if (peg$result !== peg$FAILED && peg$currPos < input.length) {', - ' peg$fail(peg$endExpectation());', - ' }', - '', - ' throw peg$buildStructuredError(', - ' peg$maxFailExpected,', - ' peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,', - ' peg$maxFailPos < input.length', - ' ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)', - ' : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)', - ' );', - ' }', - '}' - ].join('\n')); - - return parts.join('\n'); + "", + " if (peg$result !== peg$FAILED && peg$currPos === input.length) {", + " return peg$result;", + " } else {", + " if (peg$result !== peg$FAILED && peg$currPos < input.length) {", + " peg$fail(peg$endExpectation());", + " }", + "", + " throw peg$buildStructuredError(", + " peg$maxFailExpected,", + " peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,", + " peg$maxFailPos < input.length", + " ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)", + " : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)", + " );", + " }", + "}" + ].join("\n")); + + return parts.join("\n"); } function generateWrapper(toplevelCode) { function generateGeneratedByComment() { return [ - '// Generated by PEG.js 0.10.0.', - '//', - '// http://pegjs.org/' - ].join('\n'); + "// Generated by PEG.js 0.10.0.", + "//", + "// http://pegjs.org/" + ].join("\n"); } function generateParserObject() { return options.trace ? [ - '{', - ' SyntaxError: peg$SyntaxError,', - ' DefaultTracer: peg$DefaultTracer,', - ' parse: peg$parse', - '}' - ].join('\n') + "{", + " SyntaxError: peg$SyntaxError,", + " DefaultTracer: peg$DefaultTracer,", + " parse: peg$parse", + "}" + ].join("\n") : [ - '{', - ' SyntaxError: peg$SyntaxError,', - ' parse: peg$parse', - '}' - ].join('\n'); + "{", + " SyntaxError: peg$SyntaxError,", + " parse: peg$parse", + "}" + ].join("\n"); } let generators = { bare: function() { return [ generateGeneratedByComment(), - '(function() {', - ' "use strict";', - '', + "(function() {", + " \"use strict\";", + "", indent2(toplevelCode), - '', - indent2('return ' + generateParserObject() + ';'), - '})()' - ].join('\n'); + "", + indent2("return " + generateParserObject() + ";"), + "})()" + ].join("\n"); }, commonjs: function() { @@ -1242,112 +1242,112 @@ function generateJS(ast, options) { parts.push([ generateGeneratedByComment(), - '', - '"use strict";', - '' - ].join('\n')); + "", + "\"use strict\";", + "" + ].join("\n")); if (dependencyVars.length > 0) { dependencyVars.forEach(variable => { - parts.push('var ' + variable - + ' = require("' + parts.push("var " + variable + + " = require(\"" + js.stringEscape(options.dependencies[variable]) - + '");' + + "\");" ); }); - parts.push(''); + parts.push(""); } parts.push([ toplevelCode, - '', - 'module.exports = ' + generateParserObject() + ';', - '' - ].join('\n')); + "", + "module.exports = " + generateParserObject() + ";", + "" + ].join("\n")); - return parts.join('\n'); + return parts.join("\n"); }, amd: function() { let dependencyVars = Object.keys(options.dependencies); let dependencyIds = dependencyIds.map(v => options.dependencies[v]); - let dependencies = '[' + let dependencies = "[" + dependencyIds.map( - id => '"' + js.stringEscape(id) + '"' - ).join(', ') - + ']'; - let params = dependencyVars.join(', '); + id => "\"" + js.stringEscape(id) + "\"" + ).join(", ") + + "]"; + let params = dependencyVars.join(", "); return [ generateGeneratedByComment(), - 'define(' + dependencies + ', function(' + params + ') {', - ' "use strict";', - '', + "define(" + dependencies + ", function(" + params + ") {", + " \"use strict\";", + "", indent2(toplevelCode), - '', - indent2('return ' + generateParserObject() + ';'), - '});', - '' - ].join('\n'); + "", + indent2("return " + generateParserObject() + ";"), + "});", + "" + ].join("\n"); }, globals: function() { return [ generateGeneratedByComment(), - '(function(root) {', - ' "use strict";', - '', + "(function(root) {", + " \"use strict\";", + "", indent2(toplevelCode), - '', - indent2('root.' + options.exportVar + ' = ' + generateParserObject() + ';'), - '})(this);', - '' - ].join('\n'); + "", + indent2("root." + options.exportVar + " = " + generateParserObject() + ";"), + "})(this);", + "" + ].join("\n"); }, umd: function() { let parts = []; let dependencyVars = Object.keys(options.dependencies); let dependencyIds = dependencyIds.map(v => options.dependencies[v]); - let dependencies = '[' + let dependencies = "[" + dependencyIds.map( - id => '"' + js.stringEscape(id) + '"' - ).join(', ') - + ']'; + id => "\"" + js.stringEscape(id) + "\"" + ).join(", ") + + "]"; let requires = dependencyIds.map( - id => 'require("' + js.stringEscape(id) + '")' - ).join(', '); - let params = dependencyVars.join(', '); + id => "require(\"" + js.stringEscape(id) + "\")" + ).join(", "); + let params = dependencyVars.join(", "); parts.push([ generateGeneratedByComment(), - '(function(root, factory) {', - ' if (typeof define === "function" && define.amd) {', - ' define(' + dependencies + ', factory);', - ' } else if (typeof module === "object" && module.exports) {', - ' module.exports = factory(' + requires + ');' - ].join('\n')); + "(function(root, factory) {", + " if (typeof define === \"function\" && define.amd) {", + " define(" + dependencies + ", factory);", + " } else if (typeof module === \"object\" && module.exports) {", + " module.exports = factory(" + requires + ");" + ].join("\n")); if (options.exportVar !== null) { parts.push([ - ' } else {', - ' root.' + options.exportVar + ' = factory();' - ].join('\n')); + " } else {", + " root." + options.exportVar + " = factory();" + ].join("\n")); } parts.push([ - ' }', - '})(this, function(' + params + ') {', - ' "use strict";', - '', + " }", + "})(this, function(" + params + ") {", + " \"use strict\";", + "", indent2(toplevelCode), - '', - indent2('return ' + generateParserObject() + ';'), - '});', - '' - ].join('\n')); + "", + indent2("return " + generateParserObject() + ";"), + "});", + "" + ].join("\n")); - return parts.join('\n'); + return parts.join("\n"); } }; diff --git a/lib/parser.js b/lib/parser.js index 1990dbe..ca017ec 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -62,28 +62,28 @@ peg$SyntaxError.buildMessage = function(expected, found) { function literalEscape(s) { return s - .replace(/\\/g, '\\\\') - .replace(/"/g, '\\"') - .replace(/\0/g, '\\0') - .replace(/\t/g, '\\t') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) - .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); }); + .replace(/\\/g, "\\\\") + .replace(/"/g, "\\\"") + .replace(/\0/g, "\\0") + .replace(/\t/g, "\\t") + .replace(/\n/g, "\\n") + .replace(/\r/g, "\\r") + .replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); }) + .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); }); } function classEscape(s) { return s - .replace(/\\/g, '\\\\') - .replace(/\]/g, '\\]') - .replace(/\^/g, '\\^') - .replace(/-/g, '\\-') - .replace(/\0/g, '\\0') - .replace(/\t/g, '\\t') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) - .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); }); + .replace(/\\/g, "\\\\") + .replace(/\]/g, "\\]") + .replace(/\^/g, "\\^") + .replace(/-/g, "\\-") + .replace(/\0/g, "\\0") + .replace(/\t/g, "\\t") + .replace(/\n/g, "\\n") + .replace(/\r/g, "\\r") + .replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); }) + .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); }); } function describeExpectation(expectation) { @@ -238,7 +238,7 @@ function peg$parse(input, options) { // don't need to put it around nodes that can't contain any labels or // nodes that already isolate label scope themselves. This leaves us with // "labeled" and "sequence". - return expression.type === 'labeled' || expression.type === 'sequence' + return expression.type === "labeled" || expression.type === "sequence" ? { type: "group", expression: expression } : expression; }; diff --git a/spec/api/generated-parser-api.spec.js b/spec/api/generated-parser-api.spec.js index c261b55..1577670 100644 --- a/spec/api/generated-parser-api.spec.js +++ b/spec/api/generated-parser-api.spec.js @@ -8,22 +8,22 @@ let peg = require("../../lib/peg"); describe("generated parser API", function() { describe("parse", function() { it("parses input", function() { - let parser = peg.generate('start = "a"'); + let parser = peg.generate("start = 'a'"); expect(parser.parse("a")).toBe("a"); }); it("throws an exception on syntax error", function() { - let parser = peg.generate('start = "a"'); + let parser = peg.generate("start = 'a'"); expect(() => { parser.parse("b"); }).toThrow(); }); describe("start rule", function() { let parser = peg.generate([ - 'a = "x" { return "a"; }', - 'b = "x" { return "b"; }', - 'c = "x" { return "c"; }' + "a = 'x' { return 'a'; }", + "b = 'x' { return 'b'; }", + "c = 'x' { return 'c'; }" ].join("\n"), { allowedStartRules: ["b", "c"] }); describe("when |startRule| is not set", function() { @@ -48,9 +48,9 @@ describe("generated parser API", function() { describe("tracing", function() { let parser = peg.generate([ - 'start = a / b', - 'a = "a"', - 'b = "b"' + "start = a / b", + "a = 'a'", + "b = 'b'" ].join("\n"), { trace: true }); describe("default tracer", function() { @@ -135,7 +135,7 @@ describe("generated parser API", function() { }); it("accepts custom options", function() { - let parser = peg.generate('start = "a"'); + let parser = peg.generate("start = 'a'"); parser.parse("a", { foo: 42 }); }); diff --git a/spec/api/pegjs-api.spec.js b/spec/api/pegjs-api.spec.js index 6c25c5c..ea2dde1 100644 --- a/spec/api/pegjs-api.spec.js +++ b/spec/api/pegjs-api.spec.js @@ -5,25 +5,25 @@ let peg = require("../../lib/peg"); describe("PEG.js API", function() { describe("generate", function() { it("generates a parser", function() { - let parser = peg.generate('start = "a"'); + let parser = peg.generate("start = 'a'"); expect(typeof parser).toBe("object"); expect(parser.parse("a")).toBe("a"); }); it("throws an exception on syntax error", function() { - expect(() => { peg.generate('start = @'); }).toThrow(); + expect(() => { peg.generate("start = @"); }).toThrow(); }); it("throws an exception on semantic error", function() { - expect(() => { peg.generate('start = undefined'); }).toThrow(); + expect(() => { peg.generate("start = undefined"); }).toThrow(); }); describe("allowed start rules", function() { let grammar = [ - 'a = "x"', - 'b = "x"', - 'c = "x"' + "a = 'x'", + "b = 'x'", + "c = 'x'" ].join("\n"); // The |allowedStartRules| option is implemented separately for each @@ -82,9 +82,9 @@ describe("PEG.js API", function() { describe("intermediate results caching", function() { let grammar = [ - '{ var n = 0; }', - 'start = (a "b") / (a "c") { return n; }', - 'a = "a" { n++; }' + "{ var n = 0; }", + "start = (a 'b') / (a 'c') { return n; }", + "a = 'a' { n++; }" ].join("\n"); describe("when |cache| is not set", function() { @@ -113,7 +113,7 @@ describe("PEG.js API", function() { }); describe("tracing", function() { - let grammar = 'start = "a"'; + let grammar = "start = 'a'"; describe("when |trace| is not set", function() { it("generated parser doesn't trace", function() { @@ -153,7 +153,7 @@ describe("PEG.js API", function() { // write the specs without turning this into a performance test. describe("output", function() { - let grammar = 'start = "a"'; + let grammar = "start = 'a'"; describe("when |output| is not set", function() { it("returns generated parser object", function() { @@ -190,7 +190,7 @@ describe("PEG.js API", function() { // The |plugins| option is tested in plugin API specs. it("accepts custom options", function() { - peg.generate('start = "a"', { foo: 42 }); + peg.generate("start = 'a'", { foo: 42 }); }); }); }); diff --git a/spec/api/plugin-api.spec.js b/spec/api/plugin-api.spec.js index 7308edd..09dbc6e 100644 --- a/spec/api/plugin-api.spec.js +++ b/spec/api/plugin-api.spec.js @@ -35,7 +35,7 @@ describe("plugin API", function() { }); describe("use", function() { - let grammar = 'start = "a"'; + let grammar = "start = 'a'"; it("is called for each plugin", function() { let pluginsUsed = [false, false, false]; @@ -56,7 +56,7 @@ describe("plugin API", function() { expect(config).toBeObject(); expect(config.parser).toBeObject(); - expect(config.parser.parse('start = "a"')).toBeObject(); + expect(config.parser.parse("start = 'a'")).toBeObject(); expect(config.passes).toBeObject(); @@ -95,24 +95,24 @@ describe("plugin API", function() { let plugin = { use: function(config) { let parser = peg.generate([ - 'start = .* {', - ' return {', - ' type: "grammar",', - ' rules: [', - ' {', - ' type: "rule",', - ' name: "start",', - ' expression: { type: "literal", value: text(), ignoreCase: false }', - ' }', - ' ]', - ' };', - '}' + "start = .* {", + " return {", + " type: 'grammar',", + " rules: [", + " {", + " type: 'rule',", + " name: 'start',", + " expression: { type: 'literal', value: text(), ignoreCase: false }", + " }", + " ]", + " };", + "}" ].join("\n")); config.parser = parser; } }; - let parser = peg.generate('a', { plugins: [plugin] }); + let parser = peg.generate("a", { plugins: [plugin] }); expect(parser.parse("a")).toBe("a"); }); @@ -121,7 +121,7 @@ describe("plugin API", function() { let plugin = { use: function(config) { let pass = ast => { - ast.code = '({ parse: function() { return 42; } })'; + ast.code = "({ parse: function() { return 42; } })"; }; config.passes.generate = [pass]; @@ -134,9 +134,9 @@ describe("plugin API", function() { it("can change options", function() { let grammar = [ - 'a = "x"', - 'b = "x"', - 'c = "x"' + "a = 'x'", + "b = 'x'", + "c = 'x'" ].join("\n"); let plugin = { use: function(config, options) { diff --git a/spec/behavior/generated-parser-behavior.spec.js b/spec/behavior/generated-parser-behavior.spec.js index b7b3c3b..266d862 100644 --- a/spec/behavior/generated-parser-behavior.spec.js +++ b/spec/behavior/generated-parser-behavior.spec.js @@ -131,8 +131,8 @@ describe("generated parser behavior", function() { describe("initializer", function() { it("executes the code before parsing starts", function() { let parser = peg.generate([ - '{ var result = 42; }', - 'start = "a" { return result; }' + "{ var result = 42; }", + "start = 'a' { return result; }" ].join("\n"), options); expect(parser).toParse("a", 42); @@ -141,8 +141,8 @@ describe("generated parser behavior", function() { describe("available variables and functions", function() { it("|options| contains options", function() { let parser = peg.generate([ - '{ var result = options; }', - 'start = "a" { return result; }' + "{ var result = options; }", + "start = 'a' { return result; }" ].join("\n"), options); expect(parser).toParse("a", { a: 42 }, { a: 42 }); @@ -154,9 +154,9 @@ describe("generated parser behavior", function() { if (options.cache) { it("caches rule match results", function() { let parser = peg.generate([ - '{ var n = 0; }', - 'start = (a "b") / (a "c") { return n; }', - 'a = "a" { n++; }' + "{ var n = 0; }", + "start = (a 'b') / (a 'c') { return n; }", + "a = 'a' { n++; }" ].join("\n"), options); expect(parser).toParse("ac", 1); @@ -164,9 +164,9 @@ describe("generated parser behavior", function() { } else { it("doesn't cache rule match results", function() { let parser = peg.generate([ - '{ var n = 0; }', - 'start = (a "b") / (a "c") { return n; }', - 'a = "a" { n++; }' + "{ var n = 0; }", + "start = (a 'b') / (a 'c') { return n; }", + "a = 'a' { n++; }" ].join("\n"), options); expect(parser).toParse("ac", 2); @@ -175,7 +175,7 @@ describe("generated parser behavior", function() { describe("when the expression matches", function() { it("returns its match result", function() { - let parser = peg.generate('start = "a"'); + let parser = peg.generate("start = 'a'"); expect(parser).toParse("a", "a"); }); @@ -184,7 +184,7 @@ describe("generated parser behavior", function() { describe("when the expression doesn't match", function() { describe("without display name", function() { it("reports match failure and doesn't record any expectation", function() { - let parser = peg.generate('start = "a"'); + let parser = peg.generate("start = 'a'"); expect(parser).toFailToParse("b", { expected: [{ type: "literal", text: "a", ignoreCase: false }] @@ -194,7 +194,7 @@ describe("generated parser behavior", function() { describe("with display name", function() { it("reports match failure and records an expectation of type \"other\"", function() { - let parser = peg.generate('start "start" = "a"'); + let parser = peg.generate("start 'start' = 'a'"); expect(parser).toFailToParse("b", { expected: [{ type: "other", description: "start" }] @@ -202,7 +202,7 @@ describe("generated parser behavior", function() { }); it("discards any expectations recorded when matching the expression", function() { - let parser = peg.generate('start "start" = "a"'); + let parser = peg.generate("start 'start' = 'a'"); expect(parser).toFailToParse("b", { expected: [{ type: "other", description: "start" }] @@ -215,34 +215,34 @@ describe("generated parser behavior", function() { describe("literal", function() { describe("matching", function() { it("matches empty literals", function() { - let parser = peg.generate('start = ""', options); + let parser = peg.generate("start = ''", options); expect(parser).toParse(""); }); it("matches one-character literals", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toParse("a"); expect(parser).toFailToParse("b"); }); it("matches multi-character literals", function() { - let parser = peg.generate('start = "abcd"', options); + let parser = peg.generate("start = 'abcd'", options); expect(parser).toParse("abcd"); expect(parser).toFailToParse("efgh"); }); it("is case sensitive without the \"i\" flag", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toParse("a"); expect(parser).toFailToParse("A"); }); it("is case insensitive with the \"i\" flag", function() { - let parser = peg.generate('start = "a"i', options); + let parser = peg.generate("start = 'a'i", options); expect(parser).toParse("a"); expect(parser).toParse("A"); @@ -251,13 +251,13 @@ describe("generated parser behavior", function() { describe("when it matches", function() { it("returns the matched text", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toParse("a", "a"); }); it("consumes the matched text", function() { - let parser = peg.generate('start = "a" .', options); + let parser = peg.generate("start = 'a' .", options); expect(parser).toParse("ab"); }); @@ -265,7 +265,7 @@ describe("generated parser behavior", function() { describe("when it doesn't match", function() { it("reports match failure and records an expectation of type \"literal\"", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toFailToParse("b", { expected: [{ type: "literal", text: "a", ignoreCase: false }] @@ -277,13 +277,13 @@ describe("generated parser behavior", function() { describe("character class", function() { describe("matching", function() { it("matches empty classes", function() { - let parser = peg.generate('start = []', options); + let parser = peg.generate("start = []", options); expect(parser).toFailToParse("a"); }); it("matches classes with a character list", function() { - let parser = peg.generate('start = [abc]', options); + let parser = peg.generate("start = [abc]", options); expect(parser).toParse("a"); expect(parser).toParse("b"); @@ -292,7 +292,7 @@ describe("generated parser behavior", function() { }); it("matches classes with a character range", function() { - let parser = peg.generate('start = [a-c]', options); + let parser = peg.generate("start = [a-c]", options); expect(parser).toParse("a"); expect(parser).toParse("b"); @@ -301,21 +301,21 @@ describe("generated parser behavior", function() { }); it("matches inverted classes", function() { - let parser = peg.generate('start = [^a]', options); + let parser = peg.generate("start = [^a]", options); expect(parser).toFailToParse("a"); expect(parser).toParse("b"); }); it("is case sensitive without the \"i\" flag", function() { - let parser = peg.generate('start = [a]', options); + let parser = peg.generate("start = [a]", options); expect(parser).toParse("a"); expect(parser).toFailToParse("A"); }); it("is case insensitive with the \"i\" flag", function() { - let parser = peg.generate('start = [a]i', options); + let parser = peg.generate("start = [a]i", options); expect(parser).toParse("a"); expect(parser).toParse("A"); @@ -324,13 +324,13 @@ describe("generated parser behavior", function() { describe("when it matches", function() { it("returns the matched character", function() { - let parser = peg.generate('start = [a]', options); + let parser = peg.generate("start = [a]", options); expect(parser).toParse("a", "a"); }); it("consumes the matched character", function() { - let parser = peg.generate('start = [a] .', options); + let parser = peg.generate("start = [a] .", options); expect(parser).toParse("ab"); }); @@ -338,7 +338,7 @@ describe("generated parser behavior", function() { describe("when it doesn't match", function() { it("reports match failure and records an expectation of type \"class\"", function() { - let parser = peg.generate('start = [a]', options); + let parser = peg.generate("start = [a]", options); expect(parser).toFailToParse("b", { expected: [{ type: "class", parts: ["a"], inverted: false, ignoreCase: false }] @@ -350,7 +350,7 @@ describe("generated parser behavior", function() { describe("dot", function() { describe("matching", function() { it("matches any character", function() { - let parser = peg.generate('start = .', options); + let parser = peg.generate("start = .", options); expect(parser).toParse("a"); expect(parser).toParse("b"); @@ -360,13 +360,13 @@ describe("generated parser behavior", function() { describe("when it matches", function() { it("returns the matched character", function() { - let parser = peg.generate('start = .', options); + let parser = peg.generate("start = .", options); expect(parser).toParse("a", "a"); }); it("consumes the matched character", function() { - let parser = peg.generate('start = . .', options); + let parser = peg.generate("start = . .", options); expect(parser).toParse("ab"); }); @@ -374,7 +374,7 @@ describe("generated parser behavior", function() { describe("when it doesn't match", function() { it("reports match failure and records an expectation of type \"any\"", function() { - let parser = peg.generate('start = .', options); + let parser = peg.generate("start = .", options); expect(parser).toFailToParse("", { expected: [{ type: "any" }] @@ -387,8 +387,8 @@ describe("generated parser behavior", function() { describe("when referenced rule's expression matches", function() { it("returns its result", function() { let parser = peg.generate([ - 'start = a', - 'a = "a"' + "start = a", + "a = 'a'" ].join("\n"), options); expect(parser).toParse("a", "a"); @@ -398,8 +398,8 @@ describe("generated parser behavior", function() { describe("when referenced rule's expression doesn't match", function() { it("reports match failure", function() { let parser = peg.generate([ - 'start = a', - 'a = "a"' + "start = a", + "a = 'a'" ].join("\n"), options); expect(parser).toFailToParse("b"); @@ -413,7 +413,7 @@ describe("generated parser behavior", function() { // The |""| is needed so that the parser doesn't return just // |undefined| which we can't compare against in |toParse| due to the // way optional parameters work. - let parser = peg.generate('start = &{ return true; } ""', options); + let parser = peg.generate("start = &{ return true; } ''", options); expect(parser).toParse("", [undefined, ""]); }); @@ -421,7 +421,7 @@ describe("generated parser behavior", function() { describe("when the code returns a falsey value", function() { it("reports match failure", function() { - let parser = peg.generate('start = &{ return false; }', options); + let parser = peg.generate("start = &{ return false; }", options); expect(parser).toFailToParse(""); }); @@ -431,7 +431,7 @@ describe("generated parser behavior", function() { describe("in containing sequence", function() { it("can access variables defined by preceding labeled elements", function() { let parser = peg.generate( - 'start = a:"a" &{ return a === "a"; }', + "start = a:'a' &{ return a === 'a'; }", options ); @@ -440,7 +440,7 @@ describe("generated parser behavior", function() { it("cannot access variable defined by labeled predicate element", function() { let parser = peg.generate( - 'start = "a" b:&{ return b === undefined; } "c"', + "start = 'a' b:&{ return b === undefined; } 'c'", options ); @@ -449,7 +449,7 @@ describe("generated parser behavior", function() { it("cannot access variables defined by following labeled elements", function() { let parser = peg.generate( - 'start = &{ return a === "a"; } a:"a"', + "start = &{ return a === 'a'; } a:'a'", options ); @@ -459,47 +459,47 @@ describe("generated parser behavior", function() { it("cannot access variables defined by subexpressions", function() { let testcases = [ { - grammar: 'start = (a:"a") &{ return a === "a"; }', + grammar: "start = (a:'a') &{ return a === 'a'; }", input: "a" }, { - grammar: 'start = (a:"a")? &{ return a === "a"; }', + grammar: "start = (a:'a')? &{ return a === 'a'; }", input: "a" }, { - grammar: 'start = (a:"a")* &{ return a === "a"; }', + grammar: "start = (a:'a')* &{ return a === 'a'; }", input: "a" }, { - grammar: 'start = (a:"a")+ &{ return a === "a"; }', + grammar: "start = (a:'a')+ &{ return a === 'a'; }", input: "a" }, { - grammar: 'start = $(a:"a") &{ return a === "a"; }', + grammar: "start = $(a:'a') &{ return a === 'a'; }", input: "a" }, { - grammar: 'start = &(a:"a") "a" &{ return a === "a"; }', + grammar: "start = &(a:'a') 'a' &{ return a === 'a'; }", input: "a" }, { - grammar: 'start = !(a:"a") "b" &{ return a === "a"; }', + grammar: "start = !(a:'a') 'b' &{ return a === 'a'; }", input: "b" }, { - grammar: 'start = b:(a:"a") &{ return a === "a"; }', + grammar: "start = b:(a:'a') &{ return a === 'a'; }", input: "a" }, { - grammar: 'start = ("a" b:"b" "c") &{ return b === "b"; }', + grammar: "start = ('a' b:'b' 'c') &{ return b === 'b'; }", input: "abc" }, { - grammar: 'start = (a:"a" { return a; }) &{ return a === "a"; }', + grammar: "start = (a:'a' { return a; }) &{ return a === 'a'; }", input: "a" }, { - grammar: 'start = ("a" / b:"b" / "c") &{ return b === "b"; }', + grammar: "start = ('a' / b:'b' / 'c') &{ return b === 'b'; }", input: "b" } ]; @@ -515,7 +515,7 @@ describe("generated parser behavior", function() { describe("in outer sequence", function() { it("can access variables defined by preceding labeled elements", function() { let parser = peg.generate( - 'start = a:"a" ("b" &{ return a === "a"; })', + "start = a:'a' ('b' &{ return a === 'a'; })", options ); @@ -524,7 +524,7 @@ describe("generated parser behavior", function() { it("cannot access variable defined by labeled predicate element", function() { let parser = peg.generate( - 'start = "a" b:("b" &{ return b === undefined; }) "c"', + "start = 'a' b:('b' &{ return b === undefined; }) 'c'", options ); @@ -533,7 +533,7 @@ describe("generated parser behavior", function() { it("cannot access variables defined by following labeled elements", function() { let parser = peg.generate( - 'start = ("a" &{ return b === "b"; }) b:"b"', + "start = ('a' &{ return b === 'b'; }) b:'b'", options ); @@ -545,8 +545,8 @@ describe("generated parser behavior", function() { describe("initializer variables & functions", function() { it("can access variables defined in the initializer", function() { let parser = peg.generate([ - '{ var v = 42 }', - 'start = &{ return v === 42; }' + "{ var v = 42 }", + "start = &{ return v === 42; }" ].join("\n"), options); expect(parser).toParse(""); @@ -554,8 +554,8 @@ describe("generated parser behavior", function() { it("can access functions defined in the initializer", function() { let parser = peg.generate([ - '{ function f() { return 42; } }', - 'start = &{ return f() === 42; }' + "{ function f() { return 42; } }", + "start = &{ return f() === 42; }" ].join("\n"), options); expect(parser).toParse(""); @@ -565,8 +565,8 @@ describe("generated parser behavior", function() { describe("available variables & functions", function() { it("|options| contains options", function() { let parser = peg.generate([ - '{ var result; }', - 'start = &{ result = options; return true; } { return result; }' + "{ var result; }", + "start = &{ result = options; return true; } { return result; }" ].join("\n"), options); expect(parser).toParse("", { a: 42 }, { a: 42 }); @@ -574,13 +574,13 @@ describe("generated parser behavior", function() { it("|location| returns current location info", function() { let parser = peg.generate([ - '{ var result; }', - 'start = line (nl+ line)* { return result; }', - 'line = thing (" "+ thing)*', - 'thing = digit / mark', - 'digit = [0-9]', - 'mark = &{ result = location(); return true; } "x"', - 'nl = "\\r"? "\\n"' + "{ var result; }", + "start = line (nl+ line)* { return result; }", + "line = thing (' '+ thing)*", + "thing = digit / mark", + "digit = [0-9]", + "mark = &{ result = location(); return true; } 'x'", + "nl = '\\r'? '\\n'" ].join("\n"), options); expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", { @@ -607,7 +607,7 @@ describe("generated parser behavior", function() { // The |""| is needed so that the parser doesn't return just // |undefined| which we can't compare against in |toParse| due to the // way optional parameters work. - let parser = peg.generate('start = !{ return false; } ""', options); + let parser = peg.generate("start = !{ return false; } ''", options); expect(parser).toParse("", [undefined, ""]); }); @@ -615,7 +615,7 @@ describe("generated parser behavior", function() { describe("when the code returns a truthy value", function() { it("reports match failure", function() { - let parser = peg.generate('start = !{ return true; }', options); + let parser = peg.generate("start = !{ return true; }", options); expect(parser).toFailToParse(""); }); @@ -625,7 +625,7 @@ describe("generated parser behavior", function() { describe("in containing sequence", function() { it("can access variables defined by preceding labeled elements", function() { let parser = peg.generate( - 'start = a:"a" !{ return a !== "a"; }', + "start = a:'a' !{ return a !== 'a'; }", options ); @@ -634,7 +634,7 @@ describe("generated parser behavior", function() { it("cannot access variable defined by labeled predicate element", function() { let parser = peg.generate( - 'start = "a" b:!{ return b !== undefined; } "c"', + "start = 'a' b:!{ return b !== undefined; } 'c'", options ); @@ -643,7 +643,7 @@ describe("generated parser behavior", function() { it("cannot access variables defined by following labeled elements", function() { let parser = peg.generate( - 'start = !{ return a !== "a"; } a:"a"', + "start = !{ return a !== 'a'; } a:'a'", options ); @@ -653,47 +653,47 @@ describe("generated parser behavior", function() { it("cannot access variables defined by subexpressions", function() { let testcases = [ { - grammar: 'start = (a:"a") !{ return a !== "a"; }', + grammar: "start = (a:'a') !{ return a !== 'a'; }", input: "a" }, { - grammar: 'start = (a:"a")? !{ return a !== "a"; }', + grammar: "start = (a:'a')? !{ return a !== 'a'; }", input: "a" }, { - grammar: 'start = (a:"a")* !{ return a !== "a"; }', + grammar: "start = (a:'a')* !{ return a !== 'a'; }", input: "a" }, { - grammar: 'start = (a:"a")+ !{ return a !== "a"; }', + grammar: "start = (a:'a')+ !{ return a !== 'a'; }", input: "a" }, { - grammar: 'start = $(a:"a") !{ return a !== "a"; }', + grammar: "start = $(a:'a') !{ return a !== 'a'; }", input: "a" }, { - grammar: 'start = &(a:"a") "a" !{ return a !== "a"; }', + grammar: "start = &(a:'a') 'a' !{ return a !== 'a'; }", input: "a" }, { - grammar: 'start = !(a:"a") "b" !{ return a !== "a"; }', + grammar: "start = !(a:'a') 'b' !{ return a !== 'a'; }", input: "b" }, { - grammar: 'start = b:(a:"a") !{ return a !== "a"; }', + grammar: "start = b:(a:'a') !{ return a !== 'a'; }", input: "a" }, { - grammar: 'start = ("a" b:"b" "c") !{ return b !== "b"; }', + grammar: "start = ('a' b:'b' 'c') !{ return b !== 'b'; }", input: "abc" }, { - grammar: 'start = (a:"a" { return a; }) !{ return a !== "a"; }', + grammar: "start = (a:'a' { return a; }) !{ return a !== 'a'; }", input: "a" }, { - grammar: 'start = ("a" / b:"b" / "c") !{ return b !== "b"; }', + grammar: "start = ('a' / b:'b' / 'c') !{ return b !== 'b'; }", input: "b" } ]; @@ -709,7 +709,7 @@ describe("generated parser behavior", function() { describe("in outer sequence", function() { it("can access variables defined by preceding labeled elements", function() { let parser = peg.generate( - 'start = a:"a" ("b" !{ return a !== "a"; })', + "start = a:'a' ('b' !{ return a !== 'a'; })", options ); @@ -718,7 +718,7 @@ describe("generated parser behavior", function() { it("cannot access variable defined by labeled predicate element", function() { let parser = peg.generate( - 'start = "a" b:("b" !{ return b !== undefined; }) "c"', + "start = 'a' b:('b' !{ return b !== undefined; }) 'c'", options ); @@ -727,7 +727,7 @@ describe("generated parser behavior", function() { it("cannot access variables defined by following labeled elements", function() { let parser = peg.generate( - 'start = ("a" !{ return b !== "b"; }) b:"b"', + "start = ('a' !{ return b !== 'b'; }) b:'b'", options ); @@ -739,8 +739,8 @@ describe("generated parser behavior", function() { describe("initializer variables & functions", function() { it("can access variables defined in the initializer", function() { let parser = peg.generate([ - '{ var v = 42 }', - 'start = !{ return v !== 42; }' + "{ var v = 42 }", + "start = !{ return v !== 42; }" ].join("\n"), options); expect(parser).toParse(""); @@ -748,8 +748,8 @@ describe("generated parser behavior", function() { it("can access functions defined in the initializer", function() { let parser = peg.generate([ - '{ function f() { return 42; } }', - 'start = !{ return f() !== 42; }' + "{ function f() { return 42; } }", + "start = !{ return f() !== 42; }" ].join("\n"), options); expect(parser).toParse(""); @@ -759,8 +759,8 @@ describe("generated parser behavior", function() { describe("available variables & functions", function() { it("|options| contains options", function() { let parser = peg.generate([ - '{ var result; }', - 'start = !{ result = options; return false; } { return result; }' + "{ var result; }", + "start = !{ result = options; return false; } { return result; }" ].join("\n"), options); expect(parser).toParse("", { a: 42 }, { a: 42 }); @@ -768,13 +768,13 @@ describe("generated parser behavior", function() { it("|location| returns current location info", function() { let parser = peg.generate([ - '{ var result; }', - 'start = line (nl+ line)* { return result; }', - 'line = thing (" "+ thing)*', - 'thing = digit / mark', - 'digit = [0-9]', - 'mark = !{ result = location(); return false; } "x"', - 'nl = "\\r"? "\\n"' + "{ var result; }", + "start = line (nl+ line)* { return result; }", + "line = thing (' '+ thing)*", + "thing = digit / mark", + "digit = [0-9]", + "mark = !{ result = location(); return false; } 'x'", + "nl = '\\r'? '\\n'" ].join("\n"), options); expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", { @@ -798,7 +798,7 @@ describe("generated parser behavior", function() { describe("group", function() { describe("when the expression matches", function() { it("returns its match result", function() { - let parser = peg.generate('start = ("a")', options); + let parser = peg.generate("start = ('a')", options); expect(parser).toParse("a", "a"); }); @@ -806,7 +806,7 @@ describe("generated parser behavior", function() { describe("when the expression doesn't match", function() { it("reports match failure", function() { - let parser = peg.generate('start = ("a")', options); + let parser = peg.generate("start = ('a')", options); expect(parser).toFailToParse("b"); }); @@ -816,7 +816,7 @@ describe("generated parser behavior", function() { describe("optional", function() { describe("when the expression matches", function() { it("returns its match result", function() { - let parser = peg.generate('start = "a"?', options); + let parser = peg.generate("start = 'a'?", options); expect(parser).toParse("a", "a"); }); @@ -824,7 +824,7 @@ describe("generated parser behavior", function() { describe("when the expression doesn't match", function() { it("returns |null|", function() { - let parser = peg.generate('start = "a"?', options); + let parser = peg.generate("start = 'a'?", options); expect(parser).toParse("", null); }); @@ -834,7 +834,7 @@ describe("generated parser behavior", function() { describe("zero or more", function() { describe("when the expression matches zero or more times", function() { it("returns an array of its match results", function() { - let parser = peg.generate('start = "a"*', options); + let parser = peg.generate("start = 'a'*", options); expect(parser).toParse("", []); expect(parser).toParse("a", ["a"]); @@ -846,7 +846,7 @@ describe("generated parser behavior", function() { describe("one or more", function() { describe("when the expression matches one or more times", function() { it("returns an array of its match results", function() { - let parser = peg.generate('start = "a"+', options); + let parser = peg.generate("start = 'a'+", options); expect(parser).toParse("a", ["a"]); expect(parser).toParse("aaa", ["a", "a", "a"]); @@ -855,7 +855,7 @@ describe("generated parser behavior", function() { describe("when the expression doesn't match", function() { it("reports match failure", function() { - let parser = peg.generate('start = "a"+', options); + let parser = peg.generate("start = 'a'+", options); expect(parser).toFailToParse(""); }); @@ -865,7 +865,7 @@ describe("generated parser behavior", function() { describe("text", function() { describe("when the expression matches", function() { it("returns the matched text", function() { - let parser = peg.generate('start = $("a" "b" "c")', options); + let parser = peg.generate("start = $('a' 'b' 'c')", options); expect(parser).toParse("abc", "abc"); }); @@ -873,7 +873,7 @@ describe("generated parser behavior", function() { describe("when the expression doesn't match", function() { it("reports match failure", function() { - let parser = peg.generate('start = $("a")', options); + let parser = peg.generate("start = $('a')", options); expect(parser).toFailToParse("b"); }); @@ -883,13 +883,13 @@ describe("generated parser behavior", function() { describe("positive simple predicate", function() { describe("when the expression matches", function() { it("returns |undefined|", function() { - let parser = peg.generate('start = &"a" "a"', options); + let parser = peg.generate("start = &'a' 'a'", options); expect(parser).toParse("a", [undefined, "a"]); }); it("resets parse position", function() { - let parser = peg.generate('start = &"a" "a"', options); + let parser = peg.generate("start = &'a' 'a'", options); expect(parser).toParse("a"); }); @@ -897,13 +897,13 @@ describe("generated parser behavior", function() { describe("when the expression doesn't match", function() { it("reports match failure", function() { - let parser = peg.generate('start = &"a"', options); + let parser = peg.generate("start = &'a'", options); expect(parser).toFailToParse("b"); }); it("discards any expectations recorded when matching the expression", function() { - let parser = peg.generate('start = "a" / &"b" / "c"', options); + let parser = peg.generate("start = 'a' / &'b' / 'c'", options); expect(parser).toFailToParse("d", { expected: [ @@ -918,7 +918,7 @@ describe("generated parser behavior", function() { describe("negative simple predicate", function() { describe("when the expression matches", function() { it("reports match failure", function() { - let parser = peg.generate('start = !"a"', options); + let parser = peg.generate("start = !'a'", options); expect(parser).toFailToParse("a"); }); @@ -926,19 +926,19 @@ describe("generated parser behavior", function() { describe("when the expression doesn't match", function() { it("returns |undefined|", function() { - let parser = peg.generate('start = !"a" "b"', options); + let parser = peg.generate("start = !'a' 'b'", options); expect(parser).toParse("b", [undefined, "b"]); }); it("resets parse position", function() { - let parser = peg.generate('start = !"a" "b"', options); + let parser = peg.generate("start = !'a' 'b'", options); expect(parser).toParse("b"); }); it("discards any expectations recorded when matching the expression", function() { - let parser = peg.generate('start = "a" / !"b" / "c"', options); + let parser = peg.generate("start = 'a' / !'b' / 'c'", options); expect(parser).toFailToParse("b", { expected: [ @@ -953,7 +953,7 @@ describe("generated parser behavior", function() { describe("label", function() { describe("when the expression matches", function() { it("returns its match result", function() { - let parser = peg.generate('start = a:"a"', options); + let parser = peg.generate("start = a:'a'", options); expect(parser).toParse("a", "a"); }); @@ -961,7 +961,7 @@ describe("generated parser behavior", function() { describe("when the expression doesn't match", function() { it("reports match failure", function() { - let parser = peg.generate('start = a:"a"', options); + let parser = peg.generate("start = a:'a'", options); expect(parser).toFailToParse("b"); }); @@ -971,7 +971,7 @@ describe("generated parser behavior", function() { describe("sequence", function() { describe("when all expressions match", function() { it("returns an array of their match results", function() { - let parser = peg.generate('start = "a" "b" "c"', options); + let parser = peg.generate("start = 'a' 'b' 'c'", options); expect(parser).toParse("abc", ["a", "b", "c"]); }); @@ -979,7 +979,7 @@ describe("generated parser behavior", function() { describe("when any expression doesn't match", function() { it("reports match failure", function() { - let parser = peg.generate('start = "a" "b" "c"', options); + let parser = peg.generate("start = 'a' 'b' 'c'", options); expect(parser).toFailToParse("dbc"); expect(parser).toFailToParse("adc"); @@ -987,7 +987,7 @@ describe("generated parser behavior", function() { }); it("resets parse position", function() { - let parser = peg.generate('start = "a" "b" / "a"', options); + let parser = peg.generate("start = 'a' 'b' / 'a'", options); expect(parser).toParse("a", "a"); }); @@ -997,7 +997,7 @@ describe("generated parser behavior", function() { describe("action", function() { describe("when the expression matches", function() { it("returns the value returned by the code", function() { - let parser = peg.generate('start = "a" { return 42; }', options); + let parser = peg.generate("start = 'a' { return 42; }", options); expect(parser).toParse("a", 42); }); @@ -1005,14 +1005,14 @@ describe("generated parser behavior", function() { describe("label variables", function() { describe("in the expression", function() { it("can access variable defined by labeled expression", function() { - let parser = peg.generate('start = a:"a" { return a; }', options); + let parser = peg.generate("start = a:'a' { return a; }", options); expect(parser).toParse("a", "a"); }); it("can access variables defined by labeled sequence elements", function() { let parser = peg.generate( - 'start = a:"a" b:"b" c:"c" { return [a, b, c]; }', + "start = a:'a' b:'b' c:'c' { return [a, b, c]; }", options ); @@ -1022,47 +1022,47 @@ describe("generated parser behavior", function() { it("cannot access variables defined by subexpressions", function() { let testcases = [ { - grammar: 'start = (a:"a") { return a; }', + grammar: "start = (a:'a') { return a; }", input: "a" }, { - grammar: 'start = (a:"a")? { return a; }', + grammar: "start = (a:'a')? { return a; }", input: "a" }, { - grammar: 'start = (a:"a")* { return a; }', + grammar: "start = (a:'a')* { return a; }", input: "a" }, { - grammar: 'start = (a:"a")+ { return a; }', + grammar: "start = (a:'a')+ { return a; }", input: "a" }, { - grammar: 'start = $(a:"a") { return a; }', + grammar: "start = $(a:'a') { return a; }", input: "a" }, { - grammar: 'start = &(a:"a") "a" { return a; }', + grammar: "start = &(a:'a') 'a' { return a; }", input: "a" }, { - grammar: 'start = !(a:"a") "b" { return a; }', + grammar: "start = !(a:'a') 'b' { return a; }", input: "b" }, { - grammar: 'start = b:(a:"a") { return a; }', + grammar: "start = b:(a:'a') { return a; }", input: "a" }, { - grammar: 'start = ("a" b:"b" "c") { return b; }', + grammar: "start = ('a' b:'b' 'c') { return b; }", input: "abc" }, { - grammar: 'start = (a:"a" { return a; }) { return a; }', + grammar: "start = (a:'a' { return a; }) { return a; }", input: "a" }, { - grammar: 'start = ("a" / b:"b" / "c") { return b; }', + grammar: "start = ('a' / b:'b' / 'c') { return b; }", input: "b" } ]; @@ -1078,7 +1078,7 @@ describe("generated parser behavior", function() { describe("in outer sequence", function() { it("can access variables defined by preceding labeled elements", function() { let parser = peg.generate( - 'start = a:"a" ("b" { return a; })', + "start = a:'a' ('b' { return a; })", options ); @@ -1087,7 +1087,7 @@ describe("generated parser behavior", function() { it("cannot access variable defined by labeled action element", function() { let parser = peg.generate( - 'start = "a" b:("b" { return b; }) c:"c"', + "start = 'a' b:('b' { return b; }) c:'c'", options ); @@ -1096,7 +1096,7 @@ describe("generated parser behavior", function() { it("cannot access variables defined by following labeled elements", function() { let parser = peg.generate( - 'start = ("a" { return b; }) b:"b"', + "start = ('a' { return b; }) b:'b'", options ); @@ -1108,8 +1108,8 @@ describe("generated parser behavior", function() { describe("initializer variables & functions", function() { it("can access variables defined in the initializer", function() { let parser = peg.generate([ - '{ var v = 42 }', - 'start = "a" { return v; }' + "{ var v = 42 }", + "start = 'a' { return v; }" ].join("\n"), options); expect(parser).toParse("a", 42); @@ -1117,8 +1117,8 @@ describe("generated parser behavior", function() { it("can access functions defined in the initializer", function() { let parser = peg.generate([ - '{ function f() { return 42; } }', - 'start = "a" { return f(); }' + "{ function f() { return 42; } }", + "start = 'a' { return f(); }" ].join("\n"), options); expect(parser).toParse("a", 42); @@ -1128,7 +1128,7 @@ describe("generated parser behavior", function() { describe("available variables & functions", function() { it("|options| contains options", function() { let parser = peg.generate( - 'start = "a" { return options; }', + "start = 'a' { return options; }", options ); @@ -1137,7 +1137,7 @@ describe("generated parser behavior", function() { it("|text| returns text matched by the expression", function() { let parser = peg.generate( - 'start = "a" { return text(); }', + "start = 'a' { return text(); }", options ); @@ -1146,13 +1146,13 @@ describe("generated parser behavior", function() { it("|location| returns location info of the expression", function() { let parser = peg.generate([ - '{ var result; }', - 'start = line (nl+ line)* { return result; }', - 'line = thing (" "+ thing)*', - 'thing = digit / mark', - 'digit = [0-9]', - 'mark = "x" { result = location(); }', - 'nl = "\\r"? "\\n"' + "{ var result; }", + "start = line (nl+ line)* { return result; }", + "line = thing (' '+ thing)*", + "thing = digit / mark", + "digit = [0-9]", + "mark = 'x' { result = location(); }", + "nl = '\\r'? '\\n'" ].join("\n"), options); expect(parser).toParse("1\n2\n\n3\n\n\n4 5 x", { @@ -1174,12 +1174,12 @@ describe("generated parser behavior", function() { describe("|expected|", function() { it("terminates parsing and throws an exception", function() { let parser = peg.generate( - 'start = "a" { expected("a"); }', + "start = 'a' { expected('a'); }", options ); expect(parser).toFailToParse("a", { - message: 'Expected a but "a" found.', + message: "Expected a but \"a\" found.", expected: [{ type: "other", description: "a" }], found: "a", location: { @@ -1191,16 +1191,16 @@ describe("generated parser behavior", function() { it("allows to set custom location info", function() { let parser = peg.generate([ - 'start = "a" {', - ' expected("a", {', - ' start: { offset: 1, line: 1, column: 2 },', - ' end: { offset: 2, line: 1, column: 3 }', - ' });', - '}' + "start = 'a' {", + " expected('a', {", + " start: { offset: 1, line: 1, column: 2 },", + " end: { offset: 2, line: 1, column: 3 }", + " });", + "}" ].join("\n"), options); expect(parser).toFailToParse("a", { - message: 'Expected a but "a" found.', + message: "Expected a but \"a\" found.", expected: [{ type: "other", description: "a" }], found: "a", location: { @@ -1214,7 +1214,7 @@ describe("generated parser behavior", function() { describe("|error|", function() { it("terminates parsing and throws an exception", function() { let parser = peg.generate( - 'start = "a" { error("a"); }', + "start = 'a' { error('a'); }", options ); @@ -1231,12 +1231,12 @@ describe("generated parser behavior", function() { it("allows to set custom location info", function() { let parser = peg.generate([ - 'start = "a" {', - ' error("a", {', - ' start: { offset: 1, line: 1, column: 2 },', - ' end: { offset: 2, line: 1, column: 3 }', - ' });', - '}' + "start = 'a' {", + " error('a', {", + " start: { offset: 1, line: 1, column: 2 },", + " end: { offset: 2, line: 1, column: 3 }", + " });", + "}" ].join("\n"), options); expect(parser).toFailToParse("a", { @@ -1255,14 +1255,14 @@ describe("generated parser behavior", function() { describe("when the expression doesn't match", function() { it("reports match failure", function() { - let parser = peg.generate('start = "a" { return 42; }', options); + let parser = peg.generate("start = 'a' { return 42; }", options); expect(parser).toFailToParse("b"); }); it("doesn't execute the code", function() { let parser = peg.generate( - 'start = "a" { throw "Boom!"; } / "b"', + "start = 'a' { throw 'Boom!'; } / 'b'", options ); @@ -1274,7 +1274,7 @@ describe("generated parser behavior", function() { describe("choice", function() { describe("when any expression matches", function() { it("returns its match result", function() { - let parser = peg.generate('start = "a" / "b" / "c"', options); + let parser = peg.generate("start = 'a' / 'b' / 'c'", options); expect(parser).toParse("a", "a"); expect(parser).toParse("b", "b"); @@ -1284,7 +1284,7 @@ describe("generated parser behavior", function() { describe("when all expressions don't match", function() { it("reports match failure", function() { - let parser = peg.generate('start = "a" / "b" / "c"', options); + let parser = peg.generate("start = 'a' / 'b' / 'c'", options); expect(parser).toFailToParse("d"); }); @@ -1294,7 +1294,7 @@ describe("generated parser behavior", function() { describe("error reporting", function() { describe("behavior", function() { it("reports only the rightmost error", function() { - let parser = peg.generate('start = "a" "b" / "a" "c" "d"', options); + let parser = peg.generate("start = 'a' 'b' / 'a' 'c' 'd'", options); expect(parser).toFailToParse("ace", { expected: [{ type: "literal", text: "d", ignoreCase: false }] @@ -1304,7 +1304,7 @@ describe("generated parser behavior", function() { describe("expectations reporting", function() { it("reports expectations correctly with no alternative", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toFailToParse("ab", { expected: [{ type: "end" }] @@ -1312,7 +1312,7 @@ describe("generated parser behavior", function() { }); it("reports expectations correctly with one alternative", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toFailToParse("b", { expected: [{ type: "literal", text: "a", ignoreCase: false }] @@ -1320,7 +1320,7 @@ describe("generated parser behavior", function() { }); it("reports expectations correctly with multiple alternatives", function() { - let parser = peg.generate('start = "a" / "b" / "c"', options); + let parser = peg.generate("start = 'a' / 'b' / 'c'", options); expect(parser).toFailToParse("d", { expected: [ @@ -1334,13 +1334,13 @@ describe("generated parser behavior", function() { describe("found string reporting", function() { it("reports found string correctly at the end of input", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toFailToParse("", { found: null }); }); it("reports found string correctly in the middle of input", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toFailToParse("b", { found: "b" }); }); @@ -1348,58 +1348,58 @@ describe("generated parser behavior", function() { describe("message building", function() { it("builds message correctly with no alternative", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toFailToParse("ab", { - message: 'Expected end of input but "b" found.' + message: "Expected end of input but \"b\" found." }); }); it("builds message correctly with one alternative", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toFailToParse("b", { - message: 'Expected "a" but "b" found.' + message: "Expected \"a\" but \"b\" found." }); }); it("builds message correctly with multiple alternatives", function() { - let parser = peg.generate('start = "a" / "b" / "c"', options); + let parser = peg.generate("start = 'a' / 'b' / 'c'", options); expect(parser).toFailToParse("d", { - message: 'Expected "a", "b", or "c" but "d" found.' + message: "Expected \"a\", \"b\", or \"c\" but \"d\" found." }); }); it("builds message correctly at the end of input", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toFailToParse("", { - message: 'Expected "a" but end of input found.' + message: "Expected \"a\" but end of input found." }); }); it("builds message correctly in the middle of input", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toFailToParse("b", { - message: 'Expected "a" but "b" found.' + message: "Expected \"a\" but \"b\" found." }); }); it("removes duplicates from expectations", function() { - let parser = peg.generate('start = "a" / "a"', options); + let parser = peg.generate("start = 'a' / 'a'", options); expect(parser).toFailToParse("b", { - message: 'Expected "a" but "b" found.' + message: "Expected \"a\" but \"b\" found." }); }); it("sorts expectations", function() { - let parser = peg.generate('start = "c" / "b" / "a"', options); + let parser = peg.generate("start = 'c' / 'b' / 'a'", options); expect(parser).toFailToParse("d", { - message: 'Expected "a", "b", or "c" but "d" found.' + message: "Expected \"a\", \"b\", or \"c\" but \"d\" found." }); }); @@ -1407,7 +1407,7 @@ describe("generated parser behavior", function() { describe("position reporting", function() { it("reports position correctly at the end of input", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toFailToParse("", { location: { @@ -1418,7 +1418,7 @@ describe("generated parser behavior", function() { }); it("reports position correctly in the middle of input", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toFailToParse("b", { location: { @@ -1429,7 +1429,7 @@ describe("generated parser behavior", function() { }); it("reports position correctly with trailing input", function() { - let parser = peg.generate('start = "a"', options); + let parser = peg.generate("start = 'a'", options); expect(parser).toFailToParse("aa", { location: { @@ -1441,10 +1441,10 @@ describe("generated parser behavior", function() { it("reports position correctly in complex cases", function() { let parser = peg.generate([ - 'start = line (nl+ line)*', - 'line = digit (" "+ digit)*', - 'digit = [0-9]', - 'nl = "\\r"? "\\n"' + "start = line (nl+ line)*", + "line = digit (' '+ digit)*", + "digit = [0-9]", + "nl = '\\r'? '\\n'" ].join("\n"), options); expect(parser).toFailToParse("1\n2\n\n3\n\n\n4 5 x", { @@ -1480,21 +1480,21 @@ describe("generated parser behavior", function() { // Sum ← Product (('+' / '-') Product)* // Expr ← Sum let parser = peg.generate([ - 'Expr = Sum', - 'Sum = head:Product tail:(("+" / "-") Product)* {', - ' return tail.reduce(function(result, element) {', - ' if (element[0] === "+") { return result + element[1]; }', - ' if (element[0] === "-") { return result - element[1]; }', - ' }, head);', - ' }', - 'Product = head:Value tail:(("*" / "/") Value)* {', - ' return tail.reduce(function(result, element) {', - ' if (element[0] === "*") { return result * element[1]; }', - ' if (element[0] === "/") { return result / element[1]; }', - ' }, head);', - ' }', - 'Value = digits:[0-9]+ { return parseInt(digits.join(""), 10); }', - ' / "(" expr:Expr ")" { return expr; }' + "Expr = Sum", + "Sum = head:Product tail:(('+' / '-') Product)* {", + " return tail.reduce(function(result, element) {", + " if (element[0] === '+') { return result + element[1]; }", + " if (element[0] === '-') { return result - element[1]; }", + " }, head);", + " }", + "Product = head:Value tail:(('*' / '/') Value)* {", + " return tail.reduce(function(result, element) {", + " if (element[0] === '*') { return result * element[1]; }", + " if (element[0] === '/') { return result / element[1]; }", + " }, head);", + " }", + "Value = digits:[0-9]+ { return parseInt(digits.join(''), 10); }", + " / '(' expr:Expr ')' { return expr; }" ].join("\n"), options); // The "value" rule @@ -1531,9 +1531,9 @@ describe("generated parser behavior", function() { // A ← a A? b // B ← b B? c let parser = peg.generate([ - 'S = &(A "c") a:"a"+ B:B !("a" / "b" / "c") { return a.join("") + B; }', - 'A = a:"a" A:A? b:"b" { return [a, A, b].join(""); }', - 'B = b:"b" B:B? c:"c" { return [b, B, c].join(""); }' + "S = &(A 'c') a:'a'+ B:B !('a' / 'b' / 'c') { return a.join('') + B; }", + "A = a:'a' A:A? b:'b' { return [a, A, b].join(''); }", + "B = b:'b' B:B? c:'c' { return [b, B, c].join(''); }" ].join("\n"), options); expect(parser).toParse("abc", "abc"); @@ -1553,12 +1553,12 @@ describe("generated parser behavior", function() { // N ← C / (!Begin !End Z) // Z ← any single character let parser = peg.generate([ - 'C = begin:Begin ns:N* end:End { return begin + ns.join("") + end; }', - 'N = C', - ' / !Begin !End z:Z { return z; }', - 'Z = .', - 'Begin = "(*"', - 'End = "*)"' + "C = begin:Begin ns:N* end:End { return begin + ns.join('') + end; }", + "N = C", + " / !Begin !End z:Z { return z; }", + "Z = .", + "Begin = '(*'", + "End = '*)'" ].join("\n"), options); expect(parser).toParse("(**)", "(**)"); diff --git a/spec/unit/compiler/passes/generate-bytecode.spec.js b/spec/unit/compiler/passes/generate-bytecode.spec.js index cb6334d..a4c259d 100644 --- a/spec/unit/compiler/passes/generate-bytecode.spec.js +++ b/spec/unit/compiler/passes/generate-bytecode.spec.js @@ -16,9 +16,9 @@ describe("compiler pass |generateBytecode|", function() { describe("for grammar", function() { it("generates correct bytecode", function() { expect(pass).toChangeAST([ - 'a = "a"', - 'b = "b"', - 'c = "c"' + "a = 'a'", + "b = 'b'", + "c = 'c'" ].join("\n"), { rules: [ { bytecode: [18, 0, 2, 2, 22, 0, 23, 1] }, @@ -30,30 +30,30 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST([ - 'a = "a"', - 'b = "b"', - 'c = "c"' + "a = 'a'", + "b = 'b'", + "c = 'c'" ].join("\n"), constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)', - '"b"', - 'peg$literalExpectation("b", false)', - '"c"', - 'peg$literalExpectation("c", false)' + "\"a\"", + "peg$literalExpectation(\"a\", false)", + "\"b\"", + "peg$literalExpectation(\"b\", false)", + "\"c\"", + "peg$literalExpectation(\"c\", false)" ])); }); }); describe("for rule", function() { it("generates correct bytecode", function() { - expect(pass).toChangeAST('start = "a"', bytecodeDetails([ + expect(pass).toChangeAST("start = 'a'", bytecodeDetails([ 18, 0, 2, 2, 22, 0, 23, 1 // ])); }); }); describe("for named", function() { - let grammar = 'start "start" = "a"'; + let grammar = "start 'start' = 'a'"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -67,16 +67,16 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - 'peg$otherExpectation("start")', - '"a"', - 'peg$literalExpectation("a", false)' + "peg$otherExpectation(\"start\")", + "\"a\"", + "peg$literalExpectation(\"a\", false)" ])); }); }); describe("for choice", function() { it("generates correct bytecode", function() { - expect(pass).toChangeAST('start = "a" / "b" / "c"', bytecodeDetails([ + expect(pass).toChangeAST("start = 'a' / 'b' / 'c'", bytecodeDetails([ 18, 0, 2, 2, 22, 0, 23, 1, // 14, 21, 0, // IF_ERROR 6, // * POP @@ -90,7 +90,7 @@ describe("compiler pass |generateBytecode|", function() { describe("for action", function() { describe("without labels", function() { - let grammar = 'start = "a" { code }'; + let grammar = "start = 'a' { code }"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -105,15 +105,15 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)', - 'function() { code }' + "\"a\"", + "peg$literalExpectation(\"a\", false)", + "function() { code }" ])); }); }); describe("with one label", function() { - let grammar = 'start = a:"a" { code }'; + let grammar = "start = a:'a' { code }"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -128,15 +128,15 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)', - 'function(a) { code }' + "\"a\"", + "peg$literalExpectation(\"a\", false)", + "function(a) { code }" ])); }); }); describe("with multiple labels", function() { - let grammar = 'start = a:"a" b:"b" c:"c" { code }'; + let grammar = "start = a:'a' b:'b' c:'c' { code }"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -164,20 +164,20 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)', - '"b"', - 'peg$literalExpectation("b", false)', - '"c"', - 'peg$literalExpectation("c", false)', - 'function(a, b, c) { code }' + "\"a\"", + "peg$literalExpectation(\"a\", false)", + "\"b\"", + "peg$literalExpectation(\"b\", false)", + "\"c\"", + "peg$literalExpectation(\"c\", false)", + "function(a, b, c) { code }" ])); }); }); }); describe("for sequence", function() { - let grammar = 'start = "a" "b" "c"'; + let grammar = "start = 'a' 'b' 'c'"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -204,19 +204,19 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)', - '"b"', - 'peg$literalExpectation("b", false)', - '"c"', - 'peg$literalExpectation("c", false)' + "\"a\"", + "peg$literalExpectation(\"a\", false)", + "\"b\"", + "peg$literalExpectation(\"b\", false)", + "\"c\"", + "peg$literalExpectation(\"c\", false)" ])); }); }); describe("for labeled", function() { it("generates correct bytecode", function() { - expect(pass).toChangeAST('start = a:"a"', bytecodeDetails([ + expect(pass).toChangeAST("start = a:'a'", bytecodeDetails([ 18, 0, 2, 2, 22, 0, 23, 1 // ])); }); @@ -224,7 +224,7 @@ describe("compiler pass |generateBytecode|", function() { describe("for text", function() { it("generates correct bytecode", function() { - expect(pass).toChangeAST('start = $"a"', bytecodeDetails([ + expect(pass).toChangeAST("start = $'a'", bytecodeDetails([ 5, // PUSH_CURR_POS 18, 0, 2, 2, 22, 0, 23, 1, // 15, 2, 1, // IF_NOT_ERROR @@ -236,7 +236,7 @@ describe("compiler pass |generateBytecode|", function() { }); describe("for simple_and", function() { - let grammar = 'start = &"a"'; + let grammar = "start = &'a'"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -256,14 +256,14 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)' + "\"a\"", + "peg$literalExpectation(\"a\", false)" ])); }); }); describe("for simple_not", function() { - let grammar = 'start = !"a"'; + let grammar = "start = !'a'"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -283,14 +283,14 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)' + "\"a\"", + "peg$literalExpectation(\"a\", false)" ])); }); }); describe("for optional", function() { - let grammar = 'start = "a"?'; + let grammar = "start = 'a'?"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -303,14 +303,14 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)' + "\"a\"", + "peg$literalExpectation(\"a\", false)" ])); }); }); describe("for zero_or_more", function() { - let grammar = 'start = "a"*'; + let grammar = "start = 'a'*"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -325,14 +325,14 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)' + "\"a\"", + "peg$literalExpectation(\"a\", false)" ])); }); }); describe("for one_or_more", function() { - let grammar = 'start = "a"+'; + let grammar = "start = 'a'+"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -351,15 +351,15 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)' + "\"a\"", + "peg$literalExpectation(\"a\", false)" ])); }); }); describe("for group", function() { it("generates correct bytecode", function() { - expect(pass).toChangeAST('start = ("a")', bytecodeDetails([ + expect(pass).toChangeAST("start = ('a')", bytecodeDetails([ 18, 0, 2, 2, 22, 0, 23, 1 // ])); }); @@ -367,7 +367,7 @@ describe("compiler pass |generateBytecode|", function() { describe("for semantic_and", function() { describe("without labels", function() { - let grammar = 'start = &{ code }'; + let grammar = "start = &{ code }"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -384,13 +384,13 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST( grammar, - constsDetails(['function() { code }']) + constsDetails(["function() { code }"]) ); }); }); describe("with labels", function() { - let grammar = 'start = a:"a" b:"b" c:"c" &{ code }'; + let grammar = "start = a:'a' b:'b' c:'c' &{ code }"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -428,13 +428,13 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)', - '"b"', - 'peg$literalExpectation("b", false)', - '"c"', - 'peg$literalExpectation("c", false)', - 'function(a, b, c) { code }' + "\"a\"", + "peg$literalExpectation(\"a\", false)", + "\"b\"", + "peg$literalExpectation(\"b\", false)", + "\"c\"", + "peg$literalExpectation(\"c\", false)", + "function(a, b, c) { code }" ])); }); }); @@ -442,7 +442,7 @@ describe("compiler pass |generateBytecode|", function() { describe("for semantic_not", function() { describe("without labels", function() { - let grammar = 'start = !{ code }'; + let grammar = "start = !{ code }"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -459,13 +459,13 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST( grammar, - constsDetails(['function() { code }']) + constsDetails(["function() { code }"]) ); }); }); describe("with labels", function() { - let grammar = 'start = a:"a" b:"b" c:"c" !{ code }'; + let grammar = "start = a:'a' b:'b' c:'c' !{ code }"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -503,13 +503,13 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)', - '"b"', - 'peg$literalExpectation("b", false)', - '"c"', - 'peg$literalExpectation("c", false)', - 'function(a, b, c) { code }' + "\"a\"", + "peg$literalExpectation(\"a\", false)", + "\"b\"", + "peg$literalExpectation(\"b\", false)", + "\"c\"", + "peg$literalExpectation(\"c\", false)", + "function(a, b, c) { code }" ])); }); }); @@ -518,8 +518,8 @@ describe("compiler pass |generateBytecode|", function() { describe("for rule_ref", function() { it("generates correct bytecode", function() { expect(pass).toChangeAST([ - 'start = other', - 'other = "other"' + "start = other", + "other = 'other'" ].join("\n"), { rules: [ { @@ -533,7 +533,7 @@ describe("compiler pass |generateBytecode|", function() { describe("for literal", function() { describe("empty", function() { - let grammar = 'start = ""'; + let grammar = "start = ''"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -542,12 +542,12 @@ describe("compiler pass |generateBytecode|", function() { }); it("defines correct constants", function() { - expect(pass).toChangeAST(grammar, constsDetails(['""'])); + expect(pass).toChangeAST(grammar, constsDetails(["\"\""])); }); }); describe("non-empty case-sensitive", function() { - let grammar = 'start = "a"'; + let grammar = "start = 'a'"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -559,14 +559,14 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("a", false)' + "\"a\"", + "peg$literalExpectation(\"a\", false)" ])); }); }); describe("non-empty case-insensitive", function() { - let grammar = 'start = "A"i'; + let grammar = "start = 'A'i"; it("generates correct bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -578,8 +578,8 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST(grammar, constsDetails([ - '"a"', - 'peg$literalExpectation("A", true)' + "\"a\"", + "peg$literalExpectation(\"A\", true)" ])); }); }); @@ -587,7 +587,7 @@ describe("compiler pass |generateBytecode|", function() { describe("for class", function() { it("generates correct bytecode", function() { - expect(pass).toChangeAST('start = [a]', bytecodeDetails([ + expect(pass).toChangeAST("start = [a]", bytecodeDetails([ 20, 0, 2, 2, // MATCH_REGEXP 21, 1, // * ACCEPT_N 23, 1 // * FAIL @@ -596,43 +596,43 @@ describe("compiler pass |generateBytecode|", function() { describe("non-inverted case-sensitive", function() { it("defines correct constants", function() { - expect(pass).toChangeAST('start = [a]', constsDetails([ - '/^[a]/', - 'peg$classExpectation(["a"], false, false)' + expect(pass).toChangeAST("start = [a]", constsDetails([ + "/^[a]/", + "peg$classExpectation([\"a\"], false, false)" ])); }); }); describe("inverted case-sensitive", function() { it("defines correct constants", function() { - expect(pass).toChangeAST('start = [^a]', constsDetails([ - '/^[^a]/', - 'peg$classExpectation(["a"], true, false)' + expect(pass).toChangeAST("start = [^a]", constsDetails([ + "/^[^a]/", + "peg$classExpectation([\"a\"], true, false)" ])); }); }); describe("non-inverted case-insensitive", function() { it("defines correct constants", function() { - expect(pass).toChangeAST('start = [a]i', constsDetails([ - '/^[a]/i', - 'peg$classExpectation(["a"], false, true)' + expect(pass).toChangeAST("start = [a]i", constsDetails([ + "/^[a]/i", + "peg$classExpectation([\"a\"], false, true)" ])); }); }); describe("complex", function() { it("defines correct constants", function() { - expect(pass).toChangeAST('start = [ab-def-hij-l]', constsDetails([ - '/^[ab-def-hij-l]/', - 'peg$classExpectation(["a", ["b", "d"], "e", ["f", "h"], "i", ["j", "l"]], false, false)' + expect(pass).toChangeAST("start = [ab-def-hij-l]", constsDetails([ + "/^[ab-def-hij-l]/", + "peg$classExpectation([\"a\", [\"b\", \"d\"], \"e\", [\"f\", \"h\"], \"i\", [\"j\", \"l\"]], false, false)" ])); }); }); }); describe("for any", function() { - let grammar = 'start = .'; + let grammar = "start = ."; it("generates bytecode", function() { expect(pass).toChangeAST(grammar, bytecodeDetails([ @@ -645,7 +645,7 @@ describe("compiler pass |generateBytecode|", function() { it("defines correct constants", function() { expect(pass).toChangeAST( grammar, - constsDetails(['peg$anyExpectation()']) + constsDetails(["peg$anyExpectation()"]) ); }); }); diff --git a/spec/unit/compiler/passes/remove-proxy-rules.spec.js b/spec/unit/compiler/passes/remove-proxy-rules.spec.js index d989a8b..6e81a23 100644 --- a/spec/unit/compiler/passes/remove-proxy-rules.spec.js +++ b/spec/unit/compiler/passes/remove-proxy-rules.spec.js @@ -9,9 +9,9 @@ describe("compiler pass |removeProxyRules|", function() { it("updates references and removes it", function() { expect(pass).toChangeAST( [ - 'start = proxy', - 'proxy = proxied', - 'proxied = "a"' + "start = proxy", + "proxy = proxied", + "proxied = 'a'" ].join("\n"), { rules: [ @@ -31,9 +31,9 @@ describe("compiler pass |removeProxyRules|", function() { it("updates references but doesn't remove it", function() { expect(pass).toChangeAST( [ - 'start = proxy', - 'proxy = proxied', - 'proxied = "a"' + "start = proxy", + "proxy = proxied", + "proxied = 'a'" ].join("\n"), { rules: [ diff --git a/spec/unit/compiler/passes/report-duplicate-labels.spec.js b/spec/unit/compiler/passes/report-duplicate-labels.spec.js index 3d8aa43..c4b7551 100644 --- a/spec/unit/compiler/passes/report-duplicate-labels.spec.js +++ b/spec/unit/compiler/passes/report-duplicate-labels.spec.js @@ -7,8 +7,8 @@ describe("compiler pass |reportDuplicateLabels|", function() { describe("in a sequence", function() { it("reports labels duplicate with labels of preceding elements", function() { - expect(pass).toReportError('start = a:"a" a:"a"', { - message: 'Label "a" is already defined at line 1, column 9.', + expect(pass).toReportError("start = a:'a' a:'a'", { + message: "Label \"a\" is already defined at line 1, column 9.", location: { start: { offset: 14, line: 1, column: 15 }, end: { offset: 19, line: 1, column: 20 } @@ -17,30 +17,30 @@ describe("compiler pass |reportDuplicateLabels|", function() { }); it("doesn't report labels duplicate with labels in subexpressions", function() { - expect(pass).not.toReportError('start = ("a" / a:"a" / "a") a:"a"'); - expect(pass).not.toReportError('start = (a:"a" { }) a:"a"'); - expect(pass).not.toReportError('start = ("a" a:"a" "a") a:"a"'); - expect(pass).not.toReportError('start = b:(a:"a") a:"a"'); - expect(pass).not.toReportError('start = $(a:"a") a:"a"'); - expect(pass).not.toReportError('start = &(a:"a") a:"a"'); - expect(pass).not.toReportError('start = !(a:"a") a:"a"'); - expect(pass).not.toReportError('start = (a:"a")? a:"a"'); - expect(pass).not.toReportError('start = (a:"a")* a:"a"'); - expect(pass).not.toReportError('start = (a:"a")+ a:"a"'); - expect(pass).not.toReportError('start = (a:"a") a:"a"'); + expect(pass).not.toReportError("start = ('a' / a:'a' / 'a') a:'a'"); + expect(pass).not.toReportError("start = (a:'a' { }) a:'a'"); + expect(pass).not.toReportError("start = ('a' a:'a' 'a') a:'a'"); + expect(pass).not.toReportError("start = b:(a:'a') a:'a'"); + expect(pass).not.toReportError("start = $(a:'a') a:'a'"); + expect(pass).not.toReportError("start = &(a:'a') a:'a'"); + expect(pass).not.toReportError("start = !(a:'a') a:'a'"); + expect(pass).not.toReportError("start = (a:'a')? a:'a'"); + expect(pass).not.toReportError("start = (a:'a')* a:'a'"); + expect(pass).not.toReportError("start = (a:'a')+ a:'a'"); + expect(pass).not.toReportError("start = (a:'a') a:'a'"); }); }); describe("in a choice", function() { it("doesn't report labels duplicate with labels of preceding alternatives", function() { - expect(pass).not.toReportError('start = a:"a" / a:"a"'); + expect(pass).not.toReportError("start = a:'a' / a:'a'"); }); }); describe("in outer sequence", function() { it("reports labels duplicate with labels of preceding elements", function() { - expect(pass).toReportError('start = a:"a" (a:"a")', { - message: 'Label "a" is already defined at line 1, column 9.', + expect(pass).toReportError("start = a:'a' (a:'a')", { + message: "Label \"a\" is already defined at line 1, column 9.", location: { start: { offset: 15, line: 1, column: 16 }, end: { offset: 20, line: 1, column: 21 } @@ -49,11 +49,11 @@ describe("compiler pass |reportDuplicateLabels|", function() { }); it("doesn't report labels duplicate with the label of the current element", function() { - expect(pass).not.toReportError('start = a:(a:"a")'); + expect(pass).not.toReportError("start = a:(a:'a')"); }); it("doesn't report labels duplicate with labels of following elements", function() { - expect(pass).not.toReportError('start = (a:"a") a:"a"'); + expect(pass).not.toReportError("start = (a:'a') a:'a'"); }); }); }); diff --git a/spec/unit/compiler/passes/report-duplicate-rules.spec.js b/spec/unit/compiler/passes/report-duplicate-rules.spec.js index 46c31b4..e1a7773 100644 --- a/spec/unit/compiler/passes/report-duplicate-rules.spec.js +++ b/spec/unit/compiler/passes/report-duplicate-rules.spec.js @@ -7,10 +7,10 @@ describe("compiler pass |reportDuplicateRules|", function() { it("reports duplicate rules", function() { expect(pass).toReportError([ - 'start = "a"', - 'start = "b"' - ].join('\n'), { - message: 'Rule "start" is already defined at line 1, column 1.', + "start = 'a'", + "start = 'b'" + ].join("\n"), { + message: "Rule \"start\" is already defined at line 1, column 1.", location: { start: { offset: 12, line: 2, column: 1 }, end: { offset: 23, line: 2, column: 12 } diff --git a/spec/unit/compiler/passes/report-infinite-recursion.spec.js b/spec/unit/compiler/passes/report-infinite-recursion.spec.js index 0fda874..90dfd80 100644 --- a/spec/unit/compiler/passes/report-infinite-recursion.spec.js +++ b/spec/unit/compiler/passes/report-infinite-recursion.spec.js @@ -6,8 +6,8 @@ describe("compiler pass |reportInfiniteRecursion|", function() { let pass = peg.compiler.passes.check.reportInfiniteRecursion; it("reports direct left recursion", function() { - expect(pass).toReportError('start = start', { - message: 'Possible infinite loop when parsing (left recursion: start -> start).', + expect(pass).toReportError("start = start", { + message: "Possible infinite loop when parsing (left recursion: start -> start).", location: { start: { offset: 8, line: 1, column: 9 }, end: { offset: 13, line: 1, column: 14 } @@ -17,10 +17,10 @@ describe("compiler pass |reportInfiniteRecursion|", function() { it("reports indirect left recursion", function() { expect(pass).toReportError([ - 'start = stop', - 'stop = start' + "start = stop", + "stop = start" ].join("\n"), { - message: 'Possible infinite loop when parsing (left recursion: start -> stop -> start).', + message: "Possible infinite loop when parsing (left recursion: start -> stop -> start).", location: { start: { offset: 21, line: 2, column: 9 }, end: { offset: 26, line: 2, column: 14 } @@ -30,86 +30,86 @@ describe("compiler pass |reportInfiniteRecursion|", function() { describe("in sequences", function() { it("reports left recursion if all preceding elements match empty string", function() { - expect(pass).toReportError('start = "" "" "" start'); + expect(pass).toReportError("start = '' '' '' start"); }); it("doesn't report left recursion if some preceding element doesn't match empty string", function() { - expect(pass).not.toReportError('start = "a" "" "" start'); - expect(pass).not.toReportError('start = "" "a" "" start'); - expect(pass).not.toReportError('start = "" "" "a" start'); + expect(pass).not.toReportError("start = 'a' '' '' start"); + expect(pass).not.toReportError("start = '' 'a' '' start"); + expect(pass).not.toReportError("start = '' '' 'a' start"); }); // Regression test for #359. it("reports left recursion when rule reference is wrapped in an expression", function() { - expect(pass).toReportError('start = "" start?'); + expect(pass).toReportError("start = '' start?"); }); it("computes expressions that always consume input on success correctly", function() { expect(pass).toReportError([ - 'start = a start', - 'a "a" = ""' - ].join('\n')); + "start = a start", + "a 'a' = ''" + ].join("\n")); expect(pass).not.toReportError([ - 'start = a start', - 'a "a" = "a"' - ].join('\n')); + "start = a start", + "a 'a' = 'a'" + ].join("\n")); - expect(pass).toReportError('start = ("" / "a" / "b") start'); - expect(pass).toReportError('start = ("a" / "" / "b") start'); - expect(pass).toReportError('start = ("a" / "b" / "") start'); - expect(pass).not.toReportError('start = ("a" / "b" / "c") start'); + expect(pass).toReportError("start = ('' / 'a' / 'b') start"); + expect(pass).toReportError("start = ('a' / '' / 'b') start"); + expect(pass).toReportError("start = ('a' / 'b' / '') start"); + expect(pass).not.toReportError("start = ('a' / 'b' / 'c') start"); - expect(pass).toReportError('start = ("" { }) start'); - expect(pass).not.toReportError('start = ("a" { }) start'); + expect(pass).toReportError("start = ('' { }) start"); + expect(pass).not.toReportError("start = ('a' { }) start"); - expect(pass).toReportError('start = ("" "" "") start'); - expect(pass).not.toReportError('start = ("a" "" "") start'); - expect(pass).not.toReportError('start = ("" "a" "") start'); - expect(pass).not.toReportError('start = ("" "" "a") start'); + expect(pass).toReportError("start = ('' '' '') start"); + expect(pass).not.toReportError("start = ('a' '' '') start"); + expect(pass).not.toReportError("start = ('' 'a' '') start"); + expect(pass).not.toReportError("start = ('' '' 'a') start"); - expect(pass).toReportError('start = a:"" start'); - expect(pass).not.toReportError('start = a:"a" start'); + expect(pass).toReportError("start = a:'' start"); + expect(pass).not.toReportError("start = a:'a' start"); - expect(pass).toReportError('start = $"" start'); - expect(pass).not.toReportError('start = $"a" start'); + expect(pass).toReportError("start = $'' start"); + expect(pass).not.toReportError("start = $'a' start"); - expect(pass).toReportError('start = &"" start'); - expect(pass).toReportError('start = &"a" start'); + expect(pass).toReportError("start = &'' start"); + expect(pass).toReportError("start = &'a' start"); - expect(pass).toReportError('start = !"" start'); - expect(pass).toReportError('start = !"a" start'); + expect(pass).toReportError("start = !'' start"); + expect(pass).toReportError("start = !'a' start"); - expect(pass).toReportError('start = ""? start'); - expect(pass).toReportError('start = "a"? start'); + expect(pass).toReportError("start = ''? start"); + expect(pass).toReportError("start = 'a'? start"); - expect(pass).toReportError('start = ""* start'); - expect(pass).toReportError('start = "a"* start'); + expect(pass).toReportError("start = ''* start"); + expect(pass).toReportError("start = 'a'* start"); - expect(pass).toReportError('start = ""+ start'); - expect(pass).not.toReportError('start = "a"+ start'); + expect(pass).toReportError("start = ''+ start"); + expect(pass).not.toReportError("start = 'a'+ start"); - expect(pass).toReportError('start = ("") start'); - expect(pass).not.toReportError('start = ("a") start'); + expect(pass).toReportError("start = ('') start"); + expect(pass).not.toReportError("start = ('a') start"); - expect(pass).toReportError('start = &{ } start'); + expect(pass).toReportError("start = &{ } start"); - expect(pass).toReportError('start = !{ } start'); + expect(pass).toReportError("start = !{ } start"); expect(pass).toReportError([ - 'start = a start', - 'a = ""' - ].join('\n')); + "start = a start", + "a = ''" + ].join("\n")); expect(pass).not.toReportError([ - 'start = a start', - 'a = "a"' - ].join('\n')); + "start = a start", + "a = 'a'" + ].join("\n")); - expect(pass).toReportError('start = "" start'); - expect(pass).not.toReportError('start = "a" start'); + expect(pass).toReportError("start = '' start"); + expect(pass).not.toReportError("start = 'a' start"); - expect(pass).not.toReportError('start = [a-d] start'); + expect(pass).not.toReportError("start = [a-d] start"); - expect(pass).not.toReportError('start = . start'); + expect(pass).not.toReportError("start = . start"); }); }); }); diff --git a/spec/unit/compiler/passes/report-infinite-repetition.spec.js b/spec/unit/compiler/passes/report-infinite-repetition.spec.js index eccc349..8e9029a 100644 --- a/spec/unit/compiler/passes/report-infinite-repetition.spec.js +++ b/spec/unit/compiler/passes/report-infinite-repetition.spec.js @@ -6,7 +6,7 @@ describe("compiler pass |reportInfiniteRepetition|", function() { let pass = peg.compiler.passes.check.reportInfiniteRepetition; it("reports infinite loops for zero_or_more", function() { - expect(pass).toReportError('start = ("")*', { + expect(pass).toReportError("start = ('')*", { message: "Possible infinite loop when parsing (repetition used with an expression that may not consume any input).", location: { start: { offset: 8, line: 1, column: 9 }, @@ -16,7 +16,7 @@ describe("compiler pass |reportInfiniteRepetition|", function() { }); it("reports infinite loops for one_or_more", function() { - expect(pass).toReportError('start = ("")+', { + expect(pass).toReportError("start = ('')+", { message: "Possible infinite loop when parsing (repetition used with an expression that may not consume any input).", location: { start: { offset: 8, line: 1, column: 9 }, @@ -27,69 +27,69 @@ describe("compiler pass |reportInfiniteRepetition|", function() { it("computes expressions that always consume input on success correctly", function() { expect(pass).toReportError([ - 'start = a*', - 'a "a" = ""' - ].join('\n')); + "start = a*", + "a 'a' = ''" + ].join("\n")); expect(pass).not.toReportError([ - 'start = a*', - 'a "a" = "a"' - ].join('\n')); + "start = a*", + "a 'a' = 'a'" + ].join("\n")); - expect(pass).toReportError('start = ("" / "a" / "b")*'); - expect(pass).toReportError('start = ("a" / "" / "b")*'); - expect(pass).toReportError('start = ("a" / "b" / "")*'); - expect(pass).not.toReportError('start = ("a" / "b" / "c")*'); + expect(pass).toReportError("start = ('' / 'a' / 'b')*"); + expect(pass).toReportError("start = ('a' / '' / 'b')*"); + expect(pass).toReportError("start = ('a' / 'b' / '')*"); + expect(pass).not.toReportError("start = ('a' / 'b' / 'c')*"); - expect(pass).toReportError('start = ("" { })*'); - expect(pass).not.toReportError('start = ("a" { })*'); + expect(pass).toReportError("start = ('' { })*"); + expect(pass).not.toReportError("start = ('a' { })*"); - expect(pass).toReportError('start = ("" "" "")*'); - expect(pass).not.toReportError('start = ("a" "" "")*'); - expect(pass).not.toReportError('start = ("" "a" "")*'); - expect(pass).not.toReportError('start = ("" "" "a")*'); + expect(pass).toReportError("start = ('' '' '')*"); + expect(pass).not.toReportError("start = ('a' '' '')*"); + expect(pass).not.toReportError("start = ('' 'a' '')*"); + expect(pass).not.toReportError("start = ('' '' 'a')*"); - expect(pass).toReportError('start = (a:"")*'); - expect(pass).not.toReportError('start = (a:"a")*'); + expect(pass).toReportError("start = (a:'')*"); + expect(pass).not.toReportError("start = (a:'a')*"); - expect(pass).toReportError('start = ($"")*'); - expect(pass).not.toReportError('start = ($"a")*'); + expect(pass).toReportError("start = ($'')*"); + expect(pass).not.toReportError("start = ($'a')*"); - expect(pass).toReportError('start = (&"")*'); - expect(pass).toReportError('start = (&"a")*'); + expect(pass).toReportError("start = (&'')*"); + expect(pass).toReportError("start = (&'a')*"); - expect(pass).toReportError('start = (!"")*'); - expect(pass).toReportError('start = (!"a")*'); + expect(pass).toReportError("start = (!'')*"); + expect(pass).toReportError("start = (!'a')*"); - expect(pass).toReportError('start = (""?)*'); - expect(pass).toReportError('start = ("a"?)*'); + expect(pass).toReportError("start = (''?)*"); + expect(pass).toReportError("start = ('a'?)*"); - expect(pass).toReportError('start = (""*)*'); - expect(pass).toReportError('start = ("a"*)*'); + expect(pass).toReportError("start = (''*)*"); + expect(pass).toReportError("start = ('a'*)*"); - expect(pass).toReportError('start = (""+)*'); - expect(pass).not.toReportError('start = ("a"+)*'); + expect(pass).toReportError("start = (''+)*"); + expect(pass).not.toReportError("start = ('a'+)*"); - expect(pass).toReportError('start = ("")*'); - expect(pass).not.toReportError('start = ("a")*'); + expect(pass).toReportError("start = ('')*"); + expect(pass).not.toReportError("start = ('a')*"); - expect(pass).toReportError('start = (&{ })*'); + expect(pass).toReportError("start = (&{ })*"); - expect(pass).toReportError('start = (!{ })*'); + expect(pass).toReportError("start = (!{ })*"); expect(pass).toReportError([ - 'start = a*', - 'a = ""' - ].join('\n')); + "start = a*", + "a = ''" + ].join("\n")); expect(pass).not.toReportError([ - 'start = a*', - 'a = "a"' - ].join('\n')); + "start = a*", + "a = 'a'" + ].join("\n")); - expect(pass).toReportError('start = ""*'); - expect(pass).not.toReportError('start = "a"*'); + expect(pass).toReportError("start = ''*"); + expect(pass).not.toReportError("start = 'a'*"); - expect(pass).not.toReportError('start = [a-d]*'); + expect(pass).not.toReportError("start = [a-d]*"); - expect(pass).not.toReportError('start = .*'); + expect(pass).not.toReportError("start = .*"); }); }); diff --git a/spec/unit/compiler/passes/report-undefined-rules.spec.js b/spec/unit/compiler/passes/report-undefined-rules.spec.js index 3f4df85..18c07ab 100644 --- a/spec/unit/compiler/passes/report-undefined-rules.spec.js +++ b/spec/unit/compiler/passes/report-undefined-rules.spec.js @@ -6,8 +6,8 @@ describe("compiler pass |reportUndefinedRules|", function() { let pass = peg.compiler.passes.check.reportUndefinedRules; it("reports undefined rules", function() { - expect(pass).toReportError('start = undefined', { - message: 'Rule "undefined" is not defined.', + expect(pass).toReportError("start = undefined", { + message: "Rule \"undefined\" is not defined.", location: { start: { offset: 8, line: 1, column: 9 }, end: { offset: 17, line: 1, column: 18 } diff --git a/spec/unit/parser.spec.js b/spec/unit/parser.spec.js index c7d1ac4..8a35487 100644 --- a/spec/unit/parser.spec.js +++ b/spec/unit/parser.spec.js @@ -236,252 +236,252 @@ describe("PEG.js grammar parser", function() { }); }); - // Canonical Grammar is "a = \"abcd\"; b = \"efgh\"; c = \"ijkl\";". + // Canonical Grammar is "a = 'abcd'; b = 'efgh'; c = 'ijkl';". it("parses Grammar", function() { - expect('\na = "abcd";\n').toParseAs( + expect("\na = 'abcd';\n").toParseAs( { type: "grammar", initializer: null, rules: [ruleA] } ); - expect('\na = "abcd";\nb = "efgh";\nc = "ijkl";\n').toParseAs( + expect("\na = 'abcd';\nb = 'efgh';\nc = 'ijkl';\n").toParseAs( { type: "grammar", initializer: null, rules: [ruleA, ruleB, ruleC] } ); - expect('\n{ code };\na = "abcd";\n').toParseAs( + expect("\n{ code };\na = 'abcd';\n").toParseAs( { type: "grammar", initializer: initializer, rules: [ruleA] } ); }); // Canonical Initializer is "{ code }". it("parses Initializer", function() { - expect('{ code };start = "abcd"').toParseAs( + expect("{ code };start = 'abcd'").toParseAs( { type: "grammar", initializer: initializer, rules: [ruleStart] } ); }); - // Canonical Rule is "a = \"abcd\";". + // Canonical Rule is "a = 'abcd';". it("parses Rule", function() { - expect('start\n=\n"abcd";').toParseAs( + expect("start\n=\n'abcd';").toParseAs( oneRuleGrammar(literalAbcd) ); - expect('start\n"start rule"\n=\n"abcd";').toParseAs( + expect("start\n'start rule'\n=\n'abcd';").toParseAs( oneRuleGrammar(named) ); }); - // Canonical Expression is "\"abcd\"". + // Canonical Expression is "'abcd'". it("parses Expression", function() { - expect('start = "abcd" / "efgh" / "ijkl"').toParseAs( + expect("start = 'abcd' / 'efgh' / 'ijkl'").toParseAs( oneRuleGrammar(choice) ); }); - // Canonical ChoiceExpression is "\"abcd\" / \"efgh\" / \"ijkl\"". + // Canonical ChoiceExpression is "'abcd' / 'efgh' / 'ijkl'". it("parses ChoiceExpression", function() { - expect('start = "abcd" { code }').toParseAs( + expect("start = 'abcd' { code }").toParseAs( oneRuleGrammar(actionAbcd) ); - expect('start = "abcd" { code }\n/\n"efgh" { code }').toParseAs( + expect("start = 'abcd' { code }\n/\n'efgh' { code }").toParseAs( oneRuleGrammar(choice2) ); expect( - 'start = "abcd" { code }\n/\n"efgh" { code }\n/\n"ijkl" { code }\n/\n"mnop" { code }' + "start = 'abcd' { code }\n/\n'efgh' { code }\n/\n'ijkl' { code }\n/\n'mnop' { code }" ).toParseAs( oneRuleGrammar(choice4) ); }); - // Canonical ActionExpression is "\"abcd\" { code }". + // Canonical ActionExpression is "'abcd' { code }". it("parses ActionExpression", function() { - expect('start = "abcd" "efgh" "ijkl"').toParseAs( + expect("start = 'abcd' 'efgh' 'ijkl'").toParseAs( oneRuleGrammar(sequence) ); - expect('start = "abcd" "efgh" "ijkl"\n{ code }').toParseAs( + expect("start = 'abcd' 'efgh' 'ijkl'\n{ code }").toParseAs( oneRuleGrammar(actionSequence) ); }); - // Canonical SequenceExpression is "\"abcd\" \"efgh\" \"ijkl\"". + // Canonical SequenceExpression is "'abcd' 'efgh' 'ijkl'". it("parses SequenceExpression", function() { - expect('start = a:"abcd"').toParseAs( + expect("start = a:'abcd'").toParseAs( oneRuleGrammar(labeledAbcd) ); - expect('start = a:"abcd"\nb:"efgh"').toParseAs( + expect("start = a:'abcd'\nb:'efgh'").toParseAs( oneRuleGrammar(sequence2) ); - expect('start = a:"abcd"\nb:"efgh"\nc:"ijkl"\nd:"mnop"').toParseAs( + expect("start = a:'abcd'\nb:'efgh'\nc:'ijkl'\nd:'mnop'").toParseAs( oneRuleGrammar(sequence4) ); }); - // Canonical LabeledExpression is "a:\"abcd\"". + // Canonical LabeledExpression is "a:'abcd'". it("parses LabeledExpression", function() { - expect('start = a\n:\n!"abcd"').toParseAs(oneRuleGrammar(labeledSimpleNot)); - expect('start = !"abcd"' ).toParseAs(oneRuleGrammar(simpleNotAbcd)); + expect("start = a\n:\n!'abcd'").toParseAs(oneRuleGrammar(labeledSimpleNot)); + expect("start = !'abcd'" ).toParseAs(oneRuleGrammar(simpleNotAbcd)); }); - // Canonical PrefixedExpression is "!\"abcd\"". + // Canonical PrefixedExpression is "!'abcd'". it("parses PrefixedExpression", function() { - expect('start = !\n"abcd"?' ).toParseAs(oneRuleGrammar(simpleNotOptional)); - expect('start = "abcd"?' ).toParseAs(oneRuleGrammar(optional)); + expect("start = !\n'abcd'?" ).toParseAs(oneRuleGrammar(simpleNotOptional)); + expect("start = 'abcd'?" ).toParseAs(oneRuleGrammar(optional)); }); // Canonical PrefixedOperator is "!". it("parses PrefixedOperator", function() { - expect('start = $"abcd"?').toParseAs(oneRuleGrammar(textOptional)); - expect('start = &"abcd"?').toParseAs(oneRuleGrammar(simpleAndOptional)); - expect('start = !"abcd"?').toParseAs(oneRuleGrammar(simpleNotOptional)); + expect("start = $'abcd'?").toParseAs(oneRuleGrammar(textOptional)); + expect("start = &'abcd'?").toParseAs(oneRuleGrammar(simpleAndOptional)); + expect("start = !'abcd'?").toParseAs(oneRuleGrammar(simpleNotOptional)); }); - // Canonical SuffixedExpression is "\"ebcd\"?". + // Canonical SuffixedExpression is "'ebcd'?". it("parses SuffixedExpression", function() { - expect('start = "abcd"\n?').toParseAs(oneRuleGrammar(optional)); - expect('start = "abcd"' ).toParseAs(oneRuleGrammar(literalAbcd)); + expect("start = 'abcd'\n?").toParseAs(oneRuleGrammar(optional)); + expect("start = 'abcd'" ).toParseAs(oneRuleGrammar(literalAbcd)); }); // Canonical SuffixedOperator is "?". it("parses SuffixedOperator", function() { - expect('start = "abcd"?').toParseAs(oneRuleGrammar(optional)); - expect('start = "abcd"*').toParseAs(oneRuleGrammar(zeroOrMore)); - expect('start = "abcd"+').toParseAs(oneRuleGrammar(oneOrMore)); + expect("start = 'abcd'?").toParseAs(oneRuleGrammar(optional)); + expect("start = 'abcd'*").toParseAs(oneRuleGrammar(zeroOrMore)); + expect("start = 'abcd'+").toParseAs(oneRuleGrammar(oneOrMore)); }); - // Canonical PrimaryExpression is "\"abcd\"". + // Canonical PrimaryExpression is "'abcd'". it("parses PrimaryExpression", function() { - expect('start = "abcd"' ).toParseAs(trivialGrammar); - expect('start = [a-d]' ).toParseAs(classGrammar([["a", "d"]], false, false)); - expect('start = .' ).toParseAs(anyGrammar()); - expect('start = a' ).toParseAs(ruleRefGrammar("a")); - expect('start = &{ code }').toParseAs(oneRuleGrammar(semanticAnd)); + expect("start = 'abcd'" ).toParseAs(trivialGrammar); + expect("start = [a-d]" ).toParseAs(classGrammar([["a", "d"]], false, false)); + expect("start = ." ).toParseAs(anyGrammar()); + expect("start = a" ).toParseAs(ruleRefGrammar("a")); + expect("start = &{ code }").toParseAs(oneRuleGrammar(semanticAnd)); - expect('start = (\na:"abcd"\n)' ).toParseAs(oneRuleGrammar(groupLabeled)); - expect('start = (\n"abcd" "efgh" "ijkl"\n)').toParseAs(oneRuleGrammar(groupSequence)); - expect('start = (\n"abcd"\n)' ).toParseAs(trivialGrammar); + expect("start = (\na:'abcd'\n)" ).toParseAs(oneRuleGrammar(groupLabeled)); + expect("start = (\n'abcd' 'efgh' 'ijkl'\n)").toParseAs(oneRuleGrammar(groupSequence)); + expect("start = (\n'abcd'\n)" ).toParseAs(trivialGrammar); }); // Canonical RuleReferenceExpression is "a". it("parses RuleReferenceExpression", function() { - expect('start = a').toParseAs(ruleRefGrammar("a")); + expect("start = a").toParseAs(ruleRefGrammar("a")); - expect('start = a\n=' ).toFailToParse(); - expect('start = a\n"abcd"\n=').toFailToParse(); + expect("start = a\n=" ).toFailToParse(); + expect("start = a\n'abcd'\n=").toFailToParse(); }); // Canonical SemanticPredicateExpression is "!{ code }". it("parses SemanticPredicateExpression", function() { - expect('start = !\n{ code }').toParseAs(oneRuleGrammar(semanticNot)); + expect("start = !\n{ code }").toParseAs(oneRuleGrammar(semanticNot)); }); // Canonical SemanticPredicateOperator is "!". it("parses SemanticPredicateOperator", function() { - expect('start = &{ code }').toParseAs(oneRuleGrammar(semanticAnd)); - expect('start = !{ code }').toParseAs(oneRuleGrammar(semanticNot)); + expect("start = &{ code }").toParseAs(oneRuleGrammar(semanticAnd)); + expect("start = !{ code }").toParseAs(oneRuleGrammar(semanticNot)); }); // The SourceCharacter rule is not tested. // Canonical WhiteSpace is " ". it("parses WhiteSpace", function() { - expect('start =\t"abcd"' ).toParseAs(trivialGrammar); - expect('start =\v"abcd"' ).toParseAs(trivialGrammar); - expect('start =\f"abcd"' ).toParseAs(trivialGrammar); - expect('start = "abcd"' ).toParseAs(trivialGrammar); - expect('start =\u00A0"abcd"').toParseAs(trivialGrammar); - expect('start =\uFEFF"abcd"').toParseAs(trivialGrammar); - expect('start =\u1680"abcd"').toParseAs(trivialGrammar); + expect("start =\t'abcd'" ).toParseAs(trivialGrammar); + expect("start =\v'abcd'" ).toParseAs(trivialGrammar); + expect("start =\f'abcd'" ).toParseAs(trivialGrammar); + expect("start = 'abcd'" ).toParseAs(trivialGrammar); + expect("start =\u00A0'abcd'").toParseAs(trivialGrammar); + expect("start =\uFEFF'abcd'").toParseAs(trivialGrammar); + expect("start =\u1680'abcd'").toParseAs(trivialGrammar); }); // Canonical LineTerminator is "\n". it("parses LineTerminator", function() { - expect('start = "\n"' ).toFailToParse(); - expect('start = "\r"' ).toFailToParse(); - expect('start = "\u2028"').toFailToParse(); - expect('start = "\u2029"').toFailToParse(); + expect("start = '\n'" ).toFailToParse(); + expect("start = '\r'" ).toFailToParse(); + expect("start = '\u2028'").toFailToParse(); + expect("start = '\u2029'").toFailToParse(); }); // Canonical LineTerminatorSequence is "\r\n". it("parses LineTerminatorSequence", function() { - expect('start =\n"abcd"' ).toParseAs(trivialGrammar); - expect('start =\r\n"abcd"' ).toParseAs(trivialGrammar); - expect('start =\r"abcd"' ).toParseAs(trivialGrammar); - expect('start =\u2028"abcd"').toParseAs(trivialGrammar); - expect('start =\u2029"abcd"').toParseAs(trivialGrammar); + expect("start =\n'abcd'" ).toParseAs(trivialGrammar); + expect("start =\r\n'abcd'" ).toParseAs(trivialGrammar); + expect("start =\r'abcd'" ).toParseAs(trivialGrammar); + expect("start =\u2028'abcd'").toParseAs(trivialGrammar); + expect("start =\u2029'abcd'").toParseAs(trivialGrammar); }); // Canonical Comment is "/* comment */". it("parses Comment", function() { - expect('start =// comment\n"abcd"' ).toParseAs(trivialGrammar); - expect('start =/* comment */"abcd"').toParseAs(trivialGrammar); + expect("start =// comment\n'abcd'" ).toParseAs(trivialGrammar); + expect("start =/* comment */'abcd'").toParseAs(trivialGrammar); }); // Canonical MultiLineComment is "/* comment */". it("parses MultiLineComment", function() { - expect('start =/**/"abcd"' ).toParseAs(trivialGrammar); - expect('start =/*a*/"abcd"' ).toParseAs(trivialGrammar); - expect('start =/*abc*/"abcd"').toParseAs(trivialGrammar); + expect("start =/**/'abcd'" ).toParseAs(trivialGrammar); + expect("start =/*a*/'abcd'" ).toParseAs(trivialGrammar); + expect("start =/*abc*/'abcd'").toParseAs(trivialGrammar); - expect('start =/**/*/"abcd"').toFailToParse(); + expect("start =/**/*/'abcd'").toFailToParse(); }); // Canonical MultiLineCommentNoLineTerminator is "/* comment */". it("parses MultiLineCommentNoLineTerminator", function() { - expect('a = "abcd"/**/\r\nb = "efgh"' ).toParseAs(twoRuleGrammar); - expect('a = "abcd"/*a*/\r\nb = "efgh"' ).toParseAs(twoRuleGrammar); - expect('a = "abcd"/*abc*/\r\nb = "efgh"').toParseAs(twoRuleGrammar); + expect("a = 'abcd'/**/\r\nb = 'efgh'" ).toParseAs(twoRuleGrammar); + expect("a = 'abcd'/*a*/\r\nb = 'efgh'" ).toParseAs(twoRuleGrammar); + expect("a = 'abcd'/*abc*/\r\nb = 'efgh'").toParseAs(twoRuleGrammar); - expect('a = "abcd"/**/*/\r\nb = "efgh"').toFailToParse(); - expect('a = "abcd"/*\n*/\r\nb = "efgh"').toFailToParse(); + expect("a = 'abcd'/**/*/\r\nb = 'efgh'").toFailToParse(); + expect("a = 'abcd'/*\n*/\r\nb = 'efgh'").toFailToParse(); }); // Canonical SingleLineComment is "// comment". it("parses SingleLineComment", function() { - expect('start =//\n"abcd"' ).toParseAs(trivialGrammar); - expect('start =//a\n"abcd"' ).toParseAs(trivialGrammar); - expect('start =//abc\n"abcd"').toParseAs(trivialGrammar); + expect("start =//\n'abcd'" ).toParseAs(trivialGrammar); + expect("start =//a\n'abcd'" ).toParseAs(trivialGrammar); + expect("start =//abc\n'abcd'").toParseAs(trivialGrammar); - expect('start =//\n@\n"abcd"').toFailToParse(); + expect("start =//\n@\n'abcd'").toFailToParse(); }); // Canonical Identifier is "a". it("parses Identifier", function() { - expect('start = a:"abcd"').toParseAs(oneRuleGrammar(labeledAbcd)); + expect("start = a:'abcd'").toParseAs(oneRuleGrammar(labeledAbcd)); }); // Canonical IdentifierName is "a". it("parses IdentifierName", function() { - expect('start = a' ).toParseAs(ruleRefGrammar("a")); - expect('start = ab' ).toParseAs(ruleRefGrammar("ab")); - expect('start = abcd').toParseAs(ruleRefGrammar("abcd")); + expect("start = a" ).toParseAs(ruleRefGrammar("a")); + expect("start = ab" ).toParseAs(ruleRefGrammar("ab")); + expect("start = abcd").toParseAs(ruleRefGrammar("abcd")); }); // Canonical IdentifierStart is "a". it("parses IdentifierStart", function() { - expect('start = a' ).toParseAs(ruleRefGrammar("a")); - expect('start = $' ).toParseAs(ruleRefGrammar("$")); - expect('start = _' ).toParseAs(ruleRefGrammar("_")); - expect('start = \\u0061').toParseAs(ruleRefGrammar("a")); + expect("start = a" ).toParseAs(ruleRefGrammar("a")); + expect("start = $" ).toParseAs(ruleRefGrammar("$")); + expect("start = _" ).toParseAs(ruleRefGrammar("_")); + expect("start = \\u0061").toParseAs(ruleRefGrammar("a")); }); // Canonical IdentifierPart is "a". it("parses IdentifierPart", function() { - expect('start = aa' ).toParseAs(ruleRefGrammar("aa")); - expect('start = a\u0300').toParseAs(ruleRefGrammar("a\u0300")); - expect('start = a0' ).toParseAs(ruleRefGrammar("a0")); - expect('start = a\u203F').toParseAs(ruleRefGrammar("a\u203F")); - expect('start = a\u200C').toParseAs(ruleRefGrammar("a\u200C")); - expect('start = a\u200D').toParseAs(ruleRefGrammar("a\u200D")); + expect("start = aa" ).toParseAs(ruleRefGrammar("aa")); + expect("start = a\u0300").toParseAs(ruleRefGrammar("a\u0300")); + expect("start = a0" ).toParseAs(ruleRefGrammar("a0")); + expect("start = a\u203F").toParseAs(ruleRefGrammar("a\u203F")); + expect("start = a\u200C").toParseAs(ruleRefGrammar("a\u200C")); + expect("start = a\u200D").toParseAs(ruleRefGrammar("a\u200D")); }); // Unicode rules and reserved word rules are not tested. - // Canonical LiteralMatcher is "\"abcd\"". + // Canonical LiteralMatcher is "'abcd'". it("parses LiteralMatcher", function() { - expect('start = "abcd"' ).toParseAs(literalGrammar("abcd", false)); - expect('start = "abcd"i').toParseAs(literalGrammar("abcd", true)); + expect("start = 'abcd'" ).toParseAs(literalGrammar("abcd", false)); + expect("start = 'abcd'i").toParseAs(literalGrammar("abcd", true)); }); - // Canonical StringLiteral is "\"abcd\"". + // Canonical StringLiteral is "'abcd'". it("parses StringLiteral", function() { - expect('start = ""' ).toParseAs(literalGrammar("", false)); - expect('start = "a"' ).toParseAs(literalGrammar("a", false)); - expect('start = "abc"').toParseAs(literalGrammar("abc", false)); + expect("start = \"\"" ).toParseAs(literalGrammar("", false)); + expect("start = \"a\"" ).toParseAs(literalGrammar("a", false)); + expect("start = \"abc\"").toParseAs(literalGrammar("abc", false)); expect("start = ''" ).toParseAs(literalGrammar("", false)); expect("start = 'a'" ).toParseAs(literalGrammar("a", false)); @@ -490,13 +490,13 @@ describe("PEG.js grammar parser", function() { // Canonical DoubleStringCharacter is "a". it("parses DoubleStringCharacter", function() { - expect('start = "a"' ).toParseAs(literalGrammar("a", false)); - expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false)); - expect('start = "\\\n"').toParseAs(literalGrammar("", false)); + expect("start = \"a\"" ).toParseAs(literalGrammar("a", false)); + expect("start = \"\\n\"" ).toParseAs(literalGrammar("\n", false)); + expect("start = \"\\\n\"").toParseAs(literalGrammar("", false)); - expect('start = """' ).toFailToParse(); - expect('start = "\\"').toFailToParse(); - expect('start = "\n"').toFailToParse(); + expect("start = \"\"\"").toFailToParse(); + expect("start = \"\\\"").toFailToParse(); + expect("start = \"\n\"").toFailToParse(); }); // Canonical SingleStringCharacter is "a". @@ -512,92 +512,92 @@ describe("PEG.js grammar parser", function() { // Canonical CharacterClassMatcher is "[a-d]". it("parses CharacterClassMatcher", function() { - expect('start = []').toParseAs( + expect("start = []").toParseAs( classGrammar([], false, false) ); - expect('start = [a-d]').toParseAs( + expect("start = [a-d]").toParseAs( classGrammar([["a", "d"]], false, false) ); - expect('start = [a]').toParseAs( + expect("start = [a]").toParseAs( classGrammar(["a"], false, false) ); - expect('start = [a-de-hi-l]').toParseAs( + expect("start = [a-de-hi-l]").toParseAs( classGrammar( [["a", "d"], ["e", "h"], ["i", "l"]], false, false ) ); - expect('start = [^a-d]').toParseAs( + expect("start = [^a-d]").toParseAs( classGrammar([["a", "d"]], true, false) ); - expect('start = [a-d]i').toParseAs( + expect("start = [a-d]i").toParseAs( classGrammar([["a", "d"]], false, true) ); - expect('start = [\\\n]').toParseAs( + expect("start = [\\\n]").toParseAs( classGrammar([], false, false) ); }); // Canonical ClassCharacterRange is "a-d". it("parses ClassCharacterRange", function() { - expect('start = [a-d]').toParseAs(classGrammar([["a", "d"]], false, false)); + expect("start = [a-d]").toParseAs(classGrammar([["a", "d"]], false, false)); - expect('start = [a-a]').toParseAs(classGrammar([["a", "a"]], false, false)); - expect('start = [b-a]').toFailToParse({ + expect("start = [a-a]").toParseAs(classGrammar([["a", "a"]], false, false)); + expect("start = [b-a]").toFailToParse({ message: "Invalid character range: b-a." }); }); // Canonical ClassCharacter is "a". it("parses ClassCharacter", function() { - expect('start = [a]' ).toParseAs(classGrammar(["a"], false, false)); - expect('start = [\\n]' ).toParseAs(classGrammar(["\n"], false, false)); - expect('start = [\\\n]').toParseAs(classGrammar([], false, false)); + expect("start = [a]" ).toParseAs(classGrammar(["a"], false, false)); + expect("start = [\\n]" ).toParseAs(classGrammar(["\n"], false, false)); + expect("start = [\\\n]").toParseAs(classGrammar([], false, false)); - expect('start = []]' ).toFailToParse(); - expect('start = [\\]').toFailToParse(); - expect('start = [\n]').toFailToParse(); + expect("start = []]" ).toFailToParse(); + expect("start = [\\]").toFailToParse(); + expect("start = [\n]").toFailToParse(); }); // Canonical LineContinuation is "\\\n". it("parses LineContinuation", function() { - expect('start = "\\\r\n"').toParseAs(literalGrammar("", false)); + expect("start = '\\\r\n'").toParseAs(literalGrammar("", false)); }); // Canonical EscapeSequence is "n". it("parses EscapeSequence", function() { - expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false)); - expect('start = "\\0"' ).toParseAs(literalGrammar("\x00", false)); - expect('start = "\\xFF"' ).toParseAs(literalGrammar("\xFF", false)); - expect('start = "\\uFFFF"').toParseAs(literalGrammar("\uFFFF", false)); + expect("start = '\\n'" ).toParseAs(literalGrammar("\n", false)); + expect("start = '\\0'" ).toParseAs(literalGrammar("\x00", false)); + expect("start = '\\xFF'" ).toParseAs(literalGrammar("\xFF", false)); + expect("start = '\\uFFFF'").toParseAs(literalGrammar("\uFFFF", false)); - expect('start = "\\09"').toFailToParse(); + expect("start = '\\09'").toFailToParse(); }); // Canonical CharacterEscapeSequence is "n". it("parses CharacterEscapeSequence", function() { - expect('start = "\\n"').toParseAs(literalGrammar("\n", false)); - expect('start = "\\a"').toParseAs(literalGrammar("a", false)); + expect("start = '\\n'").toParseAs(literalGrammar("\n", false)); + expect("start = '\\a'").toParseAs(literalGrammar("a", false)); }); // Canonical SingleEscapeCharacter is "n". it("parses SingleEscapeCharacter", function() { - expect('start = "\\\'"').toParseAs(literalGrammar("'", false)); - expect('start = "\\""' ).toParseAs(literalGrammar('"', false)); - expect('start = "\\\\"').toParseAs(literalGrammar("\\", false)); - expect('start = "\\b"' ).toParseAs(literalGrammar("\b", false)); - expect('start = "\\f"' ).toParseAs(literalGrammar("\f", false)); - expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false)); - expect('start = "\\r"' ).toParseAs(literalGrammar("\r", false)); - expect('start = "\\t"' ).toParseAs(literalGrammar("\t", false)); - expect('start = "\\v"' ).toParseAs(literalGrammar("\v", false)); + expect("start = '\\''" ).toParseAs(literalGrammar("'", false)); + expect("start = '\\\"'").toParseAs(literalGrammar("\"", false)); + expect("start = '\\\\'").toParseAs(literalGrammar("\\", false)); + expect("start = '\\b'" ).toParseAs(literalGrammar("\b", false)); + expect("start = '\\f'" ).toParseAs(literalGrammar("\f", false)); + expect("start = '\\n'" ).toParseAs(literalGrammar("\n", false)); + expect("start = '\\r'" ).toParseAs(literalGrammar("\r", false)); + expect("start = '\\t'" ).toParseAs(literalGrammar("\t", false)); + expect("start = '\\v'" ).toParseAs(literalGrammar("\v", false)); }); // Canonical NonEscapeCharacter is "a". it("parses NonEscapeCharacter", function() { - expect('start = "\\a"').toParseAs(literalGrammar("a", false)); + expect("start = '\\a'").toParseAs(literalGrammar("a", false)); // The negative predicate is impossible to test with PEG.js grammar // structure. @@ -608,66 +608,66 @@ describe("PEG.js grammar parser", function() { // Canonical HexEscapeSequence is "xFF". it("parses HexEscapeSequence", function() { - expect('start = "\\xFF"').toParseAs(literalGrammar("\xFF", false)); + expect("start = '\\xFF'").toParseAs(literalGrammar("\xFF", false)); }); // Canonical UnicodeEscapeSequence is "uFFFF". it("parses UnicodeEscapeSequence", function() { - expect('start = "\\uFFFF"').toParseAs(literalGrammar("\uFFFF", false)); + expect("start = '\\uFFFF'").toParseAs(literalGrammar("\uFFFF", false)); }); // Digit rules are not tested. // Canonical AnyMatcher is ".". it("parses AnyMatcher", function() { - expect('start = .').toParseAs(anyGrammar()); + expect("start = .").toParseAs(anyGrammar()); }); // Canonical CodeBlock is "{ code }". it("parses CodeBlock", function() { - expect('start = "abcd" { code }').toParseAs(actionGrammar(" code ")); + expect("start = 'abcd' { code }").toParseAs(actionGrammar(" code ")); }); // Canonical Code is " code ". it("parses Code", function() { - expect('start = "abcd" {a}' ).toParseAs(actionGrammar("a")); - expect('start = "abcd" {abc}' ).toParseAs(actionGrammar("abc")); - expect('start = "abcd" {{a}}' ).toParseAs(actionGrammar("{a}")); - expect('start = "abcd" {{a}{b}{c}}').toParseAs(actionGrammar("{a}{b}{c}")); + expect("start = 'abcd' {a}" ).toParseAs(actionGrammar("a")); + expect("start = 'abcd' {abc}" ).toParseAs(actionGrammar("abc")); + expect("start = 'abcd' {{a}}" ).toParseAs(actionGrammar("{a}")); + expect("start = 'abcd' {{a}{b}{c}}").toParseAs(actionGrammar("{a}{b}{c}")); - expect('start = "abcd" {{}').toFailToParse(); - expect('start = "abcd" {}}').toFailToParse(); + expect("start = 'abcd' {{}").toFailToParse(); + expect("start = 'abcd' {}}").toFailToParse(); }); // Unicode character category rules and token rules are not tested. // Canonical __ is "\n". it("parses __", function() { - expect('start ="abcd"' ).toParseAs(trivialGrammar); - expect('start = "abcd"' ).toParseAs(trivialGrammar); - expect('start =\r\n"abcd"' ).toParseAs(trivialGrammar); - expect('start =/* comment */"abcd"').toParseAs(trivialGrammar); - expect('start = "abcd"' ).toParseAs(trivialGrammar); + expect("start ='abcd'" ).toParseAs(trivialGrammar); + expect("start = 'abcd'" ).toParseAs(trivialGrammar); + expect("start =\r\n'abcd'" ).toParseAs(trivialGrammar); + expect("start =/* comment */'abcd'").toParseAs(trivialGrammar); + expect("start = 'abcd'" ).toParseAs(trivialGrammar); }); // Canonical _ is " ". it("parses _", function() { - expect('a = "abcd"\r\nb = "efgh"' ).toParseAs(twoRuleGrammar); - expect('a = "abcd" \r\nb = "efgh"' ).toParseAs(twoRuleGrammar); - expect('a = "abcd"/* comment */\r\nb = "efgh"').toParseAs(twoRuleGrammar); - expect('a = "abcd" \r\nb = "efgh"' ).toParseAs(twoRuleGrammar); + expect("a = 'abcd'\r\nb = 'efgh'" ).toParseAs(twoRuleGrammar); + expect("a = 'abcd' \r\nb = 'efgh'" ).toParseAs(twoRuleGrammar); + expect("a = 'abcd'/* comment */\r\nb = 'efgh'").toParseAs(twoRuleGrammar); + expect("a = 'abcd' \r\nb = 'efgh'" ).toParseAs(twoRuleGrammar); }); // Canonical EOS is ";". it("parses EOS", function() { - expect('a = "abcd"\n;b = "efgh"' ).toParseAs(twoRuleGrammar); - expect('a = "abcd" \r\nb = "efgh"' ).toParseAs(twoRuleGrammar); - expect('a = "abcd" // comment\r\nb = "efgh"').toParseAs(twoRuleGrammar); - expect('a = "abcd"\nb = "efgh"' ).toParseAs(twoRuleGrammar); + expect("a = 'abcd'\n;b = 'efgh'" ).toParseAs(twoRuleGrammar); + expect("a = 'abcd' \r\nb = 'efgh'" ).toParseAs(twoRuleGrammar); + expect("a = 'abcd' // comment\r\nb = 'efgh'").toParseAs(twoRuleGrammar); + expect("a = 'abcd'\nb = 'efgh'" ).toParseAs(twoRuleGrammar); }); // Canonical EOF is the end of input. it("parses EOF", function() { - expect('start = "abcd"\n').toParseAs(trivialGrammar); + expect("start = 'abcd'\n").toParseAs(trivialGrammar); }); }); diff --git a/src/parser.pegjs b/src/parser.pegjs index 0feb1fb..80f597b 100644 --- a/src/parser.pegjs +++ b/src/parser.pegjs @@ -179,7 +179,7 @@ PrimaryExpression // don't need to put it around nodes that can't contain any labels or // nodes that already isolate label scope themselves. This leaves us with // "labeled" and "sequence". - return expression.type === 'labeled' || expression.type === 'sequence' + return expression.type === "labeled" || expression.type === "sequence" ? { type: "group", expression: expression } : expression; }