Browse Source

Added the Session API

master
Futago-za Ryuu 3 years ago
parent
commit
f4c67993f6
  1. 9
      lib/compiler/index.js
  2. 6
      lib/compiler/passes/calc-report-failures.js
  3. 8
      lib/compiler/passes/generate-bytecode.js
  4. 5
      lib/compiler/passes/generate-js.js
  5. 5
      lib/compiler/passes/inference-match-result.js
  6. 6
      lib/compiler/passes/remove-proxy-rules.js
  7. 5
      lib/compiler/passes/report-duplicate-labels.js
  8. 5
      lib/compiler/passes/report-duplicate-rules.js
  9. 5
      lib/compiler/passes/report-infinite-recursion.js
  10. 5
      lib/compiler/passes/report-infinite-repetition.js
  11. 5
      lib/compiler/passes/report-undefined-rules.js
  12. 35
      lib/compiler/session.js
  13. 12
      lib/peg.js
  14. 12
      test/spec/unit/compiler/passes/helpers.js

9
lib/compiler/index.js

@ -10,6 +10,7 @@ const reportInfiniteRecursion = require( "./passes/report-infinite-recursion" );
const reportInfiniteRepetition = require( "./passes/report-infinite-repetition" );
const reportUndefinedRules = require( "./passes/report-undefined-rules" );
const inferenceMatchResult = require( "./passes/inference-match-result" );
const Session = require( "./session" );
const util = require( "../util" );
function processOptions( options, defaults ) {
@ -25,6 +26,8 @@ function processOptions( options, defaults ) {
const compiler = {
Session: Session,
// Compiler passes.
//
// Each pass is a function that is passed the AST. It can perform checks on it
@ -53,7 +56,7 @@ const 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 ) {
compile( ast, session, options ) {
options = typeof options !== "undefined" ? options : {};
@ -68,11 +71,11 @@ const compiler = {
trace: false
} );
util.each( passes, stage => {
util.each( session.passes, stage => {
stage.forEach( pass => {
pass( ast, options );
pass( ast, session, options );
} );

6
lib/compiler/passes/calc-report-failures.js

@ -1,11 +1,9 @@
"use strict";
const visitor = require( "../../ast" ).visitor;
// Determines if rule always used in disabled report failure context,
// that means, that any failures, reported within it, are never will be
// visible, so the no need to report it.
function calcReportFailures( ast, options ) {
function calcReportFailures( ast, session, options ) {
// By default, not report failures for rules...
ast.rules.forEach( rule => {
@ -26,7 +24,7 @@ function calcReportFailures( ast, options ) {
} );
const calc = visitor.build( {
const calc = session.buildVisitor( {
rule( node ) {
calc( node.expression );

8
lib/compiler/passes/generate-bytecode.js

@ -1,7 +1,5 @@
"use strict";
const op = require( "../opcodes" );
const visitor = require( "../../ast" ).visitor;
const util = require( "../../util" );
// Generates bytecode.
@ -199,7 +197,9 @@ const util = require( "../../util" );
// }
// expected.top().variants.pushAll(value.variants);
// }
function generateBytecode( ast ) {
function generateBytecode( ast, session ) {
const op = session.opcodes;
const literals = [];
const classes = [];
@ -333,7 +333,7 @@ function generateBytecode( ast ) {
}
generate = visitor.build( {
generate = session.buildVisitor( {
grammar( node ) {
node.rules.forEach( generate );

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

@ -3,10 +3,11 @@
"use strict";
const js = require( "../js" );
const op = require( "../opcodes" );
// Generates parser JavaScript code.
function generateJS( ast, options ) {
function generateJS( ast, session, options ) {
const op = session.opcodes;
/* These only indent non-empty lines to avoid trailing whitespace. */
const lineMatchRE = /^([^`\r\n]+?(?:`[^`]*?`[^\r\n]*?)?)$/gm;

5
lib/compiler/passes/inference-match-result.js

@ -1,13 +1,12 @@
"use strict";
const visitor = require( "../../ast" ).visitor;
const GrammarError = require( "../../grammar-error" );
// Inference match result of the rule. Can be:
// -1: negative result, always fails
// 0: neutral result, may be fail, may be match
// 1: positive result, always match
function inferenceMatchResult( ast ) {
function inferenceMatchResult( ast, session ) {
let inference;
function sometimesMatch( node ) {
@ -72,7 +71,7 @@ function inferenceMatchResult( ast ) {
}
inference = visitor.build( {
inference = session.buildVisitor( {
rule( node ) {
let oldResult;

6
lib/compiler/passes/remove-proxy-rules.js

@ -1,9 +1,7 @@
"use strict";
const visitor = require( "../../ast" ).visitor;
// Removes proxy rules -- that is, rules that only delegate to other rule.
function removeProxyRules( ast, options ) {
function removeProxyRules( ast, session, options ) {
function isProxyRule( node ) {
@ -13,7 +11,7 @@ function removeProxyRules( ast, options ) {
function replaceRuleRefs( ast, from, to ) {
const replace = visitor.build( {
const replace = session.buildVisitor( {
rule_ref( node ) {
if ( node.name === from ) {

5
lib/compiler/passes/report-duplicate-labels.js

@ -1,12 +1,11 @@
"use strict";
const GrammarError = require( "../../grammar-error" );
const visitor = require( "../../ast" ).visitor;
const util = require( "../../util" );
const __hasOwnProperty = Object.prototype.hasOwnProperty;
// Checks that each label is defined only once within each scope.
function reportDuplicateLabels( ast ) {
function reportDuplicateLabels( ast, session ) {
let check;
@ -16,7 +15,7 @@ function reportDuplicateLabels( ast ) {
}
check = visitor.build( {
check = session.buildVisitor( {
rule( node ) {
check( node.expression, {} );

5
lib/compiler/passes/report-duplicate-rules.js

@ -1,15 +1,14 @@
"use strict";
const GrammarError = require( "../../grammar-error" );
const visitor = require( "../../ast" ).visitor;
const __hasOwnProperty = Object.prototype.hasOwnProperty;
// Checks that each rule is defined only once.
function reportDuplicateRules( ast ) {
function reportDuplicateRules( ast, session ) {
const rules = {};
const check = visitor.build( {
const check = session.buildVisitor( {
rule( node ) {
const name = node.name;

5
lib/compiler/passes/report-infinite-recursion.js

@ -1,7 +1,6 @@
"use strict";
const GrammarError = require( "../../grammar-error" );
const visitor = require( "../../ast" ).visitor;
// Reports left recursion in the grammar, which prevents infinite recursion in
// the generated parser.
@ -13,11 +12,11 @@ const visitor = require( "../../ast" ).visitor;
//
// In general, if a rule reference can be reached without consuming any input,
// it can lead to left recursion.
function reportInfiniteRecursion( ast ) {
function reportInfiniteRecursion( ast, session ) {
const visitedRules = [];
const check = visitor.build( {
const check = session.buildVisitor( {
rule( node ) {
visitedRules.push( node.name );

5
lib/compiler/passes/report-infinite-repetition.js

@ -1,13 +1,12 @@
"use strict";
const GrammarError = require( "../../grammar-error" );
const visitor = require( "../../ast" ).visitor;
// Reports expressions that don't consume any input inside |*| or |+| in the
// grammar, which prevents infinite loops in the generated parser.
function reportInfiniteRepetition( ast ) {
function reportInfiniteRepetition( ast, session ) {
const check = visitor.build( {
const check = session.buildVisitor( {
zero_or_more( node ) {
if ( ! ast.alwaysConsumesOnSuccess( node.expression ) ) {

5
lib/compiler/passes/report-undefined-rules.js

@ -1,12 +1,11 @@
"use strict";
const GrammarError = require( "../../grammar-error" );
const visitor = require( "../../ast" ).visitor;
// Checks that all referenced rules exist.
function reportUndefinedRules( ast, options ) {
function reportUndefinedRules( ast, session, options ) {
const check = visitor.build( {
const check = session.buildVisitor( {
rule_ref( node ) {
if ( ! ast.findRule( node.name ) ) {

35
lib/compiler/session.js

@ -0,0 +1,35 @@
"use strict";
const ast = require( "../ast" );
const opcodes = require( "./opcodes" );
const parser = require( "../parser" );
class Session {
constructor( options ) {
options = typeof options !== "undefined" ? options : {};
this.grammar = options.grammar;
this.opcodes = options.opcodes || opcodes;
this.parser = options.parser || parser;
this.passes = options.passes || [];
this.visitor = options.visitor || ast.visitor;
}
parse( input, options ) {
return this.parser.parse( input, options );
}
buildVisitor( functions ) {
return this.visitor.build( functions );
}
}
module.exports = Session;

12
lib/peg.js

@ -30,20 +30,20 @@ const peg = {
options = typeof options !== "undefined" ? options : {};
const plugins = "plugins" in options ? options.plugins : [];
const config = {
parser: parser,
const session = new compiler.Session( {
grammar: grammar,
passes: util.convertPasses( compiler.passes )
};
} );
plugins.forEach( p => {
p.use( config, options );
p.use( session, options );
} );
return compiler.compile(
config.parser.parse( grammar, options.parser || {} ),
config.passes,
session.parse( grammar, options.parser || {} ),
session,
options
);

12
test/spec/unit/compiler/passes/helpers.js

@ -1,7 +1,7 @@
"use strict";
const LikeHelper = require( "chai-like" );
const parser = require( "pegjs-dev" ).parser;
const Session = require( "pegjs-dev" ).compiler.Session;
module.exports = function ( chai, utils ) {
@ -14,7 +14,8 @@ module.exports = function ( chai, utils ) {
options = typeof options !== "undefined" ? options : {};
additionalRuleProps = typeof additionalRuleProps !== "undefined" ? additionalRuleProps : { reportFailures: true };
const ast = parser.parse( grammar );
const session = new Session( { grammar } );
const ast = session.parse( grammar );
if ( ! options.allowedStartRules ) {
@ -26,7 +27,7 @@ module.exports = function ( chai, utils ) {
ast.rules = ast.rules.map( rule => Object.assign( rule, additionalRuleProps ) );
utils.flag( this, "object" )( ast, options );
utils.flag( this, "object" )( ast, session, options );
new Assertion( ast ).like( props );
@ -36,7 +37,8 @@ module.exports = function ( chai, utils ) {
options = typeof options !== "undefined" ? options : {};
const ast = parser.parse( grammar );
const session = new Session( { grammar } );
const ast = session.parse( grammar );
if ( ! options.allowedStartRules ) {
@ -50,7 +52,7 @@ module.exports = function ( chai, utils ) {
try {
utils.flag( this, "object" )( ast, options );
utils.flag( this, "object" )( ast, session, options );
passed = true;
} catch ( e ) {

Loading…
Cancel
Save