OTWO-1213 Works around lost encoding in Ruby/C binding layer
[ohcount] / src / parsers / clearsilverhtml.rl
1 // cshtml.rl written by Mitchell Foral. mitchell<att>caladbolg<dott>net.
2
3 /************************* Required for every parser *************************/
4 #ifndef OHCOUNT_CSHTML_PARSER_H
5 #define OHCOUNT_CSHTML_PARSER_H
6
7 #include "../parser_macros.h"
8
9 // the name of the language
10 const char *CSHTML_LANG = LANG_HTML;
11
12 // the languages entities
13 const char *cshtml_entities[] = {
14   "space", "comment", "doctype",
15   "tag", "entity", "any"
16 };
17
18 // constants associated with the entities
19 enum {
20   CSHTML_SPACE = 0, CSHTML_COMMENT, CSHTML_DOCTYPE,
21   CSHTML_TAG, CSHTML_ENTITY, CSHTML_ANY
22 };
23
24 /*****************************************************************************/
25
26 #include "css.h"
27 #include "javascript.h"
28 #include "clearsilver.h"
29
30 %%{
31   machine cshtml;
32   write data;
33   include common "common.rl";
34   #EMBED(css)
35   #EMBED(javascript)
36   #EMBED(clearsilver)
37
38   # Line counting machine
39
40   action cshtml_ccallback {
41     switch(entity) {
42     case CSHTML_SPACE:
43       ls
44       break;
45     case CSHTML_ANY:
46       code
47       break;
48     case INTERNAL_NL:
49       emb_internal_newline(CSHTML_LANG)
50       break;
51     case NEWLINE:
52       emb_newline(CSHTML_LANG)
53       break;
54     case CHECK_BLANK_ENTRY:
55       check_blank_entry(CSHTML_LANG)
56     }
57   }
58
59   cshtml_comment := (
60     newline %{ entity = INTERNAL_NL; } %cshtml_ccallback
61     |
62     ws
63     |
64     ^(space | [\-<]) @comment
65     |
66     '<' '?cs' @{ saw(CS_LANG); fcall cshtml_cs_line; }
67     |
68     '<' !'?cs'
69   )* :>> '-->' @comment @{ fgoto cshtml_line; };
70
71   cshtml_sq_str := (
72     newline %{ entity = INTERNAL_NL; } %cshtml_ccallback
73     |
74     ws
75     |
76     [^\r\n\f\t '\\<] @code
77     |
78     '\\' nonnewline @code
79     |
80     '<' '?cs' @{ saw(CS_LANG); fcall cshtml_cs_line; }
81     |
82     '<' !'?cs'
83   )* '\'' @{ fgoto cshtml_line; };
84   cshtml_dq_str := (
85     newline %{ entity = INTERNAL_NL; } %cshtml_ccallback
86     |
87     ws
88     |
89     [^\r\n\f\t "\\<] @code
90     |
91     '\\' nonnewline @code
92     |
93     '<' '?cs' @{ saw(CS_LANG); fcall cshtml_cs_line; }
94     |
95     '<' !'?cs'
96   )* '"' @{ fgoto cshtml_line; };
97
98   ws_or_inl = (ws | newline @{ entity = INTERNAL_NL; } %cshtml_ccallback);
99
100   cshtml_css_entry = '<' /style/i [^>]+ :>> 'text/css' [^>]+ '>' @code;
101   cshtml_css_outry = '</' /style/i ws_or_inl* '>' @check_blank_outry @code;
102   cshtml_css_line := |*
103     cshtml_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   cshtml_js_entry = '<' /script/i [^>]+ :>> 'text/javascript' [^>]+ '>' @code;
113   cshtml_js_outry = '</' /script/i ws_or_inl* '>' @check_blank_outry @code;
114   cshtml_js_line := |*
115     cshtml_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   cshtml_cs_entry = '<?cs' @code;
125   cshtml_cs_outry = '?>' @check_blank_outry @code;
126   cshtml_cs_line := |*
127     cshtml_cs_outry @{ p = ts; fret; };
128     # unmodified Clearsilver patterns
129     spaces      ${ entity = CS_SPACE; } => cs_ccallback;
130     cs_comment;
131     cs_string;
132     newline     ${ entity = NEWLINE;  } => cs_ccallback;
133     ^space      ${ entity = CS_ANY;   } => cs_ccallback;
134   *|;
135
136   cshtml_line := |*
137     cshtml_css_entry @{ entity = CHECK_BLANK_ENTRY; } @cshtml_ccallback
138       @{ saw(CSS_LANG); } => { fcall cshtml_css_line; };
139     cshtml_js_entry @{ entity = CHECK_BLANK_ENTRY; } @cshtml_ccallback
140       @{ saw(JS_LANG); } => { fcall cshtml_js_line; };
141     cshtml_cs_entry @{ entity = CHECK_BLANK_ENTRY; } @cshtml_ccallback
142       @{ saw(CS_LANG); } => { fcall cshtml_cs_line; };
143     # standard CSHTML patterns
144     spaces       ${ entity = CSHTML_SPACE; } => cshtml_ccallback;
145     '<!--'       @comment                    => { fgoto cshtml_comment; };
146     '\''         @code                       => { fgoto cshtml_sq_str;  };
147     '"'          @code                       => { fgoto cshtml_dq_str;  };
148     newline      ${ entity = NEWLINE;      } => cshtml_ccallback;
149     ^space       ${ entity = CSHTML_ANY;   } => cshtml_ccallback;
150   *|;
151
152   # Entity machine
153
154   action cshtml_ecallback {
155     callback(CSHTML_LANG, cshtml_entities[entity], cint(ts), cint(te),
156              userdata);
157   }
158
159   cshtml_css_entry_entity = '<' /style/i [^>]+ :>> 'text/css' [^>]+ '>';
160   cshtml_css_outry_entity = '</' /style/i ws_or_inl* '>';
161   cshtml_css_entity := |*
162     cshtml_css_outry_entity @{ fret; };
163     # unmodified CSS patterns
164     space+             ${ entity = CSS_SPACE;   } => css_ecallback;
165     css_comment_entity ${ entity = CSS_COMMENT; } => css_ecallback;
166     # TODO:
167     ^space;
168   *|;
169
170   cshtml_js_entry_entity = '<' /script/i [^>]+ :>> 'text/javascript' [^>]+ '>';
171   cshtml_js_outry_entity = '</' /script/i ws_or_inl* '>';
172   cshtml_js_entity := |*
173     cshtml_js_outry_entity @{ fret; };
174     # unmodified Javascript patterns
175     space+            ${ entity = JS_SPACE;   } => js_ecallback;
176     js_comment_entity ${ entity = JS_COMMENT; } => js_ecallback;
177     # TODO:
178     ^space;
179   *|;
180
181   cshtml_cs_entry_entity = '<?cs';
182   cshtml_cs_outry_entity = '?>';
183   cshtml_cs_entity := |*
184     cshtml_cs_outry_entity @{ fret; };
185     # unmodified CS patterns
186     space+            ${ entity = CS_SPACE;   } => cs_ecallback;
187     cs_comment_entity ${ entity = CS_COMMENT; } => cs_ecallback;
188     # TODO:
189     ^space;
190   *|;
191
192   cshtml_comment_entity = '<!--' any* :>> '-->';
193
194   cshtml_entity := |*
195     # TODO: cshtml_ecallback for cshtml_*_{entry,outry}_entity
196     cshtml_css_entry_entity => { fcall cshtml_css_entity; };
197     cshtml_js_entry_entity  => { fcall cshtml_js_entity;  };
198     cshtml_cs_entry_entity  => { fcall cshtml_cs_entity;  };
199     # standard CSHTML patterns
200     space+                ${ entity = CSHTML_SPACE;   } => cshtml_ecallback;
201     cshtml_comment_entity ${ entity = CSHTML_COMMENT; } => cshtml_ecallback;
202     # TODO:
203     ^space;
204   *|;
205 }%%
206
207 /************************* Required for every parser *************************/
208
209 /* Parses a string buffer with Clearsilver code (in HTML).
210  *
211  * @param *buffer The string to parse.
212  * @param length The length of the string to parse.
213  * @param count Integer flag specifying whether or not to count lines. If yes,
214  *   uses the Ragel machine optimized for counting. Otherwise uses the Ragel
215  *   machine optimized for returning entity positions.
216  * @param *callback Callback function. If count is set, callback is called for
217  *   every line of code, comment, or blank with 'lcode', 'lcomment', and
218  *   'lblank' respectively. Otherwise callback is called for each entity found.
219  */
220 void parse_cshtml(char *buffer, int length, int count,
221                   void (*callback) (const char *lang, const char *entity, int s,
222                                     int e, void *udata),
223                   void *userdata
224   ) {
225   init
226
227   const char *seen = 0;
228
229   %% write init;
230   cs = (count) ? cshtml_en_cshtml_line : cshtml_en_cshtml_entity;
231   %% write exec;
232
233   // if no newline at EOF; callback contents of last line
234   if (count) { process_last_line(CSHTML_LANG) }
235 }
236
237 #endif
238
239 /*****************************************************************************/