84 Commits (83d748d52250e3e93c72a14091f3e7570ffc3dc8)

Author SHA1 Message Date
David Majda 7d6ad99e33 Code style: Remove unnecessary "eslint-disable" directives
Part of #407.
8 years ago
David Majda 88f115146d Code style: Fix ESLint "space-infix-ops" errors
Part of #407.
8 years ago
David Majda 1870308afb Code style: Fix ESLint "object-shorthand" errors
Part of #407.
8 years ago
David Majda fb26d6425b Remove extra newlines 8 years ago
David Majda 7ca229a432 Improve indentation of variable declarations
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
  };
8 years ago
David Majda 9808b88ccb generated-parser-behavior.spec.js: Move variable inside loop 8 years ago
David Majda 9648ca53d7 Use the "eslint-disable" directive instead of "eslint"
The "eslint-disable" directive is more specific.
8 years ago
David Majda c134e06229 Move "use strict" directives up
Move "use strict" directives to the first line of each file. In
particular, move them above any ESLint comments, which are far less
important.

There are few exceptions:

  Executable files

    In these, the "use strict" directive must give way to the shebang.

  lib/parser.js

    Here, the "Generated by..." comment comes first. Also, ESLint
    comments are prepended in post-processing.
8 years ago
David Majda ff7193776e Avoid aligning "="
The only exception left are instances where aligning "=" helps to
express symmetry between lines.

See #443.
8 years ago
David Majda 400a3cfa3c Avoid aligning object keys
The only exception left are objects representing a mapping with simple
keys and values -- essentially tables written as object literals.

See #443.
8 years ago
David Majda 12112310f2 Use only double quotes for strings
See #443
8 years ago
David Majda 6294bb5b13 Use only "//" comments
See #443.
8 years ago
David Majda 516023546d Use one var/let/const per variable (for initialized variables)
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.
8 years ago
David Majda 7f01db2fb8 Get rid of for-in loops
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.
8 years ago
David Majda 6fa8ad63f9 Replace some functions with arrow functions
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.
8 years ago
David Majda d00e9526c3 Minimize variable scope
Where possible, move "let" statements into inner blocks, loop headers,
etc.

See #442.
8 years ago
David Majda bdf91b5941 Replace "var" with "let" & "const"
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.
8 years ago
David Majda 5c40fff136 Pass spec code through Babel before serving it to the browser
This will allow to use ES2015 constructs in spec code.

The change required introducing a small server, which serves both PEG.js
and spec code passed through Babel and bundled together. This allowed to
convert the specs to regular modules and get rid of the hackery that was
previously needed to make them run both in Node.js and in the browser.

Note the specs no longer exercise the browser version. This will allow
to spec PEG.js internals in the future.

See #442.
8 years ago
David Majda f0657ba628 generated-parser-behavior.spec.js: Switch from first/rest to head/tail
Follow-up to these commits:

  e510ecc3d0
  a4a66a2e5b
8 years ago
David Majda 0d48ffca2b generated-parser-behavior.spec.js: s/==/===/ 8 years ago
David Majda df5f86103e Replace suitable for loops with Array methods (in /spec)
See #441.
8 years ago
David Majda 2647f5789f generated-parser-behavior.spec.js: Test also with options.trace === true
Based on a pull request by @Mingun:

  https://github.com/pegjs/pegjs/pull/397
8 years ago
David Majda bf9d9561c4 Tighten "try ... catch" clauses in spec helpers
They wrapped too much code.
8 years ago
David Majda e03d92488a Set the "found" property of syntax errors produced by "error" to null
The property doesn't correspond to anything in the error's message.
8 years ago
David Majda e8be76ee3a Don't expose the "parser" variable in parser code
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.
8 years ago
David Majda b3a90de020 Syntax error messages: Use Oxford comma
In general PEG.js uses American English, where Oxford comma is
prevalent.

Part of #371.
8 years ago
David Majda 319931876d Expectation refactoring 4/7: Generate descriptions dynamically
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.
9 years ago
David Majda 22cb123479 Expectation refactoring 3/7: Change expectation processing
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".
9 years ago
David Majda c6e8c53f1b Expectation refactoring 2/7: Restructure "class" expectations
Changes:

  * Remove the "value" property (it is replaced by other properties).

  * Add the "parts", "inverted", and "ignoreCase" properties (which
    allow more structured access to expectation data).
9 years ago
David Majda eda2a34c7f Expectation refactoring 1/7: Restructure "literal" expectations
Changes:

  * Rename the "value" property to "text" (because it doesn't contain
    the whole value, which also includes the case sensitivity flag).

  * Add the "ignoreCase" property (which was missing).
9 years ago
David Majda 1f7efd57c0 Remove various JSHint-related cruft
We use ESLint now, which is smarter about some things.
9 years ago
David Majda 6b60896216 Revert "Remove info about found string from syntax errors"
This reverts commit 25ab98027d.

Part of work on #428.
9 years ago
David Majda f4504a93fe Rename the "buildParser" function to "generate"
In most places, we talk about "generating a parser", not "building a
parser", which the function name should reflect. Also, mentioning a
parser in the name is not necessary as in case of a parser generator
it's pretty clear what is generated.
9 years ago
David Majda 0847a69643 Rename the "PEG" variable to "peg"
So far, PEG.js was exported in a "PEG" global variable when no module
loader was detected. The same variable name was also conventionally used
when requiring it in Node.js or otherwise referring to it. This was
reflected in various places in the code, documentation, examples, etc.

This commit changes the variable name to "peg" and fixes all relevant
occurrences. The main reason for the change is that in Node.js, modules
are generally referred to by lower-case variable names, so "PEG" was
sticking out when used in Node.js projects.
9 years ago
David Majda ce44c62f14 Support passing custom location info to "error" and "expected"
Based on a pull request by Konstantin (@YemSalat):

  https://github.com/pegjs/pegjs/pull/391

Resolves #390.
9 years ago
David Majda da2378d887 Rewrite handling of optional parameters
Instead of testing arguments.length to see whether an optional parameter
was passed to a function, compare its value to "undefined". This
approach has two advantages:

  * It is in line with handling of default parameters in ES6.

  * Optional parameters are actually spelled out in the parameter
    list.

There is also one important disadvantage, namely that it's impossible to
pass "undefined" as an optional parameter value. This required a small
change in two tests.

Additional notes:

  * Default parameter values are set in assignments immediately
    after the function header. This reflects the fact that these
    assignments really belong to the parameter list (which is where they
    are in ES6).

  * Parameter values are checked against "void 0" in places where
    "undefined" can potentially be redefiend.
9 years ago
David Majda f866712c90 Regularize Jasmine custom matcher signatures
The "toParse" matcher in generated-parser-behavior.spec.js effectively
had these signatures:

  toParse(input)
  toParse(input, expected)
  toParse(input, options, expected)

This commit regularizes them to:

  toParse(input)
  toParse(input, expected)
  toParse(input, expected, options)

Similarly, the "toFailToParse" matcher in
generated-parser-behavior.spec.js effectively had these signatures:

  toFailToParse(input)
  toFailToParse(input, details)
  toFailToParse(input, options, details)

This commit regularizes them to:

  toFailToParse(input)
  toFailToParse(input, details)
  toFailToParse(input, details, options)

Finally, the "toChangeAST" matcher in helpers.js effectively had these
signatures:

  toChangeAST(grammar, details)
  toChangeAST(grammar, options, details)

This commit regularizes them to:

  toChangeAST(grammar, details)
  toChangeAST(grammar, details, options)

The overall purpose of these changes is to avoid different parameters
appearing at the same position, which is hard to manage without using
"arguments".
9 years ago
David Majda 0c39f1cf86 Fix labels leaking to outer scope
Labels in expressions like "(a:"a")" or "(a:"a" b:"b" c:"c")" were
visible to the outside despite being wrapped in parens. This commit
makes them invisible, as they should be.

Note this required introduction of a new "group" AST node, whose purpose
is purely to provide label scope isolation. This was necessary because
"label" and "sequence" nodes don't (and can't!) provide this isolation
themselves.

Part of a fix of #396.
9 years ago
David Majda 58806a3d77 Label scope specs: Add negative specs (subexpressions)
Semantic predicate and action specs which verified label scope didn't
exercise labels in subexpressions. This commit adds cases exercising
them, including few commented-out cases which reveal #396 (these will be
uncommented when the bug gets fixed).

Note that added specs exercise all relevant expression types. This is
needed because code that makes subexpression labels invisible to the
outside is separate for each expression type so one generic test
wouldn't generate enough coverage.

Part of a fix of #396.
9 years ago
David Majda ffd90a8c9e Label scope specs: Add negative specs (sequences)
So far, semantic predicate and action specs which verified scope of
labels from containing or outer sequences exercised only cases where
label variables were defined. This commit adds also some negative cases.

The idea comes from @Mingun.
9 years ago
David Majda 7229318671 Label scope specs: Don't exercise all expression types
Semantic predicate and action specs which verified scope of labels from
outer sequences exercised all relevant expression types. This is not
needed as the behavior is common for all expression types and no extra
code needs to be written to make it work for each of them.

This commit changes the specs to verify scope of labels from outer
sequences using only one expression type.
9 years ago
David Majda a20d04edf4 Label scope specs: Remove redundant sequence elements
Semantic predicate specs which verified scope of labels from containing
sequences used 3 elements where 1 is enough.

This commit removes the redundant elements.
9 years ago
David Majda 6bc91c010d Label scope specs: Tweak spec descriptions 9 years ago
David Majda 921f1fa8fa Label scope specs: Tweak suite descriptions 9 years ago
David Majda 5c5f79519a Label scope specs: Simplify semantic predicate and action specs
Semantic predicate and action specs which verified label scope used
repetitive "it" blocks. Rewrite them to use just one "it" block and a
list of testcases. This makes them more concise.
9 years ago
David Majda 31e7147081 Label scope specs: No result checks in semantic predicate specs
Semantic predicate specs which verified label scope also checked parser
results. This is not necessary because for the purpose of these specs it
is enough to verify that label variables have correct values, which is
done in predicate code already.

This commit removes parser result checks from these specs.
9 years ago
David Majda 18d266be67 Remove support for newlines other than "\n" and "\r\n"
Before this commit, generated parsers considered the following character
sequences as newlines:

  Sequence   Description
  ------------------------------
  "\n"       Unix
  "\r"       Old Mac
  "\r\n"     Windows
  "\u2028"   line separator
  "\u2029"   paragraph separator

This commit limits the sequences only to "\n" and "\r\n". The reason is
that nobody uses Unicode newlines or "\r" in practice.

A positive side effect of the change is that newline-handling code
became simpler (and likely faster).
9 years ago
David Majda e61c23c634 ESLint: Set environments better
Instead of setting ESLint environment to "node" globally, set it on
per-directory basis using separate .eslintrc.json files:

  Directory   Environment
  -----------------------
  bin         node
  lib         commonjs
  spec        jasmine

It was impossible to use this approach for the "benchmark" directory
which contains a mix of files used in various environments. For
benchmark/run, the environment is set inline. For the other files, as
well as spec/helpers.js, the globals are declared manually (it is
impossible to express how these files are used just by a list of
environments).

Fixes #408.
9 years ago
David Majda 00faf20fe1 Fix ESLint errors in spec/behavior/generated-parser-behavior.spec.js
Fix the following errors:

   24:46  error  Unexpected trailing comma  comma-dangle
  403:26  error  Unexpected trailing comma  comma-dangle
  414:26  error  Unexpected trailing comma  comma-dangle
9 years ago
David Majda 768ece28e6 Use ESLint instead of JSHint
Implement the swap and change various directives in the source code. The
"make hint" target becomes "make lint".

The change leads to quite some errors being reported by ESLint. These
will be fixed in subsequent commits.

Note the configuration enables just the recommended rules. Later I plan
to enable more rules to enforce the coding standard. The configuration
also sets the environment to "node", which is far from ideal as the
codebase contains a mix of CommonJS, Node.js and browser code. I hope to
clean this up at some point.
9 years ago