1 // haml.rl written by Fedor Korsakov. spiritusobscurus at gmail dot com
3 /************************* Required for every parser *************************/
4 #ifndef OHCOUNT_HAML_PARSER_H
5 #define OHCOUNT_HAML_PARSER_H
7 #include "../parser_macros.h"
9 // the name of the language
10 const char *HAML_LANG = LANG_HAML;
12 // the languages entities
13 const char *haml_entities[] = {
14 "space", "comment", "string", "element", "element_class",
15 "element_id", "evaluator", "any"
18 // constants associated with the entities
20 HAML_SPACE = 0, HAML_COMMENT, HAML_STRING, HAML_ELEMENT, HAML_ELEMENT_CLASS,
21 HAML_ELEMENT_ID, HAML_EVALUATOR, HAML_ANY
24 /*****************************************************************************/
31 include common "common.rl";
34 # Line counting machine
36 action haml_ccallback {
45 emb_internal_newline(HAML_LANG)
48 emb_newline(HAML_LANG)
50 case CHECK_BLANK_ENTRY:
51 check_blank_entry(HAML_LANG)
55 action haml_indent_level_inc { current_indent_level++; }
56 action haml_indent_level_res { current_indent_level = 0; }
57 action haml_indent_level_set { prior_indent_level = current_indent_level; }
58 action bracket_inc { bracket_level++; }
59 action bracket_dec { bracket_level--; }
60 action bracket_level_res { bracket_level = 0; }
62 haml_indent = ([ ]{2}) @haml_indent_level_inc;
63 haml_indent_init = ([ ]{2} >haml_indent_level_res @haml_indent_level_inc)? haml_indent*;
64 haml_eol = newline >haml_indent_level_res;
65 haml_special_char = [\.%#];
66 haml_ruby_evaluator = "==" | ([&!]? "=") | "-" | "~";
67 haml_comment_delimiter = ("-#" | "/");
69 haml_xhtml_tag_modifier =
70 ('{' >bracket_level_res @code (
71 newline %{ entity = INTERNAL_NL; } %haml_ccallback
75 (nonnewline - ws - [{}]) @code
80 )* :>> ('}' when { bracket_level == 0 }) @code)
82 ('[' >bracket_level_res @code (
83 newline %{ entity = INTERNAL_NL; } %haml_ccallback
91 (nonnewline - ws - '[' - ']') @code
92 )* :>> (']' when { bracket_level == 0 }) @code);
94 haml_xhtml_tag = "%" ((nonnewline-ws-'['-'{')+ - haml_ruby_evaluator) haml_xhtml_tag_modifier? '//'?;
96 haml_block_line_transition =
97 haml_eol %{ entity = INTERNAL_NL;} %haml_ccallback
98 ( newline %{ entity = INTERNAL_NL; } %haml_ccallback )*
99 ( [ ]{2} when {current_indent_level < prior_indent_level} @haml_indent_level_inc )*
100 ( [ ]{2} when {current_indent_level >= prior_indent_level} @haml_indent_level_inc)+;
103 haml_indent_init haml_comment_delimiter >haml_indent_level_set @comment (
104 haml_block_line_transition
108 (nonnewline-ws) @comment
111 haml_comment = haml_block_comment;
116 - haml_comment_delimiter
117 - haml_ruby_evaluator
122 (nonnewline @code | ("|" @code newline %{ entity = INTERNAL_NL;}))*;
127 haml_ruby_evaluator ws @code;
130 newline %{ entity = INTERNAL_NL;} %haml_ccallback
134 haml_ruby_outry @{ p = ts; fret; };
135 spaces ${ entity = RUBY_SPACE; } => ruby_ccallback;
138 newline ${ entity = NEWLINE; } => ruby_ccallback;
139 ^space ${ entity = RUBY_ANY; } => ruby_ccallback;
143 haml_ruby_entry @{entity = CHECK_BLANK_ENTRY; } @{saw(RUBY_LANG)} => {fcall haml_ruby_line; };
144 spaces ${ entity = HAML_SPACE; } => haml_ccallback;
147 newline ${ entity = NEWLINE; } => haml_ccallback;
148 ^space ${ entity = HAML_ANY; } => haml_ccallback;
153 action haml_ecallback {
154 callback(HAML_LANG, haml_entities[entity], cint(ts), cint(te), userdata);
157 haml_element_entity = '%' alnum+;
158 haml_element_class_entity = '.' alnum+;
159 haml_element_id_entity = '#' alnum+;
161 haml_string_entity = (nonnewline
162 - haml_comment_delimiter
163 - haml_ruby_evaluator
168 (nonnewline | ("|" newline))*;
170 haml_evaluator_entity = haml_ruby_evaluator;
172 # TODO: modifier and comment entity machines
175 space+ ${ entity = HAML_SPACE; } => haml_ecallback;
176 haml_element_entity ${ entity = HAML_ELEMENT; } => haml_ecallback;
177 haml_element_class_entity ${ entity = HAML_ELEMENT_CLASS; } => haml_ecallback;
178 haml_element_id_entity ${ entity = HAML_ELEMENT_ID; } => haml_ecallback;
179 haml_evaluator_entity ${ entity = HAML_EVALUATOR; } => haml_ecallback;
180 haml_string_entity ${ entity = HAML_STRING; } => haml_ecallback;
181 ^space ${ entity = HAML_ANY; } => haml_ecallback;
185 /************************* Required for every parser *************************/
187 /* Parses a string buffer with Haml markup.
189 * @param *buffer The string to parse.
190 * @param length The length of the string to parse.
191 * @param count Integer flag specifying whether or not to count lines. If yes,
192 * uses the Ragel machine optimized for counting. Otherwise uses the Ragel
193 * machine optimized for returning entity positions.
194 * @param *callback Callback function. If count is set, callback is called for
195 * every line of code, comment, or blank with 'lcode', 'lcomment', and
196 * 'lblank' respectively. Otherwise callback is called for each entity found.
198 void parse_haml(char *buffer, int length, int count,
199 void (*callback) (const char *lang, const char *entity, int s,
205 int prior_indent_level = 0;
206 int current_indent_level = 0;
207 int bracket_level = 0;
210 cs = (count) ? haml_en_haml_line : haml_en_haml_entity;
213 // if no newline at EOF; callback contents of last line
214 if (count) { process_last_line(HAML_LANG) }
219 /*****************************************************************************/