Chris@13: Chris@13: */ Chris@13: abstract class AbstractMatcher Chris@13: { Chris@13: /** Syntax types */ Chris@13: const CONSTANT_SYNTAX = '^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$'; Chris@13: const VAR_SYNTAX = '^\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$'; Chris@13: const MISC_OPERATORS = '+-*/^|&'; Chris@13: /** Token values */ Chris@13: const T_OPEN_TAG = 'T_OPEN_TAG'; Chris@13: const T_VARIABLE = 'T_VARIABLE'; Chris@13: const T_OBJECT_OPERATOR = 'T_OBJECT_OPERATOR'; Chris@13: const T_DOUBLE_COLON = 'T_DOUBLE_COLON'; Chris@13: const T_NEW = 'T_NEW'; Chris@13: const T_CLONE = 'T_CLONE'; Chris@13: const T_NS_SEPARATOR = 'T_NS_SEPARATOR'; Chris@13: const T_STRING = 'T_STRING'; Chris@13: const T_WHITESPACE = 'T_WHITESPACE'; Chris@13: const T_AND_EQUAL = 'T_AND_EQUAL'; Chris@13: const T_BOOLEAN_AND = 'T_BOOLEAN_AND'; Chris@13: const T_BOOLEAN_OR = 'T_BOOLEAN_OR'; Chris@13: Chris@13: const T_ENCAPSED_AND_WHITESPACE = 'T_ENCAPSED_AND_WHITESPACE'; Chris@13: const T_REQUIRE = 'T_REQUIRE'; Chris@13: const T_REQUIRE_ONCE = 'T_REQUIRE_ONCE'; Chris@13: const T_INCLUDE = 'T_INCLUDE'; Chris@13: const T_INCLUDE_ONCE = 'T_INCLUDE_ONCE'; Chris@13: Chris@13: /** Chris@13: * Check whether this matcher can provide completions for $tokens. Chris@13: * Chris@13: * @param array $tokens Tokenized readline input Chris@13: * Chris@13: * @return bool Chris@13: */ Chris@13: public function hasMatched(array $tokens) Chris@13: { Chris@13: return false; Chris@13: } Chris@13: Chris@13: /** Chris@13: * Get current readline input word. Chris@13: * Chris@13: * @param array $tokens Tokenized readline input (see token_get_all) Chris@13: * Chris@13: * @return string Chris@13: */ Chris@13: protected function getInput(array $tokens) Chris@13: { Chris@13: $var = ''; Chris@17: $firstToken = \array_pop($tokens); Chris@13: if (self::tokenIs($firstToken, self::T_STRING)) { Chris@13: $var = $firstToken[1]; Chris@13: } Chris@13: Chris@13: return $var; Chris@13: } Chris@13: Chris@13: /** Chris@13: * Get current namespace and class (if any) from readline input. Chris@13: * Chris@13: * @param array $tokens Tokenized readline input (see token_get_all) Chris@13: * Chris@13: * @return string Chris@13: */ Chris@13: protected function getNamespaceAndClass($tokens) Chris@13: { Chris@13: $class = ''; Chris@13: while (self::hasToken( Chris@13: [self::T_NS_SEPARATOR, self::T_STRING], Chris@17: $token = \array_pop($tokens) Chris@13: )) { Chris@16: if (self::needCompleteClass($token)) { Chris@16: continue; Chris@16: } Chris@16: Chris@13: $class = $token[1] . $class; Chris@13: } Chris@13: Chris@13: return $class; Chris@13: } Chris@13: Chris@13: /** Chris@13: * Provide tab completion matches for readline input. Chris@13: * Chris@13: * @param array $tokens information substracted with get_token_all Chris@13: * @param array $info readline_info object Chris@13: * Chris@13: * @return array The matches resulting from the query Chris@13: */ Chris@13: abstract public function getMatches(array $tokens, array $info = []); Chris@13: Chris@13: /** Chris@13: * Check whether $word starts with $prefix. Chris@13: * Chris@13: * @param string $prefix Chris@13: * @param string $word Chris@13: * Chris@13: * @return bool Chris@13: */ Chris@13: public static function startsWith($prefix, $word) Chris@13: { Chris@17: return \preg_match(\sprintf('#^%s#', $prefix), $word); Chris@13: } Chris@13: Chris@13: /** Chris@13: * Check whether $token matches a given syntax pattern. Chris@13: * Chris@13: * @param mixed $token A PHP token (see token_get_all) Chris@13: * @param string $syntax A syntax pattern (default: variable pattern) Chris@13: * Chris@13: * @return bool Chris@13: */ Chris@13: public static function hasSyntax($token, $syntax = self::VAR_SYNTAX) Chris@13: { Chris@17: if (!\is_array($token)) { Chris@13: return false; Chris@13: } Chris@13: Chris@17: $regexp = \sprintf('#%s#', $syntax); Chris@13: Chris@17: return (bool) \preg_match($regexp, $token[1]); Chris@13: } Chris@13: Chris@13: /** Chris@13: * Check whether $token type is $which. Chris@13: * Chris@13: * @param string $which A PHP token type Chris@13: * @param mixed $token A PHP token (see token_get_all) Chris@13: * Chris@13: * @return bool Chris@13: */ Chris@13: public static function tokenIs($token, $which) Chris@13: { Chris@17: if (!\is_array($token)) { Chris@13: return false; Chris@13: } Chris@13: Chris@17: return \token_name($token[0]) === $which; Chris@13: } Chris@13: Chris@13: /** Chris@13: * Check whether $token is an operator. Chris@13: * Chris@13: * @param mixed $token A PHP token (see token_get_all) Chris@13: * Chris@13: * @return bool Chris@13: */ Chris@13: public static function isOperator($token) Chris@13: { Chris@17: if (!\is_string($token)) { Chris@13: return false; Chris@13: } Chris@13: Chris@17: return \strpos(self::MISC_OPERATORS, $token) !== false; Chris@13: } Chris@13: Chris@16: public static function needCompleteClass($token) Chris@16: { Chris@17: return \in_array($token[1], ['doc', 'ls', 'show']); Chris@16: } Chris@16: Chris@13: /** Chris@13: * Check whether $token type is present in $coll. Chris@13: * Chris@13: * @param array $coll A list of token types Chris@13: * @param mixed $token A PHP token (see token_get_all) Chris@13: * Chris@13: * @return bool Chris@13: */ Chris@13: public static function hasToken(array $coll, $token) Chris@13: { Chris@17: if (!\is_array($token)) { Chris@13: return false; Chris@13: } Chris@13: Chris@17: return \in_array(\token_name($token[0]), $coll); Chris@13: } Chris@13: }