Browse Source

Partial fix #194 - nonsenses error messages with semantic predicates (#547)

* Remove stack manipulations from FAIL opcode and rename FAIL to EXPECT
* Always save the expected values regardless of the match result of expression
* Remove unnecessary check for match result in the `named` node
* Collect and process expectations from predicates
master
Mingun 4 years ago
committed by Futago-za Ryuu
parent
commit
669f782a5f
  1. 7
      lib/compiler/opcodes.js
  2. 72
      lib/compiler/passes/generate-bytecode.js
  3. 96
      lib/compiler/passes/generate-js.js
  4. 605
      lib/parser.js
  5. 44
      test/spec/behavior/generated-parser-behavior.spec.js
  6. 363
      test/spec/unit/compiler/passes/generate-bytecode.spec.js

7
lib/compiler/opcodes.js

@ -34,7 +34,7 @@ const opcodes = {
MATCH_REGEXP: 20, // MATCH_REGEXP r, a, f, ...
ACCEPT_N: 21, // ACCEPT_N n
ACCEPT_STRING: 22, // ACCEPT_STRING s
FAIL: 23, // FAIL e
EXPECT: 23, // EXPECT e
// Calls
@ -49,7 +49,10 @@ const opcodes = {
// Failure Reporting
SILENT_FAILS_ON: 28, // SILENT_FAILS_ON
SILENT_FAILS_OFF: 29 // SILENT_FAILS_OFF
SILENT_FAILS_OFF: 29, // SILENT_FAILS_OFF
EXPECT_NS_BEGIN: 38, // EXPECT_NS_BEGIN
EXPECT_NS_END: 39 // EXPECT_NS_END invert
};

72
lib/compiler/passes/generate-bytecode.js

@ -148,10 +148,9 @@ const visitor = require( "../visitor" );
// stack.push(consts[s]);
// currPos += consts[s].length;
//
// [23] FAIL e
// [23] EXPECT e
//
// stack.push(FAILED);
// fail(consts[e]);
// expect(consts[e]);
//
// Calls
// -----
@ -187,6 +186,20 @@ const visitor = require( "../visitor" );
// [29] SILENT_FAILS_OFF
//
// silentFails--;
//
// [38] EXPECT_NS_BEGIN
//
// expected.push({ pos: curPos, variants: [] });
//
// [39] EXPECT_NS_END invert
//
// value = expected.pop();
// if (value.pos === expected.top().pos) {
// if (invert) {
// value.variants.forEach(e => { e.not = !e.not; });
// }
// expected.top().variants.pushAll(value.variants);
// }
function generateBytecode( ast ) {
const consts = [];
@ -252,13 +265,13 @@ function generateBytecode( ast ) {
return buildSequence(
[ op.PUSH_CURR_POS ],
[ op.SILENT_FAILS_ON ],
[ op.EXPECT_NS_BEGIN ],
generate( expression, {
sp: context.sp + 1,
env: cloneEnv( context.env ),
action: null
} ),
[ op.SILENT_FAILS_OFF ],
[ op.EXPECT_NS_END, negative ? 1 : 0 ],
buildCondition(
[ negative ? op.IF_ERROR : op.IF_NOT_ERROR ],
buildSequence(
@ -325,15 +338,11 @@ function generateBytecode( ast ) {
`peg$otherExpectation("${ js.stringEscape( node.name ) }")`
);
// The code generated below is slightly suboptimal because |FAIL| pushes
// to the stack, so we need to stick a |POP| in front of it. We lack a
// dedicated instruction that would just report the failure and not touch
// the stack.
return buildSequence(
[ op.EXPECT, nameIndex ],
[ op.SILENT_FAILS_ON ],
generate( node.expression, context ),
[ op.SILENT_FAILS_OFF ],
buildCondition( [ op.IF_ERROR ], [ op.FAIL, nameIndex ], [] )
[ op.SILENT_FAILS_OFF ]
);
},
@ -600,14 +609,17 @@ function generateBytecode( ast ) {
// For case-sensitive strings the value must match the beginning of the
// remaining input exactly. As a result, we can use |ACCEPT_STRING| and
// save one |substr| call that would be needed if we used |ACCEPT_N|.
return buildCondition(
node.ignoreCase
? [ op.MATCH_STRING_IC, stringIndex ]
: [ op.MATCH_STRING, stringIndex ],
node.ignoreCase
? [ op.ACCEPT_N, node.value.length ]
: [ op.ACCEPT_STRING, stringIndex ],
[ op.FAIL, expectedIndex ]
return buildSequence(
[ op.EXPECT, expectedIndex ],
buildCondition(
node.ignoreCase
? [ op.MATCH_STRING_IC, stringIndex ]
: [ op.MATCH_STRING, stringIndex ],
node.ignoreCase
? [ op.ACCEPT_N, node.value.length ]
: [ op.ACCEPT_STRING, stringIndex ],
[ op.PUSH_FAILED ]
)
);
}
@ -652,10 +664,13 @@ function generateBytecode( ast ) {
+ ")"
);
return buildCondition(
[ op.MATCH_REGEXP, regexpIndex ],
[ op.ACCEPT_N, 1 ],
[ op.FAIL, expectedIndex ]
return buildSequence(
[ op.EXPECT, expectedIndex ],
buildCondition(
[ op.MATCH_REGEXP, regexpIndex ],
[ op.ACCEPT_N, 1 ],
[ op.PUSH_FAILED ]
)
);
},
@ -664,10 +679,13 @@ function generateBytecode( ast ) {
const expectedIndex = addConst( "peg$anyExpectation()" );
return buildCondition(
[ op.MATCH_ANY ],
[ op.ACCEPT_N, 1 ],
[ op.FAIL, expectedIndex ]
return buildSequence(
[ op.EXPECT, expectedIndex ],
buildCondition(
[ op.MATCH_ANY ],
[ op.ACCEPT_N, 1 ],
[ op.PUSH_FAILED ]
)
);
}

96
lib/compiler/passes/generate-js.js

@ -391,10 +391,9 @@ function generateJS( ast, options ) {
" ip += 2;",
" break;",
"",
" case " + op.FAIL + ":", // FAIL e
" stack.push(peg$FAILED);",
" case " + op.EXPECT + ":", // EXPECT e
" if (peg$silentFails === 0) {",
" peg$fail(peg$consts[bc[ip + 1]]);",
" peg$expect(peg$consts[bc[ip + 1]]);",
" }",
" ip += 2;",
" break;",
@ -427,6 +426,16 @@ function generateJS( ast, options ) {
" ip++;",
" break;",
"",
" case " + op.EXPECT_NS_BEGIN + ":", // EXPECT_NS_BEGIN
" peg$begin();",
" ip++;",
" break;",
"",
" case " + op.EXPECT_NS_END + ":", // EXPECT_NS_END invert
" peg$end(bc[ip + 1]);",
" ip += 2;",
" break;",
"",
" // istanbul ignore next",
" default:",
" throw new Error(\"Invalid opcode: \" + bc[ip] + \".\");",
@ -748,9 +757,8 @@ function generateJS( ast, options ) {
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 ] ) + "); }" );
case op.EXPECT: // EXPECT e
parts.push( "if (peg$silentFails === 0) { peg$expect(" + c( bc[ ip + 1 ] ) + "); }" );
ip += 2;
break;
@ -783,6 +791,16 @@ function generateJS( ast, options ) {
ip++;
break;
case op.EXPECT_NS_BEGIN: // EXPECT_NS_BEGIN
parts.push( "peg$begin();" );
ip++;
break;
case op.EXPECT_NS_END: // EXPECT_NS_END invert
parts.push( "peg$end(" + ( bc[ ip + 1 ] !== 0 ) + ");" );
ip += 2;
break;
// istanbul ignore next
default:
throw new Error( "Invalid opcode: " + bc[ ip ] + "." );
@ -881,6 +899,10 @@ function generateJS( ast, options ) {
"",
" other: function(expectation) {",
" return expectation.description;",
" },",
"",
" not: function(expectation) {",
" return \"not \" + describeExpectation(expectation.expected);",
" }",
" };",
"",
@ -1065,8 +1087,7 @@ function generateJS( ast, options ) {
" var peg$currPos = 0;",
" var peg$savedPos = 0;",
" var peg$posDetailsCache = [{ line: 1, column: 1 }];",
" var peg$maxFailPos = 0;",
" var peg$maxFailExpected = [];",
" var peg$expected = [];",
" var peg$silentFails = 0;", // 0 = report failures, > 0 = silence failures
""
].join( "\n" ) );
@ -1246,15 +1267,37 @@ function generateJS( ast, options ) {
" };",
" }",
"",
" function peg$fail(expected) {",
" if (peg$currPos < peg$maxFailPos) { return; }",
" function peg$begin() {",
" peg$expected.push({ pos: peg$currPos, variants: [] });",
" }",
"",
" if (peg$currPos > peg$maxFailPos) {",
" peg$maxFailPos = peg$currPos;",
" peg$maxFailExpected = [];",
" function peg$expect(expected) {",
" var top = peg$expected[peg$expected.length - 1];",
"",
" if (peg$currPos < top.pos) { return; }",
"",
" if (peg$currPos > top.pos) {",
" top.pos = peg$currPos;",
" top.variants = [];",
" }",
"",
" top.variants.push(expected);",
" }",
"",
" function peg$end(invert) {",
" var expected = peg$expected.pop();",
" var top = peg$expected[peg$expected.length - 1];",
" var variants = expected.variants;",
"",
" if (top.pos !== expected.pos) { return; }",
"",
" if (invert) {",
" variants = variants.map(function(e) {",
" return e.type === \"not\" ? e.expected : { type: \"not\", expected: e };",
" });",
" }",
"",
" peg$maxFailExpected.push(expected);",
" Array.prototype.push.apply(top.variants, variants);",
" }",
"",
" function peg$buildSimpleError(message, location) {",
@ -1269,6 +1312,19 @@ function generateJS( ast, options ) {
" location",
" );",
" }",
"",
" function peg$buildError() {",
" var expected = peg$expected[0];",
" var failPos = expected.pos;",
"",
" return peg$buildStructuredError(",
" expected.variants,",
" failPos < input.length ? input.charAt(failPos) : null,",
" failPos < input.length",
" ? peg$computeLocation(failPos, failPos + 1)",
" : peg$computeLocation(failPos, failPos)",
" );",
" }",
""
].join( "\n" ) );
@ -1295,6 +1351,8 @@ function generateJS( ast, options ) {
}
parts.push( " peg$begin();" );
if ( options.optimize === "size" ) {
parts.push( " peg$result = peg$parseRule(peg$startRuleIndex);" );
@ -1311,16 +1369,10 @@ function generateJS( ast, options ) {
" return peg$result;",
" } else {",
" if (peg$result !== peg$FAILED && peg$currPos < input.length) {",
" peg$fail(peg$endExpectation());",
" peg$expect(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)",
" );",
" throw peg$buildError();",
" }",
"}"
].join( "\n" ) );

605
lib/parser.js
File diff suppressed because it is too large
View File

44
test/spec/behavior/generated-parser-behavior.spec.js

@ -1194,19 +1194,33 @@ describe( "generated parser behavior", function () {
} );
it( "discards any expectations recorded when matching the expression", function () {
it( "doesn't discard any expectations recorded when matching the expression", function () {
const parser = peg.generate( "start = 'a' / &'b' / 'c'", options );
expect( parser ).to.failToParse( "d", {
expected: [
{ type: "literal", text: "a", ignoreCase: false },
{ type: "literal", text: "b", ignoreCase: false },
{ type: "literal", text: "c", ignoreCase: false }
]
} );
} );
it( "records expectations from right place", function () {
const parser = peg.generate( "start = 'a' / &'b' .", options );
expect( parser ).to.failToParse( "d", {
expected: [
{ type: "literal", text: "a", ignoreCase: false },
{ type: "literal", text: "b", ignoreCase: false }
]
} );
} );
} );
} );
@ -1243,19 +1257,45 @@ describe( "generated parser behavior", function () {
} );
it( "discards any expectations recorded when matching the expression", function () {
it( "inverts any expectations recorded when matching the expression", function () {
const parser = peg.generate( "start = 'a' / !'b' / 'c'", options );
expect( parser ).to.failToParse( "b", {
expected: [
{ type: "literal", text: "a", ignoreCase: false },
{ type: "not", expected: { type: "literal", text: "b", ignoreCase: false } },
{ type: "literal", text: "c", ignoreCase: false }
]
} );
} );
it( "records expectations from right place", function () {
const parser = peg.generate( "start = 'a' / !'b' .", options );
expect( parser ).to.failToParse( "b", {
expected: [
{ type: "literal", text: "a", ignoreCase: false },
{ type: "not", expected: { type: "literal", text: "b", ignoreCase: false } }
]
} );
} );
it( "reports not inverted expectations when the expression inverted twice", function () {
const parser = peg.generate( "start = !(!'a')", options );
expect( parser ).to.failToParse( "b", {
expected: [
{ type: "literal", text: "a", ignoreCase: false }
]
} );
} );
} );
} );

363
test/spec/unit/compiler/passes/generate-bytecode.spec.js

@ -34,9 +34,9 @@ describe( "compiler pass |generateBytecode|", function () {
"c = 'c'"
].join( "\n" ), {
rules: [
{ bytecode: [ 18, 0, 2, 2, 22, 0, 23, 1 ] },
{ bytecode: [ 18, 2, 2, 2, 22, 2, 23, 3 ] },
{ bytecode: [ 18, 4, 2, 2, 22, 4, 23, 5 ] }
{ bytecode: [ 23, 1, 18, 0, 2, 1, 22, 0, 3 ] },
{ bytecode: [ 23, 3, 18, 2, 2, 1, 22, 2, 3 ] },
{ bytecode: [ 23, 5, 18, 4, 2, 1, 22, 4, 3 ] }
]
} );
@ -66,7 +66,7 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( "start = 'a'", bytecodeDetails( [
18, 0, 2, 2, 22, 0, 23, 1 // <expression>
23, 1, 18, 0, 2, 1, 22, 0, 3 // <expression>
] ) );
} );
@ -80,11 +80,10 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
28, // SILENT_FAILS_ON
18, 1, 2, 2, 22, 1, 23, 2, // <expression>
29, // SILENT_FAILS_OFF
14, 2, 0, // IF_ERROR
23, 0 // * FAIL
23, 0, // EXPECT <0>
28, // SILENT_FAILS_ON
23, 2, 18, 1, 2, 1, 22, 1, 3, // <expression>
29 // SILENT_FAILS_OFF
] ) );
} );
@ -106,13 +105,13 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( "start = 'a' / 'b' / 'c'", bytecodeDetails( [
18, 0, 2, 2, 22, 0, 23, 1, // <alternatives[0]>
14, 21, 0, // IF_ERROR
6, // * POP
18, 2, 2, 2, 22, 2, 23, 3, // <alternatives[1]>
14, 9, 0, // IF_ERROR
6, // * POP
18, 4, 2, 2, 22, 4, 23, 5 // <alternatives[2]>
23, 1, 18, 0, 2, 1, 22, 0, 3, // <alternatives[0]>
14, 23, 0, // IF_ERROR
6, // * POP
23, 3, 18, 2, 2, 1, 22, 2, 3, // <alternatives[1]>
14, 10, 0, // IF_ERROR
6, // * POP
23, 5, 18, 4, 2, 1, 22, 4, 3 // <alternatives[2]>
] ) );
} );
@ -128,12 +127,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <expression>
15, 6, 0, // IF_NOT_ERROR
24, 1, // * LOAD_SAVED_POS
26, 2, 1, 0, // CALL
9 // NIP
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
15, 6, 0, // IF_NOT_ERROR
24, 1, // * LOAD_SAVED_POS
26, 2, 1, 0, // CALL
9 // NIP
] ) );
} );
@ -157,12 +156,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <expression>
15, 7, 0, // IF_NOT_ERROR
24, 1, // * LOAD_SAVED_POS
26, 2, 1, 1, 0, // CALL
9 // NIP
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
15, 7, 0, // IF_NOT_ERROR
24, 1, // * LOAD_SAVED_POS
26, 2, 1, 1, 0, // CALL
9 // NIP
] ) );
} );
@ -186,24 +185,24 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <elements[0]>
15, 39, 3, // IF_NOT_ERROR
18, 2, 2, 2, 22, 2, 23, 3, // * <elements[1]>
15, 24, 4, // IF_NOT_ERROR
18, 4, 2, 2, 22, 4, 23, 5, // * <elements[2]>
15, 9, 4, // IF_NOT_ERROR
24, 3, // * LOAD_SAVED_POS
26, 6, 4, 3, 2, 1, 0, // CALL <6>
8, 3, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
8, 2, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
6, // * POP
7, // POP_CURR_POS
3 // PUSH_FAILED
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <elements[0]>
15, 41, 3, // IF_NOT_ERROR
23, 3, 18, 2, 2, 1, 22, 2, 3, // * <elements[1]>
15, 25, 4, // IF_NOT_ERROR
23, 5, 18, 4, 2, 1, 22, 4, 3, // * <elements[2]>
15, 9, 4, // IF_NOT_ERROR
24, 3, // * LOAD_SAVED_POS
26, 6, 4, 3, 2, 1, 0, // CALL <6>
8, 3, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
8, 2, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
6, // * POP
7, // POP_CURR_POS
3 // PUSH_FAILED
] ) );
} );
@ -233,24 +232,24 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <elements[0]>
15, 33, 3, // IF_NOT_ERROR
18, 2, 2, 2, 22, 2, 23, 3, // * <elements[1]>
15, 18, 4, // IF_NOT_ERROR
18, 4, 2, 2, 22, 4, 23, 5, // * <elements[2]>
15, 3, 4, // IF_NOT_ERROR
11, 3, // * WRAP
9, // NIP
8, 3, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
8, 2, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
6, // * POP
7, // POP_CURR_POS
3 // PUSH_FAILED
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <elements[0]>
15, 35, 3, // IF_NOT_ERROR
23, 3, 18, 2, 2, 1, 22, 2, 3, // * <elements[1]>
15, 19, 4, // IF_NOT_ERROR
23, 5, 18, 4, 2, 1, 22, 4, 3, // * <elements[2]>
15, 3, 4, // IF_NOT_ERROR
11, 3, // * WRAP
9, // NIP
8, 3, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
8, 2, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
6, // * POP
7, // POP_CURR_POS
3 // PUSH_FAILED
] ) );
} );
@ -275,7 +274,7 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( "start = a:'a'", bytecodeDetails( [
18, 0, 2, 2, 22, 0, 23, 1 // <expression>
23, 1, 18, 0, 2, 1, 22, 0, 3 // <expression>
] ) );
} );
@ -287,12 +286,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( "start = $'a'", bytecodeDetails( [
5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <expression>
15, 2, 1, // IF_NOT_ERROR
6, // * POP
12, // TEXT
9 // * NIP
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
15, 2, 1, // IF_NOT_ERROR
6, // * POP
12, // TEXT
9 // * NIP
] ) );
} );
@ -306,17 +305,17 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
28, // SILENT_FAILS_ON
18, 0, 2, 2, 22, 0, 23, 1, // <expression>
29, // SILENT_FAILS_OFF
15, 3, 3, // IF_NOT_ERROR
6, // * POP
7, // POP_CURR_POS
1, // PUSH_UNDEFINED
6, // * POP
6, // POP
3 // PUSH_FAILED
5, // PUSH_CURR_POS
38, // EXPECT_NS_BEGIN
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
39, 0, // EXPECT_NS_END <false>
15, 3, 3, // IF_NOT_ERROR
6, // * POP
7, // POP_CURR_POS
1, // PUSH_UNDEFINED
6, // * POP
6, // POP
3 // PUSH_FAILED
] ) );
} );
@ -339,17 +338,17 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
28, // SILENT_FAILS_ON
18, 0, 2, 2, 22, 0, 23, 1, // <expression>
29, // SILENT_FAILS_OFF
14, 3, 3, // IF_ERROR
6, // * POP
6, // POP
1, // PUSH_UNDEFINED
6, // * POP
7, // POP_CURR_POS
3 // PUSH_FAILED
5, // PUSH_CURR_POS
38, // EXPECT_NS_BEGIN
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
39, 1, // EXPECT_NS_END <true>
14, 3, 3, // IF_ERROR
6, // * POP
6, // POP
1, // PUSH_UNDEFINED
6, // * POP
7, // POP_CURR_POS
3 // PUSH_FAILED
] ) );
} );
@ -372,10 +371,10 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
18, 0, 2, 2, 22, 0, 23, 1, // <expression>
14, 2, 0, // IF_ERROR
6, // * POP
2 // PUSH_NULL
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
14, 2, 0, // IF_ERROR
6, // * POP
2 // PUSH_NULL
] ) );
} );
@ -398,12 +397,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
4, // PUSH_EMPTY_ARRAY
18, 0, 2, 2, 22, 0, 23, 1, // <expression>
16, 9, // WHILE_NOT_ERROR
10, // * APPEND
18, 0, 2, 2, 22, 0, 23, 1, // <expression>
6 // POP
4, // PUSH_EMPTY_ARRAY
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
16, 10, // WHILE_NOT_ERROR
10, // * APPEND
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
6 // POP
] ) );
} );
@ -426,16 +425,16 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
4, // PUSH_EMPTY_ARRAY
18, 0, 2, 2, 22, 0, 23, 1, // <expression>
15, 12, 3, // IF_NOT_ERROR
16, 9, // * WHILE_NOT_ERROR
10, // * APPEND
18, 0, 2, 2, 22, 0, 23, 1, // <expression>
6, // POP
6, // * POP
6, // POP
3 // PUSH_FAILED
4, // PUSH_EMPTY_ARRAY
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
15, 13, 3, // IF_NOT_ERROR
16, 10, // * WHILE_NOT_ERROR
10, // * APPEND
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
6, // POP
6, // * POP
6, // POP
3 // PUSH_FAILED
] ) );
} );
@ -456,7 +455,7 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( "start = ('a')", bytecodeDetails( [
18, 0, 2, 2, 22, 0, 23, 1 // <expression>
23, 1, 18, 0, 2, 1, 22, 0, 3 // <expression>
] ) );
} );
@ -501,35 +500,35 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <elements[0]>
15, 55, 3, // IF_NOT_ERROR
18, 2, 2, 2, 22, 2, 23, 3, // * <elements[1]>
15, 40, 4, // IF_NOT_ERROR
18, 4, 2, 2, 22, 4, 23, 5, // * <elements[2]>
15, 25, 4, // IF_NOT_ERROR
25, // * UPDATE_SAVED_POS
26, 6, 0, 3, 2, 1, 0, // CALL
13, 2, 2, // IF
6, // * POP
1, // PUSH_UNDEFINED
6, // * POP
3, // PUSH_FAILED
15, 3, 4, // IF_NOT_ERROR
11, 4, // * WRAP
9, // NIP
8, 4, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
8, 3, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
8, 2, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
6, // * POP
7, // POP_CURR_POS
3 // PUSH_FAILED
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <elements[0]>
15, 57, 3, // IF_NOT_ERROR
23, 3, 18, 2, 2, 1, 22, 2, 3, // * <elements[1]>
15, 41, 4, // IF_NOT_ERROR
23, 5, 18, 4, 2, 1, 22, 4, 3, // * <elements[2]>
15, 25, 4, // IF_NOT_ERROR
25, // * UPDATE_SAVED_POS
26, 6, 0, 3, 2, 1, 0, // CALL
13, 2, 2, // IF
6, // * POP
1, // PUSH_UNDEFINED
6, // * POP
3, // PUSH_FAILED
15, 3, 4, // IF_NOT_ERROR
11, 4, // * WRAP
9, // NIP
8, 4, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
8, 3, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
8, 2, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
6, // * POP
7, // POP_CURR_POS
3 // PUSH_FAILED
] ) );
} );
@ -590,35 +589,35 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <elements[0]>
15, 55, 3, // IF_NOT_ERROR
18, 2, 2, 2, 22, 2, 23, 3, // * <elements[1]>
15, 40, 4, // IF_NOT_ERROR
18, 4, 2, 2, 22, 4, 23, 5, // * <elements[2]>
15, 25, 4, // IF_NOT_ERROR
25, // * UPDATE_SAVED_POS
26, 6, 0, 3, 2, 1, 0, // CALL
13, 2, 2, // IF
6, // * POP
3, // PUSH_FAILED
6, // * POP
1, // PUSH_UNDEFINED
15, 3, 4, // IF_NOT_ERROR
11, 4, // * WRAP
9, // NIP
8, 4, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
8, 3, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
8, 2, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
6, // * POP
7, // POP_CURR_POS
3 // PUSH_FAILED
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <elements[0]>
15, 57, 3, // IF_NOT_ERROR
23, 3, 18, 2, 2, 1, 22, 2, 3, // * <elements[1]>
15, 41, 4, // IF_NOT_ERROR
23, 5, 18, 4, 2, 1, 22, 4, 3, // * <elements[2]>
15, 25, 4, // IF_NOT_ERROR
25, // * UPDATE_SAVED_POS
26, 6, 0, 3, 2, 1, 0, // CALL
13, 2, 2, // IF
6, // * POP
3, // PUSH_FAILED
6, // * POP
1, // PUSH_UNDEFINED
15, 3, 4, // IF_NOT_ERROR
11, 4, // * WRAP
9, // NIP
8, 4, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
8, 3, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
8, 2, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
6, // * POP
7, // POP_CURR_POS
3 // PUSH_FAILED
] ) );
} );
@ -690,9 +689,10 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
18, 0, 2, 2, // MATCH_STRING
23, 1, // EXPECT <1>
18, 0, 2, 1, // MATCH_STRING <0>
22, 0, // * ACCEPT_STRING
23, 1 // * FAIL
3 // * PUSH_FAILED
] ) );
} );
@ -715,9 +715,10 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
19, 0, 2, 2, // MATCH_STRING_IC
23, 1, // EXPECT <1>
19, 0, 2, 1, // MATCH_STRING_IC <0>
21, 1, // * ACCEPT_N
23, 1 // * FAIL
3 // * PUSH_FAILED
] ) );
} );
@ -740,9 +741,10 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( "start = [a]", bytecodeDetails( [
20, 0, 2, 2, // MATCH_REGEXP
23, 1, // EXPECT <1>
20, 0, 2, 1, // MATCH_REGEXP <0>
21, 1, // * ACCEPT_N
23, 1 // * FAIL
3 // * PUSH_FAILED
] ) );
} );
@ -808,9 +810,10 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
17, 2, 2, // MATCH_ANY
23, 0, // EXPECT <0>
17, 2, 1, // MATCH_ANY
21, 1, // * ACCEPT_N
23, 0 // * FAIL
3 // * PUSH_FAILED
] ) );
} );

Loading…
Cancel
Save