Skip to content

Commit

Permalink
Cleanup bytecode generator (pegjs/pegjs#450): Replace PUSH opcode wit…
Browse files Browse the repository at this point in the history
…h PUSH_EMPTY_STRING opcode because it only used with empty strings
  • Loading branch information
Mingun committed May 20, 2021
1 parent dcbe046 commit aa44ec3
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 44 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ Released: TBD

Now bytecode generation pass is independent from the JavaScript backend.
[@Mingun](https://github.com/peggyjs/peggy/pull/117)
- Some opcodes from `compiler/opcode.js` is deprecated. Although you shouldn't use
them directly because they are notconsidered as a public API, some plugins use them.
For that reason backward compatibility is preserved:
- Opcode `MATCH_REGEXP` is deprecated and replaced by `MATCH_CHAR_CLASS` with the same value.
- Added new opcode `PUSH_EMPTY_STRING` that put on stack new empty string
- Opcode `PUSH` is deprecated because it was used only for pushing empty string constants
and they now pushed with `PUSH_EMPTY_STRING`

Instead of relying on the library opcodes it is better to have a copy of them,
especially if your plugin replaces both `generateBytecode` as `generateJs` passes.

[@Mingun](https://github.com/peggyjs/peggy/pull/117)

### Bug fixes

Expand Down
69 changes: 36 additions & 33 deletions lib/compiler/opcodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,64 @@
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
PLUCK: 36, // PLUCK n, k, p1, ..., pK
/** @deprecated Unused */
PUSH: 0, // PUSH c
PUSH_EMPTY_STRING: 35, // 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
PLUCK: 36, // PLUCK n, k, p1, ..., pK

// 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_CHAR_CLASS: 20, // MATCH_CHAR_CLASS c, a, f, ...
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_CHAR_CLASS: 20, // MATCH_CHAR_CLASS c, a, f, ...
/** @deprecated Replaced with `MATCH_CHAR_CLASS` */
MATCH_REGEXP: 20, // MATCH_REGEXP r, a, f, ...
ACCEPT_N: 21, // ACCEPT_N n
ACCEPT_STRING: 22, // ACCEPT_STRING s
FAIL: 23, // FAIL e
MATCH_REGEXP: 20, // MATCH_REGEXP r, a, f, ...
ACCEPT_N: 21, // ACCEPT_N n
ACCEPT_STRING: 22, // ACCEPT_STRING s
FAIL: 23, // FAIL 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

// Because the tests have hard-coded opcode numbers, don't renumber
// existing opcodes. New opcodes that have been put in the correct
// sections above are repeated here in order to ensure we don't
// reuse them.
//
// 30-35 reserved for @mingun
// 30-34 reserved for @mingun
// PUSH_EMPTY_STRING: 35
// PLUCK: 36
};

Expand Down
10 changes: 4 additions & 6 deletions lib/compiler/passes/generate-bytecode.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ const visitor = require("../visitor");
// Stack Manipulation
// ------------------
//
// [0] PUSH c
// [35] PUSH_EMPTY_STRING
//
// stack.push(literals[c]);
// stack.push("");
//
// [1] PUSH_UNDEFINED
//
Expand Down Expand Up @@ -614,11 +614,9 @@ function generateBytecode(ast) {
: [op.ACCEPT_STRING, stringIndex],
[op.FAIL, expectedIndex]
);
} else {
const stringIndex = addLiteralConst("");

return [op.PUSH, stringIndex];
}

return [op.PUSH_EMPTY_STRING];
},

class(node) {
Expand Down
6 changes: 3 additions & 3 deletions lib/compiler/passes/generate-js.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,9 +339,9 @@ function generateJS(ast, options) {

while (ip < end) {
switch (bc[ip]) {
case op.PUSH: // PUSH c
parts.push(stack.push(l(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
Expand Down
4 changes: 2 additions & 2 deletions test/unit/compiler/passes/generate-bytecode.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -628,12 +628,12 @@ describe("compiler pass |generateBytecode|", function() {

it("generates correct bytecode", function() {
expect(pass).to.changeAST(grammar, bytecodeDetails([
0, 0 // PUSH
35 // PUSH_EMPTY_STRING
]));
});

it("defines correct constants", function() {
expect(pass).to.changeAST(grammar, constsDetails([""], [], [], []));
expect(pass).to.changeAST(grammar, constsDetails([], [], [], []));
});
});

Expand Down

0 comments on commit aa44ec3

Please sign in to comment.