1
2/*
3  +------------------------------------------------------------------------+
4  | Phalcon Framework													   |
5  +------------------------------------------------------------------------+
6  | Copyright (c) 2011-present Phalcon Team (http://www.phalconphp.com)    |
7  +------------------------------------------------------------------------+
8  | This source file is subject to the New BSD License that is bundled	   |
9  | with this package in the file docs/LICENSE.txt.					       |
10  |																		   |
11  | If you did not receive a copy of the license and are unable to		   |
12  | obtain it through the world-wide-web, please send an email			   |
13  | to license@phalconphp.com so we can send you a copy immediately.	   |
14  +------------------------------------------------------------------------+
15  | Authors: Andres Gutierrez <andres@phalconphp.com>					   |
16  |		  Eduar Carvajal <eduar@phalconphp.com>						       |
17  +------------------------------------------------------------------------+
18*/
19
20#include "php_phalcon.h"
21#include "scanner.h"
22
23#define YYCTYPE unsigned char
24#define YYCURSOR (s->start)
25#define YYLIMIT (s->end)
26#define YYMARKER q
27
28void phvolt_rtrim(phvolt_scanner_token *token) {
29
30	char *cursor, *removed_str;
31	int i;
32	char ch;
33
34	if (token->len > 0) {
35
36		cursor = token->value;
37		cursor += (token->len - 1);
38		for (i = token->len; i > 0; i--) {
39			ch = (*cursor);
40			if (ch == '\t' || ch == '\n' || ch == '\r' || ch == ' ' || ch == '\v') {
41				cursor--;
42				continue;
43			}
44			break;
45		}
46
47		if (i >= 0) {
48			removed_str = emalloc(i + 1);
49			memcpy(removed_str, token->value, i);
50			removed_str[i] = '\0';
51
52			efree(token->value);
53			token->value = removed_str;
54			token->len = i;
55		}
56	}
57
58}
59
60void phvolt_ltrim(phvolt_scanner_token *token) {
61
62	char *cursor, *removed_str;
63	int i;
64
65	if (token->len > 0) {
66
67		cursor = token->value;
68		for (i = 0; i < token->len; i++) {
69			char ch = (*cursor);
70			if (ch == '\t' || ch == '\n' || ch == '\r' || ch == ' ' || ch == '\v') {
71				cursor++;
72				continue;
73			}
74			break;
75		}
76
77		if (i >= 0) {
78			removed_str = emalloc(token->len - i + 1);
79			memcpy(removed_str, token->value + i, token->len - i);
80			removed_str[token->len - i] = '\0';
81
82			efree(token->value);
83			token->value = removed_str;
84			token->len = token->len - i;
85		}
86	}
87
88}
89
90int phvolt_get_token(phvolt_scanner_state *s, phvolt_scanner_token *token) {
91
92	unsigned char next, double_next;
93	char *q = YYCURSOR, *start = YYCURSOR;
94	int status = PHVOLT_SCANNER_RETCODE_IMPOSSIBLE;
95
96	while (PHVOLT_SCANNER_RETCODE_IMPOSSIBLE == status) {
97
98		if (s->mode == PHVOLT_MODE_RAW || s->mode == PHVOLT_MODE_COMMENT) {
99
100			next = '\0';
101			double_next = '\0';
102
103			if (*YYCURSOR == '\n') {
104				s->active_line++;
105			}
106
107			if (*YYCURSOR != '\0') {
108				next = *(YYCURSOR + 1);
109				if (next != '\0') {
110					double_next = *(YYCURSOR + 2);
111				}
112			}
113
114			if (*YYCURSOR == '\0' || (*YYCURSOR == '{' && (next == '%' || next == '{' || next == '#'))) {
115
116				if (next != '#') {
117
118					s->mode = PHVOLT_MODE_CODE;
119
120					if (s->raw_buffer_cursor > 0) {
121
122						token->opcode = PHVOLT_T_RAW_FRAGMENT;
123						token->value = emalloc(sizeof(char) * s->raw_buffer_cursor + 1);
124						memcpy(token->value, s->raw_buffer, s->raw_buffer_cursor);
125						token->value[s->raw_buffer_cursor] = 0;
126						token->len = s->raw_buffer_cursor;
127
128						if (s->whitespace_control == 1) {
129							phvolt_ltrim(token);
130							s->whitespace_control = 0;
131						}
132
133						if (double_next == '-') {
134							phvolt_rtrim(token);
135						}
136
137						s->raw_buffer_cursor = 0;
138						q = YYCURSOR;
139					} else {
140						token->opcode = PHVOLT_T_IGNORE;
141					}
142
143				} else {
144
145					while ((next = *(++YYCURSOR))) {
146						if (next == '#' && *(YYCURSOR + 1) == '}') {
147							YYCURSOR += 2;
148							token->opcode = PHVOLT_T_IGNORE;
149							return 0;
150						} else {
151							if (next == '\n') {
152								s->active_line++;
153							}
154						}
155					}
156
157					return PHVOLT_SCANNER_RETCODE_EOF;
158				}
159
160				return 0;
161
162			} else {
163
164				if (s->raw_buffer_cursor == s->raw_buffer_size) {
165					s->raw_buffer_size += PHVOLT_RAW_BUFFER_SIZE;
166					s->raw_buffer = erealloc(s->raw_buffer, s->raw_buffer_size);
167				}
168
169				memcpy(s->raw_buffer+s->raw_buffer_cursor, YYCURSOR, 1);
170				s->raw_buffer_cursor++;
171
172				++YYCURSOR;
173			}
174
175		} else {
176
177		/*!re2c
178		re2c:indent:top = 2;
179		re2c:yyfill:enable = 0;
180
181		INTEGER = [0-9]+;
182		INTEGER {
183			token->opcode = PHVOLT_T_INTEGER;
184			token->value = estrndup(start, YYCURSOR - start);
185			token->len = YYCURSOR - start;
186			q = YYCURSOR;
187			return 0;
188		}
189
190		DOUBLE = ([0-9]+[\.][0-9]+);
191		DOUBLE {
192			token->opcode = PHVOLT_T_DOUBLE;
193			token->value = estrndup(start, YYCURSOR - start);
194			token->len = YYCURSOR - start;
195			q = YYCURSOR;
196			return 0;
197		}
198
199		'if' {
200			s->statement_position++;
201			token->opcode = PHVOLT_T_IF;
202			return 0;
203		}
204
205		'else' {
206			token->opcode = PHVOLT_T_ELSE;
207			return 0;
208		}
209
210		'elsefor' {
211			token->opcode = PHVOLT_T_ELSEFOR;
212			return 0;
213		}
214
215		'elseif' {
216			token->opcode = PHVOLT_T_ELSEIF;
217			return 0;
218		}
219
220		'endif' {
221			token->opcode = PHVOLT_T_ENDIF;
222			return 0;
223		}
224
225		'for' {
226			s->statement_position++;
227			token->opcode = PHVOLT_T_FOR;
228			return 0;
229		}
230
231		'endfor' {
232			token->opcode = PHVOLT_T_ENDFOR;
233			return 0;
234		}
235
236		'switch' {
237			s->statement_position++;
238			token->opcode = PHVOLT_T_SWITCH;
239			return 0;
240		}
241
242		'case' {
243			token->opcode = PHVOLT_T_CASE;
244			return 0;
245		}
246
247		'default' {
248			token->opcode = PHVOLT_T_DEFAULT;
249
250			// TODO: Make this better.
251			// Issue: https://github.com/phalcon/cphalcon/issues/13242
252			// Introduced: https://github.com/phalcon/cphalcon/pull/13130
253			token->value = estrndup(start, YYCURSOR - start);
254			token->len = YYCURSOR - start;
255			q = YYCURSOR;
256
257			return 0;
258		}
259
260		'endswitch' {
261			token->opcode = PHVOLT_T_ENDSWITCH;
262			return 0;
263		}
264
265		'in' {
266			token->opcode = PHVOLT_T_IN;
267			return 0;
268		}
269
270		'set' {
271			token->opcode = PHVOLT_T_SET;
272			return 0;
273		}
274
275		'null' {
276			token->opcode = PHVOLT_T_NULL;
277			return 0;
278		}
279
280		'false' {
281			token->opcode = PHVOLT_T_FALSE;
282			return 0;
283		}
284
285		'true' {
286			token->opcode = PHVOLT_T_TRUE;
287			return 0;
288		}
289
290		'and' {
291			token->opcode = PHVOLT_T_AND;
292			return 0;
293		}
294
295		'or' {
296			token->opcode = PHVOLT_T_OR;
297			return 0;
298		}
299
300		'block' {
301			s->statement_position++;
302			token->opcode = PHVOLT_T_BLOCK;
303			return 0;
304		}
305
306		'endblock' {
307			token->opcode = PHVOLT_T_ENDBLOCK;
308			return 0;
309		}
310
311		'macro' {
312			s->statement_position++;
313			token->opcode = PHVOLT_T_MACRO;
314			return 0;
315		}
316
317		'endmacro' {
318			token->opcode = PHVOLT_T_ENDMACRO;
319			return 0;
320		}
321
322		'call' {
323			s->statement_position++;
324			token->opcode = PHVOLT_T_CALL;
325			return 0;
326		}
327
328		'endcall' {
329			token->opcode = PHVOLT_T_ENDCALL;
330			return 0;
331		}
332
333		'with' {
334			token->opcode = PHVOLT_T_WITH;
335			return 0;
336		}
337
338		'return' {
339			token->opcode = PHVOLT_T_RETURN;
340			return 0;
341		}
342
343		'extends' {
344			s->statement_position++;
345			token->opcode = PHVOLT_T_EXTENDS;
346			return 0;
347		}
348
349		'is not' {
350			s->statement_position++;
351			token->opcode = PHVOLT_T_NOTEQUALS;
352			return 0;
353		}
354
355		[i][s][ ]+[n][o][t] {
356			s->statement_position++;
357			token->opcode = PHVOLT_T_NOTEQUALS;
358			return 0;
359		}
360
361		'is' {
362			s->statement_position++;
363			token->opcode = PHVOLT_T_IS;
364			return 0;
365		}
366
367		'not' {
368			s->statement_position++;
369			token->opcode = PHVOLT_T_NOT;
370			return 0;
371		}
372
373		'defined' {
374			s->statement_position++;
375			token->opcode = PHVOLT_T_DEFINED;
376			return 0;
377		}
378
379		'include' {
380			s->statement_position++;
381			token->opcode = PHVOLT_T_INCLUDE;
382			return 0;
383		}
384
385		'empty' {
386			s->statement_position++;
387			token->opcode = PHVOLT_T_EMPTY;
388			return 0;
389		}
390
391		'even' {
392			s->statement_position++;
393			token->opcode = PHVOLT_T_EVEN;
394			return 0;
395		}
396
397		'odd' {
398			s->statement_position++;
399			token->opcode = PHVOLT_T_ODD;
400			return 0;
401		}
402
403		'numeric' {
404			s->statement_position++;
405			token->opcode = PHVOLT_T_NUMERIC;
406			return 0;
407		}
408
409		'scalar' {
410			s->statement_position++;
411			token->opcode = PHVOLT_T_SCALAR;
412			return 0;
413		}
414
415		'iterable' {
416			s->statement_position++;
417			token->opcode = PHVOLT_T_ITERABLE;
418			return 0;
419		}
420
421		'cache' {
422			s->statement_position++;
423			token->opcode = PHVOLT_T_CACHE;
424			return 0;
425		}
426
427		'endcache' {
428			token->opcode = PHVOLT_T_ENDCACHE;
429			return 0;
430		}
431
432		'do' {
433			s->statement_position++;
434			token->opcode = PHVOLT_T_DO;
435			return 0;
436		}
437
438		'autoescape' {
439			s->statement_position++;
440			token->opcode = PHVOLT_T_AUTOESCAPE;
441			return 0;
442		}
443
444		'endautoescape' {
445			s->statement_position++;
446			token->opcode = PHVOLT_T_ENDAUTOESCAPE;
447			return 0;
448		}
449
450		'continue' {
451			s->statement_position++;
452			token->opcode = PHVOLT_T_CONTINUE;
453			return 0;
454		}
455
456		'break' {
457			s->statement_position++;
458			token->opcode = PHVOLT_T_BREAK;
459			return 0;
460		}
461
462		'raw' {
463			s->statement_position++;
464			token->opcode = PHVOLT_T_RAW;
465			return 0;
466		}
467
468		'endraw' {
469			s->statement_position++;
470			token->opcode = PHVOLT_T_ENDRAW;
471			return 0;
472		}
473
474		"{%" {
475			s->whitespace_control = 0;
476			token->opcode = PHVOLT_T_OPEN_DELIMITER;
477			return 0;
478		}
479
480		"%}" {
481			s->mode = PHVOLT_MODE_RAW;
482			token->opcode = PHVOLT_T_CLOSE_DELIMITER;
483			return 0;
484		}
485
486		"{%-" {
487			s->whitespace_control = 0;
488			token->opcode = PHVOLT_T_OPEN_DELIMITER;
489			return 0;
490		}
491
492		"-%}" {
493			s->mode = PHVOLT_MODE_RAW;
494			s->whitespace_control = 1;
495			token->opcode = PHVOLT_T_CLOSE_DELIMITER;
496			return 0;
497		}
498
499		"{{" {
500			s->whitespace_control = 0;
501			s->statement_position++;
502			token->opcode = PHVOLT_T_OPEN_EDELIMITER;
503			return 0;
504		}
505
506		"}}" {
507			s->mode = PHVOLT_MODE_RAW;
508			token->opcode = PHVOLT_T_CLOSE_EDELIMITER;
509			return 0;
510		}
511
512		"{{-" {
513			s->whitespace_control = 0;
514			s->statement_position++;
515			token->opcode = PHVOLT_T_OPEN_EDELIMITER;
516			return 0;
517		}
518
519		"-}}" {
520			s->mode = PHVOLT_MODE_RAW;
521			s->whitespace_control = 1;
522			token->opcode = PHVOLT_T_CLOSE_EDELIMITER;
523			return 0;
524		}
525
526		STRING = (["] ([\\]["]|[\\].|[\001-\377]\[\\"])* ["])|(['] ([\\][']|[\\].|[\001-\377]\[\\'])* [']);
527		STRING {
528			token->opcode = PHVOLT_T_STRING;
529			token->value = estrndup(q, YYCURSOR - q - 1);
530			token->len = YYCURSOR - q - 1;
531			q = YYCURSOR;
532			return 0;
533		}
534
535		IDENTIFIER = [\\]?[a-zA-Z\_][a-zA-Z0-9\_\\]*;
536		IDENTIFIER {
537			token->opcode = PHVOLT_T_IDENTIFIER;
538			token->value = estrndup(start, YYCURSOR - start);
539			token->len = YYCURSOR - start;
540			q = YYCURSOR;
541			return 0;
542		}
543
544		"+" {
545			token->opcode = PHVOLT_T_ADD;
546			return 0;
547		}
548
549		"-" {
550			token->opcode = PHVOLT_T_SUB;
551			return 0;
552		}
553
554		"*" {
555			token->opcode = PHVOLT_T_MUL;
556			return 0;
557		}
558
559		"/" {
560			token->opcode = PHVOLT_T_DIV;
561			return 0;
562		}
563
564		"%" {
565			token->opcode = PHVOLT_T_MOD;
566			return 0;
567		}
568
569		"++" {
570			token->opcode = PHVOLT_T_INCR;
571			return 0;
572		}
573
574		"--" {
575			token->opcode = PHVOLT_T_DECR;
576			return 0;
577		}
578
579		"~" {
580			token->opcode = PHVOLT_T_CONCAT;
581			return 0;
582		}
583
584		".." {
585			token->opcode = PHVOLT_T_RANGE;
586			return 0;
587		}
588
589		"." {
590			token->opcode = PHVOLT_T_DOT;
591			return 0;
592		}
593
594		"," {
595			token->opcode = PHVOLT_T_COMMA;
596			return 0;
597		}
598
599		"(" {
600			token->opcode = PHVOLT_T_PARENTHESES_OPEN;
601			return 0;
602		}
603
604		")" {
605			token->opcode = PHVOLT_T_PARENTHESES_CLOSE;
606			return 0;
607		}
608
609		"[" {
610			token->opcode = PHVOLT_T_SBRACKET_OPEN;
611			return 0;
612		}
613
614		"]" {
615			token->opcode = PHVOLT_T_SBRACKET_CLOSE;
616			return 0;
617		}
618
619		"{" {
620			token->opcode = PHVOLT_T_CBRACKET_OPEN;
621			return 0;
622		}
623
624		"}" {
625			token->opcode = PHVOLT_T_CBRACKET_CLOSE;
626			return 0;
627		}
628
629		"<=" {
630			token->opcode = PHVOLT_T_LESSEQUAL;
631			return 0;
632		}
633
634		"=" {
635			token->opcode = PHVOLT_T_ASSIGN;
636			return 0;
637		}
638
639		"+=" {
640			token->opcode = PHVOLT_T_ADD_ASSIGN;
641			return 0;
642		}
643
644		"-=" {
645			token->opcode = PHVOLT_T_SUB_ASSIGN;
646			return 0;
647		}
648
649		"*=" {
650			token->opcode = PHVOLT_T_MUL_ASSIGN;
651			return 0;
652		}
653
654		"/=" {
655			token->opcode = PHVOLT_T_DIV_ASSIGN;
656			return 0;
657		}
658
659		">=" {
660			token->opcode = PHVOLT_T_GREATEREQUAL;
661			return 0;
662		}
663
664		"==" {
665			token->opcode = PHVOLT_T_EQUALS;
666			return 0;
667		}
668
669		"!=" {
670			token->opcode = PHVOLT_T_NOTEQUALS;
671			return 0;
672		}
673
674		"<>" {
675			token->opcode = PHVOLT_T_NOTEQUALS;
676			return 0;
677		}
678
679		"===" {
680			token->opcode = PHVOLT_T_IDENTICAL;
681			return 0;
682		}
683
684		"!==" {
685			token->opcode = PHVOLT_T_NOTIDENTICAL;
686			return 0;
687		}
688
689		"!" {
690			token->opcode = PHVOLT_T_NOT;
691			return 0;
692		}
693
694		"<" {
695			token->opcode = PHVOLT_T_LESS;
696			return 0;
697		}
698
699		">" {
700			token->opcode = PHVOLT_T_GREATER;
701			return 0;
702		}
703
704		"|" {
705			token->opcode = PHVOLT_T_PIPE;
706			return 0;
707		}
708
709		":" {
710			token->opcode = PHVOLT_T_COLON;
711			return 0;
712		}
713
714		"?" {
715			token->opcode = PHVOLT_T_QUESTION;
716			return 0;
717		}
718
719		[ \t\r]+ {
720			token->opcode = PHVOLT_T_IGNORE;
721			return 0;
722		}
723
724		[\n] {
725			s->active_line++;
726			token->opcode = PHVOLT_T_IGNORE;
727			return 0;
728		}
729
730		"\000" {
731			status = PHVOLT_SCANNER_RETCODE_EOF;
732			break;
733		}
734
735		[^] {
736			status = PHVOLT_SCANNER_RETCODE_ERR;
737			break;
738		}
739
740		*/
741
742		}
743	}
744
745	return status;
746}
747