1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
<?php
namespace Parsers;
use ReflectionFunction;
class FunctionParser implements ParserInterface {
private static $functions = [];
#===============================================================================
# Regular expressions
#===============================================================================
private const FUNCTION_SHELL_REGEX = '#\{\s?(%s)%s\s?\}#';
private const ARGUMENT_PARTS_REGEX = '(?:\:( (?:(?:"[^"]*"|[0-9]+)(?:,[\s]*)?)+))?';
private const ARGUMENT_SPLIT_REGEX = '#("[^"]*"|[0-9]+)(?:,[\s]*)?#';
#===============================================================================
# Register function
#===============================================================================
public static function register(string $name, callable $callback): void {
$Function = new ReflectionFunction($callback);
self::$functions[$name] = [
'callback' => $callback,
'required' => $Function->getNumberOfRequiredParameters()
];
}
#===============================================================================
# Parse functions
#===============================================================================
public function parse(string $text): array {
$functionNames = array_keys(self::$functions);
$functionNames = implode('|', $functionNames);
$pattern = self::FUNCTION_SHELL_REGEX;
$options = self::ARGUMENT_PARTS_REGEX;
preg_match_all(sprintf($pattern, $functionNames, $options), $text, $matches);
foreach(array_map(function($name, $parameters) {
return [$name , $this->parseParameterString($parameters)];
}, $matches[1], $matches[2]) as $match) {
$functions[$match[0]][] = $match[1];
}
return $functions ?? [];
}
#===============================================================================
# Transform functions
#===============================================================================
public function transform(string $text): string {
$functionData = self::$functions;
$functionNames = array_keys($functionData);
$functionNames = implode('|', $functionNames);
$pattern = self::FUNCTION_SHELL_REGEX;
$options = self::ARGUMENT_PARTS_REGEX;
return preg_replace_callback(sprintf($pattern, $functionNames, $options),
function($matches) use($functionData) {
$function = $matches[1];
$callback = $functionData[$function]['callback'];
$required = $functionData[$function]['required'];
$arguments = $this->parseParameterString($matches[2] ?? '');
if(count($arguments) < $required) {
return sprintf('`{%s: *Missing arguments*}`', $function);
}
return $callback(...$arguments);
}, $text);
}
#===============================================================================
# Parse the parameter string found within the function shell
#===============================================================================
private function parseParameterString(string $parameters): array {
preg_match_all(self::ARGUMENT_SPLIT_REGEX, $parameters, $matches);
return array_map(function($argument) {
return trim($argument, '"');
}, $matches[1]);
}
}
|