Grammar.php
<?php
namespace Tlf\Lexer\Test\Main;
/*
* Test features of the grammar class, not lexing, and not any language-specific grammars
*/
class Grammar extends \Tlf\Tester {
protected $grammar;
public function prepare(){
$this->grammar = new \Tlf\Lexer\Grammar();
}
/**
* @test `$grammar->getDirectives($name, $overrides)`
*/
public function testGetDirectives(){
$grammar = new \Tlf\Lexer\Grammar();
$grammar->directives = $this->getSourceDirectives();
foreach ($this->getDirectivesToLookup() as $testName=>$pieces){
if ($testName!='Is Directive'){
//var_dump("")
//exit;
//@todo REMOVE THIS continue
continue;
}
$this->test($testName);
$lookupName = $pieces[0];
$overrides = $pieces[1];
$expectedList = $pieces[2];
$actualList = $grammar->getDirectives($lookupName, $overrides);
foreach ($actualList as $name=>$d){
unset($d->_name);
unset($d->_grammar);
$actualList[$name] = (array)$d;
}
$this->compare($expectedList, $actualList);
}
}
/**
* Test grammar->normalizeDirective();
* @test directive `:bear` normalizes to `:bear => []`
* @test `:bear ...` normalizes to to `:bear => []`
* @test `:dog=>['override']` is unchanged by normalization
*
* Rules:
* @rule `"cmd var"` normalizes to `":cmd var" => []`
* @rule `"cmd var" => []` does not change
*
*/
public function testDirectiveNormalization(){
foreach ($this->getNormalizeDirectives() as $name=>$comparators){
$this->test($name);
$directive = $comparators[0];
$expect = $comparators[1];
$normal = $this->grammar->normalizeDirective($directive);
$this->is_object($normal);
$this->compare($expect, (array)$normal);
}
}
/**
* Test that an `is` directive expands into an array of the directives it names
*
* @test `is => [ ":target1", ":target2", ":target3" ]` expands into `[ $target1, $target2, $target3 ]` where `$target1` is a directive, possibly containing starts & stops
*/
public function testExpandIsDirective(){
$grammar = new \Tlf\Lexer\Grammar();
$dRoot = $grammar->directives = $this->getSourceDirectives();
$sourceDirective = (object)$grammar->directives['is_directive'];
$sourceDirective->_name = 'is_directive';
$sourceDirective->_grammar = 'grammar';
$directiveList = $grammar->expandDirectiveWithIs($sourceDirective);
foreach ($directiveList as $directiveName=>$directive){
unset($directive->_name);
unset($directive->_grammar);
$directiveList[$directiveName] = (array)$directive;
}
$this->compare(
[
'is_target'=>$dRoot['is_target'],
'is_target_2'=>$dRoot['is_target_2'],
'is_target_3'=>$dRoot['is_target_3'],
],
$directiveList
);
}
/**
* Rules:
* @rule source + override = override, source
* @rule source[key] + override[key] = override[key]
* @rule source[key //] + override[key] = override[key], source[key //]
*
*
* @test `:source=>[]` overridden by `:override=>[]` yields `:override=>[], :source=>[]`
* @test that `then :cat, match uhoh` overridden by `match // => abc, hide` yields `match //=>abc, hide, then :cat, match uhoh`
* @test `then :cat` overridden by `hide nothing, match abc` yields `hide nothing, match abc, then :cat`
* @test `match abc, then :cat` overriden by `hide nothing` yields `match, hide, then` (match goes first)
* @test `match abc, then cats` overridden by `match dog, rewind 1` yields `match dog, rewind 1, then cats`
*/
public function testDirectiveOverrides(){
foreach ($this->getOverrideDirectives() as $testName=>$pieces){
$source = (object)$pieces[0];
$overrides = (object)$pieces[1];
$expect = $pieces[2];
$actual = $this->grammar->getOverriddenDirective($overrides, $source);
$this->is_object($actual);
$this->test($testName);
$this->compare($expect, (array)$actual,true);
}
}
/**
*
* @return multi dimensional array
* @array.key is the thing being tested
* @array.child is an array with 3 child arrays
* @array.child.index1 is the name of the directive to load
* @array.child.index2 is the the overrides
* @array.child.index3 is the expected directive list to be returned
*/
public function getDirectivesToLookup(){
return [
'Empty Directive'=>[
':empty_directive',
[],
['empty_directive'=>[]],
],
'Is Directive'=>[
':is_directive',
[],
[
'is_target'=>[
'stop'=>[
'match'=>['/is/'],
],
],
'is_target_2'=>[
'stop'=>[
'match'=>['/is_2/'],
],
],
'is_target_3'=>[
'stop'=>[
'match'=>['/is_3/'],
],
],
],
],
];
}
public function getSourceDirectives(){
return [
'empty_directive'=>[
],
'is_directive'=>[
'is'=>[
':is_target'=>[],
':is_target_2'=>[],
':is_target_3'=>[],
],
],
'is_target'=>[
'stop'=>[
'match'=>['/is/'],
],
],
'is_target_2'=>[
'stop'=>[
'match'=>['/is_2/'],
],
],
'is_target_3'=>[
'stop'=>[
'match'=>['/is_3/'],
],
],
];
}
/**
*
* @return multi dimensional array
* @array.key is the thing being tested
* @array.child is an array with 3 child arrays
* @array.child.index1 is the source/root directive
* @array.child.index2 is the overrides
* @array.child.index3 is the expected result
*
*/
public function getOverrideDirectives(){
return [
'Is overrides'=>[
[
'is'=>[
':source'=>[],
],
],
[
'is'=>[
':override'=>[],
],
],
[
'is'=>[
':override'=>[],
':source'=>[],
],
],
],
'Source match is second'=>[
[
'start'=>[
'then'=>[':cat'],
'match'=>['uhoh'],
],
],
[
'start'=>[
'match //'=>['abc'],
'hide'=>['nothing'],
],
],
[
'start'=>[
'match //'=>['abc'],
'hide'=>['nothing'],
'then'=>[':cat'],
'match'=>['uhoh'],
]
],
],
'Source nomatch' => [
[
'start'=>[
'then'=>[':cat'],
],
],
[
'start'=>[
'hide'=>['nothing'],
'match'=>['abc'],
],
],
[
'start'=>[
'hide'=>['nothing'],
'match'=>['abc'],
'then'=>[':cat'],
]
],
],
'Source match, then overrides, then other source instructions'=>[
[
'start'=>[
'match'=>['abc'],
'then'=>[':cat'],
],
],
[
'start'=>[
'hide'=>['nothing'],
],
],
[
'start'=>[
'match'=>['abc'],
'hide'=>['nothing'],
'then'=>[':cat'],
]
],
],
'Direct Key Overrides'=>[
[
'stop'=>[
'match'=> ['abc'],
'then'=> ['cats'],
]
],
[
'stop'=>[
'match'=> ['dog'],
'rewind'=>1,
]
],
[
'stop'=>[
'match'=>['dog'],
'rewind'=>1,
'then'=>['cats'],
],
],
]
];
}
/**
*
* Get directives as they would be defined & those same directives as they would be after normaliztion
*
* @test
* @return multi dimensional array
* @child.index1 is the input directive, as one would define it
* @child.index2 is the expected output directive, as returned from the normalize method
*/
public function getNormalizeDirectives(){
return [
'Stop'=>[
[
'stop'=>[
'then :cat',
'then :dog'=>['override'],
'then :bear ...',
],
],
[
'stop'=>[
'then :cat'=>[],
'then :dog'=>['override'],
'then :bear ...'=>[],
],
],
],
'Is'=>[
[
//input
'is'=>[
':cat',
':dog'=>['override'],
':bear',
],
],
[
//normalized
'is'=>[
':cat'=>[],
':dog'=>['override'],
':bear'=>[],
],
],
],
];
}
////////////////////
//
///// abandoned test code that i might return to eventually
//
////////////////////
/** I wrote this for thinking purposes, and I will probably use it for some testing maybe????
* Might be able to delete it.
*/
protected $sampleDirectiveList = [
'grp'=>[
'stop'=>[
//overrides target.stop.rewind & target_2.stop.rewind
'rewind'=>1
],
'is'=>[
':target'=>[
//overrides grp.stop.rewind & target.stop.rewind
'rewind'=>2,
],
':target_2'=>[],
]
],
'target'=>[
'stop'=>[
'match'=>'abc',
// overrides nothing
'rewind'=>3,
]
],
'parent'=>[
'stop'=>[
'then :grp'=>[
//highest priority. This always overrides whatever its loading
'rewind'=>4
],
]
],
'target_2'=>[],
];
/**
* Test that is directives accept overrides
* The functionality exists, i think, but the test is not implemented
*/
public function testExpandIsDirectiveWithOverrides(){
$this->disable();
echo "\n\n";
echo "This test is disabled because I haven't actually implemented it yet. Its currently a copy+paste from testExpandIsDirective() (no overrides) ";
echo "\n\n";
return false;
$grammar = new \Tlf\Lexer\Grammar();
$dRoot = $grammar->directives = $this->getSourceDirectives();
$sourceDirective = (object)$grammar->directives['is_directive'];
$sourceDirective->_name = 'is_directive';
$sourceDirective->_grammar = 'grammar';
$directiveList = $grammar->expandDirectiveWithIs($sourceDirective);
foreach ($directiveList as $directiveName=>$directive){
unset($directive->_name);
unset($directive->_grammar);
$directiveList[$directiveName] = (array)$directive;
}
$this->compare(
[
'is_target'=>$dRoot['is_target'],
'is_target_2'=>$dRoot['is_target_2'],
'is_target_3'=>$dRoot['is_target_3'],
],
$directiveList
);
}
}