Completed
Push — master ( 9ad54b...895d73 )
by Federico
03:21
created

SubCodeHandler::consume()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 3
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 6
rs 9.4285
1
<?php
2
3
namespace Jade\Compiler;
4
5
/**
6
 * Class Jade\Compiler\SubCodeHandler.
7
 */
8
class SubCodeHandler
9
{
10
    protected $codeHandler;
11
    protected $input;
12
    protected $name;
13
14
    public function __construct(CodeHandler $codeHandler, $input, $name)
15
    {
16
        $this->codeHandler = $codeHandler;
17
        $this->input = $input;
18
        $this->name = $name;
19
    }
20
21
    public function getMiddleString()
22
    {
23
        $input = $this->input;
24
25
        return function ($start, $end) use ($input) {
26
            $offset = $start[1] + strlen($start[0]);
27
28
            return substr($input, $offset, isset($end) ? $end[1] - $offset : strlen($input));
29
        };
30
    }
31
32
    public function handleRecursion(&$result)
33
    {
34
        $getMiddleString = $this->getMiddleString();
35
        $codeHandler = $this->codeHandler;
36
37
        return function ($arg, $name = '') use (&$result, $codeHandler, $getMiddleString) {
38
            list($start, $end) = $arg;
39
            $str = trim($getMiddleString($start, $end));
40
41
            if (!strlen($str)) {
42
                return '';
43
            }
44
45
            $innerCode = $codeHandler->innerCode($str, $name);
46
47
            if (count($innerCode) > 1) {
48
                $result = array_merge($result, array_slice($innerCode, 0, -1));
49
50
                return array_pop($innerCode);
51
            }
52
53
            return $innerCode[0];
54
        };
55
    }
56
57
    protected function handleNestedExpression(&$result)
58
    {
59
        $handleRecursion = $this->handleRecursion($result);
60
        $name = $this->name;
61
62
        return function (&$arguments, $start, $end) use ($name, $handleRecursion) {
63
            if ($end !== false && $start[1] !== $end[1]) {
64
                array_push(
65
                    $arguments,
66
                    $handleRecursion(
67
                        array($start, $end),
68
                        $name * 10 + count($arguments)
69
                    )
70
                );
71
            }
72
        };
73
    }
74
75
    protected function scanSeparators(&$separators, &$result)
76
    {
77
        $handleNested = $this->handleNestedExpression($result);
78
79
        return function (&$arguments, $open, $close) use (&$separators, $handleNested) {
80
            $count = 1;
81
82
            do {
83
                $start = current($separators);
84
85
                do {
86
                    $curr = next($separators);
87
88
                    if ($curr[0] === $open) {
89
                        $count++;
90
                    }
91
                    if ($curr[0] === $close) {
92
                        $count--;
93
                    }
94
                } while ($curr[0] !== null && $count > 0 && $curr[0] !== ',');
95
96
                $handleNested($arguments, $start, current($separators));
97
            } while ($curr !== false && $count > 0);
98
99
            return $count;
100
        };
101
    }
102
103
    public function handleCodeInbetween(&$separators, &$result)
104
    {
105
        $scanSeparators = $this->scanSeparators($separators, $result);
106
        $input = $this->input;
107
108
        return function () use (&$separators, $input, $scanSeparators) {
109
            $arguments = array();
110
111
            $start = current($separators);
112
            $endPair = array(
113
                '[' => ']',
114
                '{' => '}',
115
                '(' => ')',
116
                ',' => false,
117
            );
118
            $open = $start[0];
119
            $close = $endPair[$start[0]];
120
121
            $count = $scanSeparators($arguments, $open, $close);
122
123
            if ($close && $count > 0) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $close of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
124
                throw new \ErrorException($input . "\nMissing closing: " . $close, 14);
125
            }
126
127
            if (($sep = current($separators)) !== false) {
128
                $end = next($separators);
129
                if ($end[0] === null && $sep[1] < $end[1]) {
130
                    $key = count($arguments) - 1;
131
                    $arguments[$key] .= substr($input, $sep[1] + 1, $end[1] - $sep[1] - 1);
132
                }
133
            }
134
135
            return $arguments;
136
        };
137
    }
138
139
    public function getNext($separators)
140
    {
141
        return function ($index) use ($separators) {
142
            if (isset($separators[$index + 1])) {
143
                return $separators[$index + 1];
144
            }
145
        };
146
    }
147
148
    public function addToOutput(&$output, &$key, &$value)
149
    {
150
        return function () use (&$output, &$key, &$value) {
151
            foreach (array('key', 'value') as $var) {
152
                ${$var} = trim(${$var});
153
                if (empty(${$var})) {
154
                    continue;
155
                }
156
                if (preg_match('/^\d*[a-zA-Z_]/', ${$var})) {
157
                    ${$var} = var_export(${$var}, true);
158
                }
159
            }
160
            $output[] = empty($value)
161
                ? $key
162
                : $key . ' => ' . $value;
163
            $key = '';
164
            $value = null;
165
        };
166
    }
167
168
    public function consume()
169
    {
170
        return function (&$argument, $start) {
171
            $argument = substr($argument, strlen($start));
172
        };
173
    }
174
}
175