parent
26969475f7
commit
460f0cc5bc
@ -0,0 +1,53 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check if the given element's expression is of type `semantic_*`
|
||||||
|
//
|
||||||
|
function isSemanticPredicate( element ) {
|
||||||
|
|
||||||
|
const type = element.expression.type;
|
||||||
|
|
||||||
|
if ( type === "semantic_and" ) return true;
|
||||||
|
if ( type === "semantic_not" ) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Compiler pass to ensure the following are enforced:
|
||||||
|
//
|
||||||
|
// - plucking can not be done with an action block
|
||||||
|
// - cannot pluck a semantic predicate
|
||||||
|
//
|
||||||
|
function reportIncorrectPlucking( ast, session ) {
|
||||||
|
|
||||||
|
session.buildVisitor( {
|
||||||
|
|
||||||
|
action( node ) {
|
||||||
|
|
||||||
|
this.visit( node.expression, true );
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
labeled( node, action ) {
|
||||||
|
|
||||||
|
if ( node.pick !== true ) return void 0;
|
||||||
|
|
||||||
|
if ( action === true )
|
||||||
|
|
||||||
|
session.error( `"@" cannot be used with an action block.`, node.location );
|
||||||
|
|
||||||
|
if ( isSemanticPredicate( node ) )
|
||||||
|
|
||||||
|
session.error( `"@" cannot be used on a semantic predicate.`, node.location );
|
||||||
|
|
||||||
|
this.visit( node.expression );
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
} )( ast );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = reportIncorrectPlucking;
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,52 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { expect, use } = require( "chai" );
|
||||||
|
const helpers = require( "./helpers" );
|
||||||
|
const pass = require( "pegjs" ).compiler.passes.check.reportIncorrectPlucking;
|
||||||
|
|
||||||
|
use( helpers );
|
||||||
|
|
||||||
|
describe( "compiler pass |reportIncorrectPlucking|", function () {
|
||||||
|
|
||||||
|
function reports( error, edgecases ) {
|
||||||
|
|
||||||
|
it( error.slice( 0, -1 ), () => {
|
||||||
|
|
||||||
|
edgecases.forEach( grammar => expect( pass ).to.reportError( grammar, error ) );
|
||||||
|
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
reports( `"@" cannot be used with an action block.`, [
|
||||||
|
|
||||||
|
`start1 = 'a' @'b' 'c' { /* empty action block */ }`,
|
||||||
|
`start2 = 'a' @('b' @'c' { /* empty action block */ })`
|
||||||
|
|
||||||
|
] );
|
||||||
|
|
||||||
|
reports( `"@" cannot be used on a semantic predicate.`, [
|
||||||
|
|
||||||
|
`start1 = 'a' @&{ /* semantic_and */ } 'c'`,
|
||||||
|
`start2 = 'a' @!{ /* semantic_not */ } 'c'`
|
||||||
|
|
||||||
|
] );
|
||||||
|
|
||||||
|
it( "allows valid plucking", function () {
|
||||||
|
|
||||||
|
expect( pass ).not.to.reportError( `
|
||||||
|
|
||||||
|
start1 = @'1' // return '1'
|
||||||
|
start2 = @'1' / @'2' // return '1' or '2'
|
||||||
|
start2 = '1' @'2' '3' // return '2'
|
||||||
|
start3 = '1' @b:'2' '3' // return '2', label "b" can be used in semantic predicates
|
||||||
|
start4 = a:'1' @b:'2' '3' // return '2', labels "a" and "b" can be used in semantic predicates
|
||||||
|
start5 = @'1' @'2' '3' // return ['1', '2']
|
||||||
|
start6 = @'1' @b:'2' '3' // return ['1', '2'], label "b" can be used in semantic predicates
|
||||||
|
start7 = a:'1' @'2' &{} // return '2' if the semantic predicate doesnt fail
|
||||||
|
|
||||||
|
` );
|
||||||
|
|
||||||
|
} );
|
||||||
|
|
||||||
|
} );
|
Loading…
Reference in New Issue