Completed
Push — master ( cc2765...340ff8 )
by Richard
08:19
created

Tokenizer::is_everything_parsed()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 2
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/******************************************************************************
3
 * An implementation of dicto (scg.unibe.ch/dicto) in and for PHP.
4
 *
5
 * Copyright (c) 2016 Richard Klees <[email protected]>
6
 *
7
 * This software is licensed under The MIT License. You should have received
8
 * a copy of the license along with the code.
9
 */
10
11
namespace Lechimp\Dicto\Definition;
12
13
/**
14
 * Tokenizes a rules file.
15
 */
16
class Tokenizer implements \Iterator {
17
    /**
18
     * @var SymbolTable
19
     */
20
    protected $symbol_table;
21
22
    /**
23
     * @var mixed[]
24
     */
25
    protected $tokens;
26
27
    /**
28
     * @var int
29
     */
30
    protected $position;
31
32
    /**
33
     * @var string
34
     */
35
    protected $source;
36
37
    /**
38
     * @var string
39
     */
40
    protected $unparsed;
41
42
    /**
43
     * @var int
44
     */
45
    protected $parsing_position;
46
47
    /**
48
     * @var bool
49
     */
50
    protected $is_end_token_added;
51
52
    static $UNPARSED_PREVIEW_FOR_ERROR = 10;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $UNPARSED_PREVIEW_FOR_ERROR.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
53
54 46
    public function __construct(SymbolTable $symbol_table, $source) {
55 46
        assert('is_string($source)');
56 46
        $this->symbol_table = $symbol_table;
57 46
        $this->tokens = array();
58 46
        $this->position = 0;
59 46
        $this->source = $source;
60 46
        $this->unparsed = $source;
61 46
        $this->is_end_token_added = false;
62 46
    }
63
64
    // Methods from Iterator-interface
65
66
    /**
67
     * @return  array (Symbol,$matches)
68
     */
69 44
    public function current() {
70 44
        $this->maybe_parse_next_token();
71 41
        return $this->tokens[$this->position];
72
    }
73
74
    /**
75
     * @inheritdocs
76
     */
77 1
    public function key() {
78 1
        return $this->position;
79
    }
80
81
    /**
82
     * @inheritdocs
83
     */
84 39
    public function next() {
85 39
        $this->position++;
86 39
    }
87
88
    /**
89
     * @inheritdocs
90
     */
91 1
    public function rewind() {
92 1
        $this->position = 0;
93 1
    }
94
95
    /**
96
     * @inheritdocs
97
     */
98 1
    public function valid() {
99 1
        $this->maybe_parse_next_token();
100 1
        return count($this->tokens) > $this->position;
101
    }
102
103
    /**
104
     * Try to parse the next token if there are currently not enough tokens
105
     * in the tokens to get a token for the current position.
106
     *
107
     * @throws  ParserException if next token can not be parsed.
108
     */
109 45
    public function maybe_parse_next_token() {
110 45
        if (count($this->tokens) <= $this->position) {
111 45
            $this->parse_next_token();
112 42
        }
113 42
    }
114
115
116
    /**
117
     * Try to parse the next token from the source.
118
     *
119
     * @throws  ParserException if next token can not be parsed.
120
     */
121 45
    protected function parse_next_token() {
122 45
        if ($this->is_everything_parsed()) {
123 39
            if (!$this->is_end_token_added) {
124 39
                $this->tokens[] = array(new Symbol("", 0), array(""));
125 39
                $this->is_end_token_added = true;
126 39
            }
127 39
            return;
128
        }
129
130 42
        foreach ($this->symbol_table->symbols() as $symbol) {
131 41
            $re = $symbol->regexp();
132 41
            $matches = array();
133 41
            if (preg_match("%^($re)%s", $this->unparsed, $matches) == 1) {
134 39
                unset($matches[1]);
135 39
                $this->advance($matches[0]);
136 39
                $this->tokens[] = array($symbol, array_values($matches));
137 39
                return;
138
            }
139 37
        }
140
141 3
        $next = substr($this->unparsed, 0, static::$UNPARSED_PREVIEW_FOR_ERROR);
0 ignored issues
show
Bug introduced by
Since $UNPARSED_PREVIEW_FOR_ERROR is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $UNPARSED_PREVIEW_FOR_ERROR to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
142 3
        throw new ParserException("Could not match \"$next\".");
143
    }
144
145
    /**
146
     * Go forward in the string we have parsed so far.
147
     *
148
     * @param  string   $match
149
     * @return null
150
     */
151 39
    public function advance($match) {
152 39
        assert('is_string($match)');
153 39
        $this->unparsed = ltrim
154 39
            ( substr($this->unparsed, strlen($match))
155 39
            , "\t \0\x0B" // don't trim linebreaks
156 39
            );
157 39
    }
158
159
    /**
160
     * Checkout if everything is parsed.
161
     *
162
     * @return  bool
163
     */
164 45
    protected function is_everything_parsed() {
165 45
        return empty($this->unparsed);
166
    }
167
}
168