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

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

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

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

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

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

@ -1,5 +1,8 @@
"use strict"; "use strict";
const visitor = require( "../compiler/visitor" );
const util = require( "../util" );
class Node { class Node {
constructor( type, location ) { constructor( type, location ) {
@ -23,7 +26,110 @@ class Grammar extends Node {
this.comments = comments; this.comments = comments;
this.rules = rules; 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; 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