2424
2525namespace PHPDataGen \Parsing ;
2626
27+ use PHPDataGen \Exception \ParsingException ;
28+
2729/**
2830 * Parsing conveyor
2931 */
3032class Conveyor {
3133
34+ /**
35+ * @var string Source string
36+ */
37+ protected $ source = null ;
38+
3239 /**
3340 * @var string Next string
3441 */
@@ -53,7 +60,9 @@ class Conveyor {
5360 * @param string $source Source of conveyor
5461 */
5562 public function __construct (string $ source ) {
63+ $ this ->source = $ source ;
5664 $ this ->next = $ source ;
65+
5766 $ this ->length = strlen ($ source );
5867 }
5968
@@ -66,6 +75,23 @@ public function length(): int {
6675 return $ this ->length ;
6776 }
6877
78+ public function makeException (string $ description , int $ code = 0 , \Throwable $ previous ): ParsingException {
79+ $ offset = strlen ($ this ->source ) - $ this ->length ;
80+
81+ for (; $ offset > 0 ; --$ offset ) {
82+ // TODO Configurable newline symbol
83+ if ($ this ->source [$ offset ] === '\n ' ) {
84+ break ;
85+ }
86+ }
87+ ++$ offset ;
88+
89+ $ line = substr ($ this ->source , $ offset );
90+ $ line = substr ($ line , 0 , strpos ($ line , "\n" ));
91+
92+ return new ParsingException ($ description , $ line , $ this ->row , $ this ->column , $ code , $ previous );
93+ }
94+
6995 /**
7096 * Moves conveyor on specified offset.
7197 * Offset must be pozitive (or null)
@@ -110,8 +136,7 @@ public function readOperator(string $operator, bool $skip = true, bool $required
110136 }
111137
112138 if ($ required ) {
113- // TODO Parsing exception class
114- throw new \Exception ("$ operator not found at {$ this ->line } line {$ this ->row } row " );
139+ throw $ this ->makeException ("\"$ operator \" expected " );
115140 }
116141
117142 return false ;
@@ -152,7 +177,7 @@ public function readNamespace(): string {
152177 return $ matches [0 ];
153178 }
154179
155- throw new \ Exception ( ' Namespace not found ' );
180+ throw $ this -> makeException ( " Namespace expected " );
156181 }
157182
158183 /**
@@ -161,14 +186,14 @@ public function readNamespace(): string {
161186 *
162187 * @return string Class name
163188 */
164- public function readClassname (): string {
189+ public function readName (): string {
165190 if (preg_match ('/^[a-z_] \\w*/i ' , $ this ->next , $ matches ) === 1 ) {
166191 $ this ->move (strlen ($ matches [0 ]));
167192
168193 return $ matches [0 ];
169194 }
170195
171- throw new \ Exception ( ' Class name not found ' );
196+ throw $ this -> makeException ( " Name expected " );
172197 }
173198
174199 /**
@@ -184,7 +209,11 @@ public function readExtendedClassname(): string {
184209 return $ matches [0 ];
185210 }
186211
187- return $ this ->readClassname ();
212+ try {
213+ return $ this ->readName ();
214+ } catch (ParseException $ e ) {
215+ throw $ this ->makeException ("Class name expected " , 0 , $ e );
216+ }
188217 }
189218
190219 /**
@@ -196,7 +225,7 @@ public function readSemicolon() {
196225 return ;
197226 }
198227
199- throw new \ Exception ( ' Semicolon not found ' );
228+ throw $ this -> makeException ( " Semicolon expected " );
200229 }
201230
202231 public function __toString () {
0 commit comments