tokens = $tokens; } /** * @param string $source * @return Lexer */ public static function tokenize(string $source) { $tokens = []; \preg_match_all(self::compileTokenRegEx(), $source, $tokens); $tokens = $tokens[0]; return new static($tokens); } /** * @return string */ private static function compileTokenRegEx() { $tokens = [ '\$?(?:(?![0-9-])[\w-]+:)?(?![0-9-])[\w-]+', // Nodename (possibly with namespace) or variable. '\/\/', // Double slash. '\.\.', // Double dot. '::', // Double colon. '\d+(?:\.\d*)?', // Number starting with digit. '\.\d+', // Number starting with decimal point. '"[^"]*"', // Double quoted string. '\'([^\\\']|\'\')*\'', // Single quoted string. '[!<>]=', // Operators '\s+', // Whitespaces. '.', // Any single character. ]; return '/' . \implode('|', $tokens) . '/'; } /** * @param array|string[] $tokens * @param int $position */ public function insert(array $tokens, $position) { \array_splice($this->tokens, (int)$position, 0, $tokens); } /** * @return string */ public function current(): string { return $this->tokens[$this->position]; } /** * @return void */ public function next(): void { $this->position++; } /** * @return int */ public function key(): int { return $this->position; } /** * @return boolean */ public function valid(): bool { return isset($this->tokens[$this->position]); } /** * @return void */ public function rewind(): void { $this->position = 0; } /** * @param int $position * @return void */ public function seek($position): void { $this->position = $position; } /** * @param int $position * @return string */ public function peek(int $position): string { return $this->tokens[$position] ?? ''; } /** * @return int */ public function count(): int { return \count($this->tokens); } public function prev() { $this->position--; } }