InputDefinitionParser::consumeArgument()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 14
nc 3
nop 0
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
1
<?php
2
/*
3
 * Copyright (c) 2015 Juan José Torroglosa Ramón
4
 *
5
 * This file is part of the Cliphar package.
6
 *
7
 * For the full copyright and license information, please view
8
 * the LICENSE file that was distributed with this source code.
9
 */
10
11
namespace Cliphar\InputDefinition;
12
13
use Cliphar\InputDefinition\Exception\ParserException;
14
use Cliphar\InputDefinition\Lexer\DefinitionLexer;
15
use Cliphar\InputDefinition\Model\Argument;
16
use Cliphar\InputDefinition\Model\InputDefinition;
17
use Cliphar\InputDefinition\Model\Option;
18
19
class InputDefinitionParser
20
{
21
    /**
22
     * @var \Cliphar\InputDefinition\Lexer\DefinitionLexer
23
     */
24
    private $lexer;
25
26
    /**
27
     * @var InputDefinition
28
     */
29
    private $inputDefinition;
30
31
    /**
32
     * @param string $string
33
     * @return InputDefinition
34
     * @throws \Cliphar\InputDefinition\Exception\ParserException
35
     */
36
    public function parse($string)
37
    {
38
        $this->lexer = new DefinitionLexer($string);
39
        list($token, $value, $position) = $this->lexer->getNextToken();
40
        $this->inputDefinition = new InputDefinition();
41
42
        switch ($token) {
43
            case DefinitionLexer::T_OPEN_ARGUMENT_SYMBOL:
44
                $this->consumeArgumentsList();
45
                break;
46
            case DefinitionLexer::T_OPEN_OPTION_SYMBOL:
47
                $this->consumeOptionsList();
48
                break;
49
            case null:
50
                break;
51
            default:
52
                throw new ParserException("Expected argument or option", $token, $value, $position);
53
        }
54
55
        return $this->inputDefinition;
56
    }
57
58
    private function consumeOptionsList()
59
    {
60
        list($token, $value, $pos) = $this->lexer->getLastOccurrence();
61
        while ($token !== null) {
62
            switch ($token) {
63
                case DefinitionLexer::T_OPEN_OPTION_SYMBOL:
64
                    $this->inputDefinition->addOption($this->consumeOption());
65
                    list($token) = $this->lexer->getNextToken();
66
                    break;
67
                case DefinitionLexer::T_OPEN_ARGUMENT_SYMBOL:
68
                    $this->consumeArgumentsList();
69
                    return;
70
                default:
71
                    throw new ParserException("Expected option or argument", $token, $value, $pos);
72
            }
73
        }
74
    }
75
76
    private function consumeOption()
77
    {
78
        $abbreviated = "";
79
80
        list($token, $string, $pos) = $this->lexer->getNextToken();
81
        if ($token !== DefinitionLexer::T_NAME) {
82
            throw new ParserException("Expected T_NAME", $token, $string, $pos);
83
        }
84
85
        $name = $string;
86
        list($token, $string, $pos) = $this->lexer->getNextToken();
87
88
        if ($token === DefinitionLexer::T_ABBREV_SEPARATOR) {
89
            list($token, $string, $pos) = $this->lexer->getNextToken();
90
            if ($token !== DefinitionLexer::T_ABBREV) {
91
                throw new ParserException("Expected abbreviated name", $token, $string, $pos);
92
            }
93
            $abbreviated = $string;
94
95
            list($token, $string, $pos) = $this->lexer->getNextToken();
96
            if ($token !== DefinitionLexer::T_CLOSE_OPTION_SYMBOL) {
97
                throw new ParserException("Expected T_CLOSE_OPTION_SYMBOL", $token, $string, $pos);
98
            }
99
        } else if ($token !== DefinitionLexer::T_CLOSE_OPTION_SYMBOL) {
100
            throw new ParserException("Expected abbreviated or close option", $token, $string, $pos);
101
        }
102
103
        list($token, $string, $pos) = $this->lexer->getNextToken();
104
        list($isOptional, $defaultValue) = $this->consumeModifiers($token, $string, $pos);
105
106
        return new Option(!$isOptional, $name, $abbreviated, $defaultValue);
107
    }
108
109
    private function consumeArgumentsList()
110
    {
111
        list($token) = $this->lexer->getLastOccurrence();
112
        while ($token !== null) {
113
            $this->inputDefinition->addArgument($this->consumeArgument());
114
            list($token) = $this->lexer->getNextToken();
115
        }
116
    }
117
118
    private function consumeArgument()
119
    {
120
        list($token, $string, $pos) = $this->lexer->getNextToken();
121
        switch($token) {
122
            case DefinitionLexer::T_NAME:
123
                $name = $string;
124
                break;
125
            default:
126
                throw new ParserException("Expected T_NAME", $token, $string, $pos);
127
        }
128
129
        list($token, $string, $pos) = $this->lexer->getNextToken();
130
131
        if ($token !== DefinitionLexer::T_CLOSE_ARGUMENT_SYMBOL) {
132
            throw new ParserException("Expected '>'",$token, $string, $pos);
133
        }
134
135
        list($token, $string, $pos) = $this->lexer->getNextToken();
136
137
        list($isOptional, $defaultValue) = $this->consumeModifiers($token, $string, $pos);
138
139
        return new Argument($name, !$isOptional, $defaultValue);
140
    }
141
142
    /**
143
     * @param $token
144
     * @param $string
145
     * @param $pos
146
     * @return array
147
     * @throws \Cliphar\InputDefinition\Exception\LexerException
148
     * @throws \Cliphar\InputDefinition\Exception\ParserException
149
     */
150
    private function consumeModifiers($token, $string, $pos)
151
    {
152
        $isOptional = false;
153
        $defaultValue = null;
154
        switch ($token) {
155
            case DefinitionLexer::T_OPTIONAL_MARK:
156
                $isOptional = true;
157
                break;
158
            case DefinitionLexer::T_EQUAL_SIGN:
159
                list($token, $string, $pos) = $this->lexer->getNextToken();
160
                if ($token !== DefinitionLexer::T_STRING_WITH_SPACES) {
161
                    throw new ParserException("Expected default value", $token, $string, $pos);
162
                }
163
                $defaultValue = str_replace('"', '', $string);
164
                break;
165
            case DefinitionLexer::T_WHITESPACES:
166
                break;
167
            case null:
168
                break;
169
            default:
170
                throw new ParserException("Unexpected token found", $token, $string, $pos);
171
        }
172
173
        if ($token !== DefinitionLexer::T_WHITESPACES) {
174
            list($token, $string, $pos) = $this->lexer->getNextToken();
175
            switch ($token) {
176
                case DefinitionLexer::T_WHITESPACES:
177
                    break;
178
                case null:
179
                    break;
180
                default:
181
                    throw new ParserException("Expected whitespace", $token, $string, $pos);
182
            }
183
            return array($isOptional, $defaultValue);
184
        }
185
        return array($isOptional, $defaultValue);
186
    }
187
}