/** * Parser. * @param string * @return array */ public function parse($input) { if (!self::$tokenizer) { // speed-up self::$tokenizer = new Tokenizer(self::$patterns, 'mi'); } $input = str_replace("\r", '', $input); $input = strtr($input, "\t", ' '); $input = "\n" . $input . "\n"; // first \n is required by "Indent" self::$tokenizer->tokenize($input); $this->n = 0; $res = $this->_parse(); while (isset(self::$tokenizer->tokens[$this->n])) { if (self::$tokenizer->tokens[$this->n][0] === "\n") { $this->n++; } else { $this->error(); } } return $res; }
/** * Decodes a NEON string. * @param string * @return mixed */ public static function decode($input) { if (!is_string($input)) { throw new \InvalidArgumentException("Argument must be a string, " . gettype($input) . " given."); } if (!self::$tokenizer) { self::$tokenizer = new Tokenizer(self::$patterns, 'mi'); } $input = str_replace("\r", '', $input); self::$tokenizer->tokenize($input); $parser = new self; $res = $parser->parse(0); while (isset(self::$tokenizer->tokens[$parser->n])) { if (self::$tokenizer->tokens[$parser->n][0] === "\n") { $parser->n++; } else { $parser->error(); } } return $res; }
/** * Tokenizer and preparser. * @return array */ private function parseMacro($input) { $this->tokenizer->tokenize($input); $this->tokenizer->tokens[] = NULL; // sentinel $inTernary = $lastSymbol = $prev = NULL; $tokens = $arrays = array(); $n = -1; while (++$n < count($this->tokenizer->tokens)) { list($token, $name) = $current = $this->tokenizer->tokens[$n]; $depth = count($arrays); if ($name === self::T_COMMENT) { continue; // remove comments } elseif ($name === self::T_WHITESPACE) { $current[2] = $depth; $tokens[] = $current; continue; } elseif ($name === self::T_SYMBOL && in_array($prev[0], array(',', '(', '[', '=', '=>', ':', '?', NULL), TRUE)) { $lastSymbol = count($tokens); // quoting pre-requirements } elseif (is_int($lastSymbol) && in_array($token, array(',', ')', ']', '=', '=>', ':', '|', NULL), TRUE)) { $tokens[$lastSymbol][0] = "'" . $tokens[$lastSymbol][0] . "'"; // quote symbols $lastSymbol = NULL; } else { $lastSymbol = NULL; } if ($token === '?') { // short ternary operators without : $inTernary = $depth; } elseif ($token === ':') { $inTernary = NULL; } elseif ($inTernary === $depth && ($token === ',' || $token === ')' || $token === ']' || $token === NULL)) { // close ternary $tokens[] = array(':', NULL, $depth); $tokens[] = array('null', NULL, $depth); $inTernary = NULL; } if ($token === '[') { // simplified array syntax [...] if ($arrays[] = $prev[0] !== ']' && $prev[1] !== self::T_SYMBOL && $prev[1] !== self::T_VARIABLE) { $tokens[] = array('array', NULL, $depth); $current = array('(', NULL); } } elseif ($token === ']') { if (array_pop($arrays) === TRUE) { $current = array(')', NULL); } } elseif ($token === '(') { // only count $arrays[] = '('; } elseif ($token === ')') { // only count array_pop($arrays); } if ($current) { $current[2] = $depth; $tokens[] = $prev = $current; } } return $tokens; }
/** * Formats parameters to PHP array. * @param string * @param string * @return string */ public static function formatArray($input, $prefix = '') { $tokenizer = new Tokenizer(array( Tokenizer::T_WHITESPACE => '\s+', Tokenizer::T_COMMENT => '/\*.*?\*/', Tokenizer::RE_STRING, 'true|false|null|and|or|xor|clone|new|instanceof', '\$[_a-z0-9\x7F-\xFF]+', // variable self::T_SYMBOL => '[_a-z0-9\x7F-\xFF]+', // string, number '=>|[^"\']', // =>, any char except quotes ), 'i'); $out = ''; $quote = TRUE; foreach ($tokenizer->tokenize($input) as $n => $token) { list($token, $name) = $token; if ($name === Tokenizer::T_COMMENT) { continue; } elseif ($name === self::T_SYMBOL && $quote && !is_numeric($token) && in_array($tokenizer->nextToken($n), array(',', '=>', ')', NULL), TRUE)) { $token = "'$token'"; } if ($name !== Tokenizer::T_WHITESPACE) { $quote = in_array($token, array('[', ',', '=', '(', '=>')); } $out .= $token; } return $out === '' ? '' : $prefix . "array($out)"; }