Browse Source

Move all codegeneration from `generateBytecode` pass to `generateJs` pass (#459)

* Split 'consts' collection by content types into:

  - literals: for literal expressions, like `"a"`
  - classes: for character class expressions, like `[a]`
  - expectations: for constants describing expected values when parse failed
  - functions: for constants with function code

* Move any JavaScript code generation from 'generateBytecode' to 'generateJs'.
* Rename opcode 'MATCH_REGEXP' to 'MATCH_CLASS' (name reflects purpose, not implementation).
* Replace 'PUSH' opcode with 'PUSH_EMPTY_STRING' opcode because it is only used with empty strings
master
Mingun 3 years ago
committed by Futago-za Ryuu
parent
commit
9b90fa1d81
  1. 64
      lib/compiler/opcodes.js
  2. 135
      lib/compiler/passes/generate-bytecode.js
  3. 154
      lib/compiler/passes/generate-js.js
  4. 619
      lib/parser/index.js
  5. 2
      src/parser.pegjs
  6. 469
      test/spec/unit/compiler/passes/generate-bytecode.spec.js

64
lib/compiler/opcodes.js

@ -5,54 +5,54 @@ const opcodes = {
// Stack Manipulation
PUSH: 0, // PUSH c
PUSH_UNDEFINED: 1, // PUSH_UNDEFINED
PUSH_NULL: 2, // PUSH_NULL
PUSH_FAILED: 3, // PUSH_FAILED
PUSH_EMPTY_ARRAY: 4, // PUSH_EMPTY_ARRAY
PUSH_CURR_POS: 5, // PUSH_CURR_POS
POP: 6, // POP
POP_CURR_POS: 7, // POP_CURR_POS
POP_N: 8, // POP_N n
NIP: 9, // NIP
APPEND: 10, // APPEND
WRAP: 11, // WRAP n
TEXT: 12, // TEXT
PUSH_EMPTY_STRING: 0, // PUSH_EMPTY_STRING
PUSH_UNDEFINED: 1, // PUSH_UNDEFINED
PUSH_NULL: 2, // PUSH_NULL
PUSH_FAILED: 3, // PUSH_FAILED
PUSH_EMPTY_ARRAY: 4, // PUSH_EMPTY_ARRAY
PUSH_CURR_POS: 5, // PUSH_CURR_POS
POP: 6, // POP
POP_CURR_POS: 7, // POP_CURR_POS
POP_N: 8, // POP_N n
NIP: 9, // NIP
APPEND: 10, // APPEND
WRAP: 11, // WRAP n
TEXT: 12, // TEXT
// Conditions and Loops
IF: 13, // IF t, f
IF_ERROR: 14, // IF_ERROR t, f
IF_NOT_ERROR: 15, // IF_NOT_ERROR t, f
WHILE_NOT_ERROR: 16, // WHILE_NOT_ERROR b
IF: 13, // IF t, f
IF_ERROR: 14, // IF_ERROR t, f
IF_NOT_ERROR: 15, // IF_NOT_ERROR t, f
WHILE_NOT_ERROR: 16, // WHILE_NOT_ERROR b
// Matching
MATCH_ANY: 17, // MATCH_ANY a, f, ...
MATCH_STRING: 18, // MATCH_STRING s, a, f, ...
MATCH_STRING_IC: 19, // MATCH_STRING_IC s, a, f, ...
MATCH_REGEXP: 20, // MATCH_REGEXP r, a, f, ...
ACCEPT_N: 21, // ACCEPT_N n
ACCEPT_STRING: 22, // ACCEPT_STRING s
EXPECT: 23, // EXPECT e
MATCH_ANY: 17, // MATCH_ANY a, f, ...
MATCH_STRING: 18, // MATCH_STRING s, a, f, ...
MATCH_STRING_IC: 19, // MATCH_STRING_IC s, a, f, ...
MATCH_CLASS: 20, // MATCH_CLASS c, a, f, ...
ACCEPT_N: 21, // ACCEPT_N n
ACCEPT_STRING: 22, // ACCEPT_STRING s
EXPECT: 23, // EXPECT e
// Calls
LOAD_SAVED_POS: 24, // LOAD_SAVED_POS p
UPDATE_SAVED_POS: 25, // UPDATE_SAVED_POS
CALL: 26, // CALL f, n, pc, p1, p2, ..., pN
LOAD_SAVED_POS: 24, // LOAD_SAVED_POS p
UPDATE_SAVED_POS: 25, // UPDATE_SAVED_POS
CALL: 26, // CALL f, n, pc, p1, p2, ..., pN
// Rules
RULE: 27, // RULE r
RULE: 27, // RULE r
// Failure Reporting
SILENT_FAILS_ON: 28, // SILENT_FAILS_ON
SILENT_FAILS_OFF: 29, // SILENT_FAILS_OFF
SILENT_FAILS_ON: 28, // SILENT_FAILS_ON
SILENT_FAILS_OFF: 29, // SILENT_FAILS_OFF
EXPECT_NS_BEGIN: 38, // EXPECT_NS_BEGIN
EXPECT_NS_END: 39 // EXPECT_NS_END invert
EXPECT_NS_BEGIN: 38, // EXPECT_NS_BEGIN
EXPECT_NS_END: 39 // EXPECT_NS_END invert
};

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

@ -1,7 +1,6 @@
"use strict";
const asts = require( "../asts" );
const js = require( "../js" );
const op = require( "../opcodes" );
const visitor = require( "../visitor" );
const util = require( "../../util" );
@ -14,9 +13,9 @@ const util = require( "../../util" );
// Stack Manipulation
// ------------------
//
// [0] PUSH c
// [0] PUSH_EMPTY_STRING
//
// stack.push(consts[c]);
// stack.push("");
//
// [1] PUSH_UNDEFINED
//
@ -117,7 +116,7 @@ const util = require( "../../util" );
//
// [18] MATCH_STRING s, a, f, ...
//
// if (input.substr(currPos, consts[s].length) === consts[s]) {
// if (input.substr(currPos, literals[s].length) === literals[s]) {
// interpret(ip + 4, ip + 4 + a);
// } else {
// interpret(ip + 4 + a, ip + 4 + a + f);
@ -125,15 +124,15 @@ const util = require( "../../util" );
//
// [19] MATCH_STRING_IC s, a, f, ...
//
// if (input.substr(currPos, consts[s].length).toLowerCase() === consts[s]) {
// if (input.substr(currPos, literals[s].length).toLowerCase() === literals[s]) {
// interpret(ip + 4, ip + 4 + a);
// } else {
// interpret(ip + 4 + a, ip + 4 + a + f);
// }
//
// [20] MATCH_REGEXP r, a, f, ...
// [20] MATCH_CLASS c, a, f, ...
//
// if (consts[r].test(input.charAt(currPos))) {
// if (classes[c].test(input.charAt(currPos))) {
// interpret(ip + 4, ip + 4 + a);
// } else {
// interpret(ip + 4 + a, ip + 4 + a + f);
@ -146,12 +145,12 @@ const util = require( "../../util" );
//
// [22] ACCEPT_STRING s
//
// stack.push(consts[s]);
// currPos += consts[s].length;
// stack.push(literals[s]);
// currPos += literals[s].length;
//
// [23] EXPECT e
//
// expect(consts[e]);
// expect(expectations[e]);
//
// Calls
// -----
@ -166,7 +165,7 @@ const util = require( "../../util" );
//
// [26] CALL f, n, pc, p1, p2, ..., pN
//
// value = consts[f](stack[p1], ..., stack[pN]);
// value = functions[f](stack[p1], ..., stack[pN]);
// stack.pop(n);
// stack.push(value);
//
@ -203,19 +202,46 @@ const util = require( "../../util" );
// }
function generateBytecode( ast ) {
const consts = [];
const literals = [];
const classes = [];
const expectations = [];
const functions = [];
let generate;
function addConst( value ) {
function addLiteralConst( value ) {
const index = consts.indexOf( value );
return index === -1 ? consts.push( value ) - 1 : index;
const index = literals.indexOf( value );
return index === -1 ? literals.push( value ) - 1 : index;
}
function addFunctionConst( params, code ) {
function addClassConst( node ) {
return addConst( `function(${ params.join( ", " ) }) {${ code }}` );
const cls = {
value: node.parts,
inverted: node.inverted,
ignoreCase: node.ignoreCase
};
const pattern = JSON.stringify( cls );
const index = classes.findIndex( c => JSON.stringify( c ) === pattern );
return index === -1 ? classes.push( cls ) - 1 : index;
}
function addExpectedConst( expected ) {
const pattern = JSON.stringify( expected );
const index = expectations.findIndex( e => JSON.stringify( e ) === pattern );
return index === -1 ? expectations.push( expected ) - 1 : index;
}
function addFunctionConst( predicate, params, code ) {
const func = { predicate: predicate, params: params, body: code };
const pattern = JSON.stringify( func );
const index = functions.findIndex( f => JSON.stringify( f ) === pattern );
return index === -1 ? functions.push( func ) - 1 : index;
}
@ -284,7 +310,7 @@ function generateBytecode( ast ) {
function buildSemanticPredicate( node, negative, context ) {
const functionIndex = addFunctionConst( Object.keys( context.env ), node.code );
const functionIndex = addFunctionConst( true, Object.keys( context.env ), node.code );
return buildSequence(
[ op.UPDATE_SAVED_POS ],
@ -312,7 +338,10 @@ function generateBytecode( ast ) {
grammar( node ) {
node.rules.forEach( generate );
node.consts = consts;
node.literals = literals;
node.classes = classes;
node.expectations = expectations;
node.functions = functions;
},
@ -330,8 +359,8 @@ function generateBytecode( ast ) {
named( node, context ) {
// Do not generate unused constant, if no need it
const nameIndex = context.reportFailures ? addConst(
`peg$otherExpectation("${ js.stringEscape( node.name ) }")`
const nameIndex = context.reportFailures ? addExpectedConst(
{ type: "rule", value: node.name }
) : null;
const expressionCode = generate( node.expression, {
sp: context.sp,
@ -393,7 +422,7 @@ function generateBytecode( ast ) {
} );
const match = node.expression.match|0;
const functionIndex = emitCall && match >= 0
? addFunctionConst( Object.keys( env ), node.code )
? addFunctionConst( false, Object.keys( env ), node.code )
: null;
return emitCall === false
@ -450,6 +479,7 @@ function generateBytecode( ast ) {
} else if ( context.action ) {
const functionIndex = addFunctionConst(
false,
Object.keys( context.env ),
context.action.code
);
@ -623,16 +653,15 @@ function generateBytecode( ast ) {
const match = node.match|0;
const needConst = match === 0 || ( match > 0 && ! node.ignoreCase );
const stringIndex = needConst ? addConst( `"${ js.stringEscape(
const stringIndex = needConst ? addLiteralConst(
node.ignoreCase ? node.value.toLowerCase() : node.value
) }"` ) : null;
// Do not generate unused constant, if no need it
const expectedIndex = context.reportFailures ? addConst(
"peg$literalExpectation("
+ `"${ js.stringEscape( node.value ) }", `
+ node.ignoreCase
+ ")"
) : null;
// Do not generate unused constant, if no need it
const expectedIndex = context.reportFailures ? addExpectedConst( {
type: "literal",
value: node.value,
ignoreCase: node.ignoreCase
} ) : null;
// For case-sensitive strings the value must match the beginning of the
// remaining input exactly. As a result, we can use |ACCEPT_STRING| and
@ -653,53 +682,27 @@ function generateBytecode( ast ) {
}
const stringIndex = addConst( "\"\"" );
return [ op.PUSH, stringIndex ];
return [ op.PUSH_EMPTY_STRING ];
},
class( node, context ) {
const 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" : "" );
const parts = "["
+ node.parts
.map( part =>
( Array.isArray( part )
? `["${ js.stringEscape( part[ 0 ] ) }", "${ js.stringEscape( part[ 1 ] ) }"]`
: "\"" + js.stringEscape( part ) + "\"" )
)
.join( ", " )
+ "]";
const match = node.match|0;
const regexpIndex = match === 0 ? addConst( regexp ) : null;
const classIndex = match === 0 ? addClassConst( node ) : null;
// Do not generate unused constant, if no need it
const expectedIndex = context.reportFailures ? addConst(
"peg$classExpectation("
+ parts + ", "
+ node.inverted + ", "
+ node.ignoreCase
+ ")"
) : null;
const expectedIndex = context.reportFailures ? addExpectedConst( {
type: "class",
value: node.parts,
inverted: node.inverted,
ignoreCase: node.ignoreCase
} ) : null;
return buildSequence(
context.reportFailures ? [ op.EXPECT, expectedIndex ] : [],
buildCondition(
match,
[ op.MATCH_REGEXP, regexpIndex ],
[ op.MATCH_CLASS, classIndex ],
[ op.ACCEPT_N, 1 ],
[ op.PUSH_FAILED ]
)
@ -711,7 +714,7 @@ function generateBytecode( ast ) {
// Do not generate unused constant, if no need it
const expectedIndex = context.reportFailures
? addConst( "peg$anyExpectation()" )
? addExpectedConst( { type: "any" } )
: null;
return buildSequence(

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

@ -22,13 +22,92 @@ function generateJS( ast, options ) {
}
const l = i => "peg$c" + i; // |literals[i]| of the abstract machine
const r = i => "peg$r" + i; // |classes[i]| of the abstract machine
const e = i => "peg$e" + i; // |expectations[i]| of the abstract machine
const f = i => "peg$f" + i; // |actions[i]| of the abstract machine
function generateTables() {
function buildLiteral( literal ) {
return `"${ js.stringEscape( literal ) }"`;
}
function buildRegexp( cls ) {
return "/^["
+ ( cls.inverted ? "^" : "" )
+ cls.value
.map( part =>
( Array.isArray( part )
? js.regexpClassEscape( part[ 0 ] )
+ "-"
+ js.regexpClassEscape( part[ 1 ] )
: js.regexpClassEscape( part ) )
)
.join( "" )
+ "]/"
+ ( cls.ignoreCase ? "i" : "" );
}
function buildExpectation( e ) {
switch ( e.type ) {
case "rule":
return `peg$otherExpectation("${ js.stringEscape( e.value ) }")`;
case "literal":
return "peg$literalExpectation(\""
+ js.stringEscape( e.value )
+ "\", "
+ e.ignoreCase
+ ")";
case "class": {
const parts = e.value.map( part =>
( Array.isArray( part )
? `["${ js.stringEscape( part[ 0 ] ) }", "${ js.stringEscape( part[ 1 ] ) }"]`
: `"${ js.stringEscape( part ) }"` )
);
return "peg$classExpectation(["
+ parts.join( ", " ) + "], "
+ e.inverted + ", "
+ e.ignoreCase
+ ")";
}
case "any": return "peg$anyExpectation()";
// istanbul ignore next
default: throw new Error( `Unknown expectation type (${ JSON.stringify( e ) })` );
}
}
function buildFunc( f ) {
return `function(${ f.params.join( ", " ) }) {${ f.body }}`;
}
if ( options.optimize === "size" ) {
return [
"var peg$consts = [",
indent2( ast.consts.join( ",\n" ) ),
"var peg$literals = [",
indent2( ast.literals.map( buildLiteral ).join( ",\n" ) ),
"];",
"var peg$regexps = [",
indent2( ast.classes.map( buildRegexp ).join( ",\n" ) ),
"];",
"var peg$expectations = [",
indent2( ast.expectations.map( buildExpectation ).join( ",\n" ) ),
"];",
"var peg$functions = [",
indent2( ast.functions.map( buildFunc ).join( ",\n" ) ),
"];",
"",
"var peg$bytecode = [",
@ -48,7 +127,15 @@ function generateJS( ast, options ) {
}
return ast.consts.map( ( c, i ) => "var peg$c" + i + " = " + c + ";" ).join( "\n" );
return ast.literals.map(
( c, i ) => "var " + l( i ) + " = " + buildLiteral( c ) + ";"
).concat( "", ast.classes.map(
( c, i ) => "var " + r( i ) + " = " + buildRegexp( c ) + ";" )
).concat( "", ast.expectations.map(
( c, i ) => "var " + e( i ) + " = " + buildExpectation( c ) + ";" )
).concat( "", ast.functions.map(
( c, i ) => "var " + f( i ) + " = " + buildFunc( c ) + ";"
) ).join( "\n" );
}
@ -220,7 +307,7 @@ function generateJS( ast, options ) {
"stack.splice(",
" stack.length - bc[ip + 2],",
" bc[ip + 2],",
" peg$consts[bc[ip + 1]].apply(null, params)",
" peg$functions[bc[ip + 1]].apply(null, params)",
");",
"",
"ip += " + baseLength + " + " + paramsLengthCode + ";",
@ -275,9 +362,9 @@ function generateJS( ast, options ) {
" while (true) {",
" while (ip < end) {",
" switch (bc[ip]) {",
" case " + op.PUSH + ":", // PUSH c
" stack.push(peg$consts[bc[ip + 1]]);",
" ip += 2;",
" case " + op.PUSH_EMPTY_STRING + ":", // PUSH_EMPTY_STRING
" stack.push('');",
" ip++;",
" break;",
"",
" case " + op.PUSH_UNDEFINED + ":", // PUSH_UNDEFINED
@ -363,19 +450,19 @@ function generateJS( ast, options ) {
"",
" 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$literals[bc[ip + 1]].length) === peg$literals[bc[ip + 1]]",
1
) ),
"",
" 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$literals[bc[ip + 1]].length).toLowerCase() === peg$literals[bc[ip + 1]]",
1
) ),
"",
" case " + op.MATCH_REGEXP + ":", // MATCH_REGEXP r, a, f, ...
" case " + op.MATCH_CLASS + ":", // MATCH_CLASS c, a, f, ...
indent10( generateCondition(
"peg$consts[bc[ip + 1]].test(input.charAt(peg$currPos))",
"peg$regexps[bc[ip + 1]].test(input.charAt(peg$currPos))",
1
) ),
"",
@ -386,14 +473,14 @@ function generateJS( ast, options ) {
" break;",
"",
" case " + op.ACCEPT_STRING + ":", // ACCEPT_STRING s
" stack.push(peg$consts[bc[ip + 1]]);",
" peg$currPos += peg$consts[bc[ip + 1]].length;",
" stack.push(peg$literals[bc[ip + 1]]);",
" peg$currPos += peg$literals[bc[ip + 1]].length;",
" ip += 2;",
" break;",
"",
" case " + op.EXPECT + ":", // EXPECT e
" if (peg$silentFails === 0) {",
" peg$expect(peg$consts[bc[ip + 1]]);",
" peg$expect(peg$expectations[bc[ip + 1]]);",
" }",
" ip += 2;",
" break;",
@ -463,11 +550,6 @@ function generateJS( ast, options ) {
const parts = [];
const stackVars = [];
function c( i ) {
return "peg$c" + i;
} // |consts[i]| of the abstract machine
function s( i ) {
return "s" + i;
@ -596,7 +678,7 @@ function generateJS( ast, options ) {
const baseLength = 4;
const paramsLength = bc[ ip + baseLength - 1 ];
const value = c( bc[ ip + 1 ] )
const value = f( bc[ ip + 1 ] )
+ "("
+ bc
.slice( ip + baseLength, ip + baseLength + paramsLength )
@ -614,9 +696,9 @@ function generateJS( ast, options ) {
switch ( bc[ ip ] ) {
case op.PUSH: // PUSH c
parts.push( stack.push( c( bc[ ip + 1 ] ) ) );
ip += 2;
case op.PUSH_EMPTY_STRING: // PUSH_EMPTY_STRING
parts.push( stack.push( "''" ) );
ip++;
break;
case op.PUSH_CURR_POS: // PUSH_CURR_POS
@ -624,7 +706,7 @@ function generateJS( ast, options ) {
ip++;
break;
case op.PUSH_UNDEFINED: // PUSH_UNDEFINED
case op.PUSH_UNDEFINED: // PUSH_UNDEFINED
parts.push( stack.push( "undefined" ) );
ip++;
break;
@ -708,13 +790,13 @@ function generateJS( ast, options ) {
case op.MATCH_STRING: // MATCH_STRING s, a, f, ...
compileCondition(
eval( ast.consts[ bc[ ip + 1 ] ] ).length > 1
ast.literals[ bc[ ip + 1 ] ].length > 1
? "input.substr(peg$currPos, "
+ eval( ast.consts[ bc[ ip + 1 ] ] ).length
+ ast.literals[ bc[ ip + 1 ] ].length
+ ") === "
+ c( bc[ ip + 1 ] )
+ l( bc[ ip + 1 ] )
: "input.charCodeAt(peg$currPos) === "
+ eval( ast.consts[ bc[ ip + 1 ] ] ).charCodeAt( 0 )
+ ast.literals[ bc[ ip + 1 ] ].charCodeAt( 0 )
, 1
);
break;
@ -722,15 +804,15 @@ function generateJS( ast, options ) {
case op.MATCH_STRING_IC: // MATCH_STRING_IC s, a, f, ...
compileCondition(
"input.substr(peg$currPos, "
+ eval( ast.consts[ bc[ ip + 1 ] ] ).length
+ ast.literals[ bc[ ip + 1 ] ].length
+ ").toLowerCase() === "
+ c( bc[ ip + 1 ] )
+ l( bc[ ip + 1 ] )
, 1
);
break;
case op.MATCH_REGEXP: // MATCH_REGEXP r, a, f, ...
compileCondition( c( bc[ ip + 1 ] ) + ".test(input.charAt(peg$currPos))", 1 );
case op.MATCH_CLASS: // MATCH_CLASS c, a, f, ...
compileCondition( r( bc[ ip + 1 ] ) + ".test(input.charAt(peg$currPos))", 1 );
break;
case op.ACCEPT_N: // ACCEPT_N n
@ -748,17 +830,17 @@ function generateJS( ast, options ) {
break;
case op.ACCEPT_STRING: // ACCEPT_STRING s
parts.push( stack.push( c( bc[ ip + 1 ] ) ) );
parts.push( stack.push( l( bc[ ip + 1 ] ) ) );
parts.push(
eval( ast.consts[ bc[ ip + 1 ] ] ).length > 1
? "peg$currPos += " + eval( ast.consts[ bc[ ip + 1 ] ] ).length + ";"
ast.literals[ bc[ ip + 1 ] ].length > 1
? "peg$currPos += " + ast.literals[ bc[ ip + 1 ] ].length + ";"
: "peg$currPos++;"
);
ip += 2;
break;
case op.EXPECT: // EXPECT e
parts.push( "if (peg$silentFails === 0) { peg$expect(" + c( bc[ ip + 1 ] ) + "); }" );
parts.push( "if (peg$silentFails === 0) { peg$expect(" + e( bc[ ip + 1 ] ) + "); }" );
ip += 2;
break;

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

2
src/parser.pegjs

@ -104,7 +104,7 @@ Grammar
return new ast.Grammar(
extractOptional(initializer, 0),
extractList(rules, 0),
location(),
location()
);
}

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

@ -18,9 +18,14 @@ describe( "compiler pass |generateBytecode|", function () {
}
function constsDetails( consts ) {
function constsDetails( literals, classes, expectations, functions ) {
return { consts: consts };
return {
literals: literals,
classes: classes,
expectations: expectations,
functions: functions
};
}
@ -34,9 +39,9 @@ describe( "compiler pass |generateBytecode|", function () {
"c = 'c'"
].join( "\n" ), {
rules: [
{ 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 ] }
{ bytecode: [ 23, 0, 18, 0, 2, 1, 22, 0, 3 ] },
{ bytecode: [ 23, 1, 18, 1, 2, 1, 22, 1, 3 ] },
{ bytecode: [ 23, 2, 18, 2, 2, 1, 22, 2, 3 ] }
]
} );
@ -48,14 +53,16 @@ describe( "compiler pass |generateBytecode|", function () {
"a = 'a'",
"b = 'b'",
"c = 'c'"
].join( "\n" ), constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"\"b\"",
"peg$literalExpectation(\"b\", false)",
"\"c\"",
"peg$literalExpectation(\"c\", false)"
] ) );
].join( "\n" ), constsDetails(
[ "a", "b", "c" ],
[],
[
{ type: "literal", value: "a", ignoreCase: false },
{ type: "literal", value: "b", ignoreCase: false },
{ type: "literal", value: "c", ignoreCase: false }
],
[]
) );
} );
@ -66,7 +73,7 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( "start = 'a'", bytecodeDetails( [
23, 1, 18, 0, 2, 1, 22, 0, 3 // <expression>
23, 0, 18, 0, 2, 1, 22, 0, 3 // <expression>
] ) );
} );
@ -92,13 +99,13 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar2, bytecodeDetails( [
23, 0, // EXPECT <0>
28, // SILENT_FAILS_ON
18, 1, 2, 1, 22, 1, 3, // <expression>
18, 0, 2, 1, 22, 0, 3, // <expression>
29 // SILENT_FAILS_OFF
] ) );
expect( pass ).to.changeAST( grammar3, bytecodeDetails( [
23, 0, // EXPECT <0>
28, // SILENT_FAILS_ON
20, 1, 2, 1, 21, 1, 3, // <expression>
20, 0, 2, 1, 21, 1, 3, // <expression>
29 // SILENT_FAILS_OFF
] ) );
@ -106,17 +113,24 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar1, constsDetails( [
"peg$otherExpectation(\"start\")"
] ) );
expect( pass ).to.changeAST( grammar2, constsDetails( [
"peg$otherExpectation(\"start\")",
"\"a\""
] ) );
expect( pass ).to.changeAST( grammar3, constsDetails( [
"peg$otherExpectation(\"start\")",
"/^[a]/"
] ) );
expect( pass ).to.changeAST( grammar1, constsDetails(
[],
[],
[ { type: "rule", value: "start" } ],
[]
) );
expect( pass ).to.changeAST( grammar2, constsDetails(
[ "a" ],
[],
[ { type: "rule", value: "start" } ],
[]
) );
expect( pass ).to.changeAST( grammar3, constsDetails(
[],
[ { value: [ "a" ], inverted: false, ignoreCase: false } ],
[ { type: "rule", value: "start" } ],
[]
) );
} );
@ -140,13 +154,15 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar1, constsDetails( [] ), {}, { reportFailures: false } );
expect( pass ).to.changeAST( grammar2, constsDetails( [
"\"a\""
] ), {}, { reportFailures: false } );
expect( pass ).to.changeAST( grammar3, constsDetails( [
"/^[a]/"
] ), {}, { reportFailures: false } );
expect( pass ).to.changeAST( grammar1, constsDetails(
[], [], [], []
), {}, { reportFailures: false } );
expect( pass ).to.changeAST( grammar2, constsDetails(
[ "a" ], [], [], []
), {}, { reportFailures: false } );
expect( pass ).to.changeAST( grammar3, constsDetails(
[], [ { value: [ "a" ], inverted: false, ignoreCase: false } ], [], []
), {}, { reportFailures: false } );
} );
@ -159,13 +175,13 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( "start = 'a' / 'b' / 'c'", bytecodeDetails( [
23, 1, 18, 0, 2, 1, 22, 0, 3, // <alternatives[0]>
23, 0, 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]>
23, 1, 18, 1, 2, 1, 22, 1, 3, // <alternatives[1]>
14, 10, 0, // IF_ERROR
6, // * POP
23, 5, 18, 4, 2, 1, 22, 4, 3 // <alternatives[2]>
23, 2, 18, 2, 2, 1, 22, 2, 3 // <alternatives[2]>
] ) );
} );
@ -182,10 +198,10 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
23, 0, 18, 0, 2, 1, 22, 0, 3, // <expression>
15, 6, 0, // IF_NOT_ERROR
24, 1, // * LOAD_SAVED_POS
26, 2, 1, 0, // CALL
26, 0, 1, 0, // CALL <0>
9 // NIP
] ) );
@ -193,11 +209,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"function() { code }"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a" ],
[],
[ { type: "literal", value: "a", ignoreCase: false } ],
[ { predicate: false, params: [], body: " code " } ]
) );
} );
@ -211,10 +228,10 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
23, 0, 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
26, 0, 1, 1, 0, // CALL <0>
9 // NIP
] ) );
@ -222,11 +239,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"function(a) { code }"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a" ],
[],
[ { type: "literal", value: "a", ignoreCase: false } ],
[ { predicate: false, params: [ "a" ], body: " code " } ]
) );
} );
@ -240,14 +258,14 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <elements[0]>
23, 0, 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]>
23, 1, 18, 1, 2, 1, 22, 1, 3, // * <elements[1]>
15, 25, 4, // IF_NOT_ERROR
23, 5, 18, 4, 2, 1, 22, 4, 3, // * <elements[2]>
23, 2, 18, 2, 2, 1, 22, 2, 3, // * <elements[2]>
15, 9, 4, // IF_NOT_ERROR
24, 3, // * LOAD_SAVED_POS
26, 6, 4, 3, 2, 1, 0, // CALL <6>
26, 0, 4, 3, 2, 1, 0, // CALL <0>
8, 3, // * POP_N
7, // POP_CURR_POS
3, // PUSH_FAILED
@ -263,15 +281,16 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"\"b\"",
"peg$literalExpectation(\"b\", false)",
"\"c\"",
"peg$literalExpectation(\"c\", false)",
"function(a, b, c) { code }"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a", "b", "c" ],
[],
[
{ type: "literal", value: "a", ignoreCase: false },
{ type: "literal", value: "b", ignoreCase: false },
{ type: "literal", value: "c", ignoreCase: false }
],
[ { predicate: false, params: [ "a", "b", "c" ], body: " code " } ]
) );
} );
@ -287,11 +306,11 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <elements[0]>
23, 0, 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]>
23, 1, 18, 1, 2, 1, 22, 1, 3, // * <elements[1]>
15, 19, 4, // IF_NOT_ERROR
23, 5, 18, 4, 2, 1, 22, 4, 3, // * <elements[2]>
23, 2, 18, 2, 2, 1, 22, 2, 3, // * <elements[2]>
15, 3, 4, // IF_NOT_ERROR
11, 3, // * WRAP
9, // NIP
@ -310,14 +329,16 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"\"b\"",
"peg$literalExpectation(\"b\", false)",
"\"c\"",
"peg$literalExpectation(\"c\", false)"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a", "b", "c" ],
[],
[
{ type: "literal", value: "a", ignoreCase: false },
{ type: "literal", value: "b", ignoreCase: false },
{ type: "literal", value: "c", ignoreCase: false }
],
[]
) );
} );
@ -328,7 +349,7 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( "start = a:'a'", bytecodeDetails( [
23, 1, 18, 0, 2, 1, 22, 0, 3 // <expression>
23, 0, 18, 0, 2, 1, 22, 0, 3 // <expression>
] ) );
} );
@ -341,7 +362,7 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( "start = $'a'", bytecodeDetails( [
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
23, 0, 18, 0, 2, 1, 22, 0, 3, // <expression>
15, 2, 1, // IF_NOT_ERROR
6, // * POP
12, // TEXT
@ -361,7 +382,7 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
38, // EXPECT_NS_BEGIN
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
23, 0, 18, 0, 2, 1, 22, 0, 3, // <expression>
39, 0, // EXPECT_NS_END <false>
15, 3, 3, // IF_NOT_ERROR
6, // * POP
@ -376,10 +397,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a" ],
[],
[ { type: "literal", value: "a", ignoreCase: false } ],
[]
) );
} );
@ -394,7 +417,7 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
38, // EXPECT_NS_BEGIN
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
23, 0, 18, 0, 2, 1, 22, 0, 3, // <expression>
39, 1, // EXPECT_NS_END <true>
14, 3, 3, // IF_ERROR
6, // * POP
@ -409,10 +432,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a" ],
[],
[ { type: "literal", value: "a", ignoreCase: false } ],
[]
) );
} );
@ -425,7 +450,7 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
23, 0, 18, 0, 2, 1, 22, 0, 3, // <expression>
14, 2, 0, // IF_ERROR
6, // * POP
2 // PUSH_NULL
@ -435,10 +460,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a" ],
[],
[ { type: "literal", value: "a", ignoreCase: false } ],
[]
) );
} );
@ -452,10 +479,10 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
4, // PUSH_EMPTY_ARRAY
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
23, 0, 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>
23, 0, 18, 0, 2, 1, 22, 0, 3, // <expression>
6 // POP
] ) );
@ -463,10 +490,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a" ],
[],
[ { type: "literal", value: "a", ignoreCase: false } ],
[]
) );
} );
@ -480,11 +509,11 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
4, // PUSH_EMPTY_ARRAY
23, 1, 18, 0, 2, 1, 22, 0, 3, // <expression>
23, 0, 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>
23, 0, 18, 0, 2, 1, 22, 0, 3, // <expression>
6, // POP
6, // * POP
6, // POP
@ -495,10 +524,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a" ],
[],
[ { type: "literal", value: "a", ignoreCase: false } ],
[]
) );
} );
@ -511,17 +542,19 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
23, 1, 18, 0, 2, 1, 22, 0, 3 // <expression>
23, 0, 18, 0, 2, 1, 22, 0, 3 // <expression>
] ) );
} );
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a" ],
[],
[ { type: "literal", value: "a", ignoreCase: false } ],
[]
) );
} );
@ -537,7 +570,7 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
25, // UPDATE_SAVED_POS
26, 0, 0, 0, // CALL
26, 0, 0, 0, // CALL <0>
13, 2, 2, // IF
6, // * POP
1, // PUSH_UNDEFINED
@ -551,7 +584,7 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST(
grammar,
constsDetails( [ "function() { code }" ] )
constsDetails( [], [], [], [ { predicate: true, params: [], body: " code " } ] )
);
} );
@ -566,14 +599,14 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <elements[0]>
23, 0, 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]>
23, 1, 18, 1, 2, 1, 22, 1, 3, // * <elements[1]>
15, 41, 4, // IF_NOT_ERROR
23, 5, 18, 4, 2, 1, 22, 4, 3, // * <elements[2]>
23, 2, 18, 2, 2, 1, 22, 2, 3, // * <elements[2]>
15, 25, 4, // IF_NOT_ERROR
25, // * UPDATE_SAVED_POS
26, 6, 0, 3, 2, 1, 0, // CALL
26, 0, 0, 3, 2, 1, 0, // CALL <0>
13, 2, 2, // IF
6, // * POP
1, // PUSH_UNDEFINED
@ -600,15 +633,16 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"\"b\"",
"peg$literalExpectation(\"b\", false)",
"\"c\"",
"peg$literalExpectation(\"c\", false)",
"function(a, b, c) { code }"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a", "b", "c" ],
[],
[
{ type: "literal", value: "a", ignoreCase: false },
{ type: "literal", value: "b", ignoreCase: false },
{ type: "literal", value: "c", ignoreCase: false }
],
[ { predicate: true, params: [ "a", "b", "c" ], body: " code " } ]
) );
} );
@ -626,7 +660,7 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
25, // UPDATE_SAVED_POS
26, 0, 0, 0, // CALL
26, 0, 0, 0, // CALL <0>
13, 2, 2, // IF
6, // * POP
3, // PUSH_FAILED
@ -640,7 +674,7 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST(
grammar,
constsDetails( [ "function() { code }" ] )
constsDetails( [], [], [], [ { predicate: true, params: [], body: " code " } ] )
);
} );
@ -655,14 +689,14 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
5, // PUSH_CURR_POS
23, 1, 18, 0, 2, 1, 22, 0, 3, // <elements[0]>
23, 0, 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]>
23, 1, 18, 1, 2, 1, 22, 1, 3, // * <elements[1]>
15, 41, 4, // IF_NOT_ERROR
23, 5, 18, 4, 2, 1, 22, 4, 3, // * <elements[2]>
23, 2, 18, 2, 2, 1, 22, 2, 3, // * <elements[2]>
15, 25, 4, // IF_NOT_ERROR
25, // * UPDATE_SAVED_POS
26, 6, 0, 3, 2, 1, 0, // CALL
26, 0, 0, 3, 2, 1, 0, // CALL <0>
13, 2, 2, // IF
6, // * POP
3, // PUSH_FAILED
@ -689,15 +723,16 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"\"b\"",
"peg$literalExpectation(\"b\", false)",
"\"c\"",
"peg$literalExpectation(\"c\", false)",
"function(a, b, c) { code }"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a", "b", "c" ],
[],
[
{ type: "literal", value: "a", ignoreCase: false },
{ type: "literal", value: "b", ignoreCase: false },
{ type: "literal", value: "c", ignoreCase: false }
],
[ { predicate: true, params: [ "a", "b", "c" ], body: " code " } ]
) );
} );
@ -736,14 +771,14 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
0, 0 // PUSH
0 // PUSH_EMPTY_STRING
] ) );
} );
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [ "\"\"" ] ) );
expect( pass ).to.changeAST( grammar, constsDetails( [], [], [], [] ) );
} );
@ -756,9 +791,9 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
23, 1, // EXPECT <1>
23, 0, // EXPECT <0>
18, 0, 2, 1, // MATCH_STRING <0>
22, 0, // * ACCEPT_STRING
22, 0, // * ACCEPT_STRING <0>
3 // * PUSH_FAILED
] ) );
@ -766,10 +801,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"a\", false)"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a" ],
[],
[ { type: "literal", value: "a", ignoreCase: false } ],
[]
) );
} );
@ -782,9 +819,9 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
23, 1, // EXPECT <1>
23, 0, // EXPECT <0>
19, 0, 2, 1, // MATCH_STRING_IC <0>
21, 1, // * ACCEPT_N
21, 1, // * ACCEPT_N <1>
3 // * PUSH_FAILED
] ) );
@ -792,10 +829,12 @@ describe( "compiler pass |generateBytecode|", function () {
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [
"\"a\"",
"peg$literalExpectation(\"A\", true)"
] ) );
expect( pass ).to.changeAST( grammar, constsDetails(
[ "a" ],
[],
[ { type: "literal", value: "A", ignoreCase: true } ],
[]
) );
} );
@ -812,14 +851,14 @@ describe( "compiler pass |generateBytecode|", function () {
it( "generates correct bytecode", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
0, 0 // PUSH
0 // PUSH_EMPTY_STRING
] ), {}, { reportFailures: false } );
} );
it( "defines correct constants", function () {
expect( pass ).to.changeAST( grammar, constsDetails( [ "\"\"" ] ), {}, { reportFailures: false } );
expect( pass ).to.changeAST( grammar, constsDetails( [], [], [], [] ), {}, { reportFailures: false } );
} );
@ -833,7 +872,7 @@ describe( "compiler pass |generateBytecode|", function () {
expect( pass ).to.changeAST( grammar, bytecodeDetails( [
18, 0, 2, 1, // MATCH_STRING <0>
22, 0, // * ACCEPT_STRING
22, 0, // * ACCEPT_STRING <0>