-
Notifications
You must be signed in to change notification settings - Fork 417
Use sanitized identifiers in generated code #92
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
Comments
I vote for |
It's a pity that JavaScript does not have better scope controlling mechanism (ability for an inner function not to inherit its lexical environment). @michaelficarra I don't think ATM I am leaning towards the |
Javascript also uses |
The
No way this is going to be configurable :-) |
Why not create an object, e.g. named start = int:[0-9]+ offset:[a-z] { return peg.int + peg.offset } |
Performance. Every property access costs a lot of time compared to plain variable access (I did some benchmarks some time ago). |
This is a complete rewrite of the PEG.js code generator. Its goals are: 1. Allow optimizing the generated parser code for code size as well as for parsing speed. 2. Prepare ground for future optimizations and big features (like incremental parsing). 2. Replace the old template-based code-generation system with something more lightweight and flexible. 4. General code cleanup (structure, style, variable names, ...). New Architecture ---------------- The new code generator consists of two steps: * Bytecode generator -- produces bytecode for an abstract virtual machine * JavaScript generator -- produces JavaScript code based on the bytecode The abstract virtual machine is stack-based. Originally I wanted to make it register-based, but it turned out that all the code related to it would be more complex and the bytecode itself would be longer (because of explicit register specifications in instructions). The only downsides of the stack-based approach seem to be few small inefficiencies (see e.g. the |NIP| instruction), which seem to be insignificant. The new generator allows optimizing for parsing speed or code size (you can choose using the |optimize| option of the |PEG.buildParser| method or the --optimize/-o option on the command-line). When optimizing for size, the JavaScript generator emits the bytecode together with its constant table and a generic bytecode interpreter. Because the interpreter is small and the bytecode and constant table grow only slowly with size of the grammar, the resulting parser is also small. When optimizing for speed, the JavaScript generator just compiles the bytecode into JavaScript. The generated code is relatively efficient, so the resulting parser is fast. Internal Identifiers -------------------- As a small bonus, all internal identifiers visible to user code in the initializer, actions and predicates are prefixed by |peg$|. This lowers the chance that identifiers in user code will conflict with the ones from PEG.js. It also makes using any internals in user code ugly, which is a good thing. This solves GH-92. Performance ----------- The new code generator improved parsing speed and parser code size significantly. The generated parsers are now: * 39% faster when optimizing for speed * 69% smaller when optimizing for size (without minification) * 31% smaller when optimizing for size (with minification) (Parsing speed was measured using the |benchmark/run| script. Code size was measured by generating parsers for examples in the |examples| directory and adding up the file sizes. Minification was done by |uglify --ascii| in version 1.3.4.) Final Note ---------- This is just a beginning! The new code generator lays a foundation upon which many optimizations and improvements can (and will) be made. Stay tuned :-)
This should be fixed by the code generator rewrite. Thanks @egonelbre for the |
May be one more hint will help you resolve it nicer (a one from my functional-version of your generator): (function() {
// here are some global variables accessible both to user
// code and to parser, like pos and line and stuff (not required
// to be initialized, just names)
var pos, line, ...;
// the very one variable a name of which may clash with user code
var user$ = (function() {
// it is a closure to hold all user variables in one context
// without access to parser inner variables
return function() {
// user initializer code, if specified, with only one restriction:
// this one is required not to have any first-level returns inside
...
// returns an object or something that stores all of the user code
// blocks in parser, in any manner you want
return { 'rule1': [ function(<code_params>) { ... }, ... ]
... };
};
})();
return (function() {
// all private parser-related code and vars go here
var code_blocks = user$(); // this one calls user initializer
// and returns his code blocks
// do anything you want with code_blocks
code_blocks['rule1'][0](...);
// parser code
...
return { /* parser object */ };
})();
})(); The only bottle-neck here I see is an object to access code blocks (I store them like |
@shamansir Yeah, there are other possible solutions. I chose the simplest one because I wanted to get the new generator done before the end of my Christmas break and I didn't have much time to experiment toward the end. As for the array access, at some point I measured the difference between Anyway, I'll look at the genreator again in the 0.9.0 timeframe, now I have different priorities. Feel free to file issues for anything you feel could be improved. |
When writing rules or identifiers it's really easy to create a name clash between reserved javascript words or internal variables used by the generators.
For example when using the online parser generator this rule :
Easiest solution would be just to use prefixed (ie. "_" or "$") identifiers in the generated code.
The text was updated successfully, but these errors were encountered: