From 616749377b7feb8ba09e07a4b85d969b05272da2 Mon Sep 17 00:00:00 2001 From: Futago-za Ryuu Date: Tue, 25 Sep 2018 17:59:38 +0100 Subject: [PATCH] Fix IE11 Support (#583) - Revert ES6 changes to arithmetics.pegjs - Use Array#forEach instead of for..of - Don't use native Array#find & Array#findIndex - Added util/arrays.js (find & findIndex) - Use Function instead of eval --- examples/arithmetics.pegjs | 12 ++-- packages/pegjs/lib/ast/Grammar.js | 12 +--- packages/pegjs/lib/compiler/index.js | 3 + .../lib/compiler/passes/generate-bytecode.js | 6 +- .../lib/compiler/passes/remove-proxy-rules.js | 6 +- packages/pegjs/lib/parser.js | 6 +- packages/pegjs/lib/util/arrays.js | 33 ++++++++++ packages/pegjs/lib/util/index.js | 2 + packages/pegjs/lib/util/vm.js | 64 +++++-------------- packages/pegjs/typings/api.d.ts | 10 ++- packages/pegjs/typings/modules.d.ts | 7 ++ src/parser.pegjs | 6 +- 12 files changed, 89 insertions(+), 78 deletions(-) create mode 100644 packages/pegjs/lib/util/arrays.js diff --git a/examples/arithmetics.pegjs b/examples/arithmetics.pegjs index dc2bc49..d2be1ab 100644 --- a/examples/arithmetics.pegjs +++ b/examples/arithmetics.pegjs @@ -5,17 +5,17 @@ Expression = head:Term tail:(_ @("+" / "-") _ @Term)* { - return tail.reduce(function(result, [operator, factor]) { - if (operator === "+") return result + factor; - if (operator === "-") return result - factor; + return tail.reduce(function(result, element) { + if (element[0] === "+") return result + element[1]; + if (element[0] === "-") return result - element[1]; }, head); } Term = head:Factor tail:(_ @("*" / "/") _ @Factor)* { - return tail.reduce(function(result, [operator, factor]) { - if (operator === "*") return result * factor; - if (operator === "/") return result / factor; + return tail.reduce(function(result, element) { + if (element[0] === "*") return result * element[1]; + if (element[0] === "/") return result / element[1]; }, head); } diff --git a/packages/pegjs/lib/ast/Grammar.js b/packages/pegjs/lib/ast/Grammar.js index 9000030..0300695 100644 --- a/packages/pegjs/lib/ast/Grammar.js +++ b/packages/pegjs/lib/ast/Grammar.js @@ -27,21 +27,13 @@ class Grammar extends Node { findRule( name ) { - return this.rules.find( rule => rule.name === name ); + return util.find( this.rules, rule => rule.name === name ); } indexOfRule( name ) { - const rules = this.rules; - - for ( let i = 0; i < rules.length; ++i ) { - - if ( rules[ i ].name === name ) return i; - - } - - return -1; + return util.findIndex( this.rules, rule => rule.name === name ); } diff --git a/packages/pegjs/lib/compiler/index.js b/packages/pegjs/lib/compiler/index.js index a2b14e2..4d44bd4 100644 --- a/packages/pegjs/lib/compiler/index.js +++ b/packages/pegjs/lib/compiler/index.js @@ -67,6 +67,9 @@ const compiler = { trace: false } ); + // We want `session.vm.runInContext` to return the parser + if ( options.output === "parser" ) options.format = "bare"; + util.each( session.passes, stage => { stage.forEach( pass => { diff --git a/packages/pegjs/lib/compiler/passes/generate-bytecode.js b/packages/pegjs/lib/compiler/passes/generate-bytecode.js index fc6d713..8278edb 100644 --- a/packages/pegjs/lib/compiler/passes/generate-bytecode.js +++ b/packages/pegjs/lib/compiler/passes/generate-bytecode.js @@ -222,7 +222,7 @@ function generateBytecode( ast, session ) { ignoreCase: node.ignoreCase }; const pattern = JSON.stringify( cls ); - const index = classes.findIndex( c => JSON.stringify( c ) === pattern ); + const index = util.findIndex( classes, c => JSON.stringify( c ) === pattern ); return index === -1 ? classes.push( cls ) - 1 : index; } @@ -230,7 +230,7 @@ function generateBytecode( ast, session ) { function addExpectedConst( expected ) { const pattern = JSON.stringify( expected ); - const index = expectations.findIndex( e => JSON.stringify( e ) === pattern ); + const index = util.findIndex( expectations, e => JSON.stringify( e ) === pattern ); return index === -1 ? expectations.push( expected ) - 1 : index; } @@ -239,7 +239,7 @@ function generateBytecode( ast, session ) { const func = { predicate: predicate, params: params, body: code }; const pattern = JSON.stringify( func ); - const index = functions.findIndex( f => JSON.stringify( f ) === pattern ); + const index = util.findIndex( functions, f => JSON.stringify( f ) === pattern ); return index === -1 ? functions.push( func ) - 1 : index; } diff --git a/packages/pegjs/lib/compiler/passes/remove-proxy-rules.js b/packages/pegjs/lib/compiler/passes/remove-proxy-rules.js index d40b3b0..2365a05 100644 --- a/packages/pegjs/lib/compiler/passes/remove-proxy-rules.js +++ b/packages/pegjs/lib/compiler/passes/remove-proxy-rules.js @@ -22,18 +22,18 @@ function removeProxyRules( ast, session, options ) { const allowedStartRules = options.allowedStartRules; const rules = []; - for ( const rule of ast.rules ) { + ast.rules.forEach( rule => { if ( isProxyRule( rule ) ) { replaceRuleRefs( ast, rule.name, rule.expression.name ); - if ( allowedStartRules.indexOf( rule.name ) < 0 ) continue; + if ( allowedStartRules.indexOf( rule.name ) < 0 ) return; } rules.push( rule ); - } + } ); ast.rules = rules; diff --git a/packages/pegjs/lib/parser.js b/packages/pegjs/lib/parser.js index 49b45e9..111d468 100644 --- a/packages/pegjs/lib/parser.js +++ b/packages/pegjs/lib/parser.js @@ -3414,11 +3414,11 @@ function peg$parse(input, options) { // Populate `RESERVED_WORDS` using the optional option `reservedWords` const reservedWords = options.reservedWords || util.reservedWords; - if ( Array.isArray( reservedWords ) ) { + if ( Array.isArray( reservedWords ) ) reservedWords.forEach( word => { - for ( const word of reservedWords ) RESERVED_WORDS[ word ] = true; + RESERVED_WORDS[ word ] = true; - } + } ); // Helper to construct a new AST Node function createNode( type, details ) { diff --git a/packages/pegjs/lib/util/arrays.js b/packages/pegjs/lib/util/arrays.js new file mode 100644 index 0000000..f8b4390 --- /dev/null +++ b/packages/pegjs/lib/util/arrays.js @@ -0,0 +1,33 @@ +"use strict"; + +/** + * The `findIndex()` method returns the index of the first element in the array that satisfies the + * provided testing function, otherwise `-1` is returned. + */ +function findIndex( array, condition ) { + + for ( let i = 0; i < array.length; ++i ) { + + if ( condition( array[ i ], i ) ) return i; + + } + + return -1; + +} + +/** + * The `find()` method returns the value of the first element in the array that satisfies the + * provided testing function, otherwise `undefined` is returned. + */ +function find( array, condition ) { + + const index = findIndex( array, condition ); + + return index < 0 ? void 0 : array[ index ]; + +} + +// Exports + +module.exports = { findIndex, find }; diff --git a/packages/pegjs/lib/util/index.js b/packages/pegjs/lib/util/index.js index 9b72348..3d39ff8 100644 --- a/packages/pegjs/lib/util/index.js +++ b/packages/pegjs/lib/util/index.js @@ -1,9 +1,11 @@ "use strict"; +const arrays = require( "./arrays" ); const js = require( "./js" ); const objects = require( "./objects" ); const vm = require( "./vm" ); +objects.extend( exports, arrays ); objects.extend( exports, js ); objects.extend( exports, objects ); objects.extend( exports, vm ); diff --git a/packages/pegjs/lib/util/vm.js b/packages/pegjs/lib/util/vm.js index 28fe03f..4e9beaa 100644 --- a/packages/pegjs/lib/util/vm.js +++ b/packages/pegjs/lib/util/vm.js @@ -1,58 +1,26 @@ "use strict"; -const code = ( () => { +/** + * `eval` the given source, using properties found in `context` as top-level variables. + * + * Based on `vm.runInContext` found in Node.js, this is a cross-env solution. + */ +function runInContext( source, context ) { - let preface = ""; - const MODULE_VARS = { + const argumentKeys = Object.keys( context ); + const argumentValues = argumentKeys.map( argument => context[ argument ] ); - "module": true, - "process": true, - "code": true, - "runInContext": true, - "source": true, - "preface": true, + const object = {}; + argumentKeys.push( "_peg$object", `_peg$object.result = ${ source };` ); + argumentValues.push( object ); - }; + Function( ...argumentKeys )( ...argumentValues ); - Object.keys( MODULE_VARS ).forEach( name => { + return object.result; - preface += `var ${ name } = void 0;`; - } ); +} - function generate( name ) { +// Exports - return `${ ( MODULE_VARS[ name ] ? "" : "var " ) + name } = __context.${ name };`; - - } - - return { generate, preface }; - -} )(); - -module.exports = { - - // `eval` the given source, using properties found in `context` as top-level - // variables, while hiding some variables in this module from the source. - // - // Based on `vm.runInContext` found in Node.js, this is a cross-env solution. - runInContext( source, __context ) { - - let preface = code.preface; - - if ( typeof __context === "object" ) { - - Object.keys( __context ).forEach( name => { - - preface += code.generate( name ); - - } ); - - } - - return eval( preface + source ); - - - }, - -}; +module.exports = { runInContext }; diff --git a/packages/pegjs/typings/api.d.ts b/packages/pegjs/typings/api.d.ts index 661463f..defcc37 100644 --- a/packages/pegjs/typings/api.d.ts +++ b/packages/pegjs/typings/api.d.ts @@ -435,7 +435,7 @@ declare namespace peg { interface ISessionVM { - runInContext( code: string, vm$context?: { [ name: string ]: any; } ): any; + runInContext( code: string, context?: { [ name: string ]: any; } ): any; } @@ -537,6 +537,12 @@ declare namespace peg { } + interface IArrayUtils { + + findIndex( array: any[], condition: IIterator ): number; + find( array: any[], condition: IIterator ): any; + + } interface IJavaScriptUtils { stringEscape( s: string ): string; @@ -554,7 +560,7 @@ declare namespace peg { enforceFastProperties( o: {} ): {}; } - interface util extends IJavaScriptUtils, IObjectUtils, compiler.ISessionVM { + interface util extends IArrayUtils, IJavaScriptUtils, IObjectUtils, compiler.ISessionVM { noop(): void; convertPasses( stages: IStageMap ): compiler.IPassesMap; diff --git a/packages/pegjs/typings/modules.d.ts b/packages/pegjs/typings/modules.d.ts index 8baa223..c51f986 100644 --- a/packages/pegjs/typings/modules.d.ts +++ b/packages/pegjs/typings/modules.d.ts @@ -151,6 +151,13 @@ declare module "pegjs/lib/util" { } +declare module "pegjs/lib/util/arrays" { + + const arrays: peg.IArrayUtils; + export default arrays; + +} + declare module "pegjs/lib/util/index" { export default peg.util; diff --git a/src/parser.pegjs b/src/parser.pegjs index e299c27..feb2b8e 100644 --- a/src/parser.pegjs +++ b/src/parser.pegjs @@ -31,11 +31,11 @@ // Populate `RESERVED_WORDS` using the optional option `reservedWords` const reservedWords = options.reservedWords || util.reservedWords; - if ( Array.isArray( reservedWords ) ) { + if ( Array.isArray( reservedWords ) ) reservedWords.forEach( word => { - for ( const word of reservedWords ) RESERVED_WORDS[ word ] = true; + RESERVED_WORDS[ word ] = true; - } + } ); // Helper to construct a new AST Node function createNode( type, details ) {