Completed
Push — master ( ed2382...c469ea )
by Tom
01:26
created

PseudoMatcher::skipWhitespace()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 3
nc 2
nop 1
1
<?php
2
/* @description     Transformation Style Sheets - Revolutionising PHP templating    *
3
 * @author          Tom Butler [email protected]                                             *
4
 * @copyright       2017 Tom Butler <[email protected]> | https://r.je/                      *
5
 * @license         http://www.opensource.org/licenses/bsd-license.php  BSD License *
6
 * @version         1.2                                                             */
7
namespace Transphporm\Hook;
8
use \Transphporm\Parser\Tokenizer;
9
/** Determines whether $element matches the pseudo rule such as nth-child() or [attribute="value"] */
10
class PseudoMatcher {
11
	private $pseudo;
12
	private $valueParser;
13
	private $functions = [];
14
	private $funcParts = [];
15
16
	public function __construct($pseudo, \Transphporm\Parser\Value $valueParser) {
17
		$this->pseudo = $pseudo;
18
		$this->valueParser = $valueParser;
19
	}
20
21
	public function registerFunction($name, \Transphporm\Pseudo $pseudo) {
22
		$this->functions[$name] = $pseudo;
23
	}
24
25
	public function matches($element) {
26
		foreach ($this->pseudo as $i => $tokens) {
27
			$parts = $this->getFuncParts($i, $tokens);
28
			if ($parts['name'] === null) $parts['name'] = 'data';
29
			if (!isset($this->functions[$parts['name']])) return true;
30
			if ($this->match($parts, $this->functions[$parts['name']], $element) === false) {
31
				return false;
32
			}
33
34
		}
35
		return true;
36
	}
37
38
	private function match($parts, $function, $element) {
39
		try {
40
			$matches = $function->match($parts['name'], $parts['args'], $element);
41
			if ($matches === false) return false;
42
		}
43
		catch (\Exception $e) {
44
			throw new \Transphporm\RunException(\Transphporm\Exception::PSEUDO, $parts['name'], $e);
45
		}
46
	}
47
	private function getFuncParts($i, $tokens) {
48
		if (isset($this->funcParts[$i])) return $this->funcParts[$i];
49
		$parts = [];
50
		$canCache = true;
51
		$parts['name'] = $this->getFuncName($tokens);
52
		if ($parts['name'] === null || in_array($parts['name'], ['data', 'iteration', 'root'])) {
53
			//If the args are dynamic, it can't be cached as it may change between calls
54
			$canCache = false;
55
			$parts['args'] = $this->valueParser->parseTokens($tokens);
56
		}
57
		else if (count($tokens) > 1) {
58
			$tokens->rewind();
59
			$tokens->next();
60
			$this->skipWhitespace($tokens);
61
			$parts['args'] = $this->valueParser->parseTokens($tokens->current()['value']);
62
		}
63
		else $parts['args'] = [['']];
64
		if ($canCache) $this->funcParts[$i] = $parts;
65
		return $parts;
66
	}
67
68
	private function skipWhitespace($tokens) {
69
		while ($tokens->current()['type'] === 'WHITESPACE' || $tokens->current()['type'] == 'NEWLINE') $tokens->next();
70
	}
71
72
	private function getFuncName($tokens) {
73
		if ($tokens->type() === Tokenizer::NAME) return $tokens->read();
74
		return null;
75
	}
76
77
	public function hasFunction($name) {
78
		foreach ($this->pseudo as $tokens) {
79
			if ($name === $this->getFuncName($tokens)) return true;
80
		}
81
	}
82
83
	public function getFuncArgs($name) {
84
		foreach ($this->pseudo as $i => $tokens) {
85
			$parts = $this->getFuncParts($i, $tokens);
86
			if ($name === $parts['name']) return $parts['args'];
87
		}
88
	}
89
}
90