- Fixed little issue with autoescape
[haanga.git] / haanga / lexer.lex
bloba4fac9a5e093fe3a86e8362dc75f6f9dc2bfdacf
1 <?php
2 /*
3   +---------------------------------------------------------------------------------+
4   | Copyright (c) 2010 Haanga                                                       |
5   +---------------------------------------------------------------------------------+
6   | Redistribution and use in source and binary forms, with or without              |
7   | modification, are permitted provided that the following conditions are met:     |
8   | 1. Redistributions of source code must retain the above copyright               |
9   |    notice, this list of conditions and the following disclaimer.                |
10   |                                                                                 |
11   | 2. Redistributions in binary form must reproduce the above copyright            |
12   |    notice, this list of conditions and the following disclaimer in the          |
13   |    documentation and/or other materials provided with the distribution.         |
14   |                                                                                 |
15   | 3. All advertising materials mentioning features or use of this software        |
16   |    must display the following acknowledgement:                                  |
17   |    This product includes software developed by César D. Rodas.                  |
18   |                                                                                 |
19   | 4. Neither the name of the César D. Rodas nor the                               |
20   |    names of its contributors may be used to endorse or promote products         |
21   |    derived from this software without specific prior written permission.        |
22   |                                                                                 |
23   | THIS SOFTWARE IS PROVIDED BY CÉSAR D. RODAS ''AS IS'' AND ANY                   |
24   | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED       |
25   | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE          |
26   | DISCLAIMED. IN NO EVENT SHALL CÉSAR D. RODAS BE LIABLE FOR ANY                  |
27   | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES      |
28   | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;    |
29   | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND     |
30   | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT      |
31   | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS   |
32   | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE                     |
33   +---------------------------------------------------------------------------------+
34   | Authors: César Rodas <crodas@php.net>                                           |
35   +---------------------------------------------------------------------------------+
38 require dirname(__FILE__)."/parser.php";
40 function do_parsing($template, $ignore_whitespace=FALSE)
42     $lexer  = new Haanga_Lexer($template, $ignore_whitespace);
43     $parser = new Parser;
44     try {
45         for($i=0; ; $i++) {
46             if  (!$lexer->yylex()) {
47                 break;
48             }
49             //var_dump(array($lexer->token, $lexer->value));
50             $parser->doParse($lexer->token, $lexer->value);
51         }
52     } catch (Exception $e) {
53         throw new CompilerException($e->getMessage(). ' on line '.$lexer->getLine());
54     }
55     $parser->doParse(0, 0);
56     return $parser->body;
59 class Haanga_Lexer
61     private $data;
62     private $N;
63     public $token;
64     public $value;
65     private $line;
66     private $state = 1;
67     private $ignore_whitespace;
69     function __construct($data, $whitespace=FALSE)
70     {
71         $this->data              = $data;
72         $this->N                 = 0;
73         $this->ignore_whitespace = $whitespace;
74         $this->line              = 1;
75     }
77     function getLine()
78     {
79         return $this->line;
80     }
82     public $custom_tags=array();
84     function is_custom_tag()
85     {
86         static $tag=NULL;
87         if (!$tag) {
88             $tag = Extensions::getInstance('Haanga_tag');
89         }
90         $value = $tag->isValid($this->value);
91         $this->token = $value ? $value : Parser::T_ALPHA;
92     }
94 /*!lex2php
95 %input          $this->data
96 %counter        $this->N
97 %token          $this->token
98 %value          $this->value
99 %line           $this->line
100 alpha           = /([a-zA-Z_][a-zA-Z_0-9]*)/
101 number          = /[0-9]/
102 numerals        = /([0-9])+/
103 whitespace      = /[ \r\t\n]+/
104 html            = /([^{]+(.[^%{#])?)+/
105 comment         = /([^\#]+\#\})+/
106 custom_tag_end  = /end([a-zA-Z][a-zA-Z0-9]*)/
107 token_end       = /[^a-zA-Z0-9]/
108 single_string   = /[^'\\]+/
109 double_string   = /[^"\\]+/
111 /*!lex2php
112 %statename IN_HTML
113 "{%" {
114     $this->token = Parser::T_OPEN_TAG;
115     $this->yypushstate(self::IN_CODE);
118 "{#" {
119     $this->token = Parser::T_COMMENT_OPEN;
120     $this->yypushstate(self::IN_COMMENT);
124 "{{" {
125     $this->token = Parser::T_PRINT_OPEN;
126     $this->yypushstate(self::IN_PRINT);
129 html {
130     $this->token = Parser::T_HTML;
134 /*!lex2php
135 %statename IN_CODE
136 "%}" {
137     $this->token = Parser::T_CLOSE_TAG;
138     $this->yypopstate();
141 "." {
142     $this->token = Parser::T_DOT;
145 "for" token_end {
146     $this->token = Parser::T_FOR;
149 "empty" token_end {
150     $this->token = Parser::T_EMPTY;
153 "firstof" token_end {
154     $this->token = Parser::T_FIRST_OF;
157 "block" token_end {
158     $this->token = Parser::T_BLOCK;
161 "&&" { 
162     $this->token = Parser::T_AND;
165 "AND" {
166     $this->token = Parser::T_AND;
169 "||" {
170     $this->token = Parser::T_OR;
173 "OR" {
174     $this->token = Parser::T_OR;
177 "==" {
178     $this->token = Parser::T_EQ;
181 "!=" {
182     $this->token = Parser::T_NE;
185 ">=" {
186     $this->token = Parser::T_GE;
189 "[" {
190     $this->token = Parser::T_BRACKETS_OPEN;
193 "]" {
194     $this->token = Parser::T_BRACKETS_CLOSE;
197 ">" {
198     $this->token = Parser::T_GT;
201 "<" {
202     $this->token = Parser::T_LT;
204 "=<" {
205     $this->token = Parser::T_LE;
208 "|" {
209     $this->token = Parser::T_PIPE;
212 ":" {
213     $this->token = Parser::T_COLON;
216 "filter" token_end {
217     $this->token = Parser::T_FILTER;
220 "regroup" token_end {
221     $this->token = Parser::T_REGROUP;
224 "endfilter" token_end {
225     $this->token = Parser::T_END_FILTER;
228 "autoescape" token_end {
229     $this->token = Parser::T_AUTOESCAPE;
233 "endautoescape" token_end {
234     $this->token = Parser::T_END_AUTOESCAPE;
238 "endblock" token_end {
239     $this->token = Parser::T_END_BLOCK;
242 "ifchanged" token_end {
243     $this->token = Parser::T_IFCHANGED;
246 "else" token_end {
247     $this->token = Parser::T_ELSE;
250 "endifchanged" token_end {
251     $this->token = Parser::T_ENDIFCHANGED;
255 "in" token_end {
256     $this->token = Parser::T_IN;
259 "endfor" token_end {
260     $this->token = Parser::T_CLOSEFOR;
263 "with" token_end {
264     $this->token = Parser::T_WITH;
267 "endwith" token_end {
268     $this->token = Parser::T_ENDWITH;
271 "as" {
272     $this->token = Parser::T_AS;
275 "on" {
276     $this->token = Parser::T_ON;
279 "off" {
280     $this->token = Parser::T_OFF;
283 "by" {
284     $this->token = Parser::T_BY;
287 "if" token_end {
288     $this->token = Parser::T_IF;
291 "else" token_end {
292     $this->token = Parser::T_ELSE;
295 "endif" token_end {
296     $this->token = Parser::T_ENDIF;
299 "(" {
300     $this->token = Parser::T_LPARENT;
303 ")" {
304     $this->token = Parser::T_RPARENT;
307 "%" {
308     $this->token = Parser::T_MOD;
311 "," {
312     $this->token = Parser::T_COMMA;
315 "+" {
316     $this->token = Parser::T_PLUS;
318 "*" {
319     $this->token = Parser::T_TIMES;
322 "/" {
323     $this->token = Parser::T_DIV;
326 "'" {
327     $this->token = Parser::T_STRING_SINGLE_INIT;
328     $this->yypushstate(self::IN_STRING_SINGLE);
331 "\"" {
332     $this->token = Parser::T_STRING_DOUBLE_INIT;
333     $this->yypushstate(self::IN_STRING_DOUBLE);
336 custom_tag_end {
337     $this->token = Parser::T_CUSTOM_END;
340 "extends" token_end {
341     $this->token = Parser::T_EXTENDS;
344 "include" token_end {
345     $this->token = Parser::T_INCLUDE;
348 numerals {
349     $this->token = Parser::T_NUMERIC;
352 numerals "."  numerals {
353     $this->token = Parser::T_NUMERIC;
356 alpha {
357     $this->is_custom_tag();
360 whitespace {
361     return FALSE;
365 /*!lex2php
366 %statename IN_PRINT
367 "}}" {
368     $this->token = Parser::T_PRINT_CLOSE;
369     $this->yypopstate();
372 "|" {
373     $this->token = Parser::T_PIPE;
376 ":" {
377     $this->token = Parser::T_COLON;
381 "." {
382     $this->token = Parser::T_DOT;
385 "[" {
386     $this->token = Parser::T_BRACKETS_OPEN;
389 "]" {
390     $this->token = Parser::T_BRACKETS_CLOSE;
393 numerals {
394     $this->token = Parser::T_NUMERIC;
397 numerals "."  numerals {
398     $this->token = Parser::T_NUMERIC;
401 "'" {
402     $this->token = Parser::T_STRING_SINGLE_INIT;
403     $this->yypushstate(self::IN_STRING_SINGLE);
406 "\"" {
407     $this->token = Parser::T_STRING_DOUBLE_INIT;
408     $this->yypushstate(self::IN_STRING_DOUBLE);
411 alpha {
412     $this->token = Parser::T_ALPHA;
415 whitespace {
416     return FALSE;
420 /*!lex2php
421 %statename IN_STRING_DOUBLE
423 "\\" "\""  {
424     $this->token = Parser::T_STRING_CONTENT;
425     $this->value = "\"";
426     $this->N    += 1;
429 "\'"  {
430     $this->token = Parser::T_STRING_CONTENT;
431     $this->value = "'";
432     $this->N    += 1;
436 "\"" {
437     $this->token = Parser::T_STRING_DOUBLE_END;
438     $this->yypopstate();
441 double_string {
442     $this->token = Parser::T_STRING_CONTENT;
447 /*!lex2php
448 %statename IN_STRING_SINGLE
449 "\'"  {
450     $this->token = Parser::T_STRING_CONTENT;
451     $this->value = "'";
452     $this->N    += 1;
455 "\\" "\""  {
456     $this->token = Parser::T_STRING_CONTENT;
457     $this->value = "\"";
458     $this->N    += 1;
462 "'" {
463     $this->token = Parser::T_STRING_SINGLE_END;
464     $this->yypopstate();
467 single_string {
468     $this->token = Parser::T_STRING_CONTENT;
473 /*!lex2php
474 %statename IN_COMMENT
475 comment {
476     $this->token = Parser::T_COMMENT;
477     $this->yypopstate();