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 6 years ago
parent 15d364587c
commit 21a6de06d5

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

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

@ -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"` 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"` 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"` 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"` 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: 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"`) optimize | `"speed"` | selects between optimizing the generated parser for parsing speed (`"speed"`) or code size (`"size"`)

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

@ -1,4 +1,4 @@
/* eslint no-mixed-operators: 0, prefer-const: 0 */ /* eslint no-mixed-operators: 0, prefer-const: 0, eqeqeq: 0 */
"use strict"; "use strict";
@ -9,6 +9,18 @@ function generateJS( ast, session, options ) {
const op = session.opcodes; 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. */ /* These only indent non-empty lines to avoid trailing whitespace. */
const lineMatchRE = /^([^`\r\n]+?(?:`[^`]*?`[^\r\n]*?)?)$/gm; const lineMatchRE = /^([^`\r\n]+?(?:`[^`]*?`[^\r\n]*?)?)$/gm;
function indent2( code ) { function indent2( code ) {
@ -1283,23 +1295,53 @@ function generateJS( ast, session, options ) {
} }
if ( use( "text" ) ) {
parts.push( [ parts.push( [
"", "",
" function text() {", " function text() {",
" return input.substring(peg$savedPos, peg$currPos);", " return input.substring(peg$savedPos, peg$currPos);",
" }", " }",
].join( "\n" ) );
}
if ( use( "offset" ) ) {
parts.push( [
"", "",
" function offset() {", " function offset() {",
" return peg$savedPos;", " return peg$savedPos;",
" }", " }",
].join( "\n" ) );
}
if ( use( "range" ) ) {
parts.push( [
"", "",
" function range() {", " function range() {",
" return [peg$savedPos, peg$currPos];", " return [peg$savedPos, peg$currPos];",
" }", " }",
].join( "\n" ) );
}
if ( use( "location" ) ) {
parts.push( [
"", "",
" function location() {", " function location() {",
" return peg$computeLocation(peg$savedPos, peg$currPos);", " return peg$computeLocation(peg$savedPos, peg$currPos);",
" }", " }",
].join( "\n" ) );
}
if ( use( "expected" ) ) {
parts.push( [
"", "",
" function expected(description, location) {", " function expected(description, location) {",
" location = location !== undefined", " location = location !== undefined",
@ -1312,6 +1354,13 @@ function generateJS( ast, session, options ) {
" location", " location",
" );", " );",
" }", " }",
].join( "\n" ) );
}
if ( use( "error" ) ) {
parts.push( [
"", "",
" function error(message, location) {", " function error(message, location) {",
" location = location !== undefined", " location = location !== undefined",
@ -1320,6 +1369,11 @@ function generateJS( ast, session, options ) {
"", "",
" throw peg$buildSimpleError(message, location);", " throw peg$buildSimpleError(message, location);",
" }", " }",
].join( "\n" ) );
}
parts.push( [
"", "",
" function peg$literalExpectation(text, ignoreCase) {", " function peg$literalExpectation(text, ignoreCase) {",
" return { type: \"literal\", text: text, ignoreCase: 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) {", " function peg$computeLocation(startPos, endPos) {",
" var startPosDetails = peg$computePosDetails(startPos);", " var loc = {};",
" var endPosDetails = peg$computePosDetails(endPos);", "",
use( "filename" ) ? " if ( peg$VALIDFILENAME ) loc.filename = options.filename;" : "",
"", "",
" return {", " var startPosDetails = peg$computePosDetails(startPos);",
" start: {", " loc.start = {",
" offset: startPos,", " offset: startPos,",
" line: startPosDetails.line,", " line: startPosDetails.line,",
" column: startPosDetails.column", " column: startPosDetails.column",
" },", " };",
" end: {", "",
" var endPosDetails = peg$computePosDetails(endPos);",
" loc.end = {",
" offset: endPos,", " offset: endPos,",
" line: endPosDetails.line,", " line: endPosDetails.line,",
" column: endPosDetails.column", " column: endPosDetails.column",
" }",
" };", " };",
"",
" return loc;",
" }", " }",
"", "",
" function peg$begin() {", " function peg$begin() {",

@ -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) { function peg$computeLocation(startPos, endPos) {
var startPosDetails = peg$computePosDetails(startPos); var loc = {};
var endPosDetails = peg$computePosDetails(endPos);
if ( peg$VALIDFILENAME ) loc.filename = options.filename;
return { var startPosDetails = peg$computePosDetails(startPos);
start: { loc.start = {
offset: startPos, offset: startPos,
line: startPosDetails.line, line: startPosDetails.line,
column: startPosDetails.column column: startPosDetails.column
}, };
end: {
var endPosDetails = peg$computePosDetails(endPos);
loc.end = {
offset: endPos, offset: endPos,
line: endPosDetails.line, line: endPosDetails.line,
column: endPosDetails.column column: endPosDetails.column
}
}; };
return loc;
} }
function peg$begin() { function peg$begin() {

@ -364,6 +364,7 @@ declare namespace peg {
context?: { [ name: string ]: any; }; context?: { [ name: string ]: any; };
dependencies?: { [ name: string ]: string; }; dependencies?: { [ name: string ]: string; };
exportVar?: string; exportVar?: string;
features?: IGeneratedParserFeatures;
format?: FormatOptions; format?: FormatOptions;
header?: string | string[]; header?: string | string[];
optimize?: OptimizeOptions; optimize?: OptimizeOptions;
@ -379,6 +380,7 @@ declare namespace peg {
context: { [ name: string ]: any; }; context: { [ name: string ]: any; };
dependencies: { [ name: string ]: string; }; dependencies: { [ name: string ]: string; };
exportVar: string; exportVar: string;
features: IGeneratedParserFeatures;
format: FormatOptions; format: FormatOptions;
header: string | string[]; header: string | string[];
optimize: OptimizeOptions; 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 { interface ICompilerPass {
( node: Grammar ): void; ( node: Grammar ): void;

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

Loading…
Cancel
Save