Completed
Pull Request — master (#5)
by X
02:25
created

FloatParser::parseDnum()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 14
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 20
ccs 15
cts 15
cp 1
crap 4
rs 9.2
1
<?php
2
/**
3
 * parser for PHP serialized float number
4
 */
5
namespace xKerman\Restricted;
6
7
/**
8
 * Parser for PHP serialized float number
9
 *
10
 * format: http://php.net/manual/en/language.types.float.php
11
 */
12
class FloatParser implements ParserInterface
13
{
14
    /**
15
     * parse given `$source` as PHP serialized float number
16
     *
17
     * @param Source $source parser input
18
     * @return array
19
     * @throws UnserializeFailedException
20
     */
21 29
    public function parse(Source $source)
22
    {
23 29
        $source->consume('d');
24 26
        $source->consume(':');
25
26 26
        $result = '';
27
28 26
        if ($source->peek() === 'N') {
29 1
            return $this->parseNan($source);
30
        }
31
32 25
        $parser = new OptionalSignParser();
33 25
        list($sign, $source) = $parser->parse($source);
34 25
        $result .= $sign;
35
36 25
        if ($source->peek() === 'I') {
37 3
            if ($result === '+') {
38 1
                return $source->triggerError();
39
            }
40 2
            return $this->parseInf($source, ($result === '-'));
41
        }
42
43 22
        list($dnum, $source) = $this->parseDnum($source);
44 14
        $result .= $dnum;
45
46 14
        list($exponential, $source) = $this->parseExponentialPart($source);
47 14
        $result .= $exponential;
48
49 14
        $source->consume(';');
50 12
        return [floatval($result), $source];
51
    }
52
53
    /**
54
     * parse given `$source` as NAN
55
     *
56
     * @param Source $source input
57
     * @return array
58
     * @throws UnserializeFailedException
59
     */
60 1
    private function parseNan($source)
61
    {
62 1
        $source->consume('N');
63 1
        $source->consume('A');
64 1
        $source->consume('N');
65 1
        $source->consume(';');
66 1
        return [NAN, $source];
67
    }
68
69
    /**
70
     * parse given `$source` as INF / -INF
71
     *
72
     * @param Source  $source input
73
     * @param boolean $minus  target is negative or not
74
     * @return array
75
     * @throws UnserializeFailedException
76
     */
77 2
    private function parseInf($source, $minus)
78
    {
79 2
        $source->consume('I');
80 2
        $source->consume('N');
81 2
        $source->consume('F');
82 2
        $source->consume(';');
83
84 2
        if ($minus) {
85 1
            return [-INF, $source];
86
        }
87 1
        return [INF, $source];
88
    }
89
90
    /**
91
     * parse given `$source` as sequence of DIGIT
92
     *
93
     * @param Source $source input
94
     * @return array
95
     * @throws UnserializeFailedException
96
     */
97 22
    private function parseDigits($source)
98
    {
99 22
        $result = '';
100 22
        while (ctype_digit($source->peek())) {
101 14
            $result .= $source->peek();
102 14
            $source->next();
103 14
        }
104 22
        return [$result, $source];
105
    }
106
107
    /**
108
     * parse integer part and fraction part
109
     *
110
     * @param Source $source input
111
     * @return array
112
     * @throws UnserializeFailedException
113
     */
114 22
    private function parseDnum($source)
115
    {
116 22
        list($digits, $source) = $this->parseDigits($source);
117 22
        $result = $digits;
118 22
        $hasIntegerPart = ($digits !== '');
119
120 22
        $hasFractionPart = false;
121 22
        if ($source->peek() === '.') {
122 13
            $result .= $source->peek();
123 13
            $source->next();
124 13
            list($digits, $source) = $this->parseDigits($source);
125 13
            $result .= $digits;
126 13
            $hasFractionPart = ($digits !== '');
127 13
        }
128
129 22
        if (!$hasIntegerPart && !$hasFractionPart) {
130 8
            return $source->triggerError();
131
        }
132 14
        return [$result, $source];
133
    }
134
135
    /**
136
     * parse given `$source` as exponentail part
137
     *
138
     * @param Source $source input
139
     * @return array
140
     * @throws UnserializeFailedException
141
     */
142 14
    private function parseExponentialPart($source)
143
    {
144 14
        if (strtolower($source->peek()) !== 'e') {
145 8
            return ['', $source];
146
        }
147
148 6
        $result = $source->peek();
149 6
        $source->next();
150 6
        $parser = new NumberStringParser();
151 6
        list($exp, $source) = $parser->parse($source);
152 6
        $result .= $exp;
153 6
        return [$result, $source];
154
    }
155
}
156