Currently, an open brace without a corresponding brace will emit this confusing error message:
> Expected "!", "$", "&", "(", "*", "+", ".", "/", "/*", "//", ";", "?", character class, code block, comment, end of line, identifier, literal, or whitespace but "{" found.
This change adds an error case to the grammar to make it clear what the problem is.
* Do not indent backtick quoted strings in initializer or rule action code blocks
* Use const instead of var for ESLint happiness
* Fix ESLint issues for double quotes and indent6
This fixes the following ESLint error, which started to appear after
eslint/eslint#7424 was fixed:
/Users/dmajda/Programming/PEG.js/pegjs/lib/compiler/js.js
37:17 error Unnecessary escape character: \] no-useless-escape
This should fix broken Travis CI builds:
https://travis-ci.org/pegjs/pegjs/builds/180092802
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.
The "global-require" rule is disabled in ESLint configuration used by
PEG.js, but the idea is not bad, so let's make all static "require"
calls global.
Follow-up to #407.
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.
The idea behind linting lib/parser.js was that it would improve quality
of code generated by PEG.js in general. However, there is a couple of
problems with it:
1. Code in lib/parser.js is ES5 while the rest of the code is ES2015.
This would mean a separate ESLint configuration and a separate set
of code style rules just for lib/parser.js once code style checks
are added.
2. Code in lib/parser.js is generated. This means that even today it
violates checks like "no-unused-var", which have to be disabled.
This would get worse once code style checks are added, again
requiring a separate ESLint configuration just for lib/parser.js.
3. Linting lib/parser.js checks only small portion of possible code
generator output. For example, code generated when optimizing for
size or when tracing is not checked at all. Thus, linting
lib/parser.js gives a false sense of security.
Because of these problems I decided not to lint lib/parser.js at all and
rely on ad-hoc linting of parser files produced by PEG.js with ignoring
false-positives. I consider this more of a pragmatic cost vs. benefits
decision than a principial one.
Part of #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
};
The lib/parser.js file is a CommonJS module like all the other files in
lib/, so setting the environment explicitly is not needed. Besides, the
environment set by "eslint-env" was wrong (since transitioning from the
AMD format).
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.
The for-in statement in JavaScript iterates also over inherited
properties. This is typically not desired and requires adding a
check using Object.prototype.hasOwnProperty inside the loop.
This commit replaces all for-in statements and related checks inside
them with iteration over Object.keys(...). The iteration is performed
using either Array.prototype.forEach of a plain for loop.
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.
Rename compiler passes as follows:
reportLeftRecursion -> reportInfiniteRecursion
reportInfiniteLoops -> reportInfiniteRepetition
This reflects the fact that both passes detect different ways of causing
the same problem (possible infinite loop when parsing).
The new terminology is more precise and in line with commonly used
programming languages.
The change involves mainly renaming related compiler pass and files
associated with it.
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.
This change makes it possible to use "generate" as a module function,
e.g. like this:
var generate = require("pegjs").generate;
var parser = generate(...);
Fixes#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".