diff --git a/spec/compiler/passes/compute-params.spec.js b/spec/compiler/passes/compute-params.spec.js index ec1bdee..16292f4 100644 --- a/spec/compiler/passes/compute-params.spec.js +++ b/spec/compiler/passes/compute-params.spec.js @@ -1,9 +1,20 @@ describe("compiler pass |computeParams|", function() { function pass(ast) { - PEG.compiler.passes.computeVarNames(ast); + PEG.compiler.passes.computeVarIndices(ast); PEG.compiler.passes.computeParams(ast); } + var result0 = { resultIndex: 0, subindices: [] }, + result0_0 = { resultIndex: 0, subindices: [0] }, + result0_1 = { resultIndex: 0, subindices: [1] }, + result0_1_0 = { resultIndex: 0, subindices: [1, 0] }, + result0_1_1 = { resultIndex: 0, subindices: [1, 1] }, + result0_1_2 = { resultIndex: 0, subindices: [1, 2] }, + result0_2 = { resultIndex: 0, subindices: [2] }, + result1_9 = { resultIndex: 1, subindices: [9] }, + result1 = { resultIndex: 1, subindices: [] }; + result2 = { resultIndex: 2, subindices: [] }; + function ruleDetails(details) { return { rules: [details] }; } function expressionDetails(details) { @@ -17,7 +28,7 @@ describe("compiler pass |computeParams|", function() { describe("basic cases", function() { it("computes params for an action", function() { expect(pass).toChangeAST('start = a:"a" { }', expressionDetails({ - params: { a: "result0" } + params: { a: result0 } })); }); @@ -25,7 +36,7 @@ describe("compiler pass |computeParams|", function() { expect(pass).toChangeAST('start = a:"a" &{ }', expressionDetails({ elements: [ {}, - { params: { a: "result0" } } + { params: { a: result0 } } ] })); }); @@ -34,7 +45,7 @@ describe("compiler pass |computeParams|", function() { expect(pass).toChangeAST('start = a:"a" !{ }', expressionDetails({ elements: [ {}, - { params: { a: "result0" } } + { params: { a: result0 } } ] })); }); @@ -44,7 +55,7 @@ describe("compiler pass |computeParams|", function() { it("computes params for a named", function() { expect(pass).toChangeAST( 'start "start" = a:"a" { }', - innerExpressionDetails({ params: { a: "result0" } }) + innerExpressionDetails({ params: { a: result0 } }) ); }); @@ -52,20 +63,20 @@ describe("compiler pass |computeParams|", function() { expect(pass).toChangeAST( 'start = a:"a" { } / "b" / "c"', expressionDetails({ - alternatives: [{ params: { a: "result0" } }, {}, {}] + alternatives: [{ params: { a: result0 } }, {}, {}] }) ); expect(pass).toChangeAST( 'start = "a" / "b" / c:"c" { }', expressionDetails({ - alternatives: [{}, {}, { params: { c: "result0" } }] + alternatives: [{}, {}, { params: { c: result0 } }] }) ); }); it("computes params for an action", function() { expect(pass).toChangeAST('start = (a:"a" { }) { }', innerExpressionDetails({ - params: { a: "result0" } + params: { a: result0 } })); }); @@ -73,50 +84,50 @@ describe("compiler pass |computeParams|", function() { expect(pass).toChangeAST( 'start = (a:"a" { }) "b" "c"', expressionDetails({ - elements: [{ params: { a: "result0" } }, {}, {}] + elements: [{ params: { a: result0 } }, {}, {}] }) ); expect(pass).toChangeAST( 'start = "a" "b" (c:"c" { })', expressionDetails({ - elements: [{}, {}, { params: { c: "result2" } }] + elements: [{}, {}, { params: { c: result2 } }] }) ); }); it("computes params for a labeled", function() { expect(pass).toChangeAST('start = a:(b:"b" { })', innerExpressionDetails({ - params: { b: "result0" } + params: { b: result0 } })); }); it("computes params for a simple and", function() { expect(pass).toChangeAST('start = &(a:"a" { })', innerExpressionDetails({ - params: { a: "result0" } + params: { a: result0 } })); }); it("computes params for a simple not", function() { expect(pass).toChangeAST('start = &(a:"a" { })', innerExpressionDetails({ - params: { a: "result0" } + params: { a: result0 } })); }); it("computes params for an optional", function() { expect(pass).toChangeAST('start = (a:"a" { })?', innerExpressionDetails({ - params: { a: "result0" } + params: { a: result0 } })); }); it("computes params for a zero or more", function() { expect(pass).toChangeAST('start = (a:"a" { })*', innerExpressionDetails({ - params: { a: "result1" } + params: { a: result1 } })); }); it("computes params for a one or more", function() { expect(pass).toChangeAST('start = (a:"a" { })+', innerExpressionDetails({ - params: { a: "result1" } + params: { a: result1 } })); }); }); @@ -139,38 +150,26 @@ describe("compiler pass |computeParams|", function() { expect(pass).toChangeAST( 'start = a:"a" b:"b" c:"c" { }', expressionDetails({ - params: { a: "result0[0]", b: "result0[1]", c: "result0[2]" } + params: { a: result0_0, b: result0_1, c: result0_2 } }) ); expect(pass).toChangeAST( 'start = a:"a" (b:"b" c:"c" d:"d") e:"e"{ }', expressionDetails({ params: { - a: "result0[0]", - b: "result0[1][0]", - c: "result0[1][1]", - d: "result0[1][2]", - e: "result0[2]" + a: result0_0, + b: result0_1_0, + c: result0_1_1, + d: result0_1_2, + e: result0_2 } }) ); - - /* - * Regression tests for a bug where e.g. resultVar names like |result10| - * were incorrectly treated as names derived from |result1|, leading to - * incorrect substitution. - */ - expect(pass).toChangeAST( - 'start = ("a" "b" "c" "d" "e" "f" "g" "h" "i" j:"j" { })*', - innerExpressionDetails({ - params: { j: "result1[9]" } // Buggy code put "result1[0]0" here. - }) - ); }); it("creates a new scope for a labeled", function() { expect(pass).toChangeAST('start = a:(b:"b") { }', expressionDetails({ - params: { a: "result0"} + params: { a: result0 } })); }); diff --git a/spec/compiler/passes/compute-var-indices.spec.js b/spec/compiler/passes/compute-var-indices.spec.js new file mode 100644 index 0000000..d57bac0 --- /dev/null +++ b/spec/compiler/passes/compute-var-indices.spec.js @@ -0,0 +1,229 @@ +describe("compiler pass |computeVarIndices|", function() { + var pass = PEG.compiler.passes.computeVarIndices; + + var leafDetails = { resultIndex: 0 }, + choiceDetails = { + resultIndex: 0, + alternatives: [ + { resultIndex: 0, posIndex: 0 }, + { resultIndex: 0, posIndex: 0 }, + { resultIndex: 0, posIndex: 0 } + ] + }, + sequenceDetails = { + resultIndex: 0, + posIndex: 0, + elements: [ + { resultIndex: 0, posIndex: 1 }, + { resultIndex: 1, posIndex: 1 }, + { resultIndex: 2, posIndex: 1 } + ] + }; + + function ruleDetails(details) { return { rules: [details] }; } + + it("computes variable indices for a named", function() { + expect(pass).toChangeAST('start "start" = &"a"', ruleDetails({ + resultIndices: [0], + posIndices: [0], + expression: { + resultIndex: 0, + expression: { resultIndex: 0, posIndex: 0 } + } + })); + }); + + it("computes variable indices for a choice", function() { + expect(pass).toChangeAST('start = &"a" / &"b" / &"c"', ruleDetails({ + resultIndices: [0], + posIndices: [0], + expression: choiceDetails + })); + expect(pass).toChangeAST('start = &"a" / &"b"* / &"c"', ruleDetails({ + resultIndices: [0, 1], + posIndices: [0], + expression: choiceDetails + })); + expect(pass).toChangeAST('start = &"a" / &(&"b") / &"c"', ruleDetails({ + resultIndices: [0], + posIndices: [0, 1], + expression: choiceDetails + })); + }); + + it("computes variable indices for an action", function() { + expect(pass).toChangeAST('start = &"a" { code }', ruleDetails({ + resultIndices: [0], + posIndices: [0, 1], + expression: { + resultIndex: 0, + posIndex: 0, + expression: { resultIndex: 0, posIndex: 1 } + } + })); + }); + + it("computes variable indices for a sequence", function() { + expect(pass).toChangeAST('start = ', ruleDetails({ + resultIndices: [0], + posIndices: [0], + expression: { resultIndex: 0, posIndex: 0 } + })); + expect(pass).toChangeAST('start = &"a" &"b" &"c"', ruleDetails({ + resultIndices: [0, 1, 2], + posIndices: [0, 1], + expression: sequenceDetails + })); + expect(pass).toChangeAST('start = &"a" &"b" &"c"*', ruleDetails({ + resultIndices: [0, 1, 2, 3], + posIndices: [0, 1], + expression: sequenceDetails + })); + expect(pass).toChangeAST('start = &"a" &"b"* &"c"', ruleDetails({ + resultIndices: [0, 1, 2], + posIndices: [0, 1], + expression: sequenceDetails + })); + expect(pass).toChangeAST('start = &"a" &("b"*)* &"c"', ruleDetails({ + resultIndices: [0, 1, 2, 3], + posIndices: [0, 1], + expression: sequenceDetails + })); + expect(pass).toChangeAST('start = &"a"* &"b" &"c"', ruleDetails({ + resultIndices: [0, 1, 2], + posIndices: [0, 1], + expression: sequenceDetails + })); + expect(pass).toChangeAST('start = &("a"*)* &"b" &"c"', ruleDetails({ + resultIndices: [0, 1, 2], + posIndices: [0, 1], + expression: sequenceDetails + })); + expect(pass).toChangeAST('start = &(("a"*)*)* &"b" &"c"', ruleDetails({ + resultIndices: [0, 1, 2, 3], + posIndices: [0, 1], + expression: sequenceDetails + })); + expect(pass).toChangeAST('start = &"a" &(&"b") &"c"', ruleDetails({ + resultIndices: [0, 1, 2], + posIndices: [0, 1, 2], + expression: sequenceDetails + })); + }); + + it("computes variable indices for a labeled", function() { + expect(pass).toChangeAST('start = label:&"a"', ruleDetails({ + resultIndices: [0], + posIndices: [0], + expression: { + resultIndex: 0, + expression: { resultIndex: 0, posIndex: 0 } + } + })); + }); + + it("computes variable indices for a simple and", function() { + expect(pass).toChangeAST('start = &(&"a")', ruleDetails({ + resultIndices: [0], + posIndices: [0, 1], + expression: { + resultIndex: 0, + posIndex: 0, + expression: { resultIndex: 0, posIndex: 1 } + } + })); + }); + + it("computes variable indices for a simple not", function() { + expect(pass).toChangeAST('start = !(&"a")', ruleDetails({ + resultIndices: [0], + posIndices: [0, 1], + expression: { + resultIndex: 0, + posIndex: 0, + expression: { resultIndex: 0, posIndex: 1 } + } + })); + }); + + it("computes variable indices for a semantic and", function() { + expect(pass).toChangeAST('start = &{ code }', ruleDetails({ + resultIndices: [0], + posIndices: [], + expression: leafDetails + })); + }); + + it("computes variable indices for a semantic not", function() { + expect(pass).toChangeAST('start = !{ code }', ruleDetails({ + resultIndices: [0], + posIndices: [], + expression: leafDetails + })); + }); + + it("computes variable indices for an optional", function() { + expect(pass).toChangeAST('start = (&"a")?', ruleDetails({ + resultIndices: [0], + posIndices: [0], + expression: { + resultIndex: 0, + expression: { resultIndex: 0, posIndex: 0 } + } + })); + }); + + it("computes variable indices for a zero or more", function() { + expect(pass).toChangeAST('start = (&"a")*', ruleDetails({ + resultIndices: [0, 1], + posIndices: [0], + expression: { + resultIndex: 0, + expression: { resultIndex: 1, posIndex: 0 } + } + })); + }); + + it("computes variable indices for a one or more", function() { + expect(pass).toChangeAST('start = (&"a")+', ruleDetails({ + resultIndices: [0, 1], + posIndices: [0], + expression: { + resultIndex: 0, + expression: { resultIndex: 1, posIndex: 0 } + } + })); + }); + + it("computes variable indices for a rule reference", function() { + expect(pass).toChangeAST('start = a', ruleDetails({ + resultIndices: [0], + posIndices: [], + expression: leafDetails + })); + }); + + it("computes variable indices for a literal", function() { + expect(pass).toChangeAST('start = "a"', ruleDetails({ + resultIndices: [0], + posIndices: [], + expression: leafDetails + })); + }); + + it("computes variable indices for a class", function() { + expect(pass).toChangeAST('start = [a-z]', ruleDetails({ + resultIndices: [0], + posIndices: [], + expression: leafDetails + })); + }); + + it("computes variable indices for an any", function() { + expect(pass).toChangeAST('start = .', ruleDetails({ + resultIndices: [0], + posIndices: [], + expression: leafDetails + })); + }); +}); diff --git a/spec/compiler/passes/compute-var-names.spec.js b/spec/compiler/passes/compute-var-names.spec.js deleted file mode 100644 index 8d32efe..0000000 --- a/spec/compiler/passes/compute-var-names.spec.js +++ /dev/null @@ -1,229 +0,0 @@ -describe("compiler pass |computeVarNames|", function() { - var pass = PEG.compiler.passes.computeVarNames; - - var leafDetails = { resultVar: "result0" }, - choiceDetails = { - resultVar: "result0", - alternatives: [ - { resultVar: "result0", posVar: "pos0" }, - { resultVar: "result0", posVar: "pos0" }, - { resultVar: "result0", posVar: "pos0" } - ] - }, - sequenceDetails = { - resultVar: "result0", - posVar: "pos0", - elements: [ - { resultVar: "result0", posVar: "pos1" }, - { resultVar: "result1", posVar: "pos1" }, - { resultVar: "result2", posVar: "pos1" } - ] - }; - - function ruleDetails(details) { return { rules: [details] }; } - - it("computes variable names for a named", function() { - expect(pass).toChangeAST('start "start" = &"a"', ruleDetails({ - resultVars: ["result0"], - posVars: ["pos0"], - expression: { - resultVar: "result0", - expression: { resultVar: "result0", posVar: "pos0" } - } - })); - }); - - it("computes variable names for a choice", function() { - expect(pass).toChangeAST('start = &"a" / &"b" / &"c"', ruleDetails({ - resultVars: ["result0"], - posVars: ["pos0"], - expression: choiceDetails - })); - expect(pass).toChangeAST('start = &"a" / &"b"* / &"c"', ruleDetails({ - resultVars: ["result0", "result1"], - posVars: ["pos0"], - expression: choiceDetails - })); - expect(pass).toChangeAST('start = &"a" / &(&"b") / &"c"', ruleDetails({ - resultVars: ["result0"], - posVars: ["pos0", "pos1"], - expression: choiceDetails - })); - }); - - it("computes variable names for an action", function() { - expect(pass).toChangeAST('start = &"a" { code }', ruleDetails({ - resultVars: ["result0"], - posVars: ["pos0", "pos1"], - expression: { - resultVar: "result0", - posVar: "pos0", - expression: { resultVar: "result0", posVar: "pos1" } - } - })); - }); - - it("computes variable names for a sequence", function() { - expect(pass).toChangeAST('start = ', ruleDetails({ - resultVars: ["result0"], - posVars: ["pos0"], - expression: { resultVar: "result0", posVar: "pos0" } - })); - expect(pass).toChangeAST('start = &"a" &"b" &"c"', ruleDetails({ - resultVars: ["result0", "result1", "result2"], - posVars: ["pos0", "pos1"], - expression: sequenceDetails - })); - expect(pass).toChangeAST('start = &"a" &"b" &"c"*', ruleDetails({ - resultVars: ["result0", "result1", "result2", "result3"], - posVars: ["pos0", "pos1"], - expression: sequenceDetails - })); - expect(pass).toChangeAST('start = &"a" &"b"* &"c"', ruleDetails({ - resultVars: ["result0", "result1", "result2"], - posVars: ["pos0", "pos1"], - expression: sequenceDetails - })); - expect(pass).toChangeAST('start = &"a" &("b"*)* &"c"', ruleDetails({ - resultVars: ["result0", "result1", "result2", "result3"], - posVars: ["pos0", "pos1"], - expression: sequenceDetails - })); - expect(pass).toChangeAST('start = &"a"* &"b" &"c"', ruleDetails({ - resultVars: ["result0", "result1", "result2"], - posVars: ["pos0", "pos1"], - expression: sequenceDetails - })); - expect(pass).toChangeAST('start = &("a"*)* &"b" &"c"', ruleDetails({ - resultVars: ["result0", "result1", "result2"], - posVars: ["pos0", "pos1"], - expression: sequenceDetails - })); - expect(pass).toChangeAST('start = &(("a"*)*)* &"b" &"c"', ruleDetails({ - resultVars: ["result0", "result1", "result2", "result3"], - posVars: ["pos0", "pos1"], - expression: sequenceDetails - })); - expect(pass).toChangeAST('start = &"a" &(&"b") &"c"', ruleDetails({ - resultVars: ["result0", "result1", "result2"], - posVars: ["pos0", "pos1", "pos2"], - expression: sequenceDetails - })); - }); - - it("computes variable names for a labeled", function() { - expect(pass).toChangeAST('start = label:&"a"', ruleDetails({ - resultVars: ["result0"], - posVars: ["pos0"], - expression: { - resultVar: "result0", - expression: { resultVar: "result0", posVar: "pos0" } - } - })); - }); - - it("computes variable names for a simple and", function() { - expect(pass).toChangeAST('start = &(&"a")', ruleDetails({ - resultVars: ["result0"], - posVars: ["pos0", "pos1"], - expression: { - resultVar: "result0", - posVar: "pos0", - expression: { resultVar: "result0", posVar: "pos1" } - } - })); - }); - - it("computes variable names for a simple not", function() { - expect(pass).toChangeAST('start = !(&"a")', ruleDetails({ - resultVars: ["result0"], - posVars: ["pos0", "pos1"], - expression: { - resultVar: "result0", - posVar: "pos0", - expression: { resultVar: "result0", posVar: "pos1" } - } - })); - }); - - it("computes variable names for a semantic and", function() { - expect(pass).toChangeAST('start = &{ code }', ruleDetails({ - resultVars: ["result0"], - posVars: [], - expression: leafDetails - })); - }); - - it("computes variable names for a semantic not", function() { - expect(pass).toChangeAST('start = !{ code }', ruleDetails({ - resultVars: ["result0"], - posVars: [], - expression: leafDetails - })); - }); - - it("computes variable names for an optional", function() { - expect(pass).toChangeAST('start = (&"a")?', ruleDetails({ - resultVars: ["result0"], - posVars: ["pos0"], - expression: { - resultVar: "result0", - expression: { resultVar: "result0", posVar: "pos0" } - } - })); - }); - - it("computes variable names for a zero or more", function() { - expect(pass).toChangeAST('start = (&"a")*', ruleDetails({ - resultVars: ["result0", "result1"], - posVars: ["pos0"], - expression: { - resultVar: "result0", - expression: { resultVar: "result1", posVar: "pos0" } - } - })); - }); - - it("computes variable names for a one or more", function() { - expect(pass).toChangeAST('start = (&"a")+', ruleDetails({ - resultVars: ["result0", "result1"], - posVars: ["pos0"], - expression: { - resultVar: "result0", - expression: { resultVar: "result1", posVar: "pos0" } - } - })); - }); - - it("computes variable names for a rule reference", function() { - expect(pass).toChangeAST('start = a', ruleDetails({ - resultVars: ["result0"], - posVars: [], - expression: leafDetails - })); - }); - - it("computes variable names for a literal", function() { - expect(pass).toChangeAST('start = "a"', ruleDetails({ - resultVars: ["result0"], - posVars: [], - expression: leafDetails - })); - }); - - it("computes variable names for a class", function() { - expect(pass).toChangeAST('start = [a-z]', ruleDetails({ - resultVars: ["result0"], - posVars: [], - expression: leafDetails - })); - }); - - it("computes variable names for an any", function() { - expect(pass).toChangeAST('start = .', ruleDetails({ - resultVars: ["result0"], - posVars: [], - expression: leafDetails - })); - }); -}); diff --git a/spec/index.html b/spec/index.html index caff802..36dc248 100644 --- a/spec/index.html +++ b/spec/index.html @@ -12,7 +12,7 @@ - +