Browse Source

Optional features

This commit enables optional features that are enabled by default in the generated parser.

For now, only some of the helpers and filename are generated based on this new option, but this will change in the future most likely.

Resolves #421
master
Futago-za Ryuu 4 years ago
parent
commit
21a6de06d5
  1. 1
      bin/options.js
  2. 2
      bin/peg.js
  3. 1
      docs/guides/javascript-api.md
  4. 1
      lib/compiler/index.js
  5. 157
      lib/compiler/passes/generate-js.js
  6. 29
      lib/parser.js
  7. 15
      lib/typings/api.d.ts
  8. 1
      lib/typings/generated-parser.d.ts

1
bin/options.js

@ -17,6 +17,7 @@ let options = {
"format": "commonjs",
"optimize": "speed",
"output": "source",
"parser": {},
"plugins": [],
"trace": false
};

2
bin/peg.js

@ -34,6 +34,7 @@ function abort( message ) {
// Main
let inputStream, outputStream;
options.parser = options.parser || {};
if ( options.inputFile === "-" ) {
@ -48,6 +49,7 @@ if ( options.inputFile === "-" ) {
} else {
inputStream = fs.createReadStream( options.inputFile );
options.parser.filename = options.inputFile;
}

1
docs/guides/javascript-api.md

@ -97,6 +97,7 @@ cache | `false` | makes the generated parser cache results, avoiding exponential
context | `{}` | contains a map of variables used by `peg.util.vm.runInContext()` when the `output` option is set to `"parser"`
dependencies | `{}` | parser dependencies, the value is an object which maps variables used to access the dependencies to module IDs used to load them; valid only when `format` is set to `"amd"`, `"commonjs"`, `"es"`, or `"umd"`
exportVar | `null` | name of an optional global variable into which the generated parser object is assigned to when no module loader is detected; valid only when `format` is set to `"globals"` or `"umd"`
features | `null` | map of optional features that are set to `true` by default: `"text"`, `"offset"`, `"range"`, `"location"`, `"expected"`, `"error"` and `"filename"`
format | `"bare"` | format of the generated parser (`"amd"`, `"bare"`, `"commonjs"`, `"es"`, `"globals"`, or `"umd"`); valid only when `output` is set to `"source"`
header | `null` | adds additional comments or content after the `Generated by ...` comment; this option is only handled if it's an array or a string:
optimize | `"speed"` | selects between optimizing the generated parser for parsing speed (`"speed"`) or code size (`"size"`)

1
lib/compiler/index.js

@ -70,6 +70,7 @@ const compiler = {
context: {},
dependencies: {},
exportVar: null,
features: null,
format: "bare",
header: null,
optimize: "speed",

157
lib/compiler/passes/generate-js.js

@ -1,4 +1,4 @@
/* eslint no-mixed-operators: 0, prefer-const: 0 */
/* eslint no-mixed-operators: 0, prefer-const: 0, eqeqeq: 0 */
"use strict";
@ -9,6 +9,18 @@ function generateJS( ast, session, options ) {
const op = session.opcodes;
/* Features that should be generated in the parser. */
const features = options.features || {};
function use( feature, use ) {
return feature in features
? !! features[ feature ]
: use == null
? true
: !! use;
}
/* These only indent non-empty lines to avoid trailing whitespace. */
const lineMatchRE = /^([^`\r\n]+?(?:`[^`]*?`[^\r\n]*?)?)$/gm;
function indent2( code ) {
@ -1283,43 +1295,85 @@ function generateJS( ast, session, options ) {
}
if ( use( "text" ) ) {
parts.push( [
"",
" function text() {",
" return input.substring(peg$savedPos, peg$currPos);",
" }",
].join( "\n" ) );
}
if ( use( "offset" ) ) {
parts.push( [
"",
" function offset() {",
" return peg$savedPos;",
" }",
].join( "\n" ) );
}
if ( use( "range" ) ) {
parts.push( [
"",
" function range() {",
" return [peg$savedPos, peg$currPos];",
" }",
].join( "\n" ) );
}
if ( use( "location" ) ) {
parts.push( [
"",
" function location() {",
" return peg$computeLocation(peg$savedPos, peg$currPos);",
" }",
].join( "\n" ) );
}
if ( use( "expected" ) ) {
parts.push( [
"",
" function expected(description, location) {",
" location = location !== undefined",
" ? location",
" : peg$computeLocation(peg$savedPos, peg$currPos);",
"",
" throw peg$buildStructuredError(",
" [peg$otherExpectation(description)],",
" input.substring(peg$savedPos, peg$currPos),",
" location",
" );",
" }",
].join( "\n" ) );
}
if ( use( "error" ) ) {
parts.push( [
"",
" function error(message, location) {",
" location = location !== undefined",
" ? location",
" : peg$computeLocation(peg$savedPos, peg$currPos);",
"",
" throw peg$buildSimpleError(message, location);",
" }",
].join( "\n" ) );
}
parts.push( [
"",
" function text() {",
" return input.substring(peg$savedPos, peg$currPos);",
" }",
"",
" function offset() {",
" return peg$savedPos;",
" }",
"",
" function range() {",
" return [peg$savedPos, peg$currPos];",
" }",
"",
" function location() {",
" return peg$computeLocation(peg$savedPos, peg$currPos);",
" }",
"",
" function expected(description, location) {",
" location = location !== undefined",
" ? location",
" : peg$computeLocation(peg$savedPos, peg$currPos);",
"",
" throw peg$buildStructuredError(",
" [peg$otherExpectation(description)],",
" input.substring(peg$savedPos, peg$currPos),",
" location",
" );",
" }",
"",
" function error(message, location) {",
" location = location !== undefined",
" ? location",
" : peg$computeLocation(peg$savedPos, peg$currPos);",
"",
" throw peg$buildSimpleError(message, location);",
" }",
"",
" function peg$literalExpectation(text, ignoreCase) {",
" return { type: \"literal\", text: text, ignoreCase: ignoreCase };",
@ -1376,22 +1430,27 @@ function generateJS( ast, session, options ) {
" }",
" }",
"",
use( "filename" ) ? " var peg$VALIDFILENAME = typeof options.filename === \"string\" && options.filename.length > 0;" : "",
" function peg$computeLocation(startPos, endPos) {",
" var loc = {};",
"",
use( "filename" ) ? " if ( peg$VALIDFILENAME ) loc.filename = options.filename;" : "",
"",
" var startPosDetails = peg$computePosDetails(startPos);",
" var endPosDetails = peg$computePosDetails(endPos);",
" loc.start = {",
" offset: startPos,",
" line: startPosDetails.line,",
" column: startPosDetails.column",
" };",
"",
" return {",
" start: {",
" offset: startPos,",
" line: startPosDetails.line,",
" column: startPosDetails.column",
" },",
" end: {",
" offset: endPos,",
" line: endPosDetails.line,",
" column: endPosDetails.column",
" }",
" var endPosDetails = peg$computePosDetails(endPos);",
" loc.end = {",
" offset: endPos,",
" line: endPosDetails.line,",
" column: endPosDetails.column",
" };",
"",
" return loc;",
" }",
"",
" function peg$begin() {",

29
lib/parser.js

@ -468,22 +468,27 @@ function peg$parse(input, options) {
}
}
var peg$VALIDFILENAME = typeof options.filename === "string" && options.filename.length > 0;
function peg$computeLocation(startPos, endPos) {
var loc = {};
if ( peg$VALIDFILENAME ) loc.filename = options.filename;
var startPosDetails = peg$computePosDetails(startPos);
var endPosDetails = peg$computePosDetails(endPos);
loc.start = {
offset: startPos,
line: startPosDetails.line,
column: startPosDetails.column
};
return {
start: {
offset: startPos,
line: startPosDetails.line,
column: startPosDetails.column
},
end: {
offset: endPos,
line: endPosDetails.line,
column: endPosDetails.column
}
var endPosDetails = peg$computePosDetails(endPos);
loc.end = {
offset: endPos,
line: endPosDetails.line,
column: endPosDetails.column
};
return loc;
}
function peg$begin() {

15
lib/typings/api.d.ts

@ -364,6 +364,7 @@ declare namespace peg {
context?: { [ name: string ]: any; };
dependencies?: { [ name: string ]: string; };
exportVar?: string;
features?: IGeneratedParserFeatures;
format?: FormatOptions;
header?: string | string[];
optimize?: OptimizeOptions;
@ -379,6 +380,7 @@ declare namespace peg {
context: { [ name: string ]: any; };
dependencies: { [ name: string ]: string; };
exportVar: string;
features: IGeneratedParserFeatures;
format: FormatOptions;
header: string | string[];
optimize: OptimizeOptions;
@ -387,6 +389,19 @@ declare namespace peg {
}
interface IGeneratedParserFeatures {
[ key: string ]: boolean;
text: boolean;
offset: boolean;
range: boolean;
location: boolean;
expected: boolean;
error: boolean;
filename: boolean;
}
interface ICompilerPass {
( node: Grammar ): void;

1
lib/typings/generated-parser.d.ts

@ -129,6 +129,7 @@ declare namespace generatedparser {
interface IOptions {
[ key: string ]: any;
filename?: string;
startRule?: string;
tracer?: ITracer;

Loading…
Cancel
Save