Generating AMD/UMD dependencies lead to an error:
$ bin/pegjs --format amd --dependency $:jquery examples/arithmetics.pegjs
dependencyIds is not defined
$ bin/pegjs --format umd --dependency $:jquery examples/arithmetics.pegjs
dependencyIds is not defined
This commit fixes the problem, which was caused by a mistake done in
d2569b9bf3.
Running ESLint on generated code with the configuration used on PEG.js
itself produces a lot of errors. This commit fixes some unnecessary ones
caught by these rules:
- max-len
- new-cap
- newline-before-return
- no-unused-vars
See also 5dd8e797f7.
Follow-up to #407.
Before this commit, continuation lines of multi-line values in variable
declaration initializers were aligned with the variable name:
let foo = {
a: 5,
b: 6
};
This was highly irregular, maintenance intensive, and made declarations
look different from assignments.
This commit changes the indentation to be more regular and similar to
assignments:
let foo = {
a: 5,
b: 6
};
Use one var/let/const per variable, but only for initialized variables.
Uninitialized variables are still grouped into one var/let/const
declaration as I don't see any value in separating them. This approach
reflects the fact that initialized and uninitialized var/let/const
declarations are really two different things.
See #443.
Because arrow functions work rather differently than normal functions (a
bad design mistake if you ask me), I decided to be conservative with the
conversion.
I converted:
* event handlers
* callbacks
* arguments to Array.prototype.map & co.
* small standalone lambda functions
I didn't convert:
* functions assigned to object literal properties (the new shorthand
syntax would be better here)
* functions passed to "describe", "it", etc. in specs (because Jasmine
relies on dynamic "this")
See #442.
This is purely a mechanical change, not taking advantage of block scope
of "let" and "const". Minimizing variable scope will come in the next
commit.
In general, "var" is converted into "let" and "const" is used only for
immutable variables of permanent character (generally spelled in
ALL_CAPS). Using it for any immutable variable regardless on its
permanence would feel confusing.
Any code which is not transpiled and needs to run in ES6 environment
(examples, code in grammars embedded in specs, ...) is kept unchanged.
This is also true for code generated by PEG.js.
See #442.
Parsers generated in this format use module.exports, so they are not
strictly CommonJS, but this is a common extension and the original name
would be confusing once Node.js implements ES2015 modules.
This change reflects the fact that PEG.js-generated parsers really
produce two kinds of syntax errors:
Structured errors
Caused by match failures, trailing input, or calls of the "expected"
function in parser code. Their messages have fixed format ("Expected
... but ... found.").
Simple errors
Caused by calls of the "error" function in parser code. Their
messages don't have any fixed format.
Each kind of error now has a separate helper function which builds its
instances.
The "parser" variable allowed access to the parser object. Among other
things, this made it possible to invoke the parser recursively using
"parser.parse".
One problem with the "parser" variable is that it bakes in the idea that
the parser is an *object*, not a *module*. While this is true now, it
won't necessarily be in the future, when parsers may be exported as ES6
modules. Also, people tend to use parsers as modules even today, e.g.
like this:
var parse = require("parser").parse;
var result = parse(...);
Such usage broke the "parser" variable (as it was implemented).
For this reasons I decided to remove the "parser" variable. If someone
needs to do tricks like recursive invocation of the parser, he/she must
pass the parser or the "parse" function itself using options.
Related to #433.
Until now, expectations were constructed using object literals. This
commit changes the construction to use factory functions.
This change makes generated parsers slightly smaller because property
names don't have to be repeated many times and factory function calls
are more amenable to minifying.
Some numbers based on the aggregate size of parsers generated from
examples/*.pegjs:
Optimization Minified? Size before Size after Saving
------------------------------------------------------------
speed no 719066 716063 0.42%
speed yes 188998 180202 4.65%
size no 194810 197813 1.52%
size yes 108782 99947 8.12%
(Minification was done using "uglify --mangle --compress" with
uglify-js 2.4.24.)
The "buildMessage" utility function, which was previously internal, is
now exposed as SyntaxError.buildMessage in generated parsers.
The motivation behind this is two-fold:
1. Building of a syntax error message is a responsibility of the
SyntaxError class, meaning the code should be placed there.
2. By exposing the message building code, parser users can use it to
generate customized error messages without duplicating PEG.js's code.
Note that helper functions inside "buildMessage" ("describeExpected",
"describeFound", etc.) currently aren't exposed. They may become exposed
in the future if there is enough demand.
Instead of pre-generating expectation descriptions when generating
parsers, generate them dynamically from structured information contained
in the expectations.
This change makes descriptions a presentation-only concept. It also
makes generated parsers smaller.
Before this commit, expectations were sorted and de-duplicated before
they were passed to "buildMessage" and exposed in the "expected"
property of syntax errors. This commit moves this processing into
"buildMessage" and rewrites it to process only expectation descriptions.
This means expectations exposed in the "expected" property are "raw"
(not sorted and de-duplicated).
This change will allow us to get rid of the "description" property of
expectations and compute descriptions dynamically from structured
information in the expectations. This will make descriptions a
presentation-only concept. It will also make generated parsers smaller.
Note that to keep expectations in the "expected" property sorted even
without the "description" property, some sorting scheme based on
structured information in the expectations would have to be devised,
which would complicate things with only a little benefit. Therefore I
chose to keep the expectations there "raw".
Simplify regexps that specify ranges of characters to escape with "\xXX"
and "\uXXXX" in various escaping functions. Until now, these regexps
were (mostly) mutually exclusive with more selective regexps applied
before them, but this became a maintenance headache. I decided to
abandon the exclusivity, which allowed to simplify these regexps (at the
cost of introducing an ordering dependency).
Change how found strings are escaped when building syntax error
messages:
* Do not escape non-ASCII characters (U+0100-U+FFFF). They are
typically more readable in their raw form.
* Escape DEL (U+007F). It is a control character.
* Escape NUL (U+0000) as "\0", not "\x00".
* Do not use less known shortcut escape sequences ("\b", "\f"), only the
well-known ones ("\0", "\t", "\n", "\r").
These changes mirror expectation escaping changes done in
4fe682794d.
Part of work on #428.
The wrapping functions are also generated by PEG.js, so the comment
should be above them to mark them as such. This shouldn't cause any
problems technically.