Merge ast utils into Grammar class
This commit is contained in:
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…
Reference in a new issue