Passed
Branch master (cc4701)
by X
02:35
created

FloatParser::parse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 3
eloc 13
c 5
b 0
f 0
nc 3
nop 1
dl 0
loc 22
ccs 13
cts 13
cp 1
crap 3
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
        if ($source->peek() === 'N') {
27 1
            return $this->parseNan($source);
28
        }
29
30 25
        $parser = new OptionalSignParser();
31 25
        list($sign, $source) = $parser->parse($source);
32
33 25
        if ($source->peek() === 'I') {
34 3
            return $this->parseInf($source, $sign);
35
        }
36
37 22
        list($dnum, $source) = $this->parseDnum($source);
38 14
        list($exponential, $source) = $this->parseExponentialPart($source);
39
40 14
        $source->consume(';');
41 12
        return [floatval(implode([$sign, $dnum, $exponential])), $source];
42
    }
43
44
    /**
45
     * parse given `$source` as NAN
46
     *
47
     * @param Source $source input
48
     * @return array
49
     * @throws UnserializeFailedException
50
     */
51 1
    private function parseNan($source)
52
    {
53 1
        $source->consume('N');
54 1
        $source->consume('A');
55 1
        $source->consume('N');
56 1
        $source->consume(';');
57 1
        return [NAN, $source];
58
    }
59
60
    /**
61
     * parse given `$source` as INF / -INF
62
     *
63
     * @param Source $source input
64
     * @param string $sign   '-', '+' or ''
65
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<integer|double|Source>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
66
     * @throws UnserializeFailedException
67
     */
68 3
    private function parseInf($source, $sign)
69
    {
70 3
        if (!in_array($sign, ['', '-'], true)) {
71 1
            return $source->triggerError();
72
        }
73
74 2
        $source->consume('I');
75 2
        $source->consume('N');
76 2
        $source->consume('F');
77 2
        $source->consume(';');
78
79 2
        if ($sign === '-') {
80 1
            return [-INF, $source];
81
        }
82 1
        return [INF, $source];
83
    }
84
85
    /**
86
     * parse given `$source` as sequence of DIGIT
87
     *
88
     * @param Source $source input
89
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string|Source>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
90
     * @throws UnserializeFailedException
91
     */
92 22
    private function parseDigits($source)
93
    {
94 22
        $result = '';
95 22
        while (ctype_digit($source->peek())) {
96 14
            $result .= $source->peek();
97 14
            $source->next();
98 14
        }
99 22
        return [$result, $source];
100
    }
101
102
    /**
103
     * parse integer part and fraction part
104
     *
105
     * @param Source $source input
106
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string|Source>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
107
     * @throws UnserializeFailedException
108
     */
109 22
    private function parseDnum($source)
110
    {
111 22
        list($digits, $source) = $this->parseDigits($source);
112 22
        $result = $digits;
113 22
        $hasIntegerPart = ($digits !== '');
114
115 22
        $hasFractionPart = false;
116 22
        if ($source->peek() === '.') {
117 13
            $result .= $source->peek();
118 13
            $source->next();
119 13
            list($digits, $source) = $this->parseDigits($source);
120 13
            $result .= $digits;
121 13
            $hasFractionPart = ($digits !== '');
122 13
        }
123
124 22
        if (!$hasIntegerPart && !$hasFractionPart) {
125 8
            return $source->triggerError();
126
        }
127 14
        return [$result, $source];
128
    }
129
130
    /**
131
     * parse given `$source` as exponentail part
132
     *
133
     * @param Source $source input
134
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string|Source>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
135
     * @throws UnserializeFailedException
136
     */
137 14
    private function parseExponentialPart($source)
138
    {
139 14
        if (strtolower($source->peek()) !== 'e') {
140 8
            return ['', $source];
141
        }
142
143 6
        $result = $source->peek();
144 6
        $source->next();
145 6
        $parser = new NumberStringParser();
146 6
        list($exp, $source) = $parser->parse($source);
147 6
        $result .= $exp;
148 6
        return [$result, $source];
149
    }
150
}
151