Implement additional PUSH_* bytecode instructions

Implement the following bytecode instructions:

  * PUSH_UNDEFINED
  * PUSH_NULL
  * PUSH_FAILED
  * PUSH_EMPTY_ARRAY

These instructions push simple JavaSccript values to the stack directly,
without going through constants. This makes the bytecode slightly
shorter and the bytecode generator somewhat simpler.

Also note that PUSH_EMPTY_ARRAY allows us to avoid a hack which protects
the [] constant from modification.
redux
David Majda 10 years ago
parent c6f0818d49
commit a815a8b902

@ -3,6 +3,10 @@ var opcodes = {
/* Stack Manipulation */ /* Stack Manipulation */
PUSH: 0, // PUSH c PUSH: 0, // PUSH c
PUSH_UNDEFINED: 26, // PUSH_UNDEFINED
PUSH_NULL: 27, // PUSH_NULL
PUSH_FAILED: 28, // PUSH_FAILED
PUSH_EMPTY_ARRAY: 29, // PUSH_EMPTY_ARRAY
PUSH_CURR_POS: 1, // PUSH_CURR_POS PUSH_CURR_POS: 1, // PUSH_CURR_POS
POP: 2, // POP POP: 2, // POP
POP_CURR_POS: 3, // POP_CURR_POS POP_CURR_POS: 3, // POP_CURR_POS

@ -17,6 +17,22 @@ var arrays = require("../../utils/arrays"),
* *
* stack.push(consts[c]); * stack.push(consts[c]);
* *
* [26] PUSH_UNDEFINED
*
* stack.push(undefined);
*
* [27] PUSH_NULL
*
* stack.push(null);
*
* [28] PUSH_FAILED
*
* stack.push(FAILED);
*
* [29] PUSH_EMPTY_ARRAY
*
* stack.push([]);
*
* [1] PUSH_CURR_POS * [1] PUSH_CURR_POS
* *
* stack.push(currPos); * stack.push(currPos);
@ -211,9 +227,6 @@ function generateBytecode(ast) {
} }
function buildSimplePredicate(expression, negative, context) { function buildSimplePredicate(expression, negative, context) {
var undefinedIndex = addConst('void 0'),
failedIndex = addConst('peg$FAILED');
return buildSequence( return buildSequence(
[op.PUSH_CURR_POS], [op.PUSH_CURR_POS],
[op.SILENT_FAILS_ON], [op.SILENT_FAILS_ON],
@ -228,21 +241,19 @@ function generateBytecode(ast) {
buildSequence( buildSequence(
[op.POP], [op.POP],
[negative ? op.POP : op.POP_CURR_POS], [negative ? op.POP : op.POP_CURR_POS],
[op.PUSH, undefinedIndex] [op.PUSH_UNDEFINED]
), ),
buildSequence( buildSequence(
[op.POP], [op.POP],
[negative ? op.POP_CURR_POS : op.POP], [negative ? op.POP_CURR_POS : op.POP],
[op.PUSH, failedIndex] [op.PUSH_FAILED]
) )
) )
); );
} }
function buildSemanticPredicate(code, negative, context) { function buildSemanticPredicate(code, negative, context) {
var functionIndex = addFunctionConst(objects.keys(context.env), code), var functionIndex = addFunctionConst(objects.keys(context.env), code);
undefinedIndex = addConst('void 0'),
failedIndex = addConst('peg$FAILED');
return buildSequence( return buildSequence(
[op.REPORT_CURR_POS], [op.REPORT_CURR_POS],
@ -251,11 +262,11 @@ function generateBytecode(ast) {
[op.IF], [op.IF],
buildSequence( buildSequence(
[op.POP], [op.POP],
[op.PUSH, negative ? failedIndex : undefinedIndex] negative ? [op.PUSH_FAILED] : [op.PUSH_UNDEFINED]
), ),
buildSequence( buildSequence(
[op.POP], [op.POP],
[op.PUSH, negative ? undefinedIndex : failedIndex] negative ? [op.PUSH_UNDEFINED] : [op.PUSH_FAILED]
) )
) )
); );
@ -377,7 +388,7 @@ function generateBytecode(ast) {
buildSequence( buildSequence(
processedCount > 1 ? [op.POP_N, processedCount] : [op.POP], processedCount > 1 ? [op.POP_N, processedCount] : [op.POP],
[op.POP_CURR_POS], [op.POP_CURR_POS],
[op.PUSH, failedIndex] [op.PUSH_FAILED]
) )
) )
); );
@ -404,8 +415,6 @@ function generateBytecode(ast) {
} }
} }
failedIndex = addConst('peg$FAILED');
return buildSequence( return buildSequence(
[op.PUSH_CURR_POS], [op.PUSH_CURR_POS],
buildElementsCode(node.elements, { buildElementsCode(node.elements, {
@ -456,8 +465,6 @@ function generateBytecode(ast) {
}, },
optional: function(node, context) { optional: function(node, context) {
var nullIndex = addConst('null');
return buildSequence( return buildSequence(
generate(node.expression, { generate(node.expression, {
sp: context.sp, sp: context.sp,
@ -466,22 +473,21 @@ function generateBytecode(ast) {
}), }),
buildCondition( buildCondition(
[op.IF_ERROR], [op.IF_ERROR],
buildSequence([op.POP], [op.PUSH, nullIndex]), buildSequence([op.POP], [op.PUSH_NULL]),
[] []
) )
); );
}, },
zero_or_more: function(node, context) { zero_or_more: function(node, context) {
var emptyArrayIndex = addConst('[]'); var expressionCode = generate(node.expression, {
expressionCode = generate(node.expression, {
sp: context.sp + 1, sp: context.sp + 1,
env: { }, env: { },
action: null action: null
}); });
return buildSequence( return buildSequence(
[op.PUSH, emptyArrayIndex], [op.PUSH_EMPTY_ARRAY],
expressionCode, expressionCode,
buildAppendLoop(expressionCode), buildAppendLoop(expressionCode),
[op.POP] [op.POP]
@ -489,21 +495,19 @@ function generateBytecode(ast) {
}, },
one_or_more: function(node, context) { one_or_more: function(node, context) {
var emptyArrayIndex = addConst('[]'); var expressionCode = generate(node.expression, {
failedIndex = addConst('peg$FAILED');
expressionCode = generate(node.expression, {
sp: context.sp + 1, sp: context.sp + 1,
env: { }, env: { },
action: null action: null
}); });
return buildSequence( return buildSequence(
[op.PUSH, emptyArrayIndex], [op.PUSH_EMPTY_ARRAY],
expressionCode, expressionCode,
buildCondition( buildCondition(
[op.IF_NOT_ERROR], [op.IF_NOT_ERROR],
buildSequence(buildAppendLoop(expressionCode), [op.POP]), buildSequence(buildAppendLoop(expressionCode), [op.POP]),
buildSequence([op.POP], [op.POP], [op.PUSH, failedIndex]) buildSequence([op.POP], [op.POP], [op.PUSH_FAILED])
) )
); );
}, },

@ -148,10 +148,6 @@ function generateJavascript(ast, options) {
} }
parts.push([ parts.push([
' function protect(object) {',
' return Object.prototype.toString.apply(object) === "[object Array]" ? [] : object;',
' }',
'',
/* /*
* The point of the outer loop and the |ips| & |ends| stacks is to avoid * The point of the outer loop and the |ips| & |ends| stacks is to avoid
* recursive calls for interpreting parts of bytecode. In other words, we * recursive calls for interpreting parts of bytecode. In other words, we
@ -163,14 +159,30 @@ function generateJavascript(ast, options) {
' while (ip < end) {', ' while (ip < end) {',
' switch (bc[ip]) {', ' switch (bc[ip]) {',
' case ' + op.PUSH + ':', // PUSH c ' case ' + op.PUSH + ':', // PUSH c
/* ' stack.push(peg$consts[bc[ip + 1]]);',
* Hack: One of the constants can be an empty array. It needs to be cloned
* because it can be modified later on the stack by |APPEND|.
*/
' stack.push(protect(peg$consts[bc[ip + 1]]));',
' ip += 2;', ' ip += 2;',
' break;', ' break;',
'', '',
' case ' + op.PUSH_UNDEFINED + ':', // PUSH_UNDEFINED
' stack.push(void 0);',
' 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 ' case ' + op.PUSH_CURR_POS + ':', // PUSH_CURR_POS
' stack.push(peg$currPos);', ' stack.push(peg$currPos);',
' ip++;', ' ip++;',
@ -445,14 +457,7 @@ function generateJavascript(ast, options) {
while (ip < end) { while (ip < end) {
switch (bc[ip]) { switch (bc[ip]) {
case op.PUSH: // PUSH c case op.PUSH: // PUSH c
/* parts.push(stack.push(c(bc[ip + 1])));
* Hack: One of the constants can be an empty array. It needs to be
* handled specially because it can be modified later on the stack
* by |APPEND|.
*/
parts.push(
stack.push(ast.consts[bc[ip + 1]] === "[]" ? "[]" : c(bc[ip + 1]))
);
ip += 2; ip += 2;
break; break;
@ -461,6 +466,26 @@ function generateJavascript(ast, options) {
ip++; ip++;
break; break;
case op.PUSH_UNDEFINED: // PUSH_UNDEFINED
parts.push(stack.push('void 0'));
ip++;
break;
case op.PUSH_NULL: // PUSH_NULL
parts.push(stack.push('null'));
ip++;
break;
case op.PUSH_FAILED: // PUSH_FAILED
parts.push(stack.push('peg$FAILED'));
ip++;
break;
case op.PUSH_EMPTY_ARRAY: // PUSH_EMPTY_ARRAY
parts.push(stack.push('[]'));
ip++;
break;
case op.POP: // POP case op.POP: // POP
stack.pop(); stack.pop();
ip++; ip++;

@ -135,30 +135,29 @@ describe("compiler pass |generateBytecode|", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).toChangeAST(grammar, bytecodeDetails([
1, // PUSH_CURR_POS 1, // PUSH_CURR_POS
14, 1, 2, 2, 18, 1, 19, 2, // <elements[0]> 14, 0, 2, 2, 18, 0, 19, 1, // <elements[0]>
11, 42, 4, // IF_NOT_ERROR 11, 40, 3, // IF_NOT_ERROR
14, 3, 2, 2, 18, 3, 19, 4, // * <elements[1]> 14, 2, 2, 2, 18, 2, 19, 3, // * <elements[1]>
11, 26, 5, // IF_NOT_ERROR 11, 25, 4, // IF_NOT_ERROR
14, 5, 2, 2, 18, 5, 19, 6, // * <elements[2]> 14, 4, 2, 2, 18, 4, 19, 5, // * <elements[2]>
11, 10, 5, // IF_NOT_ERROR 11, 10, 4, // IF_NOT_ERROR
20, 3, // * REPORT_SAVED_POS 20, 3, // * REPORT_SAVED_POS
22, 7, 3, 3, 2, 1, 0, // CALL 22, 6, 3, 3, 2, 1, 0, // CALL
5, // NIP 5, // NIP
4, 3, // * POP_N 4, 3, // * POP_N
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0, // PUSH 28, // PUSH_FAILED
4, 2, // * POP_N 4, 2, // * POP_N
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0, // PUSH 28, // PUSH_FAILED
2, // * POP 2, // * POP
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0 // PUSH 28 // PUSH_FAILED
])); ]));
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).toChangeAST(grammar, constsDetails([
'peg$FAILED',
'"a"', '"a"',
'{ type: "literal", value: "a", description: "\\"a\\"" }', '{ type: "literal", value: "a", description: "\\"a\\"" }',
'"b"', '"b"',
@ -177,29 +176,28 @@ describe("compiler pass |generateBytecode|", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).toChangeAST(grammar, bytecodeDetails([
1, // PUSH_CURR_POS 1, // PUSH_CURR_POS
14, 1, 2, 2, 18, 1, 19, 2, // <elements[0]> 14, 0, 2, 2, 18, 0, 19, 1, // <elements[0]>
11, 35, 4, // IF_NOT_ERROR 11, 33, 3, // IF_NOT_ERROR
14, 3, 2, 2, 18, 3, 19, 4, // * <elements[1]> 14, 2, 2, 2, 18, 2, 19, 3, // * <elements[1]>
11, 19, 5, // IF_NOT_ERROR 11, 18, 4, // IF_NOT_ERROR
14, 5, 2, 2, 18, 5, 19, 6, // * <elements[2]> 14, 4, 2, 2, 18, 4, 19, 5, // * <elements[2]>
11, 3, 5, // IF_NOT_ERROR 11, 3, 4, // IF_NOT_ERROR
7, 3, // * WRAP 7, 3, // * WRAP
5, // NIP 5, // NIP
4, 3, // * POP_N 4, 3, // * POP_N
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0, // PUSH 28, // PUSH_FAILED
4, 2, // * POP_N 4, 2, // * POP_N
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0, // PUSH 28, // PUSH_FAILED
2, // * POP 2, // * POP
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0 // PUSH 28 // PUSH_FAILED
])); ]));
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).toChangeAST(grammar, constsDetails([
'peg$FAILED',
'"a"', '"a"',
'{ type: "literal", value: "a", description: "\\"a\\"" }', '{ type: "literal", value: "a", description: "\\"a\\"" }',
'"b"', '"b"',
@ -237,22 +235,20 @@ describe("compiler pass |generateBytecode|", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).toChangeAST(grammar, bytecodeDetails([
1, // PUSH_CURR_POS 1, // PUSH_CURR_POS
24, // SILENT_FAILS_ON 24, // SILENT_FAILS_ON
14, 2, 2, 2, 18, 2, 19, 3, // <expression> 14, 0, 2, 2, 18, 0, 19, 1, // <expression>
25, // SILENT_FAILS_OFF 25, // SILENT_FAILS_OFF
11, 4, 4, // IF_NOT_ERROR 11, 3, 3, // IF_NOT_ERROR
2, // * POP 2, // * POP
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0, // PUSH 26, // PUSH_UNDEFINED
2, // * POP 2, // * POP
2, // POP 2, // POP
0, 1 // PUSH 28 // PUSH_FAILED
])); ]));
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).toChangeAST(grammar, constsDetails([
'void 0',
'peg$FAILED',
'"a"', '"a"',
'{ type: "literal", value: "a", description: "\\"a\\"" }' '{ type: "literal", value: "a", description: "\\"a\\"" }'
])); ]));
@ -266,22 +262,20 @@ describe("compiler pass |generateBytecode|", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).toChangeAST(grammar, bytecodeDetails([
1, // PUSH_CURR_POS 1, // PUSH_CURR_POS
24, // SILENT_FAILS_ON 24, // SILENT_FAILS_ON
14, 2, 2, 2, 18, 2, 19, 3, // <expression> 14, 0, 2, 2, 18, 0, 19, 1, // <expression>
25, // SILENT_FAILS_OFF 25, // SILENT_FAILS_OFF
10, 4, 4, // IF_ERROR 10, 3, 3, // IF_ERROR
2, // * POP 2, // * POP
2, // POP 2, // POP
0, 0, // PUSH 26, // PUSH_UNDEFINED
2, // * POP 2, // * POP
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 1 // PUSH 28 // PUSH_FAILED
])); ]));
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).toChangeAST(grammar, constsDetails([
'void 0',
'peg$FAILED',
'"a"', '"a"',
'{ type: "literal", value: "a", description: "\\"a\\"" }' '{ type: "literal", value: "a", description: "\\"a\\"" }'
])); ]));
@ -296,18 +290,18 @@ describe("compiler pass |generateBytecode|", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).toChangeAST(grammar, bytecodeDetails([
21, // REPORT_CURR_POS 21, // REPORT_CURR_POS
22, 0, 0, 0, // CALL 22, 0, 0, 0, // CALL
9, 3, 3, // IF 9, 2, 2, // IF
2, // * POP 2, // * POP
0, 1, // PUSH 26, // PUSH_UNDEFINED
2, // * POP 2, // * POP
0, 2 // PUSH 28 // PUSH_FAILED
])); ]));
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST( expect(pass).toChangeAST(
grammar, grammar,
constsDetails(['function() { code }', 'void 0', 'peg$FAILED']) constsDetails(['function() { code }'])
); );
}); });
}); });
@ -318,48 +312,46 @@ describe("compiler pass |generateBytecode|", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).toChangeAST(grammar, bytecodeDetails([
1, // PUSH_CURR_POS 1, // PUSH_CURR_POS
14, 1, 2, 2, 18, 1, 19, 2, // <elements[0]> 14, 0, 2, 2, 18, 0, 19, 1, // <elements[0]>
11, 60, 4, // IF_NOT_ERROR 11, 55, 3, // IF_NOT_ERROR
14, 3, 2, 2, 18, 3, 19, 4, // * <elements[1]> 14, 2, 2, 2, 18, 2, 19, 3, // * <elements[1]>
11, 44, 5, // IF_NOT_ERROR 11, 40, 4, // IF_NOT_ERROR
14, 5, 2, 2, 18, 5, 19, 6, // * <elements[2]> 14, 4, 2, 2, 18, 4, 19, 5, // * <elements[2]>
11, 28, 5, // IF_NOT_ERROR 11, 25, 4, // IF_NOT_ERROR
21, // * REPORT_CURR_POS 21, // * REPORT_CURR_POS
22, 7, 0, 3, 2, 1, 0, // CALL 22, 6, 0, 3, 2, 1, 0, // CALL
9, 3, 3, // IF 9, 2, 2, // IF
2, // * POP 2, // * POP
0, 8, // PUSH 26, // PUSH_UNDEFINED
2, // * POP 2, // * POP
0, 0, // PUSH 28, // PUSH_FAILED
11, 3, 5, // IF_NOT_ERROR 11, 3, 4, // IF_NOT_ERROR
7, 4, // * WRAP 7, 4, // * WRAP
5, // NIP 5, // NIP
4, 4, // * POP_N 4, 4, // * POP_N
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0, // PUSH 28, // PUSH_FAILED
4, 3, // * POP_N 4, 3, // * POP_N
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0, // PUSH 28, // PUSH_FAILED
4, 2, // * POP_N 4, 2, // * POP_N
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0, // PUSH 28, // PUSH_FAILED
2, // * POP 2, // * POP
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0 // PUSH 28 // PUSH_FAILED
])); ]));
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).toChangeAST(grammar, constsDetails([
'peg$FAILED',
'"a"', '"a"',
'{ type: "literal", value: "a", description: "\\"a\\"" }', '{ type: "literal", value: "a", description: "\\"a\\"" }',
'"b"', '"b"',
'{ type: "literal", value: "b", description: "\\"b\\"" }', '{ type: "literal", value: "b", description: "\\"b\\"" }',
'"c"', '"c"',
'{ type: "literal", value: "c", description: "\\"c\\"" }', '{ type: "literal", value: "c", description: "\\"c\\"" }',
'function(a, b, c) { code }', 'function(a, b, c) { code }'
'void 0'
])); ]));
}); });
}); });
@ -373,18 +365,18 @@ describe("compiler pass |generateBytecode|", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).toChangeAST(grammar, bytecodeDetails([
21, // REPORT_CURR_POS 21, // REPORT_CURR_POS
22, 0, 0, 0, // CALL 22, 0, 0, 0, // CALL
9, 3, 3, // IF 9, 2, 2, // IF
2, // * POP 2, // * POP
0, 2, // PUSH 28, // PUSH_FAILED
2, // * POP 2, // * POP
0, 1 // PUSH 26 // PUSH_UNDEFINED
])); ]));
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST( expect(pass).toChangeAST(
grammar, grammar,
constsDetails(['function() { code }', 'void 0', 'peg$FAILED']) constsDetails(['function() { code }'])
); );
}); });
}); });
@ -395,48 +387,46 @@ describe("compiler pass |generateBytecode|", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).toChangeAST(grammar, bytecodeDetails([
1, // PUSH_CURR_POS 1, // PUSH_CURR_POS
14, 1, 2, 2, 18, 1, 19, 2, // <elements[0]> 14, 0, 2, 2, 18, 0, 19, 1, // <elements[0]>
11, 60, 4, // IF_NOT_ERROR 11, 55, 3, // IF_NOT_ERROR
14, 3, 2, 2, 18, 3, 19, 4, // * <elements[1]> 14, 2, 2, 2, 18, 2, 19, 3, // * <elements[1]>
11, 44, 5, // IF_NOT_ERROR 11, 40, 4, // IF_NOT_ERROR
14, 5, 2, 2, 18, 5, 19, 6, // * <elements[2]> 14, 4, 2, 2, 18, 4, 19, 5, // * <elements[2]>
11, 28, 5, // IF_NOT_ERROR 11, 25, 4, // IF_NOT_ERROR
21, // * REPORT_CURR_POS 21, // * REPORT_CURR_POS
22, 7, 0, 3, 2, 1, 0, // CALL 22, 6, 0, 3, 2, 1, 0, // CALL
9, 3, 3, // IF 9, 2, 2, // IF
2, // * POP 2, // * POP
0, 0, // PUSH 28, // PUSH_FAILED
2, // * POP 2, // * POP
0, 8, // PUSH 26, // PUSH_UNDEFINED
11, 3, 5, // IF_NOT_ERROR 11, 3, 4, // IF_NOT_ERROR
7, 4, // * WRAP 7, 4, // * WRAP
5, // NIP 5, // NIP
4, 4, // * POP_N 4, 4, // * POP_N
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0, // PUSH 28, // PUSH_FAILED
4, 3, // * POP_N 4, 3, // * POP_N
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0, // PUSH 28, // PUSH_FAILED
4, 2, // * POP_N 4, 2, // * POP_N
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0, // PUSH 28, // PUSH_FAILED
2, // * POP 2, // * POP
3, // POP_CURR_POS 3, // POP_CURR_POS
0, 0 // PUSH 28 // PUSH_FAILED
])); ]));
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).toChangeAST(grammar, constsDetails([
'peg$FAILED',
'"a"', '"a"',
'{ type: "literal", value: "a", description: "\\"a\\"" }', '{ type: "literal", value: "a", description: "\\"a\\"" }',
'"b"', '"b"',
'{ type: "literal", value: "b", description: "\\"b\\"" }', '{ type: "literal", value: "b", description: "\\"b\\"" }',
'"c"', '"c"',
'{ type: "literal", value: "c", description: "\\"c\\"" }', '{ type: "literal", value: "c", description: "\\"c\\"" }',
'function(a, b, c) { code }', 'function(a, b, c) { code }'
'void 0'
])); ]));
}); });
}); });
@ -447,16 +437,15 @@ describe("compiler pass |generateBytecode|", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).toChangeAST(grammar, bytecodeDetails([
14, 1, 2, 2, 18, 1, 19, 2, // <expression> 14, 0, 2, 2, 18, 0, 19, 1, // <expression>
10, 3, 0, // IF_ERROR 10, 2, 0, // IF_ERROR
2, // * POP 2, // * POP
0, 0 // PUSH 27 // PUSH_NULL
])); ]));
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).toChangeAST(grammar, constsDetails([
'null',
'"a"', '"a"',
'{ type: "literal", value: "a", description: "\\"a\\"" }' '{ type: "literal", value: "a", description: "\\"a\\"" }'
])); ]));
@ -468,18 +457,17 @@ describe("compiler pass |generateBytecode|", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).toChangeAST(grammar, bytecodeDetails([
0, 0, // PUSH 29, // PUSH_EMPTY_ARRAY
14, 1, 2, 2, 18, 1, 19, 2, // <expression> 14, 0, 2, 2, 18, 0, 19, 1, // <expression>
12, 9, // WHILE_NOT_ERROR 12, 9, // WHILE_NOT_ERROR
6, // * APPEND 6, // * APPEND
14, 1, 2, 2, 18, 1, 19, 2, // <expression> 14, 0, 2, 2, 18, 0, 19, 1, // <expression>
2 // POP 2 // POP
])); ]));
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).toChangeAST(grammar, constsDetails([
'[]',
'"a"', '"a"',
'{ type: "literal", value: "a", description: "\\"a\\"" }' '{ type: "literal", value: "a", description: "\\"a\\"" }'
])); ]));
@ -491,23 +479,21 @@ describe("compiler pass |generateBytecode|", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).toChangeAST(grammar, bytecodeDetails([
0, 0, // PUSH 29, // PUSH_EMPTY_ARRAY
14, 2, 2, 2, 18, 2, 19, 3, // <expression> 14, 0, 2, 2, 18, 0, 19, 1, // <expression>
11, 12, 4, // IF_NOT_ERROR 11, 12, 3, // IF_NOT_ERROR
12, 9, // * WHILE_NOT_ERROR 12, 9, // * WHILE_NOT_ERROR
6, // * APPEND 6, // * APPEND
14, 2, 2, 2, 18, 2, 19, 3, // <expression> 14, 0, 2, 2, 18, 0, 19, 1, // <expression>
2, // POP 2, // POP
2, // * POP 2, // * POP
2, // POP 2, // POP
0, 1 // PUSH 28 // PUSH_FAILED
])); ]));
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).toChangeAST(grammar, constsDetails([
'[]',
'peg$FAILED',
'"a"', '"a"',
'{ type: "literal", value: "a", description: "\\"a\\"" }' '{ type: "literal", value: "a", description: "\\"a\\"" }'
])); ]));

Loading…
Cancel
Save