-
Notifications
You must be signed in to change notification settings - Fork 65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generate SourceNodes for bytecode #240
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -197,6 +197,27 @@ const { ALWAYS_MATCH, SOMETIMES_MATCH, NEVER_MATCH } = require("./inference-matc | |
// | ||
// silentFails--; | ||
// | ||
// Source Mapping | ||
// -------------- | ||
// | ||
// [37] SOURCE_MAP_PUSH n | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll need to notify downstream folks that have their own generators that there are new opcodes. At the very least, this needs to be a major change in the changelog. @markw65 can you add an entry to CHANGELOG.md, and add yourself to AUTHORS while you're at it, please? |
||
// | ||
// Everything generated from here until the corresponding SOURCE_MAP_POP | ||
// will be wrapped in a SourceNode tagged with locations[n]. | ||
// | ||
// [38] SOURCE_MAP_POP | ||
// | ||
// See above. | ||
// | ||
// [39] SOURCE_MAP_LABEL_PUSH sp, label, loc | ||
// | ||
// Mark that the stack location sp will be used to hold the value | ||
// of the label named literals[label], with location info locations[loc] | ||
// | ||
// [40] SOURCE_MAP_LABEL_POP sp | ||
// | ||
// End the region started by [39] | ||
// | ||
// This pass can use the results of other previous passes, each of which can | ||
// change the AST (and, as consequence, the bytecode). | ||
// | ||
|
@@ -217,11 +238,12 @@ const { ALWAYS_MATCH, SOMETIMES_MATCH, NEVER_MATCH } = require("./inference-matc | |
// that is equivalent of an unknown match result and signals the generator that | ||
// runtime check for the |FAILED| is required. Trick is explained on the | ||
// Wikipedia page (https://en.wikipedia.org/wiki/Asm.js#Code_generation) | ||
function generateBytecode(ast) { | ||
function generateBytecode(ast, options) { | ||
const literals = []; | ||
const classes = []; | ||
const expectations = []; | ||
const functions = []; | ||
const locations = []; | ||
|
||
function addLiteralConst(value) { | ||
const index = literals.indexOf(value); | ||
|
@@ -261,6 +283,13 @@ function generateBytecode(ast) { | |
return index === -1 ? functions.push(func) - 1 : index; | ||
} | ||
|
||
function addLocation(location) { | ||
// Don't bother de-duplicating. There can be a lot of locations, | ||
// they will almost never collide, and unlike the "consts" above, | ||
// it won't affect code generation even if they do. | ||
return locations.push(location) - 1; | ||
} | ||
|
||
function cloneEnv(env) { | ||
const clone = {}; | ||
|
||
|
@@ -355,14 +384,41 @@ function generateBytecode(ast) { | |
); | ||
} | ||
|
||
const generate = visitor.build({ | ||
function wrapGenerators(generators) { | ||
if (options && options.output === "source-and-map") { | ||
Object.entries(generators).forEach(([name, generator]) => { | ||
generators[name] = function(node, ...args) { | ||
const generated = generator(node, ...args); | ||
// Some generators ("grammar" and "rule") don't return anything, | ||
// so don't bother wrapping their return values. | ||
if (generated === undefined || !node.location) { | ||
return generated; | ||
} | ||
return buildSequence( | ||
[ | ||
op.SOURCE_MAP_PUSH, | ||
addLocation(node.location), | ||
], | ||
generated, | ||
[ | ||
op.SOURCE_MAP_POP, | ||
] | ||
); | ||
}; | ||
}); | ||
} | ||
return visitor.build(generators); | ||
} | ||
|
||
const generate = wrapGenerators({ | ||
grammar(node) { | ||
node.rules.forEach(generate); | ||
|
||
node.literals = literals; | ||
node.classes = classes; | ||
node.expectations = expectations; | ||
node.functions = functions; | ||
node.locations = locations; | ||
hildjj marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}, | ||
|
||
rule(node) { | ||
|
@@ -547,11 +603,25 @@ function generateBytecode(ast) { | |
context.pluck.push(sp); | ||
} | ||
|
||
return generate(node.expression, { | ||
const expression = generate(node.expression, { | ||
sp: context.sp, | ||
env, | ||
action: null, | ||
}); | ||
|
||
if (label && node.labelLocation && options && options.output === "source-and-map") { | ||
return buildSequence( | ||
[ | ||
op.SOURCE_MAP_LABEL_PUSH, | ||
sp, | ||
addLiteralConst(label), | ||
addLocation(node.labelLocation), | ||
], | ||
expression, | ||
[op.SOURCE_MAP_LABEL_POP, sp] | ||
); | ||
} | ||
return expression; | ||
}, | ||
|
||
text(node, context) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That needs to go up into a new section in the changelog, but I'll fix this up myself when I take #300.