Compare commits

...

10 Commits

@ -0,0 +1,3 @@
lib/parser.js
test/vendor/**/*
benchmark/vendor/**/*

@ -1,3 +1,3 @@
{
"extends": "dmajda"
"extends": "@joepie91/eslint-config"
}

4
.gitignore vendored

@ -1,3 +1,3 @@
browser/*
browser
examples/*.js
node_modules/*
node_modules

@ -1,9 +1,6 @@
[![Build status](https://img.shields.io/travis/pegjs/pegjs.svg)](https://travis-ci.org/pegjs/pegjs)
[![npm version](https://img.shields.io/npm/v/pegjs.svg)](https://www.npmjs.com/package/pegjs)
[![Bower version](https://img.shields.io/bower/v/pegjs.svg)](https://github.com/pegjs/bower)
[![License](https://img.shields.io/badge/license-mit-blue.svg)](https://opensource.org/licenses/MIT)
PEG.js
PEG-Redux
======
PEG.js is a simple parser generator for JavaScript that produces fast parsers
@ -11,6 +8,10 @@ with excellent error reporting. You can use it to process complex data or
computer languages and build transformers, interpreters, compilers and other
tools easily.
PEG-Redux is a __work-in-progress__ fork of PEG.js, with the aim of continuing
maintenance on the PEG.js project, while adding support for modern features
such as modules.
Features
--------
@ -20,49 +21,48 @@ Features
* Based on [parsing expression
grammar](http://en.wikipedia.org/wiki/Parsing_expression_grammar) formalism
— more powerful than traditional LL(*k*) and LR(*k*) parsers
* Usable [from your browser](https://pegjs.org/online), from the command line,
or via JavaScript API
* Usable from your browser, from the command line, or via JavaScript API
Getting Started
---------------
Differences from the original PEG.js
--------
[Online version](https://pegjs.org/online) is the easiest way to generate a
parser. Just enter your grammar, try parsing few inputs, and download generated
parser code.
* The plugin API has been dropped for now, as it was underspecified and not very commonly used. A new, more robust and extensive plugin API may come to exist in the future, if it turns out that there is a high demand for customizations that wouldn't fit into the PEG-Redux project itself.
* Bower and stand-alone browser builds have been discontinued. Please use a bundler (see below) instead.
* AMD, UMD and globals support have been discontinued. The generated parsers now only support CommonJS.
* Module support. Both for importing other PEGRedux files, and for `require()`ing JS modules.
Installation
------------
### Node.js
To use the `pegjs` command, install PEG.js globally:
To use the `pegjs` command, install PEG-Redux globally:
```console
$ npm install -g pegjs
$ npm install -g peg-redux
```
To use the JavaScript API, install PEG.js locally:
To use the JavaScript API, install PEG-Redux locally:
```console
$ npm install pegjs
$ npm install peg-redux
```
If you need both the `pegjs` command and the JavaScript API, install PEG.js both
ways.
If you need both the `pegjs` command and the JavaScript API, install PEG-Redux
both ways.
### Browser
[Download](https://pegjs.org/#download) the PEG.js library (regular or minified
version) or install it using Bower:
PEG-Redux works with bundlers such as [Browserify](http://browserify.org/), [Parcel](https://parceljs.org/) and [Webpack](https://webpack.js.org/).
```console
$ bower install pegjs
```
Simply `require()` and use the module like you would in Node.js. The one exception is that modules (either PEG-Redux or Javascript modules) are not currently supported in browser environments.
Bower and standalone builds have been discontinued in this fork. Getting started with Browserify will only take a few minutes, and give you a better developer experience.
Generating a Parser
-------------------
PEG.js generates parser from a grammar that describes expected input and can
PEG-Redux generates parser from a grammar that describes expected input and can
specify what the parser returns (using semantic actions on matched parts of the
input). Generated parser itself is a JavaScript object with a simple API.
@ -100,26 +100,20 @@ You can tweak the generated parser with several options:
`peg.generate`
* `--extra-options-file` — file with additional options (in JSON format) to
pass to `peg.generate`
* `--format` — format of the generated parser: `amd`, `commonjs`, `globals`,
`umd` (default: `commonjs`)
* `--optimize` — selects between optimizing the generated parser for parsing
speed (`speed`) or code size (`size`) (default: `speed`)
* `--plugin` — makes PEG.js use a specified plugin (can be specified multiple
* `--plugin` — makes PEG-Redux use a specified plugin (can be specified multiple
times)
* `--trace` — makes the parser trace its progress
### JavaScript API
In Node.js, require the PEG.js parser generator module:
Require the PEG-Redux parser generator module:
```javascript
var peg = require("pegjs");
var peg = require("peg-redux");
```
In browser, include the PEG.js library in your web page or application using the
`<script>` tag. If PEG.js detects an AMD loader, it will define itself as a
module, otherwise the API will be available in the `peg` global object.
To generate a parser, call the `peg.generate` method and pass your grammar as a
parameter:
@ -142,14 +136,7 @@ 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"`, or
`"umd"` (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"`,
`"globals"`, or `"umd"`); valid only when `output` is set to `"source"`
(default: `"bare"`)
to load them.
* `optimize`— selects between optimizing the generated parser for parsing
speed (`"speed"`) or code size (`"size"`) (default: `"speed"`)
* `output` — if set to `"parser"`, the method will return generated parser
@ -503,25 +490,14 @@ environments:
* Safari
* Opera
However, please note that it is currently only actively tested in Node.js and Firefox. This will likely change in the future.
Development
-----------
* [Project website](https://pegjs.org/)
* [Wiki](https://github.com/pegjs/pegjs/wiki)
* [Source code](https://github.com/pegjs/pegjs)
* [Issue tracker](https://github.com/pegjs/pegjs/issues)
* [Google Group](http://groups.google.com/group/pegjs)
* [Twitter](http://twitter.com/peg_js)
PEG.js is developed by [David Majda](https://majda.cz/)
([@dmajda](http://twitter.com/dmajda)). The [Bower
package](https://github.com/pegjs/bower) is maintained by [Michel
Krämer](http://www.michel-kraemer.com/)
([@michelkraemer](https://twitter.com/michelkraemer)).
PEG-Redux is maintained by [Sven Slootweg (joepie91)](http://cryto.net/~joepie91).
The original PEG.js was developed by [David Majda](http://majda.cz/) ([@dmajda](http://twitter.com/dmajda)).
You are welcome to contribute code. Unless your contribution is really trivial
you should get in touch with me first — this can prevent wasted effort on both
sides. You can send code both as a patch or a GitHub pull request.
Note that PEG.js is still very much work in progress. There are no compatibility
guarantees until version 1.0.
sides. You can send code both as a patch or a pull request.

@ -67,6 +67,7 @@ $("#run").click(() => {
};
if (isNaN(runCount) || runCount <= 0) {
// eslint-disable-next-line no-alert
alert("Number of runs must be a positive integer.");
return;

@ -1,7 +1,5 @@
"use strict";
/* global setTimeout */
let peg = require("../lib/peg");
let Runner = {

@ -26,11 +26,12 @@ app.get("/bundle.js", (req, res) => {
});
browserify(files)
.transform(babelify, { presets: "es2015", compact: false })
.transform(babelify, { presets: "env", compact: false })
.bundle()
.pipe(res);
});
app.listen(8000, () => {
// eslint-disable-next-line no-console
console.log("Benchmark server running at http://localhost:8000...");
});

@ -0,0 +1,14 @@
"use strict";
const fs = require("fs");
const path = require("path");
const util = require("util");
const generate = require("../").generate;
const parser = require("../lib/parser");
let grammar = fs.readFileSync(path.join(__dirname, "test.pegjs"), { encoding: "utf-8" });
// let parseResult = parser.parse(grammar);
let parseResult = generate(grammar);
console.log(util.inspect(parseResult, { depth: null, colors: true }));

@ -0,0 +1,5 @@
import Foo from "./util.pegjs"
import { CommaDelimited as DelimitedNumber } from "./delimited-number"
TopLevelRule
= "hello"

@ -1,52 +1,9 @@
"use strict";
/* eslint-env node */
let babelify = require("babelify");
let browserify = require("browserify");
let buffer = require("vinyl-buffer");
let del = require("del");
let eslint = require("gulp-eslint");
let gulp = require("gulp");
let header = require("gulp-header");
let mocha = require("gulp-mocha");
let package_ = require("./package");
let peg = require("./lib/peg");
let rename = require("gulp-rename");
let runSequence = require("run-sequence");
let source = require("vinyl-source-stream");
let spawn = require("child_process").spawn;
let transform = require("gulp-transform");
let uglify = require("gulp-uglify");
const HEADER = [
"// PEG.js " + package_.version,
"//",
"// https://pegjs.org/",
"//",
"// Copyright (c) 2010-2016 David Majda",
"// Licensed under the MIT License.",
""
].map(line => `${line}\n`).join("");
const JS_FILES = [
"lib/**/*.js",
"!lib/parser.js",
"test/**/*.js",
"test/server",
"!test/vendor/**/*",
"benchmark/**/*.js",
"benchmark/run",
"benchmark/server",
"!benchmark/vendor/**/*",
"bin/pegjs",
"gulpfile.js"
];
const TEST_FILES = [
"test/**/*.js",
"!test/vendor/**/*"
];
function generate(contents) {
return peg.generate(contents.toString(), {
@ -55,54 +12,10 @@ function generate(contents) {
});
}
// Run ESLint on all JavaScript files.
gulp.task("lint", () =>
gulp.src(JS_FILES)
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError())
);
// Run tests.
gulp.task("test", () =>
gulp.src(TEST_FILES, { read: false })
.pipe(mocha())
);
// Run benchmarks.
gulp.task("benchmark", () =>
spawn("benchmark/run", { stdio: "inherit" })
);
// Create the browser build.
gulp.task("browser:build", () =>
browserify("lib/peg.js", { standalone: "peg" })
.transform(babelify, { presets: "es2015", compact: false })
.bundle()
.pipe(source("peg.js"))
.pipe(header(HEADER))
.pipe(gulp.dest("browser"))
.pipe(rename({ suffix: ".min" }))
.pipe(buffer())
.pipe(uglify())
.pipe(header(HEADER))
.pipe(gulp.dest("browser"))
);
// Delete the browser build.
gulp.task("browser:clean", () =>
del("browser")
);
// Generate the grammar parser.
gulp.task("parser", () =>
gulp.src("src/parser.pegjs")
.pipe(transform(generate))
.pipe(transform("utf8", generate))
.pipe(rename({ extname: ".js" }))
.pipe(gulp.dest("lib"))
);
// Default task.
gulp.task("default", cb =>
runSequence("lint", "test", cb)
);

@ -11,19 +11,7 @@ let reportUndefinedRules = require("./passes/report-undefined-rules");
let visitor = require("./visitor");
function processOptions(options, defaults) {
let processedOptions = {};
Object.keys(options).forEach(name => {
processedOptions[name] = options[name];
});
Object.keys(defaults).forEach(name => {
if (!Object.prototype.hasOwnProperty.call(processedOptions, name)) {
processedOptions[name] = defaults[name];
}
});
return processedOptions;
return Object.assign({}, defaults, options);
}
let compiler = {
@ -57,10 +45,8 @@ let compiler = {
// if the AST contains a semantic error. Note that not all errors are detected
// during the generation and some may protrude to the generated parser and
// cause its malfunction.
compile(ast, passes, options) {
options = options !== undefined ? options : {};
options = processOptions(options, {
compile(ast, passes, options = {}) {
let processedOptions = processOptions(options, {
allowedStartRules: [ast.rules[0].name],
cache: false,
dependencies: {},
@ -71,19 +57,20 @@ let compiler = {
trace: false
});
Object.keys(passes).forEach(stage => {
passes[stage].forEach(p => { p(ast, options); });
Object.values(passes).forEach((stagePasses) => {
stagePasses.forEach(pass => { pass(ast, processedOptions); });
});
switch (options.output) {
switch (processedOptions.output) {
case "parser":
return eval(ast.code);
case "source":
return ast.code;
// FIXME: Move to Validatem code at entrypoint
default:
throw new Error("Invalid output format: " + options.output + ".");
throw new Error("Invalid output format: " + processedOptions.output + ".");
}
}
};

@ -1,6 +1,11 @@
"use strict";
function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
function hex(character) {
return character
.charCodeAt(0)
.toString(16)
.toUpperCase();
}
// JavaScript code generation helpers.
let js = {

@ -1204,7 +1204,7 @@ function generateJS(ast, options) {
function generateWrapper(toplevelCode) {
function generateGeneratedByComment() {
return [
"// Generated by PEG.js 0.10.0.",
`// Generated by PEG.js ${require("../../../package.json").version}.`,
"//",
"// https://pegjs.org/"
].join("\n");

File diff suppressed because one or more lines are too long

@ -1,12 +1,14 @@
"use strict";
const mapObj = require("map-obj");
let GrammarError = require("./grammar-error");
let compiler = require("./compiler");
let parser = require("./parser");
let peg = {
module.exports = {
// PEG.js version (uses semantic versioning).
VERSION: "0.10.0",
VERSION: require("../package.json").version,
GrammarError: GrammarError,
parser: parser,
@ -21,34 +23,29 @@ let peg = {
// |peg.GrammarError| if it contains a semantic error. Note that not all
// errors are detected during the generation and some may protrude to the
// generated parser and cause its malfunction.
generate(grammar, options) {
options = options !== undefined ? options : {};
function convertPasses(passes) {
let converted = {};
Object.keys(passes).forEach(stage => {
converted[stage] = Object.keys(passes[stage])
.map(name => passes[stage][name]);
});
return converted;
}
generate(grammar, options = {}) {
// FIXME: Validatem
let plugins = "plugins" in options ? options.plugins : [];
let config = {
parser: peg.parser,
passes: convertPasses(peg.compiler.passes)
parser: parser,
passes: mapObj(compiler.passes, (stage, passesForStage) => {
return [ stage, Object.values(passesForStage) ];
})
};
plugins.forEach(p => { p.use(config, options); });
let parseResult = config.parser.parse(grammar);
return peg.compiler.compile(
config.parser.parse(grammar),
if (parseResult.imports.length === 0) {
return compiler.compile(
parseResult,
config.passes,
options
);
} else {
throw new Error("`import` syntax can only be used with `generateFromFile`");
}
},
generateFromFile: function (path, options = {}) {
throw new Error(`Unimplemented`);
}
};
module.exports = peg;

@ -0,0 +1,52 @@
Import syntax
import Foo from packagename
import { Foo, Bar } from ./util
import { Foo as Bar, Baz, Qux } from ../quz
need to mangle identifiers declared in the initializer!
===========
Benchmark before internals changes (best of 3):
$ yarn benchmark
yarn run v1.21.1
$ node benchmark/run
┌─────────────────────────────────────┬───────────┬────────────┬──────────────┐
│ Test │ Inp. size │ Avg. time │ Avg. speed │
├─────────────────────────────────────┴───────────┴────────────┴──────────────┤
│ JSON │
├─────────────────────────────────────┬───────────┬────────────┬──────────────┤
│ Example 1 │ 0.69 kB │ 0.40 ms │ 1723.63 kB/s │
│ Example 2 │ 0.24 kB │ 0.10 ms │ 2363.28 kB/s │
│ Example 3 │ 0.59 kB │ 0.40 ms │ 1474.61 kB/s │
│ Example 4 │ 3.39 kB │ 0.90 ms │ 3763.02 kB/s │
│ Example 5 │ 0.85 kB │ 0.20 ms │ 4262.70 kB/s │
├─────────────────────────────────────┼───────────┼────────────┼──────────────┤
│ JSON total │ 5.75 kB │ 2.00 ms │ 2877.44 kB/s │
├─────────────────────────────────────┴───────────┴────────────┴──────────────┤
│ CSS │
├─────────────────────────────────────┬───────────┬────────────┬──────────────┤
│ Blueprint - reset.css (source) │ 1.20 kB │ 3.00 ms │ 401.04 kB/s │
│ Blueprint - typography.css (source) │ 3.11 kB │ 5.00 ms │ 621.48 kB/s │
│ Blueprint - forms.css (source) │ 1.79 kB │ 2.00 ms │ 896.00 kB/s │
│ Blueprint - grid.css (source) │ 9.54 kB │ 6.50 ms │ 1467.25 kB/s │
│ Blueprint - print.css (source) │ 1.78 kB │ 1.10 ms │ 1621.09 kB/s │
│ Blueprint - screen.css (minified) │ 11.83 kB │ 8.00 ms │ 1478.64 kB/s │
│ Blueprint - print.css (minified) │ 1.25 kB │ 0.60 ms │ 2089.84 kB/s │
│ 960.gs - reset.css (source) │ 0.99 kB │ 0.50 ms │ 1980.47 kB/s │
│ 960.gs - text.css (source) │ 0.97 kB │ 0.40 ms │ 2426.76 kB/s │
│ 960.gs - 960.css (source) │ 8.94 kB │ 3.00 ms │ 2979.49 kB/s │
│ 960.gs - 960_24_col.css (source) │ 7.48 kB │ 2.60 ms │ 2877.85 kB/s │
│ 960.gs - reset.css (minified) │ 0.63 kB │ 0.50 ms │ 1265.63 kB/s │
│ 960.gs - text.css (minified) │ 0.41 kB │ 0.40 ms │ 1020.51 kB/s │
│ 960.gs - 960.css (minified) │ 5.21 kB │ 2.60 ms │ 2004.21 kB/s │
│ 960.gs - 960_24_col.css (minified) │ 4.94 kB │ 2.40 ms │ 2057.70 kB/s │
├─────────────────────────────────────┼───────────┼────────────┼──────────────┤
│ CSS total │ 60.08 kB │ 38.60 ms │ 1556.43 kB/s │
├─────────────────────────────────────┼───────────┼────────────┼──────────────┤
│ Total │ 65.83 kB │ 40.60 ms │ 1621.50 kB/s │
└─────────────────────────────────────┴───────────┴────────────┴──────────────┘
Done in 0.60s.

@ -1,15 +1,16 @@
{
"name": "pegjs",
"name": "peg-redux",
"version": "0.10.0",
"description": "Parser generator for JavaScript",
"keywords": [
"parser generator",
"PEG"
],
"homepage": "https://pegjs.org/",
"bugs": "https://github.com/pegjs/pegjs/issues",
"license": "MIT",
"author": "David Majda <david@majda.cz> (https://majda.cz/)",
"contributors": [
"David Majda <david@majda.cz> (http://majda.cz/)",
"Sven Slootweg <admin@cryto.net>"
],
"files": [
"CHANGELOG.md",
"LICENSE",
@ -41,31 +42,32 @@
"bin": "bin/pegjs",
"repository": "pegjs/pegjs",
"scripts": {
"test": "gulp"
"test": "mocha 'test/**/*.js' '!test.vendor.**/*'",
"benchmark": "node benchmark/run",
"lint": "eslint .",
"build": "gulp parser",
"validate": "yarn build && yarn lint && yarn test"
},
"devDependencies": {
"babel-preset-es2015": "6.14.0",
"babelify": "7.3.0",
"browserify": "13.1.0",
"@joepie91/eslint-config": "^1.1.0",
"babelify": "^10.0.0",
"browserify": "^17.0.0",
"chai": "3.5.0",
"del": "2.2.2",
"eslint-config-dmajda": "1.0.0",
"express": "4.14.0",
"glob": "7.0.6",
"gulp": "3.9.1",
"gulp-eslint": "3.0.1",
"gulp-header": "1.8.8",
"gulp-mocha": "3.0.1",
"express": "^4.17.1",
"glob": "^7.1.6",
"gulp": "^4.0.2",
"gulp-rename": "1.2.2",
"gulp-transform": "1.0.8",
"gulp-uglify": "2.0.0",
"gulp-transform": "^3.0.5",
"mocha": "^8.2.0",
"morgan": "1.7.0",
"run-sequence": "1.2.2",
"sinon": "1.17.6",
"vinyl-buffer": "1.0.0",
"vinyl-source-stream": "1.1.0"
"@babel/preset-env": "^7.12.1",
"eslint": "^7.12.0"
},
"engines": {
"node": ">=4"
},
"dependencies": {
"map-obj": "^4.1.0"
}
}

@ -55,15 +55,45 @@
// ---- Syntactic Grammar -----
Grammar
= __ initializer:(Initializer __)? rules:(Rule __)+ {
= __ imports:(ImportStatement __)* initializer:(Initializer __)? rules:(Rule __)+ {
return {
type: "grammar",
initializer: extractOptional(initializer, 0),
rules: extractList(rules, 0),
imports: extractList(imports, 0),
location: location()
};
}
ImportStatement
= "import" _ bindings:ImportBindings _ "from" _ path:StringLiteral EOS {
return {
type: "import",
path: path,
bindings: bindings,
location: location()
};
}
ImportBindings
= TopLevelImportBinding
/ NamedImportBindings
TopLevelImportBinding
= binding:ImportBinding {
return { type: "topLevelBinding", binding: binding, location: location() };
}
NamedImportBindings
= "{" __ head:(ImportBinding __) tail:("," __ ImportBinding __)* "}" {
return { type: "namedBindings", bindings: buildList(head[0], tail, 2), location: location() };
}
ImportBinding
= name:IdentifierName alias:(_ "as" _ IdentifierName)? {
return { type: "binding", name: name, alias: extractOptional(alias, 3), location: location() };
}
Initializer
= code:CodeBlock EOS {
return { type: "initializer", code: code, location: location() };
@ -242,6 +272,7 @@ SingleLineComment
Identifier
= !ReservedWord name:IdentifierName { return name; }
// TODO: Can performance here be improved by using $?
IdentifierName "identifier"
= head:IdentifierStart tail:IdentifierPart* { return head + tail.join(""); }

@ -1,7 +1,6 @@
/* eslint-disable no-console */
"use strict";
/* global console */
let chai = require("chai");
let peg = require("../../lib/peg");
let sinon = require("sinon");

@ -1,128 +0,0 @@
"use strict";
let chai = require("chai");
let peg = require("../../lib/peg");
let expect = chai.expect;
describe("plugin API", function() {
describe("use", function() {
let grammar = "start = 'a'";
it("is called for each plugin", function() {
let pluginsUsed = [false, false, false];
let plugins = [
{ use() { pluginsUsed[0] = true; } },
{ use() { pluginsUsed[1] = true; } },
{ use() { pluginsUsed[2] = true; } }
];
peg.generate(grammar, { plugins: plugins });
expect(pluginsUsed).to.deep.equal([true, true, true]);
});
it("receives configuration", function() {
let plugin = {
use(config) {
expect(config).to.be.an("object");
expect(config.parser).to.be.an("object");
expect(config.parser.parse("start = 'a'")).to.be.an("object");
expect(config.passes).to.be.an("object");
expect(config.passes.check).to.be.an("array");
config.passes.check.forEach(pass => {
expect(pass).to.be.a("function");
});
expect(config.passes.transform).to.be.an("array");
config.passes.transform.forEach(pass => {
expect(pass).to.be.a("function");
});
expect(config.passes.generate).to.be.an("array");
config.passes.generate.forEach(pass => {
expect(pass).to.be.a("function");
});
}
};
peg.generate(grammar, { plugins: [plugin] });
});
it("receives options", function() {
let plugin = {
use(config, options) {
expect(options).to.equal(generateOptions);
}
};
let generateOptions = { plugins: [plugin], foo: 42 };
peg.generate(grammar, generateOptions);
});
it("can replace parser", function() {
let plugin = {
use(config) {
let parser = peg.generate([
"start = .* {",
" return {",
" type: 'grammar',",
" rules: [",
" {",
" type: 'rule',",
" name: 'start',",
" expression: { type: 'literal', value: text(), ignoreCase: false }",
" }",
" ]",
" };",
"}"
].join("\n"));
config.parser = parser;
}
};
let parser = peg.generate("a", { plugins: [plugin] });
expect(parser.parse("a")).to.equal("a");
});
it("can change compiler passes", function() {
let plugin = {
use(config) {
function pass(ast) {
ast.code = "({ parse: function() { return 42; } })";
}
config.passes.generate = [pass];
}
};
let parser = peg.generate(grammar, { plugins: [plugin] });
expect(parser.parse("a")).to.equal(42);
});
it("can change options", function() {
let grammar = [
"a = 'x'",
"b = 'x'",
"c = 'x'"
].join("\n");
let plugin = {
use(config, options) {
options.allowedStartRules = ["b", "c"];
}
};
let parser = peg.generate(grammar, {
allowedStartRules: ["a"],
plugins: [plugin]
});
expect(() => { parser.parse("x", { startRule: "a" }); }).to.throw();
expect(parser.parse("x", { startRule: "b" })).to.equal("x");
expect(parser.parse("x", { startRule: "c" })).to.equal("x");
});
});
});

@ -1,7 +1,6 @@
/* eslint-disable no-console */
"use strict";
/* global console */
let chai = require("chai");
let peg = require("../../lib/peg");
let sinon = require("sinon");

@ -25,7 +25,7 @@ app.get("/bundle.js", (req, res) => {
});
browserify(files)
.transform(babelify, { presets: "es2015", compact: false })
.transform(babelify, { presets: "env", compact: false })
.bundle()
.pipe(res);
});

@ -65,6 +65,7 @@ describe("PEG.js grammar parser", function() {
function oneRuleGrammar(expression) {
return {
type: "grammar",
imports: [],
initializer: null,
rules: [{ type: "rule", name: "start", expression: expression }]
};
@ -102,6 +103,7 @@ describe("PEG.js grammar parser", function() {
let trivialGrammar = literalGrammar("abcd", false);
let twoRuleGrammar = {
type: "grammar",
imports: [],
initializer: null,
rules: [ruleA, ruleB]
};
@ -226,20 +228,20 @@ describe("PEG.js grammar parser", function() {
// Canonical Grammar is "a = 'abcd'; b = 'efgh'; c = 'ijkl';".
it("parses Grammar", function() {
expect("\na = 'abcd';\n").to.parseAs(
{ type: "grammar", initializer: null, rules: [ruleA] }
{ type: "grammar", imports: [], initializer: null, rules: [ruleA] }
);
expect("\na = 'abcd';\nb = 'efgh';\nc = 'ijkl';\n").to.parseAs(
{ type: "grammar", initializer: null, rules: [ruleA, ruleB, ruleC] }
{ type: "grammar", imports: [], initializer: null, rules: [ruleA, ruleB, ruleC] }
);
expect("\n{ code };\na = 'abcd';\n").to.parseAs(
{ type: "grammar", initializer: initializer, rules: [ruleA] }
{ type: "grammar", imports: [], initializer: initializer, rules: [ruleA] }
);
});
// Canonical Initializer is "{ code }".
it("parses Initializer", function() {
expect("{ code };start = 'abcd'").to.parseAs(
{ type: "grammar", initializer: initializer, rules: [ruleStart] }
{ type: "grammar", imports: [], initializer: initializer, rules: [ruleStart] }
);
});

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save