- Added fixes to AST
[haanga.git] / lib / Haanga / Compiler / Lexer.lex
blobfc4ad534493f46b0060f1a740eee7be74a7f650e
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 class HG_Parser Extends Haanga_Compiler_Parser
40     /* subclass to made easier references to constants */
43 class Haanga_Compiler_Lexer
45     private $data;
46     private $N;
47     public $token;
48     public $value;
49     private $line;
50     private $state = 1;
52     function __construct($data, $compiler)
53     {
54         $this->data     = $data;
55         $this->compiler = $compiler;
56         $this->N        = 0;
57         $this->line     = 1;
58     }
60     function init($template, $compiler)
61     {
62         $lexer  = new Haanga_Compiler_Lexer($template, $compiler);
63         $parser = new Haanga_Compiler_Parser;
65         $parser->compiler = $compiler;
67         try {
68             for($i=0; ; $i++) {
69                 if  (!$lexer->yylex()) {
70                     break;
71                 }
72                 $parser->doParse($lexer->token, $lexer->value);
73             }
74         } catch (Exception $e) {
75             throw new Haanga_Compiler_Exception($e->getMessage(). ' on line '.$lexer->getLine());
76         }
77         $parser->doParse(0, 0);
78         return (array)$parser->body;
79     }
81     function getLine()
82     {
83         return $this->line;
84     }
86     public $custom_tags=array();
88     function is_custom_tag()
89     {
90         static $tag=NULL;
91         if (!$tag) {
92             $tag = Haanga_Extension::getInstance('Tag');
93         }
94         $value = $tag->isValid($this->value);
95         $this->token = $value ? $value : HG_Parser::T_ALPHA;
96     }
98 /*!lex2php
99 %input          $this->data
100 %counter        $this->N
101 %token          $this->token
102 %value          $this->value
103 %line           $this->line
104 alpha           = /([a-zA-Z_][a-zA-Z_0-9]*)/
105 number          = /[0-9]/
106 numerals        = /([0-9])+/
107 whitespace      = /[ \r\t\n]+/
108 html            = /([^{]+(.[^%{#])?)+/
109 comment         = /([^\#]+\#\})+/
110 custom_tag_end  = /end([a-zA-Z][a-zA-Z0-9]*)/
111 token_end       = /[^a-zA-Z0-9_\.]/
112 single_string   = /[^'\\]+/
113 double_string   = /[^"\\]+/
115 /*!lex2php
116 %statename IN_HTML
117 "{%" {
118     $this->token = HG_Parser::T_OPEN_TAG;
119     $this->yypushstate(self::IN_CODE);
122 "{#" {
123     $this->token = HG_Parser::T_COMMENT_OPEN;
124     $this->yypushstate(self::IN_COMMENT);
128 "{{" {
129     $this->token = HG_Parser::T_PRINT_OPEN;
130     $this->yypushstate(self::IN_PRINT);
133 html {
134     $this->token = HG_Parser::T_HTML;
138 /*!lex2php
139 %statename IN_CODE
140 "%}" {
141     $this->token = HG_Parser::T_CLOSE_TAG;
142     $this->yypopstate();
145 "->" {
146     $this->token = HG_Parser::T_OBJ;
150 "." {
151     $this->token = HG_Parser::T_DOT;
154 "buffer" token_end {
155     $this->token = HG_Parser::T_BUFFER;
159 "for" token_end {
160     $this->token = HG_Parser::T_FOR;
163 "empty" token_end {
164     $this->token = HG_Parser::T_EMPTY;
167 "load" token_end {
168     $this->token = HG_Parser::T_LOAD;
171 "block" token_end {
172     $this->token = HG_Parser::T_BLOCK;
175 "&&" { 
176     $this->token = HG_Parser::T_AND;
179 "AND" token_end {
180     $this->token = HG_Parser::T_AND;
183 "||" {
184     $this->token = HG_Parser::T_OR;
187 "OR" token_end {
188     $this->token = HG_Parser::T_OR;
191 "==" {
192     $this->token = HG_Parser::T_EQ;
195 "!=" {
196     $this->token = HG_Parser::T_NE;
199 ">=" {
200     $this->token = HG_Parser::T_GE;
203 "not" token_end {
204     $this->token = HG_Parser::T_NOT;
206     
207 "!" token_end {
208     $this->token = HG_Parser::T_NOT;
210     
212 "[" {
213     $this->token = HG_Parser::T_BRACKETS_OPEN;
216 "]" {
217     $this->token = HG_Parser::T_BRACKETS_CLOSE;
220 ">" {
221     $this->token = HG_Parser::T_GT;
224 "<" {
225     $this->token = HG_Parser::T_LT;
227 "=<" {
228     $this->token = HG_Parser::T_LE;
231 "|" {
232     $this->token = HG_Parser::T_PIPE;
235 ":" {
236     $this->token = HG_Parser::T_COLON;
239 "filter" token_end {
240     $this->token = HG_Parser::T_FILTER;
243 "regroup" token_end {
244     $this->token = HG_Parser::T_REGROUP;
247 "endfilter" token_end {
248     $this->token = HG_Parser::T_END_FILTER;
251 "autoescape" token_end {
252     $this->token = HG_Parser::T_AUTOESCAPE;
256 "endautoescape" token_end {
257     $this->token = HG_Parser::T_END_AUTOESCAPE;
261 "endblock" token_end {
262     $this->token = HG_Parser::T_END_BLOCK;
265 "ifchanged" token_end {
266     $this->token = HG_Parser::T_IFCHANGED;
269 "ifequal" token_end {
270     $this->token = HG_Parser::T_IFEQUAL;
273 "endifequal" token_end {
274     $this->token = HG_Parser::T_END_IFEQUAL;
277 "ifnotequal" token_end {
278     $this->token = HG_Parser::T_IFNOTEQUAL;
281 "endifnotequal" token_end {
282     $this->token = HG_Parser::T_END_IFNOTEQUAL;
286 "else" token_end {
287     $this->token = HG_Parser::T_ELSE;
290 "endifchanged" token_end {
291     $this->token = HG_Parser::T_ENDIFCHANGED;
295 "in" token_end {
296     $this->token = HG_Parser::T_IN;
299 "endfor" token_end {
300     $this->token = HG_Parser::T_CLOSEFOR;
303 "with" token_end {
304     $this->token = HG_Parser::T_WITH;
307 "endwith" token_end {
308     $this->token = HG_Parser::T_ENDWITH;
311 "as" {
312     $this->token = HG_Parser::T_AS;
315 "on" {
316     $this->token = HG_Parser::T_ON;
319 "off" {
320     $this->token = HG_Parser::T_OFF;
323 "by" {
324     $this->token = HG_Parser::T_BY;
327 "if" token_end {
328     $this->token = HG_Parser::T_IF;
331 "else" token_end {
332     $this->token = HG_Parser::T_ELSE;
335 "endif" token_end {
336     $this->token = HG_Parser::T_ENDIF;
339 "_("  {
340     $this->token = HG_Parser::T_INTL;
344 "(" {
345     $this->token = HG_Parser::T_LPARENT;
348 ")" {
349     $this->token = HG_Parser::T_RPARENT;
352 "%" {
353     $this->token = HG_Parser::T_MOD;
356 "," {
357     $this->token = HG_Parser::T_COMMA;
360 "+" {
361     $this->token = HG_Parser::T_PLUS;
363 "-" {
364     $this->token = HG_Parser::T_MINUS;
366 "*" {
367     $this->token = HG_Parser::T_TIMES;
370 "/" {
371     $this->token = HG_Parser::T_DIV;
374 "'" {
375     $this->token = HG_Parser::T_STRING_SINGLE_INIT;
376     $this->yypushstate(self::IN_STRING_SINGLE);
379 "\"" {
380     $this->token = HG_Parser::T_STRING_DOUBLE_INIT;
381     $this->yypushstate(self::IN_STRING_DOUBLE);
384 custom_tag_end {
385     $this->token = HG_Parser::T_CUSTOM_END;
388 "extends" token_end {
389     $this->token = HG_Parser::T_EXTENDS;
392 "include" token_end {
393     $this->token = HG_Parser::T_INCLUDE;
396 numerals {
397     $this->token = HG_Parser::T_NUMERIC;
400 numerals "."  numerals {
401     $this->token = HG_Parser::T_NUMERIC;
404 alpha  {
405     $this->is_custom_tag();
408 whitespace {
409     return FALSE;
413 /*!lex2php
414 %statename IN_PRINT
415 "}}" {
416     $this->token = HG_Parser::T_PRINT_CLOSE;
417     $this->yypopstate();
420 "|" {
421     $this->token = HG_Parser::T_PIPE;
424 ":" {
425     $this->token = HG_Parser::T_COLON;
428 "->" {
429     $this->token = HG_Parser::T_OBJ;
433 "." {
434     $this->token = HG_Parser::T_DOT;
437 "[" {
438     $this->token = HG_Parser::T_BRACKETS_OPEN;
441 "]" {
442     $this->token = HG_Parser::T_BRACKETS_CLOSE;
445 numerals {
446     $this->token = HG_Parser::T_NUMERIC;
449 numerals "."  numerals {
450     $this->token = HG_Parser::T_NUMERIC;
453 "'" {
454     $this->token = HG_Parser::T_STRING_SINGLE_INIT;
455     $this->yypushstate(self::IN_STRING_SINGLE);
458 "\"" {
459     $this->token = HG_Parser::T_STRING_DOUBLE_INIT;
460     $this->yypushstate(self::IN_STRING_DOUBLE);
463 alpha {
464     $this->token = HG_Parser::T_ALPHA;
467 whitespace {
468     return FALSE;
472 /*!lex2php
473 %statename IN_STRING_DOUBLE
475 "\\" "\""  {
476     $this->token = HG_Parser::T_STRING_CONTENT;
477     $this->value = "\"";
478     $this->N    += 1;
481 "\'"  {
482     $this->token = HG_Parser::T_STRING_CONTENT;
483     $this->value = "'";
484     $this->N    += 1;
488 "\"" {
489     $this->token = HG_Parser::T_STRING_DOUBLE_END;
490     $this->yypopstate();
493 double_string {
494     $this->token = HG_Parser::T_STRING_CONTENT;
499 /*!lex2php
500 %statename IN_STRING_SINGLE
501 "\'"  {
502     $this->token = HG_Parser::T_STRING_CONTENT;
503     $this->value = "'";
504     $this->N    += 1;
507 "\\" "\""  {
508     $this->token = HG_Parser::T_STRING_CONTENT;
509     $this->value = "\"";
510     $this->N    += 1;
514 "'" {
515     $this->token = HG_Parser::T_STRING_SINGLE_END;
516     $this->yypopstate();
519 single_string {
520     $this->token = HG_Parser::T_STRING_CONTENT;
525 /*!lex2php
526 %statename IN_COMMENT
527 comment {
528     $this->token = HG_Parser::T_COMMENT;
529     $this->yypopstate();