JsonGrammar.php
<?php
namespace Tlf\Lexer;
/**
*
* This is an incomplete grammar, mainly used for testing & building v0.5 of the lexer. It gets "quoted values" and nested arrays.
*
*/
class JsonGrammar extends Grammar {
public function getNamespace(){return 'json';}
public function getAstClass():string{
return \Tlf\Lexer\JsonAst::class;
}
public function onLexerStart($lexer,$file,$token){
// $lexer->stackDirectiveList('phpgrammar:html', 'phpgrammar:php_open');
// $lexer->setDirective([$this->getDirective('html')]);
$directiveList = $this->getDirectives(':file');
foreach ($directiveList as $d){
$lexer->addDirective($d);
}
}
public function appendValueToAst($lexer, $ast, $token){
$ast->add('value', $token->buffer());
}
public $directives = [
'file'=>[
// it automatically starts
// and immediately rewinds one
// so each of its 'then's can see the first character
'onStart'=>[
'rewind'=>1,
'then'=>[
':object',
':array',
':whitespace',
],
],
],
// @todo I need to apply php_close to almost everything...
'object' => [
'start'=>'{',
'onStart'=>[
'buffer.clear'=>true,
'ast.new'=>[
'_setto'=>'root',
'type'=>'object',
],
],
'stop'=>'}',
'onStop'=>
[
'pop_head'=>true,
'pop_directive'=>true,
'buffer.clear'=>true,
],
'then'=>[
':key'=>[],
':whitespace'=>[],
]
],
'array' => [
'start'=>'[',
'onStart'=>[
'buffer.clear'=>true,
//ast.head =>[ // to say new & set as head?
'ast.new'=>[
'_setto'=> 'root',
//automatically sets as head?
'type'=>"array",
],
'then'=>[
//':array.stop', // it would add a duplicate?
':array'=>[
'onStart'=>[
'buffer.clear'=>true,
//ast.head =>[ // to say new & set as head?
'ast.new'=>[
'_addto'=>'value',
//automatically sets as head?
'type'=>"array",
],
],
'onStop'=>[
'pop_head'=>true,
'buffer.clear'=>true,
'pop_directive'=>false,
'then'=>[
':whitespace',
':comma',
':array.stop'=>[
'onStart'=>[
'pop_directive'=>true,
'pop_head'=>false,
// 'rewind'=>1,
// 'badbubble'=>true,
]
],
]
],
],
':whitespace',
':value'=>[
'onStop'=>[
'rewind'=>1,
'this:appendValueToAst',
'forward'=>1,
'buffer.clear'=>true,
// 'pop_directive'=>true,
'then'=>[
':whitespace',
':comma'=>[
// 'onStart'=>[
// 'then'=>[
// ''
// ],
// ]
],
':array.stop'=>[
'onStart'=>[
'pop_head'=>false,
'pop_directive'=>true,
'rewind'=>1,
// 'bubble'=>true,
]
],
],
],
],
':array.stop'=>[
'onStart'=>[
'pop_head'=>false,
'pop_directive'=>true,
'rewind'=>1,
// 'bubble'=>true,
]
],
],
],
'stop'=>']',
'onStop'=>[
'pop_head'=>true,
'pop_directive'=>true,
'buffer.clear'=>true,
],
],
'key'=>[
// I think it takes other chars too... need to look up
// 'start' => '/(\'|\")/',
'start' => ["'", '"'],
'onStart'=>[
'buffer.clear',
],
'match'=>'/^$1([a-zA-Z0-9_\-]+)/',
'stop'=>'/$1$/',
'onStop'=>[
// 'call'=> 'keyFound',
//this could set the whole match stored to previous
//So, like... whatever onStop would have had access to gets stored as previous('key')???
'previous'=>'key',
'pop_directive'=>true,
],
'then'=>[
':whitespace',
':colon'=>[
],
]
],
'value'=>[
'is'=>[
// ':bool_value',
// ':numeric_value',
':str_value',
],
],
// 'bool_value'=>[
// ],
// 'numeric_value'=>[
// ],
'str_value'=>[
'start' => [
"'",
'"',
],
'onStart'=>[
'buffer.clear',
],
// 'match'=>'/((?<!\\\\)[^$1])+/',
// fill with the 1st match
'match'=>[['/((?<!\\\\)[^' ,1, '])+/']],
// fill with the 1st match
'stop'=>[['/[^\\\\]',1,'$/']],
'onStop'=>[
// this will have to either save it to the object with the previous key
// or append it to an array
// I suppose previous(key) will be null if we're inside an array
// 'call'=> 'store_value',
'buffer.clear'=>true,
// 'pop_directive'=>true,
//because its only after the stop
'then'=>[
':comma'=>[
],
':whitespace',
]
],
],
'comma'=>[
'start'=>',',
'onStart'=>[
'buffer.clear'=>true,
// 'stop'=>true,
//pop this directive stack?
'pop_directive'=>true,
],
],
'colon'=>[
'match'=> ':',
'then'=> [
':whitespace'=> [
],
':value'=>[
'then'=>[
':comma'=>[
'then'=>[
':key',
':object.stop'=>[
'bubble'=>true,
],
]
],
],
],
],
],
'whitespace'=>[
// serves as start.
// Since there's no 'stop', not matching will trigger onStop
// is i dotall?
'match'=>'/^\s+$/i',
'onStop'=>[
'buffer.clear'=>true,
],
],
];
}