Skip to content

Commit

Permalink
Merge pull request peggyjs#73 from jaubourg/main
Browse files Browse the repository at this point in the history
Adds top level initializer block.
  • Loading branch information
hildjj authored Apr 19, 2021
2 parents 434c4b9 + 4b54845 commit a822ffe
Show file tree
Hide file tree
Showing 10 changed files with 865 additions and 710 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Futago-za Ryuu <[email protected]> (https://github.com/futagoza/)
Jakub Vrana <[email protected]> (https://github.com/vrana/)
Jason Davies <[email protected]> (https://github.com/jasondavies/)
Joseph Frazier <[email protected]> (https://github.com/joseph-onsip/)
Julian Aubourg <[email protected]> (https://github.com/jaubourg)
Justin Blank <[email protected]> (https://github.com/hyperpape/)
Marco Baumgartl <[email protected]>
Mingun <[email protected]> (https://github.com/Mingun/)
Expand Down
45 changes: 34 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,15 @@ object to `peg.generate`. The following options are supported:
`false`)
- `dependencies` — parser dependencies, the value is an object which maps
variables used to access the dependencies in the parser to module IDs used
to load them; valid only when `format` is set to `"amd"`, `"commonjs"`, `"es"`, or
`"umd"` (default: `{}`)
to load them; valid only when `format` is set to `"amd"`, `"commonjs"`,
`"es"`, or `"umd"`. Dependencies variables will be available in both the
_general initializer_ and the _per-parse initializer_. Unless the parser is
to be generated in different formats, it is recommended to rather import
dependencies from within the _global initializer_. (default: `{}`)
- `exportVar` — name of a global variable into which the parser object is
assigned to when no module loader is detected; valid only when `format` is
set to `"globals"` or `"umd"` (default: `null`)
- `format` — format of the genreated parser (`"amd"`, `"bare"`, `"commonjs"`,
- `format` — format of the generated parser (`"amd"`, `"bare"`, `"commonjs"`,
`"es"`, `"globals"`, or `"umd"`); valid only when `output` is set to `"source"`
(default: `"bare"`)
- `optimize`— selects between optimizing the generated parser for parsing
Expand Down Expand Up @@ -235,19 +238,39 @@ written as a JavaScript string between the name and separating equality sign.
Rules need to be separated only by whitespace (their beginning is easily
recognizable), but a semicolon (“;”) after the parsing expression is allowed.

The first rule can be preceded by an _initializer_ — a piece of JavaScript code
in curly braces (“{” and “}”). This code is executed before the generated parser
starts parsing. All variables and functions defined in the initializer are
accessible in rule actions and semantic predicates. The code inside the
initializer can access options passed to the parser using the `options`
variable. Curly braces in the initializer code must be balanced. Let's look at
the example grammar from above using a simple initializer.
The first rule can be preceded by a _global initializer_ and/or a _per-parse
initializer_, in that order. Both are pieces of JavaScript code in double
curly braces (“{{” and “}}”) and single curly braces (“{” and “}”) respectively.
All variables and functions defined in both _initializers_ are accessible in
rule actions and semantic predicates. Curly braces in both _initializers_ code
must be balanced.

The _global initializer_ is executed once and only once, when the generated
parser is loaded (through a `require` or an `import` statement for instance). It
is the ideal location to require, to import or to declare utility functions to
be used in rule actions and semantic predicates.

The _per-parse initializer_ is called before the generated parser starts
parsing. The code inside the _per-parse initializer_ can access the input
string and the options passed to the parser using the `input` variable and the
`options` variable respectively. It is the ideal location to create data
structures that are unique to each parse or to modify the input before the
parse.

Let's look at the example grammar from above using a _global initializer_ and
a _per-parse initializer_:

```peggy
{
{{
function makeInteger(o) {
return parseInt(o.join(""), 10);
}
}}
{
if (options.multiplier) {
input = "(" + input + ")*(" + options.multiplier + ")";
}
}
start
Expand Down
49 changes: 35 additions & 14 deletions docs/documentation.html
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,11 @@ <h3 id="generating-a-parser-javascript-api">JavaScript API</h3>
<dd>Parser dependencies, the value is an object which maps variables used to
access the dependencies in the parser to module IDs used to load them; valid
only when <code>format</code> is set to <code>"amd"</code>,
<code>"commonjs"</code>, or <code>"umd"</code> (default:
<code>"commonjs"</code>, <code>"es"</code>, or <code>"umd"</code>.
Dependencies variables will be available in both the <em>general
initializer</em> and the <em>per-parse initializer</em>. Unless the parser is
to be generated in different formats, it is recommended to rather import
dependencies from within the <em>global initializer</em> (default:
<code>{}</code>).</dd>

<dt><code>exportVar</code></dt>
Expand All @@ -222,9 +226,9 @@ <h3 id="generating-a-parser-javascript-api">JavaScript API</h3>

<dt><code>format</code></dt>
<dd>format of the generated parser (<code>"amd"</code>, <code>"bare"</code>,
<code>"commonjs"</code>, <code>"globals"</code>, or <code>"umd"</code>); valid
only when <code>output</code> is set to <code>"source"</code> (default:
<code>"bare"</code>).</dd>
<code>"commonjs"</code>, <code>"es"</code>, <code>"globals"</code>, or
<code>"umd"</code>); valid only when <code>output</code> is set to
<code>"source"</code> (default: <code>"bare"</code>).</dd>

<dt><code>optimize</code></dt>
<dd>Selects between optimizing the generated parser for parsing speed
Expand Down Expand Up @@ -316,19 +320,36 @@ <h2 id="grammar-syntax-and-semantics">Grammar Syntax and Semantics</h2>
recognizable), but a semicolon (“;”) after the parsing expression is
allowed.</p>

<p>The first rule can be preceded by an <em>initializer</em> &mdash; a piece of
JavaScript code in curly braces (“{” and “}”). This code is executed before the
generated parser starts parsing. All variables and functions defined in the
initializer are accessible in rule actions and semantic predicates. The code
inside the initializer can access options passed to the parser using the
<code>options</code> variable. Curly braces in the initializer code must be
balanced. Let's look at the example grammar from above using a simple
initializer.</p>

<pre><code>{
<p>The first rule can be preceded by a <em>global initializer</em> and/or a
<em>per-parse initializer</em>, in that order. Both are pieces of JavaScript
code in double curly braces (“{{” and “}}”) and single curly braces (“{” and
“}”) respectively. All variables and functions defined in both
<em>initializers</em> are accessible in rule actions and semantic predicates.
Curly braces in both <em>initializers</em> code must be balanced.</p>
<p>The <em>global initializer</em> is executed once and only once, when the
generated parser is loaded (through a <code>require</code> or an
<code>import</code> statement for instance). It is the ideal location to
require, to import or to declare utility functions to be used in rule actions
and semantic predicates.</p>
<p>The <em>per-parse initializer</em> is called before the generated parser
starts parsing. The code inside the <em>per-parse initializer</em> can access
the input string and the options passed to the parser using the
<code>input</code> variable and the <code>options</code> variable respectively.
It is the ideal location to create data structures that are unique to each
parse or to modify the input before the parse.</p>
<p>Let's look at the example grammar from above using a <em>global
initializer</em> and a <em>per-parse initializer</em>:</p>

<pre><code>{{
function makeInteger(o) {
return parseInt(o.join(""), 10);
}
}}

{
if (options.multiplier) {
input = "(" + input + ")*(" + options.multiplier + ")";
}
}

start
Expand Down
4 changes: 2 additions & 2 deletions examples/css.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// [2] http://www.w3.org/Style/css2-updates/REC-CSS2-20110607-errata.html
// [3] http://www.w3.org/TR/DOM-Level-2-Style/css.html

{
{{
function extractOptional(optional, index) {
return optional ? optional[index] : null;
}
Expand All @@ -41,7 +41,7 @@
};
}, head);
}
}
}}

start
= stylesheet:stylesheet comment* { return stylesheet; }
Expand Down
4 changes: 2 additions & 2 deletions examples/javascript.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
// [3] http://inimino.org/~inimino/blog/
// [4] http://boshi.inimino.org/3box/asof/1270029991384/PEG/ECMAScript_unified.peg

{
{{
var TYPES_TO_PROPERTY_NAMES = {
CallExpression: "callee",
MemberExpression: "object",
Expand Down Expand Up @@ -78,7 +78,7 @@
function optionalList(value) {
return value !== null ? value : [];
}
}
}}

Start
= __ program:Program __ { return program; }
Expand Down
5 changes: 5 additions & 0 deletions lib/compiler/passes/generate-js.js
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,11 @@ function generateJS(ast, options) {
function generateToplevel() {
const parts = [];

if (ast.topLevelInitializer) {
parts.push(ast.topLevelInitializer.code);
parts.push("");
}

parts.push([
"function peg$subclass(child, parent) {",
" function C() { this.constructor = child; }",
Expand Down
5 changes: 5 additions & 0 deletions lib/compiler/visitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ const visitor = {
grammar(node) {
const extraArgs = Array.prototype.slice.call(arguments, 1);

if (node.topLevelInitializer) {
visit.apply(null, [node.topLevelInitializer].concat(extraArgs));
}

if (node.initializer) {
visit.apply(null, [node.initializer].concat(extraArgs));
}
Expand All @@ -40,6 +44,7 @@ const visitor = {
});
},

top_level_initializer: visitNop,
initializer: visitNop,
rule: visitExpression,
named: visitExpression,
Expand Down
Loading

0 comments on commit a822ffe

Please sign in to comment.