Merge ast utils into Grammar class

master
Futago-za Ryuu 6 years ago
parent 1a713d0175
commit 9d266625b4

@ -1,102 +0,0 @@
"use strict";
const visitor = require( "./visitor" );
// AST utilities.
const asts = {
findRule( ast, name ) {
for ( let i = 0; i < ast.rules.length; i++ ) {
if ( ast.rules[ i ].name === name ) return ast.rules[ i ];
}
return void 0;
},
indexOfRule( ast, name ) {
for ( let i = 0; i < ast.rules.length; i++ ) {
if ( ast.rules[ i ].name === name ) return i;
}
return -1;
},
alwaysConsumesOnSuccess( ast, node ) {
let consumes;
function consumesTrue() {
return true;
}
function consumesFalse() {
return false;
}
function consumesExpression( node ) {
return consumes( node.expression );
}
consumes = visitor.build( {
rule: consumesExpression,
named: consumesExpression,
choice( node ) {
return node.alternatives.every( consumes );
},
action: consumesExpression,
sequence( node ) {
return node.elements.some( consumes );
},
labeled: consumesExpression,
text: consumesExpression,
simple_and: consumesFalse,
simple_not: consumesFalse,
optional: consumesFalse,
zero_or_more: consumesFalse,
one_or_more: consumesExpression,
group: consumesExpression,
semantic_and: consumesFalse,
semantic_not: consumesFalse,
rule_ref( node ) {
return consumes( asts.findRule( ast, node.name ) );
},
literal( node ) {
return node.value !== "";
},
class: consumesTrue,
any: consumesTrue
} );
return consumes( node );
}
};
module.exports = asts;

@ -1,6 +1,5 @@
"use strict";
const asts = require( "../asts" );
const visitor = require( "../visitor" );
// Determines if rule always used in disabled report failure context,
@ -19,7 +18,7 @@ function calcReportFailures( ast, options ) {
// always enabled
const changedRules = options.allowedStartRules.map( name => {
const rule = asts.findRule( ast, name );
const rule = ast.findRule( name );
rule.reportFailures = true;
@ -42,7 +41,7 @@ function calcReportFailures( ast, options ) {
rule_ref( node ) {
const rule = asts.findRule( ast, node.name );
const rule = ast.findRule( node.name );
// This function only called when rule can report failures. If so, we
// need recalculate all rules that referenced from it. But do not do

@ -1,6 +1,5 @@
"use strict";
const asts = require( "../asts" );
const op = require( "../opcodes" );
const visitor = require( "../visitor" );
const util = require( "../../util" );
@ -643,7 +642,7 @@ function generateBytecode( ast ) {
rule_ref( node ) {
return [ op.RULE, asts.indexOfRule( ast, node.name ) ];
return [ op.RULE, ast.indexOfRule( node.name ) ];
},

@ -2,7 +2,6 @@
"use strict";
const asts = require( "../asts" );
const js = require( "../js" );
const op = require( "../opcodes" );
@ -954,7 +953,7 @@ function generateJS( ast, options ) {
parts.push( indent2( generateRuleHeader(
"\"" + js.stringEscape( rule.name ) + "\"",
asts.indexOfRule( ast, rule.name )
ast.indexOfRule( rule.name )
) ) );
parts.push( indent2( code ) );
parts.push( indent2( generateRuleFooter(
@ -1173,10 +1172,10 @@ function generateJS( ast, options ) {
const startRuleIndices = "{ "
+ options.allowedStartRules
.map( r => r + ": " + asts.indexOfRule( ast, r ) )
.map( r => r + ": " + ast.indexOfRule( r ) )
.join( ", " )
+ " }";
const startRuleIndex = asts.indexOfRule( ast, options.allowedStartRules[ 0 ] );
const startRuleIndex = ast.indexOfRule( options.allowedStartRules[ 0 ] );
parts.push( [
" var peg$startRuleIndices = " + startRuleIndices + ";",

@ -1,7 +1,6 @@
"use strict";
const visitor = require( "../visitor" );
const asts = require( "../asts" );
const GrammarError = require( "../../grammar-error" );
// Inference match result of the rule. Can be:
@ -140,7 +139,7 @@ function inferenceMatchResult( ast ) {
semantic_not: sometimesMatch,
rule_ref( node ) {
const rule = asts.findRule( ast, node.name );
const rule = ast.findRule( node.name );
node.match = inference( rule );
return node.match;

@ -1,7 +1,6 @@
"use strict";
const GrammarError = require( "../../grammar-error" );
const asts = require( "../asts" );
const visitor = require( "../visitor" );
// Reports left recursion in the grammar, which prevents infinite recursion in
@ -33,7 +32,7 @@ function reportInfiniteRecursion( ast ) {
check( element );
return ! asts.alwaysConsumesOnSuccess( ast, element );
return ! ast.alwaysConsumesOnSuccess( element );
} );
@ -53,7 +52,7 @@ function reportInfiniteRecursion( ast ) {
}
check( asts.findRule( ast, node.name ) );
check( ast.findRule( node.name ) );
}
} );

@ -1,7 +1,6 @@
"use strict";
const GrammarError = require( "../../grammar-error" );
const asts = require( "../asts" );
const visitor = require( "../visitor" );
// Reports expressions that don't consume any input inside |*| or |+| in the
@ -11,7 +10,7 @@ function reportInfiniteRepetition( ast ) {
const check = visitor.build( {
zero_or_more( node ) {
if ( ! asts.alwaysConsumesOnSuccess( ast, node.expression ) ) {
if ( ! ast.alwaysConsumesOnSuccess( node.expression ) ) {
throw new GrammarError(
"Possible infinite loop when parsing (repetition used with an expression that may not consume any input).",
@ -24,7 +23,7 @@ function reportInfiniteRepetition( ast ) {
one_or_more( node ) {
if ( ! asts.alwaysConsumesOnSuccess( ast, node.expression ) ) {
if ( ! ast.alwaysConsumesOnSuccess( node.expression ) ) {
throw new GrammarError(
"Possible infinite loop when parsing (repetition used with an expression that may not consume any input).",

@ -1,7 +1,6 @@
"use strict";
const GrammarError = require( "../../grammar-error" );
const asts = require( "../asts" );
const visitor = require( "../visitor" );
// Checks that all referenced rules exist.
@ -10,7 +9,7 @@ function reportUndefinedRules( ast, options ) {
const check = visitor.build( {
rule_ref( node ) {
if ( ! asts.findRule( ast, node.name ) ) {
if ( ! ast.findRule( node.name ) ) {
throw new GrammarError(
`Rule "${ node.name }" is not defined.`,
@ -26,7 +25,7 @@ function reportUndefinedRules( ast, options ) {
options.allowedStartRules.forEach( rule => {
if ( ! asts.findRule( ast, rule ) ) {
if ( ! ast.findRule( rule ) ) {
throw new GrammarError( `Start rule "${ rule }" is not defined.` );

@ -1,5 +1,8 @@
"use strict";
const visitor = require( "../compiler/visitor" );
const util = require( "../util" );
class Node {
constructor( type, location ) {
@ -23,7 +26,110 @@ class Grammar extends Node {
this.comments = comments;
this.rules = rules;
this._alwaysConsumesOnSuccess = new AlwaysConsumesOnSuccess( this );
}
alwaysConsumesOnSuccess( node ) {
return this._alwaysConsumesOnSuccess.visit( node );
}
findRule( name ) {
return this.rules.find( 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;
}
}
exports.Grammar = Grammar;
/* ***************************** @private ***************************** */
class AlwaysConsumesOnSuccess extends visitor.ASTVisitor {
constructor( ast ) {
super();
this.ast = ast;
}
choice( node ) {
return node.alternatives.every( this.visit, this );
}
sequence( node ) {
return node.elements.some( this.visit, this );
}
rule_ref( node ) {
return this.visit( this.ast.findRule( node.name ) );
}
literal( node ) {
return node.value !== "";
}
}
function consumesTrue() {
return true;
}
function consumesFalse() {
return false;
}
function consumesExpression( node ) {
return this.visit( node.expression );
}
util.extend( AlwaysConsumesOnSuccess.prototype, {
rule: consumesExpression,
named: consumesExpression,
action: consumesExpression,
labeled: consumesExpression,
text: consumesExpression,
simple_and: consumesFalse,
simple_not: consumesFalse,
optional: consumesFalse,
zero_or_more: consumesFalse,
one_or_more: consumesExpression,
group: consumesExpression,
semantic_and: consumesFalse,
semantic_not: consumesFalse,
class: consumesTrue,
any: consumesTrue,
} );

Loading…
Cancel
Save