Compare commits
10 Commits
Author | SHA1 | Date |
---|---|---|
|
1d3a57d256 | 2 years ago |
|
1431320019 | 2 years ago |
|
f11ef306c8 | 2 years ago |
|
51d6414151 | 2 years ago |
|
233f92f285 | 2 years ago |
|
937e1d4698 | 2 years ago |
|
baf846b53f | 2 years ago |
|
8f737014fe | 2 years ago |
|
30400240e3 | 2 years ago |
|
69dbe3a4e4 | 2 years ago |
45 changed files with 12951 additions and 6984 deletions
@ -0,0 +1,3 @@ |
|||
lib/parser.js |
|||
test/vendor/**/* |
|||
benchmark/vendor/**/* |
@ -1,3 +1,3 @@ |
|||
{ |
|||
"extends": "dmajda" |
|||
"extends": "@joepie91/eslint-config" |
|||
} |
|||
|
@ -1,3 +1,3 @@ |
|||
browser/* |
|||
browser |
|||
examples/*.js |
|||
node_modules/* |
|||
node_modules |
|||
|
@ -1,42 +1,42 @@ |
|||
"use strict"; |
|||
|
|||
let benchmarks = [ |
|||
{ |
|||
id: "json", |
|||
title: "JSON", |
|||
tests: [ |
|||
{ file: "example1.json", title: "Example 1" }, |
|||
{ file: "example2.json", title: "Example 2" }, |
|||
{ file: "example3.json", title: "Example 3" }, |
|||
{ file: "example4.json", title: "Example 4" }, |
|||
{ file: "example5.json", title: "Example 5" } |
|||
] |
|||
}, |
|||
{ |
|||
id: "css", |
|||
title: "CSS", |
|||
tests: [ |
|||
{ file: "blueprint/src/reset.css", title: "Blueprint - reset.css (source)" }, |
|||
{ file: "blueprint/src/typography.css", title: "Blueprint - typography.css (source)" }, |
|||
{ file: "blueprint/src/forms.css", title: "Blueprint - forms.css (source)" }, |
|||
{ file: "blueprint/src/grid.css", title: "Blueprint - grid.css (source)" }, |
|||
{ file: "blueprint/src/print.css", title: "Blueprint - print.css (source)" }, |
|||
// Contains syntax errors.
|
|||
// { file: "blueprint/src/ie.css", title: "Blueprint - ie.css (source)" },
|
|||
{ file: "blueprint/min/screen.css", title: "Blueprint - screen.css (minified)" }, |
|||
{ file: "blueprint/min/print.css", title: "Blueprint - print.css (minified)" }, |
|||
// Contains syntax errors.
|
|||
// { file: "blueprint/min/ie.css", title: "Blueprint - ie.css (minified)" },
|
|||
{ file: "960.gs/src/reset.css", title: "960.gs - reset.css (source)" }, |
|||
{ file: "960.gs/src/text.css", title: "960.gs - text.css (source)" }, |
|||
{ file: "960.gs/src/960.css", title: "960.gs - 960.css (source)" }, |
|||
{ file: "960.gs/src/960_24_col.css", title: "960.gs - 960_24_col.css (source)" }, |
|||
{ file: "960.gs/min/reset.css", title: "960.gs - reset.css (minified)" }, |
|||
{ file: "960.gs/min/text.css", title: "960.gs - text.css (minified)" }, |
|||
{ file: "960.gs/min/960.css", title: "960.gs - 960.css (minified)" }, |
|||
{ file: "960.gs/min/960_24_col.css", title: "960.gs - 960_24_col.css (minified)" } |
|||
] |
|||
} |
|||
{ |
|||
id: "json", |
|||
title: "JSON", |
|||
tests: [ |
|||
{ file: "example1.json", title: "Example 1" }, |
|||
{ file: "example2.json", title: "Example 2" }, |
|||
{ file: "example3.json", title: "Example 3" }, |
|||
{ file: "example4.json", title: "Example 4" }, |
|||
{ file: "example5.json", title: "Example 5" } |
|||
] |
|||
}, |
|||
{ |
|||
id: "css", |
|||
title: "CSS", |
|||
tests: [ |
|||
{ file: "blueprint/src/reset.css", title: "Blueprint - reset.css (source)" }, |
|||
{ file: "blueprint/src/typography.css", title: "Blueprint - typography.css (source)" }, |
|||
{ file: "blueprint/src/forms.css", title: "Blueprint - forms.css (source)" }, |
|||
{ file: "blueprint/src/grid.css", title: "Blueprint - grid.css (source)" }, |
|||
{ file: "blueprint/src/print.css", title: "Blueprint - print.css (source)" }, |
|||
// Contains syntax errors.
|
|||
// { file: "blueprint/src/ie.css", title: "Blueprint - ie.css (source)" },
|
|||
{ file: "blueprint/min/screen.css", title: "Blueprint - screen.css (minified)" }, |
|||
{ file: "blueprint/min/print.css", title: "Blueprint - print.css (minified)" }, |
|||
// Contains syntax errors.
|
|||
// { file: "blueprint/min/ie.css", title: "Blueprint - ie.css (minified)" },
|
|||
{ file: "960.gs/src/reset.css", title: "960.gs - reset.css (source)" }, |
|||
{ file: "960.gs/src/text.css", title: "960.gs - text.css (source)" }, |
|||
{ file: "960.gs/src/960.css", title: "960.gs - 960.css (source)" }, |
|||
{ file: "960.gs/src/960_24_col.css", title: "960.gs - 960_24_col.css (source)" }, |
|||
{ file: "960.gs/min/reset.css", title: "960.gs - reset.css (minified)" }, |
|||
{ file: "960.gs/min/text.css", title: "960.gs - text.css (minified)" }, |
|||
{ file: "960.gs/min/960.css", title: "960.gs - 960.css (minified)" }, |
|||
{ file: "960.gs/min/960_24_col.css", title: "960.gs - 960_24_col.css (minified)" } |
|||
] |
|||
} |
|||
]; |
|||
|
|||
module.exports = benchmarks; |
|||
|
@ -1,118 +1,116 @@ |
|||
"use strict"; |
|||
|
|||
/* global setTimeout */ |
|||
|
|||
let peg = require("../lib/peg"); |
|||
|
|||
let Runner = { |
|||
run(benchmarks, runCount, options, callbacks) { |
|||
// Queue
|
|||
|
|||
let Q = { |
|||
functions: [], |
|||
|
|||
add(f) { |
|||
this.functions.push(f); |
|||
}, |
|||
|
|||
run() { |
|||
if (this.functions.length > 0) { |
|||
this.functions.shift()(); |
|||
|
|||
// We can't use |arguments.callee| here because |this| would get
|
|||
// messed-up in that case.
|
|||
setTimeout(() => { Q.run(); }, 0); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// The benchmark itself is factored out into several functions (some of them
|
|||
// generated), which are enqueued and run one by one using |setTimeout|. We
|
|||
// do this for two reasons:
|
|||
//
|
|||
// 1. To avoid bowser mechanism for interrupting long-running scripts to
|
|||
// kick-in (or at least to not kick-in that often).
|
|||
//
|
|||
// 2. To ensure progressive rendering of results in the browser (some
|
|||
// browsers do not render at all when running JavaScript code).
|
|||
//
|
|||
// The enqueued functions share state, which is all stored in the properties
|
|||
// of the |state| object.
|
|||
|
|||
let state = {}; |
|||
|
|||
function initialize() { |
|||
callbacks.start(); |
|||
|
|||
state.totalInputSize = 0; |
|||
state.totalParseTime = 0; |
|||
} |
|||
|
|||
function benchmarkInitializer(benchmark) { |
|||
return function() { |
|||
callbacks.benchmarkStart(benchmark); |
|||
|
|||
state.parser = peg.generate( |
|||
callbacks.readFile("../examples/" + benchmark.id + ".pegjs"), |
|||
options |
|||
); |
|||
state.benchmarkInputSize = 0; |
|||
state.benchmarkParseTime = 0; |
|||
}; |
|||
} |
|||
|
|||
function testRunner(benchmark, test) { |
|||
return function() { |
|||
callbacks.testStart(benchmark, test); |
|||
|
|||
let input = callbacks.readFile(benchmark.id + "/" + test.file); |
|||
|
|||
let parseTime = 0; |
|||
for (let i = 0; i < runCount; i++) { |
|||
let t = (new Date()).getTime(); |
|||
state.parser.parse(input); |
|||
parseTime += (new Date()).getTime() - t; |
|||
} |
|||
let averageParseTime = parseTime / runCount; |
|||
|
|||
callbacks.testFinish(benchmark, test, input.length, averageParseTime); |
|||
|
|||
state.benchmarkInputSize += input.length; |
|||
state.benchmarkParseTime += averageParseTime; |
|||
}; |
|||
} |
|||
|
|||
function benchmarkFinalizer(benchmark) { |
|||
return function() { |
|||
callbacks.benchmarkFinish( |
|||
benchmark, |
|||
state.benchmarkInputSize, |
|||
state.benchmarkParseTime |
|||
); |
|||
|
|||
state.totalInputSize += state.benchmarkInputSize; |
|||
state.totalParseTime += state.benchmarkParseTime; |
|||
}; |
|||
} |
|||
|
|||
function finalize() { |
|||
callbacks.finish(state.totalInputSize, state.totalParseTime); |
|||
} |
|||
|
|||
// Main
|
|||
|
|||
Q.add(initialize); |
|||
benchmarks.forEach(benchmark => { |
|||
Q.add(benchmarkInitializer(benchmark)); |
|||
benchmark.tests.forEach(test => { |
|||
Q.add(testRunner(benchmark, test)); |
|||
}); |
|||
Q.add(benchmarkFinalizer(benchmark)); |
|||
}); |
|||
Q.add(finalize); |
|||
|
|||
Q.run(); |
|||
} |
|||
run(benchmarks, runCount, options, callbacks) { |
|||
// Queue
|
|||
|
|||
let Q = { |
|||
functions: [], |
|||
|
|||
add(f) { |
|||
this.functions.push(f); |
|||
}, |
|||
|
|||
run() { |
|||
if (this.functions.length > 0) { |
|||
this.functions.shift()(); |
|||
|
|||
// We can't use |arguments.callee| here because |this| would get
|
|||
// messed-up in that case.
|
|||
setTimeout(() => { Q.run(); }, 0); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// The benchmark itself is factored out into several functions (some of them
|
|||
// generated), which are enqueued and run one by one using |setTimeout|. We
|
|||
// do this for two reasons:
|
|||
//
|
|||
// 1. To avoid bowser mechanism for interrupting long-running scripts to
|
|||
// kick-in (or at least to not kick-in that often).
|
|||
//
|
|||
// 2. To ensure progressive rendering of results in the browser (some
|
|||
// browsers do not render at all when running JavaScript code).
|
|||
//
|
|||
// The enqueued functions share state, which is all stored in the properties
|
|||
// of the |state| object.
|
|||
|
|||
let state = {}; |
|||
|
|||
function initialize() { |
|||
callbacks.start(); |
|||
|
|||
state.totalInputSize = 0; |
|||
state.totalParseTime = 0; |
|||
} |
|||
|
|||
function benchmarkInitializer(benchmark) { |
|||
return function() { |
|||
callbacks.benchmarkStart(benchmark); |
|||
|
|||
state.parser = peg.generate( |
|||
callbacks.readFile("../examples/" + benchmark.id + ".pegjs"), |
|||
options |
|||
); |
|||
state.benchmarkInputSize = 0; |
|||
state.benchmarkParseTime = 0; |
|||
}; |
|||
} |
|||
|
|||
function testRunner(benchmark, test) { |
|||
return function() { |
|||
callbacks.testStart(benchmark, test); |
|||
|
|||
let input = callbacks.readFile(benchmark.id + "/" + test.file); |
|||
|
|||
let parseTime = 0; |
|||
for (let i = 0; i < runCount; i++) { |
|||
let t = (new Date()).getTime(); |
|||
state.parser.parse(input); |
|||
parseTime += (new Date()).getTime() - t; |
|||
} |
|||
let averageParseTime = parseTime / runCount; |
|||
|
|||
callbacks.testFinish(benchmark, test, input.length, averageParseTime); |
|||
|
|||
state.benchmarkInputSize += input.length; |
|||
state.benchmarkParseTime += averageParseTime; |
|||
}; |
|||
} |
|||
|
|||
function benchmarkFinalizer(benchmark) { |
|||
return function() { |
|||
callbacks.benchmarkFinish( |
|||
benchmark, |
|||
state.benchmarkInputSize, |
|||
state.benchmarkParseTime |
|||
); |
|||
|
|||
state.totalInputSize += state.benchmarkInputSize; |
|||
state.totalParseTime += state.benchmarkParseTime; |
|||
}; |
|||
} |
|||
|
|||
function finalize() { |
|||
callbacks.finish(state.totalInputSize, state.totalParseTime); |
|||
} |
|||
|
|||
// Main
|
|||
|
|||
Q.add(initialize); |
|||
benchmarks.forEach(benchmark => { |
|||
Q.add(benchmarkInitializer(benchmark)); |
|||
benchmark.tests.forEach(test => { |
|||
Q.add(testRunner(benchmark, test)); |
|||
}); |
|||
Q.add(benchmarkFinalizer(benchmark)); |
|||
}); |
|||
Q.add(finalize); |
|||
|
|||
Q.run(); |
|||
} |
|||
}; |
|||
|
|||
module.exports = Runner; |
|||
|
@ -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,108 +1,21 @@ |
|||
"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(), { |
|||
output: "source", |
|||
format: "commonjs" |
|||
}); |
|||
return peg.generate(contents.toString(), { |
|||
output: "source", |
|||
format: "commonjs" |
|||
}); |
|||
} |
|||
|
|||
// 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(rename({ extname: ".js" })) |
|||
.pipe(gulp.dest("lib")) |
|||
); |
|||
|
|||
// Default task.
|
|||
gulp.task("default", cb => |
|||
runSequence("lint", "test", cb) |
|||
gulp.src("src/parser.pegjs") |
|||
.pipe(transform("utf8", generate)) |
|||
.pipe(rename({ extname: ".js" })) |
|||
.pipe(gulp.dest("lib")) |
|||
); |
|||
|
@ -1,54 +1,59 @@ |
|||
"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 = { |
|||
stringEscape(s) { |
|||
// ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a string
|
|||
// literal except for the closing quote character, backslash, carriage
|
|||
// return, line separator, paragraph separator, and line feed. Any character
|
|||
// may appear in the form of an escape sequence.
|
|||
//
|
|||
// For portability, we also escape all control and non-ASCII characters.
|
|||
return s |
|||
.replace(/\\/g, "\\\\") // backslash
|
|||
.replace(/"/g, "\\\"") // closing double quote
|
|||
.replace(/\0/g, "\\0") // null
|
|||
.replace(/\x08/g, "\\b") // backspace
|
|||
.replace(/\t/g, "\\t") // horizontal tab
|
|||
.replace(/\n/g, "\\n") // line feed
|
|||
.replace(/\v/g, "\\v") // vertical tab
|
|||
.replace(/\f/g, "\\f") // form feed
|
|||
.replace(/\r/g, "\\r") // carriage return
|
|||
.replace(/[\x00-\x0F]/g, ch => "\\x0" + hex(ch)) |
|||
.replace(/[\x10-\x1F\x7F-\xFF]/g, ch => "\\x" + hex(ch)) |
|||
.replace(/[\u0100-\u0FFF]/g, ch => "\\u0" + hex(ch)) |
|||
.replace(/[\u1000-\uFFFF]/g, ch => "\\u" + hex(ch)); |
|||
}, |
|||
stringEscape(s) { |
|||
// ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a string
|
|||
// literal except for the closing quote character, backslash, carriage
|
|||
// return, line separator, paragraph separator, and line feed. Any character
|
|||
// may appear in the form of an escape sequence.
|
|||
//
|
|||
// For portability, we also escape all control and non-ASCII characters.
|
|||
return s |
|||
.replace(/\\/g, "\\\\") // backslash
|
|||
.replace(/"/g, "\\\"") // closing double quote
|
|||
.replace(/\0/g, "\\0") // null
|
|||
.replace(/\x08/g, "\\b") // backspace
|
|||
.replace(/\t/g, "\\t") // horizontal tab
|
|||
.replace(/\n/g, "\\n") // line feed
|
|||
.replace(/\v/g, "\\v") // vertical tab
|
|||
.replace(/\f/g, "\\f") // form feed
|
|||
.replace(/\r/g, "\\r") // carriage return
|
|||
.replace(/[\x00-\x0F]/g, ch => "\\x0" + hex(ch)) |
|||
.replace(/[\x10-\x1F\x7F-\xFF]/g, ch => "\\x" + hex(ch)) |
|||
.replace(/[\u0100-\u0FFF]/g, ch => "\\u0" + hex(ch)) |
|||
.replace(/[\u1000-\uFFFF]/g, ch => "\\u" + hex(ch)); |
|||
}, |
|||
|
|||
regexpClassEscape(s) { |
|||
// Based on ECMA-262, 5th ed., 7.8.5 & 15.10.1.
|
|||
//
|
|||
// For portability, we also escape all control and non-ASCII characters.
|
|||
return s |
|||
.replace(/\\/g, "\\\\") // backslash
|
|||
.replace(/\//g, "\\/") // closing slash
|
|||
.replace(/]/g, "\\]") // closing bracket
|
|||
.replace(/\^/g, "\\^") // caret
|
|||
.replace(/-/g, "\\-") // dash
|
|||
.replace(/\0/g, "\\0") // null
|
|||
.replace(/\x08/g, "\\b") // backspace
|
|||
.replace(/\t/g, "\\t") // horizontal tab
|
|||
.replace(/\n/g, "\\n") // line feed
|
|||
.replace(/\v/g, "\\v") // vertical tab
|
|||
.replace(/\f/g, "\\f") // form feed
|
|||
.replace(/\r/g, "\\r") // carriage return
|
|||
.replace(/[\x00-\x0F]/g, ch => "\\x0" + hex(ch)) |
|||
.replace(/[\x10-\x1F\x7F-\xFF]/g, ch => "\\x" + hex(ch)) |
|||
.replace(/[\u0100-\u0FFF]/g, ch => "\\u0" + hex(ch)) |
|||
.replace(/[\u1000-\uFFFF]/g, ch => "\\u" + hex(ch)); |
|||
} |
|||
regexpClassEscape(s) { |
|||
// Based on ECMA-262, 5th ed., 7.8.5 & 15.10.1.
|
|||
//
|
|||
// For portability, we also escape all control and non-ASCII characters.
|
|||
return s |
|||
.replace(/\\/g, "\\\\") // backslash
|
|||
.replace(/\//g, "\\/") // closing slash
|
|||
.replace(/]/g, "\\]") // closing bracket
|
|||
.replace(/\^/g, "\\^") // caret
|
|||
.replace(/-/g, "\\-") // dash
|
|||
.replace(/\0/g, "\\0") // null
|
|||
.replace(/\x08/g, "\\b") // backspace
|
|||
.replace(/\t/g, "\\t") // horizontal tab
|
|||
.replace(/\n/g, "\\n") // line feed
|
|||
.replace(/\v/g, "\\v") // vertical tab
|
|||
.replace(/\f/g, "\\f") // form feed
|
|||
.replace(/\r/g, "\\r") // carriage return
|
|||
.replace(/[\x00-\x0F]/g, ch => "\\x0" + hex(ch)) |
|||
.replace(/[\x10-\x1F\x7F-\xFF]/g, ch => "\\x" + hex(ch)) |
|||
.replace(/[\u0100-\u0FFF]/g, ch => "\\u0" + hex(ch)) |
|||
.replace(/[\u1000-\uFFFF]/g, ch => "\\u" + hex(ch)); |
|||
} |
|||
}; |
|||
|
|||
module.exports = js; |
|||
|