<?php
class Token {
public function __toString() { return get_called_class(); }
}
class ParensOpenToken extends Token {}
class ParensCloseToken extends Token {}
class SemicolonToken extends Token {}
class ValueToken extends Token {
public $value = '';
public function __toString() {
return parent::__toString() . '("' . $this->value . '")';
}
}
class OtherToken extends Token {
public $value = '';
public function __toString() {
return parent::__toString() . '("' . $this->value . '")';
}
}
class Tokenizer {
public function tokenize($string) {
$tokensList = [
'[ \t\n]' => OtherToken::class,
'\\{' => ParensOpenToken::class,
'\\}' => ParensCloseToken::class,
';' => SemicolonToken::class,
'[a-zA-Zа-яА-Я\-_0-9]+' => ValueToken::class
];
$tokens = [];
while (mb_strlen($string) > 0) {
$matched = false;
foreach ($tokensList as $pattern => $token) {
if (preg_match('/^(' . $pattern . ')/', $string, $out) !== FALSE) {
if (isset($out[1])) {
$token = new $token();
if ($token instanceof ValueToken && !is_null($out[1])) {
$token->value = $out[1];
}
$tokens[] = $token;
$string = mb_substr($string, mb_strlen($out[1]));
$matched = true;
break;
}
}
}
if (!$matched) {
$value = mb_substr($string, 0, 1);
$otherToken = new OtherToken();
$otherToken->value = $value;
$string = mb_substr($string, 1);
}
}
return $tokens;
}
}
class Parser {
private $_tokens = [];
private $_index = 0;
private function isTokensAvailable() {
return $this->_index < count($this->_tokens);
}
private function peekCurrentToken() {
return $this->_tokens[$this->_index];
}
private function popCurrentToken() {
return $this->_tokens[$this->_index++];
}
private function parsePrimary() {
$peek = $this->peekCurrentToken();
if ($peek instanceof ParensOpenToken) {
return $this->parseParens();
} elseif ($peek instanceof ValueToken) {
return $this->parseValue();
} else {
throw new \Exception('Parser error: unexpected character at index ' . $this->_index);
return null;
}
}
private function parseParens() {
$token = $this->popCurrentToken();
if (!($token instanceof ParensOpenToken)) {
throw new \Exception('Parser error: expected {');
}
$expressions = [];
while (true) {
$expression = $this->parsePrimary();
$expressions[] = $expression;
$token = $this->peekCurrentToken();
if ($token instanceof ParensCloseToken) {
$this->popCurrentToken();
return $expressions;
} elseif (!($token instanceof SemicolonToken)) {
throw new \Exception('Parser error: expected semicolon after object in array');
} else {
$this->popCurrentToken();
}
}
return $expressions;
}
private function parseValue() {
$token = $this->popCurrentToken();
if (!($token instanceof ValueToken)) {
throw new \Exception('Parser error: expected value token');
}
return $token->value;
}
public function parse($tokens) {
$result = [];
$this->_tokens = $tokens;
$this->_index = 0;
while ($this->isTokensAvailable()) {
$result[] = $this->parsePrimary();
}
return $result;
}
}
$tokenizer = new Tokenizer();
$parser = new Parser();
$string = '{{param1;{param2_array};param3;param4};{param5;{param6_array};param7;param8}}';
$tokens = $tokenizer->tokenize($string);
$result = $parser->parse($tokens);
print_r($result);
$string2 = '{{param1;{param2_array;param2_array;param2_array};param3;param4}}';
$tokens2 = $tokenizer->tokenize($string2);
$result2 = $parser->parse($tokens2);
print_r($result2);
- Output for git.master, git.master_jit, rfc.property-hooks
- Array
(
[0] => Array
(
[0] => Array
(
[0] => param1
[1] => Array
(
[0] => param2_array
)
[2] => param3
[3] => param4
)
[1] => Array
(
[0] => param5
[1] => Array
(
[0] => param6_array
)
[2] => param7
[3] => param8
)
)
)
Array
(
[0] => Array
(
[0] => Array
(
[0] => param1
[1] => Array
(
[0] => param2_array
[1] => param2_array
[2] => param2_array
)
[2] => param3
[3] => param4
)
)
)
This tab shows result from various feature-branches currently under review by the php developers. Contact me to have additional branches featured.
Active branches
Archived branches
Once feature-branches are merged or declined, they are no longer available. Their functionality (when merged) can be viewed from the main output page
preferences:
76.7 ms | 403 KiB | 8 Q