Merge git://github.com/korsakov/ohcount
[ohcount] / ext / ohcount_native / ragel_parsers / phphtml.rl
1 // phtml.rl written by Mitchell Foral. mitchell<att>caladbolg<dott>net.
2
3 /************************* Required for every parser *************************/
4 #ifndef RAGEL_PHTML_PARSER
5 #define RAGEL_PHTML_PARSER
6
7 #include "ragel_parser_macros.h"
8
9 // the name of the language
10 const char *PHTML_LANG = "html";
11
12 // the languages entities
13 const char *phtml_entities[] = {
14   "space", "comment", "doctype",
15   "tag", "entity", "any"
16 };
17
18 // constants associated with the entities
19 enum {
20   PHTML_SPACE = 0, PHTML_COMMENT, PHTML_DOCTYPE,
21   PHTML_TAG, PHTML_ENTITY, PHTML_ANY
22 };
23
24 /*****************************************************************************/
25
26 #include "css_parser.h"
27 #include "javascript_parser.h"
28 #include "php_parser.h"
29
30 %%{
31   machine phtml;
32   write data;
33   include common "common.rl";
34   #EMBED(css)
35   #EMBED(javascript)
36   #EMBED(php)
37
38   # Line counting machine
39
40   action phtml_ccallback {
41     switch(entity) {
42     case PHTML_SPACE:
43       ls
44       break;
45     case PHTML_ANY:
46       code
47       break;
48     case INTERNAL_NL:
49       emb_internal_newline(PHTML_LANG)
50       break;
51     case NEWLINE:
52       emb_newline(PHTML_LANG)
53       break;
54     case CHECK_BLANK_ENTRY:
55       check_blank_entry(PHTML_LANG)
56     }
57   }
58
59   phtml_comment := (
60     newline %{ entity = INTERNAL_NL; } %phtml_ccallback
61     |
62     ws
63     |
64     ^(space | [\-<]) @comment
65     |
66     '<' '?php' @{ saw(PHP_LANG); fcall phtml_php_line; }
67     |
68     '<' !'?php'
69   )* :>> '-->' @comment @{ fgoto phtml_line; };
70
71   phtml_sq_str := (
72     newline %{ entity = INTERNAL_NL; } %phtml_ccallback
73     |
74     ws
75     |
76     [^\r\n\f\t '\\<] @code
77     |
78     '\\' nonnewline @code
79     |
80     '<' '?php' @{ saw(PHP_LANG); fcall phtml_php_line; }
81     |
82     '<' !'?php'
83   )* '\'' @{ fgoto phtml_line; };
84   phtml_dq_str := (
85     newline %{ entity = INTERNAL_NL; } %phtml_ccallback
86     |
87     ws
88     |
89     [^\r\n\f\t "\\<] @code
90     |
91     '\\' nonnewline @code
92     |
93     '<' '?php' @{ saw(PHP_LANG); fcall phtml_php_line; }
94     |
95     '<' !'?php'
96   )* '"' @{ fgoto phtml_line; };
97
98   ws_or_inl = (ws | newline @{ entity = INTERNAL_NL; } %phtml_ccallback);
99
100   phtml_css_entry = '<' /style/i [^>]+ :>> 'text/css' [^>]+ '>' @code;
101   phtml_css_outry = '</' /style/i ws_or_inl* '>' @check_blank_outry @code;
102   phtml_css_line := |*
103     phtml_css_outry @{ p = ts; fret; };
104     # unmodified CSS patterns
105     spaces      ${ entity = CSS_SPACE; } => css_ccallback;
106     css_comment;
107     css_string;
108     newline     ${ entity = NEWLINE;   } => css_ccallback;
109     ^space      ${ entity = CSS_ANY;   } => css_ccallback;
110   *|;
111
112   phtml_js_entry = '<' /script/i [^>]+ :>> 'text/javascript' [^>]+ '>' @code;
113   phtml_js_outry = '</' /script/i ws_or_inl* '>' @check_blank_outry @code;
114   phtml_js_line := |*
115     phtml_js_outry @{ p = ts; fret; };
116     # unmodified Javascript patterns
117     spaces     ${ entity = JS_SPACE; } => js_ccallback;
118     js_comment;
119     js_string;
120     newline    ${ entity = NEWLINE;  } => js_ccallback;
121     ^space     ${ entity = JS_ANY;   } => js_ccallback;
122   *|;
123
124   phtml_php_entry = ('<?' 'php'?) @code;
125   phtml_php_outry = '?>' @check_blank_outry @code;
126   phtml_php_line := |*
127     phtml_php_outry @{ p = ts; fret; };
128     # unmodified PHP patterns
129     spaces       ${ entity = PHP_SPACE; } => php_ccallback;
130     php_comment;
131     php_string;
132     newline      ${ entity = NEWLINE;   } => php_ccallback;
133     ^space       ${ entity = PHP_ANY;   } => php_ccallback;
134   *|;
135
136   phtml_line := |*
137     phtml_css_entry @{ entity = CHECK_BLANK_ENTRY; } @phtml_ccallback
138       @{ saw(CSS_LANG); } => { fcall phtml_css_line; };
139     phtml_js_entry @{ entity = CHECK_BLANK_ENTRY; } @phtml_ccallback
140       @{ saw(JS_LANG); } => { fcall phtml_js_line; };
141     phtml_php_entry @{ entity = CHECK_BLANK_ENTRY; } @phtml_ccallback
142       @{ saw(PHP_LANG); } => { fcall phtml_php_line; };
143     # standard PHTML patterns
144     spaces       ${ entity = PHTML_SPACE; } => phtml_ccallback;
145     '<!--'       @comment                   => { fgoto phtml_comment; };
146     '\''         @code                      => { fgoto phtml_sq_str;  };
147     '"'          @code                      => { fgoto phtml_dq_str;  };
148     newline      ${ entity = NEWLINE;     } => phtml_ccallback;
149     ^space       ${ entity = PHTML_ANY;   } => phtml_ccallback;
150   *|;
151
152   # Entity machine
153
154   action phtml_ecallback {
155     callback(PHTML_LANG, phtml_entities[entity], cint(ts), cint(te));
156   }
157
158   phtml_css_entry_entity = '<' /style/i [^>]+ :>> 'text/css' [^>]+ '>';
159   phtml_css_outry_entity = '</' /style/i ws_or_inl* '>';
160   phtml_css_entity := |*
161     phtml_css_outry_entity @{ fret; };
162     # unmodified CSS patterns
163     space+             ${ entity = CSS_SPACE;   } => css_ecallback;
164     css_comment_entity ${ entity = CSS_COMMENT; } => css_ecallback;
165     # TODO:
166     ^space;
167   *|;
168
169   phtml_js_entry_entity = '<' /script/i [^>]+ :>> 'text/javascript' [^>]+ '>';
170   phtml_js_outry_entity = '</' /script/i ws_or_inl* '>';
171   phtml_js_entity := |*
172     phtml_js_outry_entity @{ fret; };
173     # unmodified Javascript patterns
174     space+            ${ entity = JS_SPACE;   } => js_ecallback;
175     js_comment_entity ${ entity = JS_COMMENT; } => js_ecallback;
176     # TODO:
177     ^space;
178   *|;
179
180   phtml_php_entry_entity = '<?' 'php'?;
181   phtml_php_outry_entity = '?>';
182   phtml_php_entity := |*
183     phtml_php_outry_entity @{ fret; };
184     # unmodified PHP patterns
185     space+             ${ entity = PHP_SPACE;   } => php_ecallback;
186     php_comment_entity ${ entity = PHP_COMMENT; } => php_ecallback;
187     # TODO:
188     ^space;
189   *|;
190
191   phtml_comment_entity = '<!--' any* :>> '-->';
192
193   phtml_entity := |*
194     # TODO: phtml_ecallback for phtml_*_{entry,outry}_entity
195     phtml_css_entry_entity => { fcall phtml_css_entity; };
196     phtml_js_entry_entity  => { fcall phtml_js_entity;  };
197     phtml_php_entry_entity => { fcall phtml_php_entity; };
198     # standard PHML patterns
199     space+               ${ entity = PHTML_SPACE;   } => phtml_ecallback;
200     phtml_comment_entity ${ entity = PHTML_COMMENT; } => phtml_ecallback;
201     # TODO:
202     ^space;
203   *|;
204 }%%
205
206 /************************* Required for every parser *************************/
207
208 /* Parses a string buffer with PHP code (in HTML).
209  *
210  * @param *buffer The string to parse.
211  * @param length The length of the string to parse.
212  * @param count Integer flag specifying whether or not to count lines. If yes,
213  *   uses the Ragel machine optimized for counting. Otherwise uses the Ragel
214  *   machine optimized for returning entity positions.
215  * @param *callback Callback function. If count is set, callback is called for
216  *   every line of code, comment, or blank with 'lcode', 'lcomment', and
217  *   'lblank' respectively. Otherwise callback is called for each entity found.
218  */
219 void parse_phtml(char *buffer, int length, int count,
220   void (*callback) (const char *lang, const char *entity, int start, int end)
221   ) {
222   init
223
224   const char *seen = 0;
225
226   %% write init;
227   cs = (count) ? phtml_en_phtml_line : phtml_en_phtml_entity;
228   %% write exec;
229
230   // if no newline at EOF; callback contents of last line
231   if (count) { process_last_line(PHTML_LANG) }
232 }
233
234 #endif
235
236 /*****************************************************************************/