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.

675 lines
25 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
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
11 years ago
11 years ago
5 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
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
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
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
11 years ago
  1. [![Build status](https://img.shields.io/travis/pegjs/pegjs.svg?label=travis)](https://travis-ci.org/pegjs/pegjs)
  2. [![npm/pegjs version](https://img.shields.io/npm/v/pegjs.svg?label=npm/pegjs)](https://www.npmjs.com/package/pegjs)
  3. [![npm/pegjs-dev version](https://img.shields.io/npm/v/pegjs-dev.svg?label=npm/pegjs-dev)](https://www.npmjs.com/package/pegjs-dev)
  4. [![Bower version](https://img.shields.io/bower/v/pegjs.svg?label=bower/pegjs)](https://github.com/pegjs/bower)
  5. [![License](https://img.shields.io/badge/license-mit-blue.svg)](https://opensource.org/licenses/MIT)
  6. PEG.js is a simple parser generator for JavaScript that produces fast parsers with excellent error reporting. You can use it to
  7. process complex data or computer languages and build transformers, interpreters, compilers and other tools easily.
  8. > PEG.js is still very much work in progress. There are no compatibility guarantees until version 1.0
  9. Table of Contents
  10. -----------------
  11. - [Features](#features)
  12. - [Getting Started](#getting-Started)
  13. - [Installation](#installation)
  14. * [Node.js](#nodejs)
  15. * [Browser](#browser)
  16. * [Latest](#latest)
  17. - [Generating a Parser](#generating-a-parser)
  18. * [Command Line](#command-line)
  19. * [JavaScript API](#javascript-api)
  20. - [Using the Parser](#using-the-parser)
  21. - [Grammar Syntax and Semantics](#grammar-syntax-and-semantics)
  22. * [Case-insensitivity](#case-insensitivity)
  23. * [Backtracking](#backtracking)
  24. * [Parsing Expression Types](#parsing-expression-types)
  25. - [Error Messages](#error-messages)
  26. - [Compatibility](#compatibility)
  27. - [Development](#development)
  28. * [Useful Links](#useful-links)
  29. * [Contribution](#contribution)
  30. Features
  31. --------
  32. * Simple and expressive grammar syntax
  33. * Integrates both lexical and syntactical analysis
  34. * Parsers have excellent error reporting out of the box
  35. * Based on [parsing expression
  36. grammar](http://en.wikipedia.org/wiki/Parsing_expression_grammar) formalism
  37. — more powerful than traditional LL(*k*) and LR(*k*) parsers
  38. * Usable [from your browser](https://pegjs.org/online), from the command line,
  39. or via JavaScript API
  40. Getting Started
  41. ---------------
  42. [Online version](https://pegjs.org/online) is the easiest way to generate a
  43. parser. Just enter your grammar, try parsing few inputs, and download generated
  44. parser code.
  45. Installation
  46. ------------
  47. ### Node.js
  48. To use the `pegjs` command, install PEG.js globally:
  49. ```console
  50. $ npm install -g pegjs
  51. ```
  52. To use the JavaScript API, install PEG.js locally:
  53. ```console
  54. $ npm install pegjs
  55. ```
  56. If you need both the `pegjs` command and the JavaScript API, install PEG.js both
  57. ways.
  58. ### Browser
  59. [Download](https://pegjs.org/#download) the PEG.js library (regular or minified
  60. version) or install it using Bower:
  61. ```console
  62. $ bower install pegjs
  63. ```
  64. ### Latest
  65. To use the latest features, fixes and changes of PEG.js, directly install from the repository:
  66. ```console
  67. $ npm install pegjs/pegjs#master
  68. ```
  69. Alternatively, you can use the most recently packaged version of the PEG.js code hosted on GitHub:
  70. ```console
  71. $ npm install pegjs-dev
  72. ```
  73. Generating a Parser
  74. -------------------
  75. PEG.js generates parser from a grammar that describes expected input and can
  76. specify what the parser returns (using semantic actions on matched parts of the
  77. input). Generated parser itself is a JavaScript object with a simple API.
  78. ### Command Line
  79. To generate a parser from your grammar, use the `pegjs` command:
  80. ```console
  81. $ pegjs arithmetics.pegjs
  82. ```
  83. This writes parser source code into a file with the same name as the grammar
  84. file but with “.js” extension. You can also specify the output file explicitly:
  85. ```console
  86. $ pegjs -o arithmetics-parser.js arithmetics.pegjs
  87. ```
  88. If you omit both input and output file, standard input and output are used.
  89. By default, the generated parser is in the Node.js module format. You can
  90. override this using the `--format` option.
  91. You can tweak the generated parser with several options:
  92. * `--allowed-start-rules` — comma-separated list of rules the parser will be
  93. allowed to start parsing from (default: the first rule in the grammar)
  94. * `--cache` — makes the parser cache results, avoiding exponential parsing
  95. time in pathological cases but making the parser slower
  96. * `--dependency` — makes the parser require a specified dependency (can be
  97. specified multiple times)
  98. * `--export-var` — name of a global variable into which the parser object is
  99. assigned to when no module loader is detected
  100. * `--extra-options` — additional options (in JSON format) to pass to
  101. `peg.generate`
  102. * `--extra-options-file` — file with additional options (in JSON format) to
  103. pass to `peg.generate`
  104. * `--format` — format of the generated parser: `amd`, `commonjs`, `es`,
  105. `globals`, `umd` (default: `commonjs`)
  106. * `--optimize` — selects between optimizing the generated parser for parsing
  107. speed (`speed`) or code size (`size`) (default: `speed`)
  108. * `--plugin` — makes PEG.js use a specified plugin (can be specified multiple
  109. times)
  110. * `--trace` — makes the parser trace its progress
  111. ### JavaScript API
  112. In Node.js, require the PEG.js parser generator module:
  113. ```javascript
  114. var peg = require("pegjs");
  115. ```
  116. In browser, include the PEG.js library in your web page or application using the
  117. `<script>` tag. If PEG.js detects an AMD loader, it will define itself as a
  118. module, otherwise the API will be available in the `peg` global object.
  119. To generate a parser, call the `peg.generate` method and pass your grammar as a
  120. parameter:
  121. ```javascript
  122. var parser = peg.generate("start = ('a' / 'b')+");
  123. ```
  124. The method will return generated parser object or its source code as a string
  125. (depending on the value of the `output` option — see below). It will throw an
  126. exception if the grammar is invalid. The exception will contain `message`
  127. property with more details about the error.
  128. You can tweak the generated parser by passing a second parameter with an options
  129. object to `peg.generate`. The following options are supported:
  130. * `allowedStartRules` — rules the parser will be allowed to start parsing from
  131. (default: the first rule in the grammar)
  132. * `cache` — if `true`, makes the parser cache results, avoiding exponential
  133. parsing time in pathological cases but making the parser slower (default:
  134. `false`)
  135. * `dependencies` — parser dependencies, the value is an object which maps
  136. variables used to access the dependencies in the parser to module IDs used
  137. to load them; valid only when `format` is set to `"amd"`, `"commonjs"`,
  138. `"es"`, or `"umd"` (default: `{}`)
  139. * `exportVar` — name of a global variable into which the parser object is
  140. assigned to when no module loader is detected; valid only when `format` is
  141. set to `"globals"` or `"umd"` (default: `null`)
  142. * `format` — format of the generated parser (`"amd"`, `"bare"`, `"commonjs"`,
  143. `"es"`, `"globals"`, or `"umd"`); valid only when `output` is set to
  144. `"source"` (default: `"bare"`)
  145. * `optimize`— selects between optimizing the generated parser for parsing
  146. speed (`"speed"`) or code size (`"size"`) (default: `"speed"`)
  147. * `output` — if set to `"parser"`, the method will return generated parser
  148. object; if set to `"source"`, it will return parser source code as a string
  149. (default: `"parser"`)
  150. * `plugins` — plugins to use
  151. * `trace` — makes the parser trace its progress (default: `false`)
  152. Using the Parser
  153. ----------------
  154. Using the generated parser is simple — just call its `parse` method and pass an
  155. input string as a parameter. The method will return a parse result (the exact
  156. value depends on the grammar used to generate the parser) or throw an exception
  157. if the input is invalid. The exception will contain `location`, `expected`,
  158. `found`, and `message` properties with more details about the error.
  159. ```javascript
  160. parser.parse("abba"); // returns ["a", "b", "b", "a"]
  161. parser.parse("abcd"); // throws an exception
  162. ```
  163. You can tweak parser behavior by passing a second parameter with an options
  164. object to the `parse` method. The following options are supported:
  165. * `startRule` — name of the rule to start parsing from
  166. * `tracer` — tracer to use
  167. Parsers can also support their own custom options.
  168. Grammar Syntax and Semantics
  169. ----------------------------
  170. The grammar syntax is similar to JavaScript in that it is not line-oriented and
  171. ignores whitespace between tokens. You can also use JavaScript-style comments
  172. (`// ...` and `/* ... */`).
  173. Let's look at example grammar that recognizes simple arithmetic expressions like
  174. `2*(3+4)`. A parser generated from this grammar computes their values.
  175. ```pegjs
  176. start
  177. = additive
  178. additive
  179. = left:multiplicative "+" right:additive { return left + right; }
  180. / multiplicative
  181. multiplicative
  182. = left:primary "*" right:multiplicative { return left * right; }
  183. / primary
  184. primary
  185. = integer
  186. / "(" additive:additive ")" { return additive; }
  187. integer "integer"
  188. = digits:[0-9]+ { return parseInt(digits.join(""), 10); }
  189. ```
  190. On the top level, the grammar consists of *rules* (in our example, there are
  191. five of them). Each rule has a *name* (e.g. `integer`) that identifies the rule,
  192. and a *parsing expression* (e.g. `digits:[0-9]+ { return
  193. parseInt(digits.join(""), 10); }`) that defines a pattern to match against the
  194. input text and possibly contains some JavaScript code that determines what
  195. happens when the pattern matches successfully. A rule can also contain
  196. *human-readable name* that is used in error messages (in our example, only the
  197. `integer` rule has a human-readable name). The parsing starts at the first rule,
  198. which is also called the *start rule*.
  199. A rule name must be a JavaScript identifier. It is followed by an equality sign
  200. (“=”) and a parsing expression. If the rule has a human-readable name, it is
  201. written as a JavaScript string between the name and separating equality sign.
  202. Rules need to be separated only by whitespace (their beginning is easily
  203. recognizable), but a semicolon (“;”) after the parsing expression is allowed.
  204. The first rule can be preceded by an *initializer* — a piece of JavaScript code
  205. in curly braces (“{” and “}”). This code is executed before the generated parser
  206. starts parsing. All variables and functions defined in the initializer are
  207. accessible in rule actions and semantic predicates. The code inside the
  208. initializer can access options passed to the parser using the `options`
  209. variable. Curly braces in the initializer code must be balanced. Let's look at
  210. the example grammar from above using a simple initializer.
  211. ```pegjs
  212. {
  213. function makeInteger(o) {
  214. return parseInt(o.join(""), 10);
  215. }
  216. }
  217. start
  218. = additive
  219. additive
  220. = left:multiplicative "+" right:additive { return left + right; }
  221. / multiplicative
  222. multiplicative
  223. = left:primary "*" right:multiplicative { return left * right; }
  224. / primary
  225. primary
  226. = integer
  227. / "(" additive:additive ")" { return additive; }
  228. integer "integer"
  229. = digits:[0-9]+ { return makeInteger(digits); }
  230. ```
  231. The parsing expressions of the rules are used to match the input text to the
  232. grammar. There are various types of expressions — matching characters or
  233. character classes, indicating optional parts and repetition, etc. Expressions
  234. can also contain references to other rules. See detailed description below.
  235. If an expression successfully matches a part of the text when running the
  236. generated parser, it produces a *match result*, which is a JavaScript value. For
  237. example:
  238. * An expression matching a literal string produces a JavaScript string
  239. containing matched text.
  240. * An expression matching repeated occurrence of some subexpression produces a
  241. JavaScript array with all the matches.
  242. The match results propagate through the rules when the rule names are used in
  243. expressions, up to the start rule. The generated parser returns start rule's
  244. match result when parsing is successful.
  245. One special case of parser expression is a *parser action* — a piece of
  246. JavaScript code inside curly braces (“{” and “}”) that takes match results of
  247. some of the the preceding expressions and returns a JavaScript value. This value
  248. is considered match result of the preceding expression (in other words, the
  249. parser action is a match result transformer).
  250. In our arithmetics example, there are many parser actions. Consider the action
  251. in expression `digits:[0-9]+ { return parseInt(digits.join(""), 10); }`. It
  252. takes the match result of the expression [0-9]+, which is an array of strings
  253. containing digits, as its parameter. It joins the digits together to form a
  254. number and converts it to a JavaScript `number` object.
  255. ### Case-insensitivity
  256. Appending `i` right after either [a literal](#literalliteral) or a [a character set](#characters) makes the match
  257. case-insensitive. The rules shown in the following example all produce the same result:
  258. ```pegjs
  259. a1 = "a" / "b" / "c" / "A" / "B" / "C"
  260. a2 = "a"i / "b"i / "c"i
  261. a3 = [a-cA-C]
  262. a4 = [a-c]i
  263. ```
  264. ### Backtracking
  265. Unlike in regular expressions, there is no backtracking in PEG.js expressions.
  266. For example, using the input "hi!":
  267. ```pegjs
  268. // This will fail
  269. HI = "hi" / "hi!"
  270. // This will pass
  271. HI = "hi!" / "hi"
  272. // This will also pass
  273. HI = w:"hi" !"!" { return w } / "hi!"
  274. ```
  275. For more information on backtracking in PEG, [checkout this excellent answer on Stack Overflow](https://stackoverflow.com/a/24809596/1518408).
  276. ### Parsing Expression Types
  277. There are several types of parsing expressions, some of them containing
  278. subexpressions and thus forming a recursive structure:
  279. * ["literal"](#literalliteral)
  280. * [. (dot character)](#--dot-character-)
  281. * [[characters]](#characters)
  282. * [rule](#rule)
  283. * [( expression )](#-expression-)
  284. * [expression *](#expression-)
  285. * [expression +](#expression--1)
  286. * [expression ?](#expression--2)
  287. * [& expression](#-expression)
  288. * [! expression](#-expression-1)
  289. * [& { predicate }](#--predicate-)
  290. * [! { predicate }](#--predicate--1)
  291. * [$ expression](#-expression-2)
  292. * [label : expression](#label--expression)
  293. * [expression1 expression2 ... expressionN](#expression1-expression2---expressionn)
  294. * [expression { action }](#expression--action-)
  295. * [expression1 / expression2 / ... / expressionN](#expression1--expression2----expressionn)
  296. #### "*literal*"<br>'*literal*'
  297. Match exact literal string and return it. The string syntax is the same as in
  298. JavaScript. Appending `i` right after the literal makes the match
  299. case-insensitive.
  300. #### . *(dot character)*
  301. Match exactly one character and return it as a string.
  302. #### [*characters*]
  303. Match one character from a set and return it as a string. The characters in the
  304. list can be escaped in exactly the same way as in JavaScript string. The list of
  305. characters can also contain ranges (e.g. `[a-z]` means “all lowercase letters”).
  306. Preceding the characters with `^` inverts the matched set (e.g. `[^a-z]` means
  307. “all character but lowercase letters”). Appending `i` right after the right
  308. bracket makes the match case-insensitive.
  309. #### *rule*
  310. Match a parsing expression of a rule recursively and return its match result.
  311. #### ( *expression* )
  312. Match a subexpression and return its match result.
  313. #### *expression* \*
  314. Match zero or more repetitions of the expression and return their match results
  315. in an array. The matching is greedy, i.e. the parser tries to match the
  316. expression as many times as possible. Unlike in regular expressions, there is no
  317. backtracking.
  318. #### *expression* +
  319. Match one or more repetitions of the expression and return their match results
  320. in an array. The matching is greedy, i.e. the parser tries to match the
  321. expression as many times as possible. Unlike in regular expressions, there is no
  322. backtracking.
  323. #### *expression* ?
  324. Try to match the expression. If the match succeeds, return its match result,
  325. otherwise return `null`. Unlike in regular expressions, there is no
  326. backtracking.
  327. #### & *expression*
  328. Try to match the expression. If the match succeeds, just return `undefined` and
  329. do not consume any input, otherwise consider the match failed.
  330. #### ! *expression*
  331. Try to match the expression. If the match does not succeed, just return
  332. `undefined` and do not consume any input, otherwise consider the match failed.
  333. #### & { *predicate* }
  334. The predicate is a piece of JavaScript code that is executed as if it was inside
  335. a function. It gets the match results of labeled expressions in preceding
  336. expression as its arguments. It should return some JavaScript value using the
  337. `return` statement. If the returned value evaluates to `true` in boolean
  338. context, just return `undefined` and do not consume any input; otherwise
  339. consider the match failed.
  340. The code inside the predicate can access all variables and functions defined in
  341. the initializer at the beginning of the grammar.
  342. The code inside the predicate can also access location information using the
  343. `location` function. It returns an object like this:
  344. ```javascript
  345. {
  346. start: { offset: 23, line: 5, column: 6 },
  347. end: { offset: 23, line: 5, column: 6 }
  348. }
  349. ```
  350. The `start` and `end` properties both refer to the current parse position. The
  351. `offset` property contains an offset as a zero-based index and `line` and
  352. `column` properties contain a line and a column as one-based indices.
  353. The code inside the predicate can also access options passed to the parser using
  354. the `options` variable.
  355. Note that curly braces in the predicate code must be balanced.
  356. #### ! { *predicate* }
  357. The predicate is a piece of JavaScript code that is executed as if it was inside
  358. a function. It gets the match results of labeled expressions in preceding
  359. expression as its arguments. It should return some JavaScript value using the
  360. `return` statement. If the returned value evaluates to `false` in boolean
  361. context, just return `undefined` and do not consume any input; otherwise
  362. consider the match failed.
  363. The code inside the predicate can access all variables and functions defined in
  364. the initializer at the beginning of the grammar.
  365. The code inside the predicate can also access location information using the
  366. `location` function. It returns an object like this:
  367. ```javascript
  368. {
  369. start: { offset: 23, line: 5, column: 6 },
  370. end: { offset: 23, line: 5, column: 6 }
  371. }
  372. ```
  373. The `start` and `end` properties both refer to the current parse position. The
  374. `offset` property contains an offset as a zero-based index and `line` and
  375. `column` properties contain a line and a column as one-based indices.
  376. The code inside the predicate can also access options passed to the parser using
  377. the `options` variable.
  378. Note that curly braces in the predicate code must be balanced.
  379. #### $ *expression*
  380. Try to match the expression. If the match succeeds, return the matched text
  381. instead of the match result.
  382. #### *label* : *expression*
  383. Match the expression and remember its match result under given label. The label
  384. must be a JavaScript identifier.
  385. Labeled expressions are useful together with actions, where saved match results
  386. can be accessed by action's JavaScript code.
  387. #### *expression<sub>1</sub>* *expression<sub>2</sub>* ... *expression<sub>n</sub>*
  388. Match a sequence of expressions and return their match results in an array.
  389. #### *expression* { *action* }
  390. Match the expression. If the match is successful, run the action, otherwise
  391. consider the match failed.
  392. The action is a piece of JavaScript code that is executed as if it was inside a
  393. function. It gets the match results of labeled expressions in preceding
  394. expression as its arguments. The action should return some JavaScript value
  395. using the `return` statement. This value is considered match result of the
  396. preceding expression.
  397. To indicate an error, the code inside the action can invoke the `expected`
  398. function, which makes the parser throw an exception. The function takes two
  399. parameters — a description of what was expected at the current position and
  400. optional location information (the default is what `location` would return — see
  401. below). The description will be used as part of a message of the thrown
  402. exception.
  403. The code inside an action can also invoke the `error` function, which also makes
  404. the parser throw an exception. The function takes two parameters — an error
  405. message and optional location information (the default is what `location` would
  406. return — see below). The message will be used by the thrown exception.
  407. The code inside the action can access all variables and functions defined in the
  408. initializer at the beginning of the grammar. Curly braces in the action code
  409. must be balanced.
  410. The code inside the action can also access the text matched by the expression
  411. using the `text` function.
  412. The code inside the action can also access location information using the
  413. `location` function. It returns an object like this:
  414. ```javascript
  415. {
  416. start: { offset: 23, line: 5, column: 6 },
  417. end: { offset: 25, line: 5, column: 8 }
  418. }
  419. ```
  420. The `start` property refers to the position at the beginning of the expression,
  421. the `end` property refers to position after the end of the expression. The
  422. `offset` property contains an offset as a zero-based index and `line` and
  423. `column` properties contain a line and a column as one-based indices.
  424. The code inside the action can also access options passed to the parser using
  425. the `options` variable.
  426. Note that curly braces in the action code must be balanced.
  427. #### *expression<sub>1</sub>* / *expression<sub>2</sub>* / ... / *expression<sub>n</sub>*
  428. Try to match the first expression, if it does not succeed, try the second one,
  429. etc. Return the match result of the first successfully matched expression. If no
  430. expression matches, consider the match failed.
  431. Error Messages
  432. --------------
  433. As described above, you can annotate your grammar rules with human-readable
  434. names that will be used in error messages. For example, this production:
  435. integer "integer"
  436. = digits:[0-9]+
  437. will produce an error message like:
  438. > Expected integer but "a" found.
  439. when parsing a non-number, referencing the human-readable name "integer."
  440. Without the human-readable name, PEG.js instead uses a description of the
  441. character class that failed to match:
  442. > Expected [0-9] but "a" found.
  443. Aside from the text content of messages, human-readable names also have a
  444. subtler effect on *where* errors are reported. PEG.js prefers to match
  445. named rules completely or not at all, but not partially. Unnamed rules,
  446. on the other hand, can produce an error in the middle of their
  447. subexpressions.
  448. For example, for this rule matching a comma-separated list of integers:
  449. seq
  450. = integer ("," integer)*
  451. an input like `1,2,a` produces this error message:
  452. > Expected integer but "a" found.
  453. But if we add a human-readable name to the `seq` production:
  454. seq "list of numbers"
  455. = integer ("," integer)*
  456. then PEG.js prefers an error message that implies a smaller attempted parse
  457. tree:
  458. > Expected end of input but "," found.
  459. Compatibility
  460. -------------
  461. Both the parser generator and generated parsers should run well in the following
  462. environments:
  463. * Node.js 4+
  464. * Internet Explorer 9+
  465. * Edge
  466. * Firefox
  467. * Chrome
  468. * Safari
  469. * Opera
  470. Development
  471. -----------
  472. PEG.js is currently maintained by [Futago-za Ryuu](https://github.com/futagoza). Since it's [inception](https://www.google.com/search?q=inception+meaning) in 2010, PEG.js was maintained by [David Majda](https://majda.cz/) ([@dmajda](http://twitter.com/dmajda)), until [May 2017](https://github.com/pegjs/pegjs/issues/503).
  473. The [Bower package](https://github.com/pegjs/bower) is maintained by [Michel Krämer](http://www.michel-kraemer.com/) ([@michelkraemer](https://twitter.com/michelkraemer)).
  474. ### Useful Links
  475. * [Project website](https://pegjs.org/)
  476. * [Wiki](https://github.com/pegjs/pegjs/wiki)
  477. * [Source code](https://github.com/pegjs/pegjs)
  478. * [Issue tracker](https://github.com/pegjs/pegjs/issues)
  479. * [Google Group](http://groups.google.com/group/pegjs)
  480. * [Stack Overflow](https://stackoverflow.com/questions/tagged/pegjs)
  481. * [Twitter](http://twitter.com/peg_js)
  482. ### Contribution
  483. You are welcome to contribute code using [GitHub pull requests](https://github.com/pegjs/pegjs/pulls). Unless your contribution is really trivial you should get in touch with me first (preferably by creating a new issue on the [issue tracker](https://github.com/pegjs/pegjs/issues)) - this can prevent wasted effort on both sides.
  484. > Before submitting a pull request, please make sure you've checked out the [Contribution Guidelines](https://github.com/pegjs/pegjs/blob/master/CONTRIBUTING.md).
  485. 1. Create a fork of https://github.com/pegjs/pegjs
  486. 2. Clone your fork, and optionally create a new branch
  487. 3. Run the command `npm install` from the root of your clone
  488. 4. Add and commit your changes
  489. 5. Validate your changes:
  490. - Lint the JavaScript changes (command line only, run `gulp lint` or `npm run lint`)
  491. - Run tests to ensure nothing's broken: [see separate documentation](https://github.com/pegjs/pegjs/blob/master/test/README.md)
  492. - Optionally, check benchmark results: [see separate documentation](https://github.com/pegjs/pegjs/blob/master/benchmark/README.md)
  493. - Optionally, check commit impact (this is a bash script, run `tools/impact`)
  494. 6. If validation fails: reverse your commit, fix the problem and then add/commit again
  495. 7. Push the commits from your clone to the fork
  496. 8. From your fork, start a new pull request
  497. It's also a good idea to check out the [gulpfile.js](https://github.com/pegjs/pegjs/blob/master/gulpfile.js) that defines
  498. various tasks that are commented with a description of each task.
  499. To see the list of contributors check out the [repository's contributors page](https://github.com/pegjs/pegjs/graphs/contributors).