Passed
Pull Request — master (#203)
by
unknown
03:01
created

Parser::checkConsecutiveDots()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6

Duplication

Lines 3
Ratio 50 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 3
loc 6
ccs 4
cts 4
cp 1
rs 10
cc 3
nc 2
nop 0
crap 3
1
<?php
2
3
namespace Egulias\EmailValidator\Parser;
4
5
use Egulias\EmailValidator\EmailLexer;
6
use Egulias\EmailValidator\Exception\AtextAfterCFWS;
7
use Egulias\EmailValidator\Exception\ConsecutiveDot;
8
use Egulias\EmailValidator\Exception\CRLFAtTheEnd;
9
use Egulias\EmailValidator\Exception\CRLFX2;
10
use Egulias\EmailValidator\Exception\CRNoLF;
11
use Egulias\EmailValidator\Exception\ExpectingQPair;
12
use Egulias\EmailValidator\Exception\ExpectingATEXT;
13
use Egulias\EmailValidator\Exception\ExpectingCTEXT;
14
use Egulias\EmailValidator\Exception\UnclosedComment;
15
use Egulias\EmailValidator\Exception\UnclosedQuotedString;
16
use Egulias\EmailValidator\Warning\CFWSNearAt;
17
use Egulias\EmailValidator\Warning\CFWSWithFWS;
18
use Egulias\EmailValidator\Warning\Comment;
19
use Egulias\EmailValidator\Warning\QuotedPart;
20
use Egulias\EmailValidator\Warning\QuotedString;
21
22
abstract class Parser
23
{
24
    protected $warnings = [];
25
    protected $lexer;
26
    protected $openedParenthesis = 0;
27
28 130
    public function __construct(EmailLexer $lexer)
29
    {
30 130
        $this->lexer = $lexer;
31 130
    }
32
33 52
    public function getWarnings()
34
    {
35 52
        return $this->warnings;
36
    }
37
38
    abstract public function parse($str);
39
40
    /** @return int */
41 6
    public function getOpenedParenthesis()
42
    {
43 6
        return $this->openedParenthesis;
44
    }
45
46
    /**
47
     * validateQuotedPair
48
     */
49
    protected function validateQuotedPair()
50
    {
51 View Code Duplication
        if (!($this->lexer->token['type'] === EmailLexer::INVALID
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
52
            || $this->lexer->token['type'] === EmailLexer::C_DEL)) {
53
            throw new ExpectingQPair();
54
        }
55
56
        $previous = $this->lexer->getPrevious() ?: ['type' => null];
57
58
        $this->warnings[QuotedPart::CODE] =
59
            new QuotedPart($previous['type'], $this->lexer->token['type']);
60
    }
61
62 10
    protected function parseComments()
63
    {
64 10
        $this->openedParenthesis = 1;
65 10
        $this->isUnclosedComment();
66 6
        $this->warnings[Comment::CODE] = new Comment();
67 6
        while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) {
68 6
            if ($this->lexer->isNextToken(EmailLexer::S_OPENPARENTHESIS)) {
69 1
                $this->openedParenthesis++;
70 1
            }
71 6
            $this->warnEscaping();
72 6
            $this->lexer->moveNext();
73 6
        }
74
75 6
        $this->lexer->moveNext();
76 6
        if ($this->lexer->isNextTokenAny(array(EmailLexer::GENERIC, EmailLexer::S_EMPTY))) {
77
            throw new ExpectingATEXT();
78
        }
79
80 6
        if ($this->lexer->isNextToken(EmailLexer::S_AT)) {
81 1
            $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt();
82 1
        }
83 6
    }
84
85 13
    protected function isUnclosedComment()
86
    {
87
        try {
88 13
            $this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS);
89 7
            return true;
90 6
        } catch (\RuntimeException $e) {
91 6
            throw new UnclosedComment();
92
        }
93
    }
94
95 16
    protected function parseFWS()
96
    {
97 16
        $previous = $this->lexer->getPrevious() ?: ['type' => null];
98
99 16
        $this->checkCRLFInFWS();
100
101 16
        if ($this->lexer->token['type'] === EmailLexer::S_CR) {
102 2
            throw new CRNoLF();
103
        }
104
105 14 View Code Duplication
        if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type']  !== EmailLexer::S_AT) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106 7
            throw new AtextAfterCFWS();
107
        }
108
109 10 View Code Duplication
        if ($this->lexer->token['type'] === EmailLexer::S_LF || $this->lexer->token['type'] === EmailLexer::C_NUL) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
110
            throw new ExpectingCTEXT();
111
        }
112
113 10
        if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous['type']  === EmailLexer::S_AT) {
114 3
            $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt();
115 3
        } else {
116 8
            $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
117
        }
118 10
    }
119
120 114
    protected function checkConsecutiveDots()
121
    {
122 114 View Code Duplication
        if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
123 3
            throw new ConsecutiveDot();
124
        }
125 114
    }
126
127 108
    protected function isFWS()
128
    {
129 108
        if ($this->escaped()) {
130 1
            return false;
131
        }
132
133 108
        if ($this->lexer->token['type'] === EmailLexer::S_SP ||
134 108
            $this->lexer->token['type'] === EmailLexer::S_HTAB ||
135 108
            $this->lexer->token['type'] === EmailLexer::S_CR ||
136 108
            $this->lexer->token['type'] === EmailLexer::S_LF ||
137 108
            $this->lexer->token['type'] === EmailLexer::CRLF
138 108
        ) {
139 16
            return true;
140
        }
141
142 108
        return false;
143
    }
144
145 115
    protected function escaped()
146
    {
147 115
        $previous = $this->lexer->getPrevious() ?: ['type' => null];
148
149 115
        if ($previous['type'] === EmailLexer::S_BACKSLASH
150 115
            &&
151 3
            $this->lexer->token['type'] !== EmailLexer::GENERIC
152 115
        ) {
153 2
            return true;
154
        }
155
156 115
        return false;
157
    }
158
159 114
    protected function warnEscaping()
160
    {
161 114
        if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) {
162 109
            return false;
163
        }
164
165 7
        if ($this->lexer->isNextToken(EmailLexer::GENERIC)) {
166 6
            throw new ExpectingATEXT();
167
        }
168
169 1
        if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) {
170
            return false;
171
        }
172
173 1
        $previous = $this->lexer->getPrevious() ?: ['type' => null];
174
175 1
        $this->warnings[QuotedPart::CODE] =
176 1
            new QuotedPart($previous['type'], $this->lexer->token['type']);
177 1
        return true;
178
179
    }
180
181 126
    protected function checkDQUOTE($hasClosingQuote)
182
    {
183 126
        if ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE) {
184 105
            return $hasClosingQuote;
185
        }
186 22
        if ($hasClosingQuote) {
187
            return $hasClosingQuote;
188
        }
189 22
        $previous = $this->lexer->getPrevious() ?: ['type' => null, 'value' => ''];
190 22 View Code Duplication
        if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191 1
            throw new ExpectingATEXT();
192
        }
193
194
        try {
195 21
            $this->lexer->find(EmailLexer::S_DQUOTE);
196 20
            $hasClosingQuote = true;
197 21
        } catch (\Exception $e) {
198 1
            throw new UnclosedQuotedString();
199
        }
200 20
        $this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], $this->lexer->token['value']);
201
202 20
        return $hasClosingQuote;
203
    }
204
205 16
    protected function checkCRLFInFWS()
206
    {
207 16
        if ($this->lexer->token['type'] !== EmailLexer::CRLF) {
208 16
            return;
209
        }
210
211
        if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
212
            throw new CRLFX2();
213
        }
214
215
        if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
216
            throw new CRLFAtTheEnd();
217
        }
218
    }
219
}
220