Merge pull request #41 from blackducksw/ubuntu_14
[ohcount] / src / parsers / lua.rl
1 // lua.rl written by Mitchell Foral. mitchell<att>caladbolg<dott>net.
2
3 /************************* Required for every parser *************************/
4 #ifndef OHCOUNT_LUA_PARSER_H
5 #define OHCOUNT_LUA_PARSER_H
6
7 #include "../parser_macros.h"
8
9 // the name of the language
10 const char *LUA_LANG = LANG_LUA;
11
12 // the languages entities
13 const char *lua_entities[] = {
14   "space", "comment", "string", "number", "keyword",
15   "identifier", "operator", "any"
16 };
17
18 // constants associated with the entities
19 enum {
20   LUA_SPACE = 0, LUA_COMMENT, LUA_STRING, LUA_NUMBER, LUA_KEYWORD,
21   LUA_IDENTIFIER, LUA_OPERATOR, LUA_ANY
22 };
23
24 /*****************************************************************************/
25
26 %%{
27   machine lua;
28   write data;
29   include common "common.rl";
30
31   # Line counting machine
32
33   action lua_ccallback {
34     switch(entity) {
35     case LUA_SPACE:
36       ls
37       break;
38     case LUA_ANY:
39       code
40       break;
41     case INTERNAL_NL:
42       std_internal_newline(LUA_LANG)
43       break;
44     case NEWLINE:
45       std_newline(LUA_LANG)
46     }
47   }
48
49   action lua_long_ec_res { equal_count = 0; }
50   action lua_long_ec_inc { equal_count++; }
51   action lua_long_ec_dec { equal_count--; }
52
53   lua_long_comment =
54     '--' ('[' >lua_long_ec_res '='* $lua_long_ec_inc '[') @enqueue @comment (
55       newline %{ entity = INTERNAL_NL; } %lua_ccallback
56       |
57       ws
58       |
59       (nonnewline - ws) @comment
60     )* :>> (']' '='* $lua_long_ec_dec ']' when { equal_count == 0 }) @commit;
61   lua_line_comment = '--' @comment nonnewline*;
62   lua_comment = lua_long_comment | lua_line_comment;
63
64   lua_long_string =
65     ('[' >lua_long_ec_res '='* $lua_long_ec_inc '[') @enqueue @code (
66       newline %{ entity = INTERNAL_NL; } %lua_ccallback
67       |
68       ws
69       |
70       (nonnewline - ws) @code
71     )* :>> (']' '='* $lua_long_ec_dec ']' when { equal_count == 0 }) @commit;
72   lua_sq_str =
73     '\'' @code (
74       newline %{ entity = INTERNAL_NL; } %lua_ccallback
75       |
76       ws
77       |
78       [^\r\n\f\t '\\] @code
79       |
80       '\\' nonnewline @code
81     )* '\'';
82   lua_dq_str =
83     '"' @code (
84       newline %{ entity = INTERNAL_NL; } %lua_ccallback
85       |
86       ws
87       |
88       [^\r\n\f\t "\\] @code
89       |
90       '\\' nonnewline @code
91     )* '"';
92   lua_string = lua_sq_str | lua_dq_str | lua_long_string;
93
94   lua_line := |*
95     spaces      ${ entity = LUA_SPACE; } => lua_ccallback;
96     lua_comment;
97     lua_string;
98     newline     ${ entity = NEWLINE;   } => lua_ccallback;
99     ^space      ${ entity = LUA_ANY;   } => lua_ccallback;
100   *|;
101
102   # Entity machine
103
104   action lua_ecallback {
105     callback(LUA_LANG, lua_entities[entity], cint(ts), cint(te), userdata);
106   }
107
108   lua_block_comment_entity =
109     '--[' >lua_long_ec_res '='* $lua_long_ec_inc '[' any*
110     :>> (']' '='* $lua_long_ec_dec ']' when { equal_count == 0 });
111   lua_line_comment_entity = '--' (nonnewline)*;
112   lua_comment_entity = lua_block_comment_entity | lua_line_comment_entity;
113
114   lua_string_entity = sq_str_with_escapes | dq_str_with_escapes;
115
116   lua_integer = '-'? (dec_num | hex_num);
117   lua_number_entity = float | lua_integer;
118
119   lua_keyword_entity =
120     'and' | 'break' | 'do' | 'else' | 'elseif' | 'end' | 'false' | 'for' |
121     'function' | 'if' | 'in' | 'local' | 'nil' | 'not' | 'or' | 'repeat' |
122     'return' | 'then' | 'true' | 'until' | 'while';
123
124   lua_identifier_entity = (alpha | '_') alnum*;
125
126   lua_operator_entity = '~=' | [+\-*/%^#=<>;:,.{}\[\]()];
127
128   lua_entity := |*
129     space+                ${ entity = LUA_SPACE;      } => lua_ecallback;
130     lua_comment_entity    ${ entity = LUA_COMMENT;    } => lua_ecallback;
131     lua_string_entity     ${ entity = LUA_STRING;     } => lua_ecallback;
132     lua_number_entity     ${ entity = LUA_NUMBER;     } => lua_ecallback;
133     lua_identifier_entity ${ entity = LUA_IDENTIFIER; } => lua_ecallback;
134     lua_keyword_entity    ${ entity = LUA_KEYWORD;    } => lua_ecallback;
135     lua_operator_entity   ${ entity = LUA_OPERATOR;   } => lua_ecallback;
136     ^space                ${ entity = LUA_ANY;        } => lua_ecallback;
137   *|;
138 }%%
139
140 /************************* Required for every parser *************************/
141
142 /* Parses a string buffer with Lua code.
143  *
144  * @param *buffer The string to parse.
145  * @param length The length of the string to parse.
146  * @param count Integer flag specifying whether or not to count lines. If yes,
147  *   uses the Ragel machine optimized for counting. Otherwise uses the Ragel
148  *   machine optimized for returning entity positions.
149  * @param *callback Callback function. If count is set, callback is called for
150  *   every line of code, comment, or blank with 'lcode', 'lcomment', and
151  *   'lblank' respectively. Otherwise callback is called for each entity found.
152  */
153 void parse_lua(char *buffer, int length, int count,
154                void (*callback) (const char *lang, const char *entity, int s,
155                                  int e, void *udata),
156                void *userdata
157   ) {
158   init
159
160   int equal_count = 0;
161
162   %% write init;
163   cs = (count) ? lua_en_lua_line : lua_en_lua_entity;
164   %% write exec;
165
166   // if no newline at EOF; callback contents of last line
167   if (count) { process_last_line(LUA_LANG) }
168 }
169
170 #endif
171
172 /*****************************************************************************/