208 Commits (89146915ce7e3f593fce96d217c06f287fc15bab)

Author SHA1 Message Date
David Majda 89146915ce Add location information to AST nodes
This will allow to add location information to |GrammarError| exceptions
thrown in various passes.
9 years ago
David Majda d1fe86683b Improve location info in tracing events
Replace |line|, |column|, and |offset| properties of tracing events with
the |location| property. It contains an object similar to the one
returned by the |location| function available in action code:

  {
    start: { offset: 23, line: 5, column: 6 },
    end:   { offset: 25, line: 5, column: 8 }
  }

For the |rule.match| event, |start| refers to the position at the
beginning of the matched input and |end| refers to the position after
the end of the matched input.

For |rule.enter| and |rule.fail| events, both |start| and |end| refer to
the current position at the time the rule was entered.
9 years ago
David Majda 065f4e1b75 Improve location info in syntax errors
Replace |line|, |column|, and |offset| properties of |SyntaxError| with
the |location| property. It contains an object similar to the one
returned by the |location| function available in action code:

  {
    start: { offset: 23, line: 5, column: 6 },
    end:   { offset: 25, line: 5, column: 8 }
  }

For syntax errors produced in the middle of the input, |start| refers to
the first unparsed character and |end| refers to the character behind it
(meaning the span is 1 character). This corresponds to the portion of
the input in the |found| property.

For syntax errors produced the end of the input, both |start| and |end|
refer to a character past the end of the input (meaning the span is 0
characters).

For syntax errors produced by calling |expected| or |error| functions in
action code the location info is the same as the |location| function
would return.
9 years ago
David Majda b1ad2a1f61 Rename |reportedPos| to |savedPos|
Preform the following renames:

  * |reportedPos| -> |savedPos| (abstract machine variable)
  * |peg$reportedPos| -> |peg$savedPos| (variable in generated code)
  * |REPORT_SAVED_POS| -> |LOAD_SAVED_POS| (instruction)
  * |REPORT_CURR_POS| -> |UPDATE_SAVED_POS| (instruction)

The idea is that the name |reportedPos| is no longer accurate after the
|location| change (seea the previous commit) because now both
|reportedPos| and |currPos| are reported to user code. Renaming to
|savedPos| resolves this inaccuracy.

There is probably some better name for the concept than quite generic
|savedPos|, but it doesn't come to me.
9 years ago
David Majda 4f7145e360 Improve location info available in action code
Replace |line|, |column|, and |offset| functions with the |location|
function. It returns an object like this:

  {
    start: { offset: 23, line: 5, column: 6 },
    end:   { offset: 25, line: 5, column: 8 }
  }

In actions, |start| refers to the position at the beginning of action's
expression and |end| refers to the position after the end of action's
expression. This allows one to easily add location info e.g. to AST
nodes created in actions.

In predicates, both |start| and |end| refer to the current position.

Fixes #246.
9 years ago
David Majda d7fc0b5c3b Implement infinite loop detection
Fixes #26.
9 years ago
David Majda 95ce20ed92 Extract the |matchesEmpty| visitor from the |reportLeftRecursion| pass
Beside the recursion detector, the visitor will also be used by infinite
loop detector.

Note the newly created |asts.matchesEmpty| function re-creates the
visitor each time it is called, which makes it slower than necessary.
This could have been worked around in various ways but I chose to defer
that optimization because real-world performance impact is small.
9 years ago
David Majda 03a391e874 s/appliedRules/visitedRules/
The rules are not really *applied* by the |reportLeftRecursion| pass,
they are just *visited*.
9 years ago
David Majda 25ed2b7ee2 Improve comment describing the |reportLeftRecursion| pass 9 years ago
David Majda 6ce97457bf Fix left recursion detection
So far, left recursion detector assumed that left recursion occurs only
when the recursive rule is at the very left-hand side of rule's
expression:

  start = start

This didn't catch cases like this:

  start = "a"? start

In general, if a rule reference can be reached without consuming any
input, it can lead to left recursion. This commit fixes the detector to
consider that.

Fixes #190.
9 years ago
David Majda da57118a43 Implement basic support for tracing
Parsers can now be generated with support for tracing using the --trace
CLI option or a boolean |trace| option to |PEG.buildParser|. This makes
them trace their progress, which can be useful for debugging. Parsers
generated with tracing support are called "tracing parsers".

When a tracing parser executes, by default it traces the rules it enters
and exits by writing messages to the console. For example, a parser
built from this grammar:

  start = a / b
  a = "a"
  b = "b"

will write this to the console when parsing input "b":

  1:1 rule.enter start
  1:1 rule.enter   a
  1:1 rule.fail    a
  1:1 rule.enter   b
  1:2 rule.match   b
  1:2 rule.match start

You can customize tracing by passing a custom *tracer* to parser's
|parse| method using the |tracer| option:

  parser.parse(input, { trace: tracer });

This will replace the built-in default tracer (which writes to the
console) by the tracer you supplied.

The tracer must be an object with a |trace| method. This method is
called each time a tracing event happens. It takes one argument which is
an object describing the tracing event.

Currently, three events are supported:

  * rule.enter -- triggered when a rule is entered
  * rule.match -- triggered when a rule matches successfully
  * rule.fail  -- triggered when a rule fails to match

These events are triggered in nested pairs -- for each rule.enter event
there is a matching rule.match or rule.fail event.

The event object passed as an argument to |trace| contains these
properties:

  * type   -- event type
  * rule   -- name of the rule the event is related to
  * offset -- parse position at the time of the event
  * line   -- line at the time of the event
  * column -- column at the time of the event
  * result -- rule's match result (only for rule.match event)

The whole tracing API is somewhat experimental (which is why it isn't
documented properly yet) and I expect it will evolve over time as
experience is gained.

The default tracer is also somewhat bare-bones. I hope that PEG.js user
community will develop more sophisticated tracers over time and I'll be
able to integrate their best ideas into the default tracer.
9 years ago
David Majda 675561f085 Rename and generalize |generateCache{Header,Footer}|
Rename |generateCache{Header,Footer}| to |generateRule{Header,Footer}|
and change their responsibility to generate overall header/footer of a
rule function (when optimizing for speed) or the |peg$parseRule|
function (when optimizing for speed). This creates a natural place where
to generate tracing code (coming soon).
9 years ago
David Majda fb5f6c6ee9 Make labels behave like block-scoped variables
Action and predicate code can now see variables defined in expressions
"above" them.

Based on a pull request by Bryon Vandiver (@asterick):

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

Fixes #316.
9 years ago
David Majda fb7de36051 Update website URL
PEG.js website was moved from http://pegjs.majda.cz/ to http://pegjs.org/.
10 years ago
David Majda 0977dd37a3 Reordering in visitors and their specs
Reorder visiting functions and their specs to more closely match
ordering used in the PEG.js grammar.
10 years ago
David Majda 4ec9e6ba10 Remove useless test in the |reportLeftRecursion| pass
Empty sequences are not allowed anymore so we don't have to test for
them.
10 years ago
David Majda 898a7b5a2d Simplify visitors by providing default visit functions
The |visitor.build| function now supplies default visit functions for
visitors it builds. These functions don't do anything beside traversing
the tree and passing arguments around to child visit functions.

Having the default visit functions allowed to simplify several visitors.
10 years ago
David Majda f457c41dd4 Declare the |j| variable before use in lib/utils/arrays.js
Until now it was inadvertently global.
10 years ago
David Majda 24394e3f91 Fix comment alignment in lib/compiler/passes/generate-javascript.js 10 years ago
David Majda 2b06476c69 Regenerate lib/parser.js after bytecode changes 10 years ago
David Majda dad1207c46 Improve semantics of the TEXT bytecode instruction
The TEXT instruction now replaces position at the top of the stack with
the input from that position until the current position. This is simpler
and cleaner semantics than the previous one, where TEXT also popped an
additional value from the stack and kept the position there.
10 years ago
David Majda a815a8b902 Implement additional PUSH_* bytecode instructions
Implement the following bytecode instructions:

  * PUSH_UNDEFINED
  * PUSH_NULL
  * PUSH_FAILED
  * PUSH_EMPTY_ARRAY

These instructions push simple JavaSccript values to the stack directly,
without going through constants. This makes the bytecode slightly
shorter and the bytecode generator somewhat simpler.

Also note that PUSH_EMPTY_ARRAY allows us to avoid a hack which protects
the [] constant from modification.
10 years ago
David Majda 85c8f386c1 Formatting 10 years ago
David Majda f03ba4bf4f generate-javascript.js: s/generateJavaScript/generateJavascript/
This makes the variable name in sync with pass name in lib/compiler.js.
10 years ago
David Majda 57f7fae684 Fix a bug in |stringEscape|
The |stringEscape| function both in lib/compiler/javascript.js and in
generated parsers didn't escape characters in the U+0100..U+107F and
U+1000..U+107F ranges.
10 years ago
David Majda 88e5f136e1 Utility functions cleanup: Cleanup lib/compiler/javascript.js 10 years ago
David Majda c1e1502d43 Utility functions cleanup: Cleanup lib/compiler/visitor.js 10 years ago
David Majda bfaad70899 Utility functions cleanup: Cleanup lib/compiler/asts.js 10 years ago
David Majda 05f97f444d Utility functions cleanup: Cleanup lib/utils/classes.js 10 years ago
David Majda 1582304f16 Utility functions cleanup: Cleanup lib/utils/objects.js 10 years ago
David Majda 50b2054fbf Utility functions cleanup: Cleanup lib/utils/arrays.js 10 years ago
David Majda 5adad3ae12 Utility functions cleanup: Split lib/utils.js
Split lib/utils.js into multiple files. Some of the functions were
generic, these were moved into files in lib/utils. Other funtions were
specific for the compiler, these were moved to files in lib/compiler.

This commit only moves functions around -- there is no renaming and
cleanup performed. Both will come later.
10 years ago
David Majda ff8e877fce Change module exporting style
Modules now generally store the exported object in a named variable or
function first and only assign |module.exports| at the very end. This is
a difference when compared to style used until now, where most modules
started with a |module.exports| assignment.

I think the explicit name helps readability and understandability.
10 years ago
David Majda d9354c4632 Standardize on 3 spaces before // comments 10 years ago
David Majda f3a83788aa Inline functions extracted just because of JSHint
Rather than extracting functions just because JSHint complained about
defining functions inside a loop, let's inline then and silence the
warning.
10 years ago
David Majda 46ac1bf171 Wrap initializer code in generated parsers into |{...}|
Initializer code is usually indented and this indentation is carried
over to generated code. This resulted in a piece of indented code in the
middle of the parser.

This commit wraps initializer code in |{...}|, which makes indentation
in generated parsers look a bit more natural.
10 years ago
David Majda 39084496ca Expose the parser object in action/predicate code
The action/predicate code didn't have access to the parser object. This
was mostly a side effect actions/predicates being implemented as nested
functions, in which |this| is a reference to the global object (an ugly
JavaScript quirk). The initializer, being implemented differently, had
access to the parser object via |this|, but this was not documented.

Because having access to the parser object can be useful, this commits
introduces a new |parser| variable which holds a reference to it, is
visible in action/predicate/initializer code, and is properly
documented.

See also:

  https://groups.google.com/forum/#!topic/pegjs/Na7YWnz6Bmg
10 years ago
David Majda c7521fb868 Mark |parse| and |SyntaxError| as internal identifiers
The |parse| function and the |SyntaxError| exception were meant as
internal, so let's mark them as such.
10 years ago
David Majda 7e3b4ec4f8 PEG.js grammar: Remove reserved word detection
This is mostly done for consistency with the JavaScript example grammar,
from which the |Identifier| rule is taken from. See the previous commit
for details.
10 years ago
David Majda e78ffbba9c PEG.js grammar: Improve the |Code| rule a bit
Instead of matching segments between blocks character by character,
match them as a whole. Also align the style with other similar rules
(e.g. the comment ones).
10 years ago
David Majda 64eb5faf54 PEG.js grammar: Fix line continuation handling in character classes
Before this commit, line continuations in character classes contributed
an empty string to the list of characters and character ranges matched
by a class. While this didn't lead to a buggy behavior with the current
code generator, the AST was wrong and the problem could have caused bugs
later.

This commit fixes the problem.
10 years ago
David Majda 0678bd8a0c PEG.js grammar: Add missing semicolon
Fixes the following JSHint error:

  lib/parser.js: line 108, col 54, Missing semicolon.
10 years ago
David Majda 0459ab6b37 PEG.js grammar: Formatting & comments 10 years ago
David Majda 6f2510e49e PEG.js grammar: Make rules with operators more generic 10 years ago
David Majda 45c29a886f PEG.js grammar: Extract the |SemanticPredicateExpression| rule
Semantic predicates are kind of |PrimaryExpression|, not kind of
|PrefixedExpression|. Therefore I extracted a rule for them and
referenced it from the |PrimaryExpression|.
10 years ago
David Majda da18f6a729 PEG.js grammar: Extract the |RuleReferenceExpression| rule
This makes the |Primary| rule a bit more tidy.
10 years ago
David Majda 8e6f98e45c PEG.js grammar: Extract the |ActionExpression| rule
Having it separated from the |SequenceExpression| rule is cleaner and
more logical.
10 years ago
David Majda 5c6f4dd38b PEG.js grammar: Append |Expression| to expression rule names
Makes the rule names a bit longer but also clearer.
10 years ago
David Majda 27c2d26203 PEG.js grammar: More JavaScript-like initializer/rule separation
Initializer and rules are now separated in a similar way as JavaScript
statements -- either by a semicolon or a line terminator, possibly with
whitespace and comments mixed in.

One consequence is that the grammars like this are now illegal:

  foo = "a" bar = "b"

A semicolon needs to be inserted between the rules:

  foo = "a";bar = "b"

I consider this a good change as the now-illegal syntax was somewhat
confusing.
10 years ago
David Majda 4ce7593f5f PEG.js grammar: Extract the |AnyMatcher| rule
This makes the |Primary| rule a bit more tidy. Also, matching the |.|
character really belongs to the lexical part of the grammar, next to
literals and character classes.
10 years ago