public static function dumpTokens(TokenIterator $tokens) { $position = $tokens->position; while ($token = $tokens->nextToken()) { list($value, $_, $type) = $token; $typeFmt = str_pad($type, 15, ' ', STR_PAD_LEFT); // $value = trim($value); echo "{$typeFmt}: ▷{$value}◁\n"; } $tokens->position = $position; }
/** * @param TokenIterator $tokens * @return mixed TODO */ public function parse(TokenIterator $tokens) { $state = self::HOST; $hosts = []; $keyword = NULL; $currentHost = []; $close = function ($currentHost) use(&$hosts) { $key = $currentHost['host']; $hosts[$key] = array_replace($currentHost, isset($hosts[$key]) ? $hosts[$key] : []); }; while ($token = $tokens->nextToken()) { list($value, $_, $type) = $token; $value = trim($value); switch ($type) { case Lexer::T_NEWLINE: case Lexer::T_SEPARATOR: case Lexer::T_COMMENT: break; case Lexer::T_KEYWORD: $keyword = strToLower($value); if ($keyword === 'host') { $this->assertState([self::HOST, self::KEYWORD], $state); if ($currentHost !== []) { call_user_func($close, $currentHost); } $currentHost = []; } else { $this->assertState([self::KEYWORD], $state); } $state = self::ARGUMENTS; break; case Lexer::T_ARG_QUOT: $value = substr($value, 1, -1); // intentional fall-through // intentional fall-through case Lexer::T_ARG: $this->assertState([self::ARGUMENTS], $state); if (!array_key_exists($keyword, $currentHost)) { $currentHost[$keyword] = $value; } $state = self::KEYWORD; break; } } call_user_func($close, $currentHost); return $hosts; }
private function processArgs(TokenIterator $iterator, $modifierName, $inArray) { $result = []; $iterator->position++; while (isset($iterator->tokens[$iterator->position])) { list($value, , $type) = $iterator->currentToken(); if ($type === self::TOKEN_RBRACKET) { if ($inArray) { return $result; } else { throw new InvalidModifierDefinitionException("Modifier {" . "{$modifierName}} mismatches brackets."); } } elseif ($type === self::TOKEN_STRING || $type === self::TOKEN_KEYWORD) { $iterator->position++; list(, , $nextToken) = $iterator->currentToken(); if ($nextToken === self::TOKEN_EQUAL) { $iterator->position++; list(, , $nextToken) = $iterator->currentToken(); $nextValue = $iterator->currentValue(); if ($nextToken === self::TOKEN_LBRACKET) { $result[$value] = $this->processArgs($iterator, $modifierName, TRUE); } elseif ($nextToken === self::TOKEN_STRING || $nextToken === self::TOKEN_KEYWORD) { $result[$value] = $nextValue; } elseif ($nextToken !== NULL) { throw new InvalidModifierDefinitionException("Modifier {" . "{$modifierName}} has invalid token after =."); } } elseif ($type !== NULL) { $iterator->position--; $result[] = $value; } } else { throw new InvalidModifierDefinitionException("Modifier {" . "{$modifierName}} has invalid token, expected string or keyword."); } $iterator->position++; list(, , $type) = $iterator->currentToken(); if ($type === self::TOKEN_RBRACKET && $inArray) { return $result; } elseif ($type !== NULL && $type !== self::TOKEN_SEPARATOR) { throw new InvalidModifierDefinitionException("Modifier {" . "{$modifierName}} misses argument separator."); } $iterator->position++; } if ($inArray) { throw new InvalidModifierDefinitionException("Modifier {" . "{$modifierName}} has unclosed array argument."); } return $result; }
protected function next() { parent::next(); if ($this->isCurrent('[', '(', '{')) { $this->depth++; } elseif ($this->isCurrent(']', ')', '}')) { $this->depth--; } }
/** * @param TokenIterator $tokens * @param array|string $types * @param array|string $allowedToSkip * @throws \Kdyby\Aop\ParserException * @return NULL|string */ protected static function nextValue(TokenIterator $tokens, $types, $allowedToSkip = []) { do { if (call_user_func_array([$tokens, 'isCurrent'], (array) $types)) { return $tokens->currentValue(); } if (!$allowedToSkip || !call_user_func_array([$tokens, 'isCurrent'], (array) $allowedToSkip)) { $type = $tokens->currentToken(); throw new Kdyby\Aop\ParserException('Unexpected token ' . $type[Tokenizer::TYPE] . ' at offset ' . $type[Tokenizer::OFFSET]); } } while ($token = $tokens->nextToken()); throw new Kdyby\Aop\ParserException('Expected token ' . implode(', ', (array) $types)); }