You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

494 lines
19 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
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.
7 years ago
11 years ago
11 years ago
11 years ago
12 years ago
11 years ago
11 years ago
Code generator rewrite 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 :-)
9 years ago
11 years ago
11 years ago
12 years ago
11 years ago
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.
7 years ago
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.
7 years ago
11 years ago
11 years ago
11 years ago
12 years ago
11 years ago
11 years ago
11 years ago
12 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
Refine error handling further Before this commit, the |expected| and |error| functions didn't halt the parsing immediately, but triggered a regular match failure. After they were called, the parser could backtrack, try another branches, and only if no other branch succeeded, it triggered an exception with information possibly based on parameters passed to the |expected| or |error| function (this depended on positions where failures in other branches have occurred). While nice in theory, this solution didn't work well in practice. There were at least two problems: 1. Action expression could have easily triggered a match failure later in the input than the action itself. This resulted in the action-triggered failure to be shadowed by the expression-triggered one. Consider the following example: integer = digits:[0-9]+ { var result = parseInt(digits.join(""), 10); if (result % 2 === 0) { error("The number must be an odd integer."); return; } return result; } Given input "2", the |[0-9]+| expression would record a match failure at position 1 (an unsuccessful attempt to parse yet another digit after "2"). However, a failure triggered by the |error| call would occur at position 0. This problem could have been solved by silencing match failures in action expressions, but that would lead to severe performance problems (yes, I tried and measured). Other possible solutions are hacks which I didn't want to introduce into PEG.js. 2. Triggering a match failure in action code could have lead to unexpected backtracking. Consider the following example: class = "[" (charRange / char)* "]" charRange = begin:char "-" end:char { if (begin.data.charCodeAt(0) > end.data.charCodeAt(0)) { error("Invalid character range: " + begin + "-" + end + "."); } // ... } char = [a-zA-Z0-9_\-] Given input "[b-a]", the |charRange| rule would fail, but the parser would try the |char| rule and succeed repeatedly, resulting in "b-a" being parsed as a sequence of three |char|'s, which it is not. This problem could have been solved by using negative predicates, but that would complicate the grammar and still wouldn't get rid of unintuitive behavior. Given these problems I decided to change the semantics of the |expected| and |error| functions. They don't interact with regular match failure mechanism anymore, but they cause and immediate parse failure by throwing an exception. I think this is more intuitive behavior with less harmful side effects. The disadvantage of the new approach is that one can't backtrack from an action-triggered error. I don't see this as a big deal as I think this will be rarely needed and one can always use a semantic predicate as a workaround. Speed impact ------------ Before: 993.84 kB/s After: 998.05 kB/s Difference: 0.42% Size impact ----------- Before: 1019968 b After: 975434 b Difference: -4.37% (Measured by /tools/impact with Node.js v0.6.18 on x86_64 GNU/Linux.)
8 years ago
Refine error handling further Before this commit, the |expected| and |error| functions didn't halt the parsing immediately, but triggered a regular match failure. After they were called, the parser could backtrack, try another branches, and only if no other branch succeeded, it triggered an exception with information possibly based on parameters passed to the |expected| or |error| function (this depended on positions where failures in other branches have occurred). While nice in theory, this solution didn't work well in practice. There were at least two problems: 1. Action expression could have easily triggered a match failure later in the input than the action itself. This resulted in the action-triggered failure to be shadowed by the expression-triggered one. Consider the following example: integer = digits:[0-9]+ { var result = parseInt(digits.join(""), 10); if (result % 2 === 0) { error("The number must be an odd integer."); return; } return result; } Given input "2", the |[0-9]+| expression would record a match failure at position 1 (an unsuccessful attempt to parse yet another digit after "2"). However, a failure triggered by the |error| call would occur at position 0. This problem could have been solved by silencing match failures in action expressions, but that would lead to severe performance problems (yes, I tried and measured). Other possible solutions are hacks which I didn't want to introduce into PEG.js. 2. Triggering a match failure in action code could have lead to unexpected backtracking. Consider the following example: class = "[" (charRange / char)* "]" charRange = begin:char "-" end:char { if (begin.data.charCodeAt(0) > end.data.charCodeAt(0)) { error("Invalid character range: " + begin + "-" + end + "."); } // ... } char = [a-zA-Z0-9_\-] Given input "[b-a]", the |charRange| rule would fail, but the parser would try the |char| rule and succeed repeatedly, resulting in "b-a" being parsed as a sequence of three |char|'s, which it is not. This problem could have been solved by using negative predicates, but that would complicate the grammar and still wouldn't get rid of unintuitive behavior. Given these problems I decided to change the semantics of the |expected| and |error| functions. They don't interact with regular match failure mechanism anymore, but they cause and immediate parse failure by throwing an exception. I think this is more intuitive behavior with less harmful side effects. The disadvantage of the new approach is that one can't backtrack from an action-triggered error. I don't see this as a big deal as I think this will be rarely needed and one can always use a semantic predicate as a workaround. Speed impact ------------ Before: 993.84 kB/s After: 998.05 kB/s Difference: 0.42% Size impact ----------- Before: 1019968 b After: 975434 b Difference: -4.37% (Measured by /tools/impact with Node.js v0.6.18 on x86_64 GNU/Linux.)
8 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  1. [![Build status](https://img.shields.io/travis/pegjs/pegjs.svg)](https://travis-ci.org/pegjs/pegjs)
  2. [![npm version](https://img.shields.io/npm/v/pegjs.svg)](https://www.npmjs.com/package/pegjs)
  3. [![Bower version](https://img.shields.io/bower/v/pegjs.svg)](https://github.com/pegjs/bower)
  4. [![License](https://img.shields.io/badge/license-mit-blue.svg)](https://opensource.org/licenses/MIT)
  5. PEG.js
  6. ======
  7. PEG.js is a simple parser generator for JavaScript that produces fast parsers
  8. with excellent error reporting. You can use it to process complex data or
  9. computer languages and build transformers, interpreters, compilers and other
  10. tools easily.
  11. Features
  12. --------
  13. * Simple and expressive grammar syntax
  14. * Integrates both lexical and syntactical analysis
  15. * Parsers have excellent error reporting out of the box
  16. * Based on [parsing expression
  17. grammar](http://en.wikipedia.org/wiki/Parsing_expression_grammar) formalism
  18. — more powerful than traditional LL(*k*) and LR(*k*) parsers
  19. * Usable [from your browser](http://pegjs.org/online), from the command line,
  20. or via JavaScript API
  21. Getting Started
  22. ---------------
  23. [Online version](http://pegjs.org/online) is the easiest way to generate a
  24. parser. Just enter your grammar, try parsing few inputs, and download generated
  25. parser code.
  26. Installation
  27. ------------
  28. ### Node.js
  29. To use the `pegjs` command, install PEG.js globally:
  30. $ npm install -g pegjs
  31. To use the JavaScript API, install PEG.js locally:
  32. $ npm install pegjs
  33. If you need both the `pegjs` command and the JavaScript API, install PEG.js both
  34. ways.
  35. ### Browser
  36. [Download](http://pegjs.org/#download) the PEG.js library (regular or minified
  37. version) or install it using Bower:
  38. $ bower install pegjs
  39. Generating a Parser
  40. -------------------
  41. PEG.js generates parser from a grammar that describes expected input and can
  42. specify what the parser returns (using semantic actions on matched parts of the
  43. input). Generated parser itself is a JavaScript object with a simple API.
  44. ### Command Line
  45. To generate a parser from your grammar, use the `pegjs` command:
  46. $ pegjs arithmetics.pegjs
  47. This writes parser source code into a file with the same name as the grammar
  48. file but with “.js” extension. You can also specify the output file explicitly:
  49. $ pegjs arithmetics.pegjs arithmetics-parser.js
  50. If you omit both input and output file, standard input and output are used.
  51. The generated parser is in the [UMD](https://github.com/umdjs/umd) format, which
  52. means it works as a Node.js or AMD module. You can also use the
  53. `-e`/`--export-var` option to define a global variable into which the parser
  54. object is assigned to when no module loader is detected.
  55. You can tweak the generated parser with several options:
  56. * `--cache` — makes the parser cache results, avoiding exponential parsing
  57. time in pathological cases but making the parser slower
  58. * `--allowed-start-rules` — comma-separated list of rules the parser will be
  59. allowed to start parsing from (default: the first rule in the grammar)
  60. * `--plugin` — makes PEG.js use a specified plugin (can be specified multiple
  61. times)
  62. * `--extra-options` — additional options (in JSON format) to pass to
  63. `PEG.buildParser`
  64. * `--extra-options-file` — file with additional options (in JSON format) to
  65. pass to `PEG.buildParser`
  66. * `--trace` — makes the parser trace its progress
  67. ### JavaScript API
  68. In Node.js, require the PEG.js parser generator module:
  69. var PEG = require("pegjs");
  70. In browser, include the PEG.js library in your web page or application using the
  71. `<script>` tag. If PEG.js detects an AMD loader, it will define itself as a
  72. module, otherwise the API will be available in the `PEG` global object.
  73. To generate a parser, call the `PEG.buildParser` method and pass your grammar as
  74. a parameter:
  75. var parser = PEG.buildParser("start = ('a' / 'b')+");
  76. The method will return generated parser object or its source code as a string
  77. (depending on the value of the `output` option — see below). It will throw an
  78. exception if the grammar is invalid. The exception will contain `message`
  79. property with more details about the error.
  80. You can tweak the generated parser by passing a second parameter with an options
  81. object to `PEG.buildParser`. The following options are supported:
  82. * `cache` — if `true`, makes the parser cache results, avoiding exponential
  83. parsing time in pathological cases but making the parser slower (default:
  84. `false`)
  85. * `allowedStartRules` — rules the parser will be allowed to start parsing from
  86. (default: the first rule in the grammar)
  87. * `dependencies` — parser dependencies, the value is an object which maps
  88. variables used to access the dependencies in the parser to module IDs used
  89. to load them; valid only when `format` is set to `"umd"` (default: `{}`)
  90. * `exportVar` — name of a global variable into which the parser object is
  91. assigned to when no module loader is detected; valid only when `format` is
  92. set to `"umd"` (default: `null`)
  93. * `format` — format of the genreated parser (`"bare"` or `"umd"`); valid only
  94. when `output` is set to `"source"` (default: `"bare"`)
  95. * `output` — if set to `"parser"`, the method will return generated parser
  96. object; if set to `"source"`, it will return parser source code as a string
  97. (default: `"parser"`)
  98. * `optimize`— selects between optimizing the generated parser for parsing
  99. speed (`"speed"`) or code size (`"size"`) (default: `"speed"`)
  100. * `plugins` — plugins to use
  101. Using the Parser
  102. ----------------
  103. Using the generated parser is simple — just call its `parse` method and pass an
  104. input string as a parameter. The method will return a parse result (the exact
  105. value depends on the grammar used to build the parser) or throw an exception if
  106. the input is invalid. The exception will contain `location`, `expected` and
  107. `message` properties with more details about the error.
  108. parser.parse("abba"); // returns ["a", "b", "b", "a"]
  109. parser.parse("abcd"); // throws an exception
  110. You can tweak parser behavior by passing a second parameter with an options
  111. object to the `parse` method. The following options are supported:
  112. * `startRule` — name of the rule to start parsing from
  113. * `tracer` — tracer to use
  114. Parsers can also support their own custom options.
  115. Grammar Syntax and Semantics
  116. ----------------------------
  117. The grammar syntax is similar to JavaScript in that it is not line-oriented and
  118. ignores whitespace between tokens. You can also use JavaScript-style comments
  119. (`// ...` and `/* ... */`).
  120. Let's look at example grammar that recognizes simple arithmetic expressions like
  121. `2*(3+4)`. A parser generated from this grammar computes their values.
  122. start
  123. = additive
  124. additive
  125. = left:multiplicative "+" right:additive { return left + right; }
  126. / multiplicative
  127. multiplicative
  128. = left:primary "*" right:multiplicative { return left * right; }
  129. / primary
  130. primary
  131. = integer
  132. / "(" additive:additive ")" { return additive; }
  133. integer "integer"
  134. = digits:[0-9]+ { return parseInt(digits.join(""), 10); }
  135. On the top level, the grammar consists of *rules* (in our example, there are
  136. five of them). Each rule has a *name* (e.g. `integer`) that identifies the rule,
  137. and a *parsing expression* (e.g. `digits:[0-9]+ { return
  138. parseInt(digits.join(""), 10); }`) that defines a pattern to match against the
  139. input text and possibly contains some JavaScript code that determines what
  140. happens when the pattern matches successfully. A rule can also contain
  141. *human-readable name* that is used in error messages (in our example, only the
  142. `integer` rule has a human-readable name). The parsing starts at the first rule,
  143. which is also called the *start rule*.
  144. A rule name must be a JavaScript identifier. It is followed by an equality sign
  145. (“=”) and a parsing expression. If the rule has a human-readable name, it is
  146. written as a JavaScript string between the name and separating equality sign.
  147. Rules need to be separated only by whitespace (their beginning is easily
  148. recognizable), but a semicolon (“;”) after the parsing expression is allowed.
  149. The first rule can be preceded by an *initializer* — a piece of JavaScript code
  150. in curly braces (“{” and “}”). This code is executed before the generated parser
  151. starts parsing. All variables and functions defined in the initializer are
  152. accessible in rule actions and semantic predicates. The code inside the
  153. initializer can access the parser object using the `parser` variable and options
  154. passed to the parser using the `options` variable. Curly braces in the
  155. initializer code must be balanced. Let's look at the example grammar from above
  156. using a simple initializer.
  157. {
  158. function makeInteger(o) {
  159. return parseInt(o.join(""), 10);
  160. }
  161. }
  162. start
  163. = additive
  164. additive
  165. = left:multiplicative "+" right:additive { return left + right; }
  166. / multiplicative
  167. multiplicative
  168. = left:primary "*" right:multiplicative { return left * right; }
  169. / primary
  170. primary
  171. = integer
  172. / "(" additive:additive ")" { return additive; }
  173. integer "integer"
  174. = digits:[0-9]+ { return makeInteger(digits); }
  175. The parsing expressions of the rules are used to match the input text to the
  176. grammar. There are various types of expressions — matching characters or
  177. character classes, indicating optional parts and repetition, etc. Expressions
  178. can also contain references to other rules. See detailed description below.
  179. If an expression successfully matches a part of the text when running the
  180. generated parser, it produces a *match result*, which is a JavaScript value. For
  181. example:
  182. * An expression matching a literal string produces a JavaScript string
  183. containing matched text.
  184. * An expression matching repeated occurrence of some subexpression produces a
  185. JavaScript array with all the matches.
  186. The match results propagate through the rules when the rule names are used in
  187. expressions, up to the start rule. The generated parser returns start rule's
  188. match result when parsing is successful.
  189. One special case of parser expression is a *parser action* — a piece of
  190. JavaScript code inside curly braces (“{” and “}”) that takes match results of
  191. some of the the preceding expressions and returns a JavaScript value. This value
  192. is considered match result of the preceding expression (in other words, the
  193. parser action is a match result transformer).
  194. In our arithmetics example, there are many parser actions. Consider the action
  195. in expression `digits:[0-9]+ { return parseInt(digits.join(""), 10); }`. It
  196. takes the match result of the expression [0-9]+, which is an array of strings
  197. containing digits, as its parameter. It joins the digits together to form a
  198. number and converts it to a JavaScript `number` object.
  199. ### Parsing Expression Types
  200. There are several types of parsing expressions, some of them containing
  201. subexpressions and thus forming a recursive structure:
  202. #### "*literal*"<br>'*literal*'
  203. Match exact literal string and return it. The string syntax is the same as in
  204. JavaScript. Appending `i` right after the literal makes the match
  205. case-insensitive.
  206. #### .
  207. Match exactly one character and return it as a string.
  208. #### [*characters*]
  209. Match one character from a set and return it as a string. The characters in the
  210. list can be escaped in exactly the same way as in JavaScript string. The list of
  211. characters can also contain ranges (e.g. `[a-z]` means “all lowercase letters”).
  212. Preceding the characters with `^` inverts the matched set (e.g. `[^a-z]` means
  213. “all character but lowercase letters”). Appending `i` right after the right
  214. bracket makes the match case-insensitive.
  215. #### *rule*
  216. Match a parsing expression of a rule recursively and return its match result.
  217. #### ( *expression* )
  218. Match a subexpression and return its match result.
  219. #### *expression* \*
  220. Match zero or more repetitions of the expression and return their match results
  221. in an array. The matching is greedy, i.e. the parser tries to match the
  222. expression as many times as possible. Unlike in regular expressions, there is no
  223. backtracking.
  224. #### *expression* +
  225. Match one or more repetitions of the expression and return their match results
  226. in an array. The matching is greedy, i.e. the parser tries to match the
  227. expression as many times as possible. Unlike in regular expressions, there is no
  228. backtracking.
  229. #### *expression* ?
  230. Try to match the expression. If the match succeeds, return its match result,
  231. otherwise return `null`. Unlike in regular expressions, there is no
  232. backtracking.
  233. #### & *expression*
  234. Try to match the expression. If the match succeeds, just return `undefined` and
  235. do not consume any input, otherwise consider the match failed.
  236. #### ! *expression*
  237. Try to match the expression. If the match does not succeed, just return
  238. `undefined` and do not consume any input, otherwise consider the match failed.
  239. #### & { *predicate* }
  240. The predicate is a piece of JavaScript code that is executed as if it was inside
  241. a function. It gets the match results of labeled expressions in preceding
  242. expression as its arguments. It should return some JavaScript value using the
  243. `return` statement. If the returned value evaluates to `true` in boolean
  244. context, just return `undefined` and do not consume any input; otherwise
  245. consider the match failed.
  246. The code inside the predicate can access all variables and functions defined in
  247. the initializer at the beginning of the grammar.
  248. The code inside the predicate can also access location information using the
  249. `location` function. It returns an object like this:
  250. {
  251. start: { offset: 23, line: 5, column: 6 },
  252. end: { offset: 23, line: 5, column: 6 }
  253. }
  254. The `start` and `end` properties both refer to the current parse position. The
  255. `offset` property contains an offset as a zero-based index and `line` and
  256. `column` properties contain a line and a column as one-based indices.
  257. The code inside the predicate can also access the parser object using the
  258. `parser` variable and options passed to the parser using the `options` variable.
  259. Note that curly braces in the predicate code must be balanced.
  260. #### ! { *predicate* }
  261. The predicate is a piece of JavaScript code that is executed as if it was inside
  262. a function. It gets the match results of labeled expressions in preceding
  263. expression as its arguments. It should return some JavaScript value using the
  264. `return` statement. If the returned value evaluates to `false` in boolean
  265. context, just return `undefined` and do not consume any input; otherwise
  266. consider the match failed.
  267. The code inside the predicate can access all variables and functions defined in
  268. the initializer at the beginning of the grammar.
  269. The code inside the predicate can also access location information using the
  270. `location` function. It returns an object like this:
  271. {
  272. start: { offset: 23, line: 5, column: 6 },
  273. end: { offset: 23, line: 5, column: 6 }
  274. }
  275. The `start` and `end` properties both refer to the current parse position. The
  276. `offset` property contains an offset as a zero-based index and `line` and
  277. `column` properties contain a line and a column as one-based indices.
  278. The code inside the predicate can also access the parser object using the
  279. `parser` variable and options passed to the parser using the `options` variable.
  280. Note that curly braces in the predicate code must be balanced.
  281. #### $ *expression*
  282. Try to match the expression. If the match succeeds, return the matched text
  283. instead of the match result.
  284. #### *label* : *expression*
  285. Match the expression and remember its match result under given label. The label
  286. must be a JavaScript identifier.
  287. Labeled expressions are useful together with actions, where saved match results
  288. can be accessed by action's JavaScript code.
  289. #### *expression<sub>1</sub>* *expression<sub>2</sub>* ... *expression<sub>n</sub>*
  290. Match a sequence of expressions and return their match results in an array.
  291. #### *expression* { *action* }
  292. Match the expression. If the match is successful, run the action, otherwise
  293. consider the match failed.
  294. The action is a piece of JavaScript code that is executed as if it was inside a
  295. function. It gets the match results of labeled expressions in preceding
  296. expression as its arguments. The action should return some JavaScript value
  297. using the `return` statement. This value is considered match result of the
  298. preceding expression.
  299. To indicate an error, the code inside the action can invoke the `expected`
  300. function, which makes the parser throw an exception. The function takes two
  301. parameters — a description of what was expected at the current position and
  302. optional location information (the default is what `location` would return — see
  303. below). The description will be used as part of a message of the thrown
  304. exception.
  305. The code inside an action can also invoke the `error` function, which also makes
  306. the parser throw an exception. The function takes two parameters — an error
  307. message and optional location information (the default is what `location` would
  308. return — see below). The message will be used by the thrown exception.
  309. The code inside the action can access all variables and functions defined in the
  310. initializer at the beginning of the grammar. Curly braces in the action code
  311. must be balanced.
  312. The code inside the action can also access the text matched by the expression
  313. using the `text` function.
  314. The code inside the action can also access location information using the
  315. `location` function. It returns an object like this:
  316. {
  317. start: { offset: 23, line: 5, column: 6 },
  318. end: { offset: 25, line: 5, column: 8 }
  319. }
  320. The `start` property refers to the position at the beginning of the expression,
  321. the `end` property refers to position after the end of the expression. The
  322. `offset` property contains an offset as a zero-based index and `line` and
  323. `column` properties contain a line and a column as one-based indices.
  324. The code inside the action can also access the parser object using the `parser`
  325. variable and options passed to the parser using the `options` variable.
  326. Note that curly braces in the action code must be balanced.
  327. #### *expression<sub>1</sub>* / *expression<sub>2</sub>* / ... / *expression<sub>n</sub>*
  328. Try to match the first expression, if it does not succeed, try the second one,
  329. etc. Return the match result of the first successfully matched expression. If no
  330. expression matches, consider the match failed.
  331. Compatibility
  332. -------------
  333. Both the parser generator and generated parsers should run well in the following
  334. environments:
  335. * Node.js 0.10.0+
  336. * io.js
  337. * Internet Explorer 8+
  338. * Edge
  339. * Firefox
  340. * Chrome
  341. * Safari
  342. * Opera
  343. Development
  344. -----------
  345. * [Project website](http://pegjs.org/)
  346. * [Wiki](https://github.com/pegjs/pegjs/wiki)
  347. * [Source code](https://github.com/pegjs/pegjs)
  348. * [Issue tracker](https://github.com/pegjs/pegjs/issues)
  349. * [Google Group](http://groups.google.com/group/pegjs)
  350. * [Twitter](http://twitter.com/peg_js)
  351. PEG.js is developed by [David Majda](http://majda.cz/)
  352. ([@dmajda](http://twitter.com/dmajda)). The [Bower
  353. package](https://github.com/pegjs/bower) is maintained by [Michel
  354. Krämer](http://www.michel-kraemer.com/)
  355. ([@michelkraemer](https://twitter.com/michelkraemer)).
  356. You are welcome to contribute code. Unless your contribution is really trivial
  357. you should get in touch with me first — this can prevent wasted effort on both
  358. sides. You can send code both as a patch or a GitHub pull request.
  359. Note that PEG.js is still very much work in progress. There are no compatibility
  360. guarantees until version 1.0.