1<?php
2
3/**
4* @package   s9e\TextFormatter
5* @copyright Copyright (c) 2010-2021 The s9e authors
6* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7*/
8namespace s9e\TextFormatter\Configurator\RendererGenerators\PHP\XPathConvertor\Convertors;
9
10class SingleByteStringFunctions extends AbstractConvertor
11{
12	/**
13	* {@inheritdoc}
14	*/
15	public function getMatchers(): array
16	{
17		return [
18			'Boolean:BooleanFunction:Contains'      => 'contains \\( ((?&String)) , ((?&String)) \\)',
19			'Boolean:BooleanFunction:EndsWith'      => 'ends-with \\( ((?&String)) , ((?&String)) \\)',
20			'Boolean:BooleanFunction:NotContains'   => 'not \\( contains \\( ((?&String)) , ((?&String)) \\) \\)',
21			'Boolean:BooleanFunction:NotEndsWith'   => 'not \\( ends-with \\( ((?&String)) , ((?&String)) \\) \\)',
22			'Boolean:BooleanFunction:NotStartsWith' => 'not \\( starts-with \\( ((?&String)) , ((?&String)) \\) \\)',
23			'Boolean:BooleanFunction:StartsWith'    => 'starts-with \\( ((?&String)) , ((?&String)) \\)',
24			'Number:StringLength'                   => 'string-length \\( ((?&String))? \\)'
25		];
26	}
27
28	/**
29	* Convert a call to contains()
30	*
31	* @param  string $haystack Expression for the haystack part of the call
32	* @param  string $needle   Expression for the needle part of the call
33	* @return string
34	*/
35	public function parseContains($haystack, $needle)
36	{
37		return $this->generateContains($haystack, $needle, true);
38	}
39
40	/**
41	* Convert a call to ends-with()
42	*
43	* @param  string $string    Expression for the string part of the call
44	* @param  string $substring Expression for the substring part of the call
45	* @return string
46	*/
47	public function parseEndsWith($string, $substring)
48	{
49		return $this->generateEndsWith($string, $substring, true);
50	}
51
52	/**
53	* Convert a call to not(contains())
54	*
55	* @param  string $haystack Expression for the haystack part of the call
56	* @param  string $needle   Expression for the needle part of the call
57	* @return string
58	*/
59	public function parseNotContains($haystack, $needle)
60	{
61		return $this->generateContains($haystack, $needle, false);
62	}
63
64	/**
65	* Convert a call to not(ends-with())
66	*
67	* @param  string $string    Expression for the string part of the call
68	* @param  string $substring Expression for the substring part of the call
69	* @return string
70	*/
71	public function parseNotEndsWith($string, $substring)
72	{
73		return $this->generateEndsWith($string, $substring, false);
74	}
75
76	/**
77	* Convert a call to not(starts-with())
78	*
79	* @param  string $string    Expression for the string part of the call
80	* @param  string $substring Expression for the substring part of the call
81	* @return string
82	*/
83	public function parseNotStartsWith($string, $substring)
84	{
85		return $this->generateStartsWith($string, $substring, false);
86	}
87
88	/**
89	* Convert a call to starts-with()
90	*
91	* @param  string $string    Expression for the string part of the call
92	* @param  string $substring Expression for the substring part of the call
93	* @return string
94	*/
95	public function parseStartsWith($string, $substring)
96	{
97		return $this->generateStartsWith($string, $substring, true);
98	}
99
100	/**
101	* Convert a call to string-length()
102	*
103	* @param  string $expr
104	* @return string
105	*/
106	public function parseStringLength($expr = '.')
107	{
108		return "preg_match_all('(.)su'," . $this->recurse($expr) . ')';
109	}
110
111	/**
112	* Generate the code for a call to contains()
113	*
114	* @param  string $haystack Expression for the haystack part of the call
115	* @param  string $needle   Expression for the needle part of the call
116	* @param  bool   $bool     Return value for a positive match
117	* @return string
118	*/
119	protected function generateContains($haystack, $needle, $bool)
120	{
121		$operator = ($bool) ? '!==' : '===';
122
123		return '(strpos(' . $this->recurse($haystack) . ',' . $this->recurse($needle) . ')' . $operator . 'false)';
124	}
125
126	/**
127	* Generate the code for a call to ends-with()
128	*
129	* @param  string $string    Expression for the string part of the call
130	* @param  string $substring Expression for the substring part of the call
131	* @param  bool   $bool      Return value for a positive match
132	* @return string
133	*/
134	protected function generateEndsWith($string, $substring, $bool)
135	{
136		return (preg_match('(^(?:\'[^\']+\'|"[^"]+")$)D', $substring))
137		     ? $this->generateEndsWithLiteral($string, $substring, $bool)
138		     : $this->generateEndsWithExpression($string, $substring, $bool);
139	}
140
141	/**
142	* Generate the code for a call to ends-with() where the second argument is a literal string
143	*
144	* @param  string $string    Expression for the string part of the call
145	* @param  string $substring Expression for a literal substring
146	* @param  bool   $bool      Return value for a positive match
147	* @return string
148	*/
149	protected function generateEndsWithLiteral($string, $substring, $bool)
150	{
151		$operator = ($bool) ? '===' : '!==';
152
153		return '(substr(' . $this->recurse($string) . ',-' . (strlen($substring) - 2) . ')' . $operator . $this->recurse($substring) . ')';
154	}
155
156	/**
157	* Generate the code for a call to ends-with()
158	*
159	* @param  string $string    Expression for the string part of the call
160	* @param  string $substring Expression for the substring part of the call
161	* @param  bool   $bool      Return value for a positive match
162	* @return string
163	*/
164	protected function generateEndsWithExpression($string, $substring, $bool)
165	{
166		$operator = ($bool) ? '' : '!';
167
168		return $operator . "preg_match('('.preg_quote(" . $this->recurse($substring) . ").'$)D'," . $this->recurse($string) . ')';
169	}
170
171	/**
172	* Generate the code for a call to starts-with()
173	*
174	* @param  string $string    Expression for the string part of the call
175	* @param  string $substring Expression for the substring part of the call
176	* @param  bool   $bool      Return value for a positive match
177	* @return string
178	*/
179	protected function generateStartsWith($string, $substring, $bool)
180	{
181		$operator = ($bool) ? '===' : '!==';
182
183		return '(strpos(' . $this->recurse($string) . ',' . $this->recurse($substring) . ')' . $operator . '0)';
184	}
185}