Merge pull request #41 from blackducksw/ubuntu_14
[ohcount] / src / parsers / chaiscript.rl
1 // Chaiscript.rl written by Jason Turner. lefticus<att>gmail<dott>com
2 // based on Javascript.rl written by Mitchell Foral. mitchell<att>caladbolg<dott>net.
3
4 /************************* Required for every parser *************************/
5 #ifndef OHCOUNT_CHAISCRIPT_PARSER_H
6 #define OHCOUNT_CHAISCRIPT_PARSER_H
7
8 #include "../parser_macros.h"
9
10 // the name of the language
11 const char *CHAI_LANG = LANG_CHAISCRIPT;
12
13 // the languages entities
14 const char *chai_entities[] = {
15   "space", "comment", "string", "number", "keyword",
16   "identifier", "operator", "any"
17 };
18
19 // constants associated with the entities
20 enum {
21   CHAI_SPACE = 0, CHAI_COMMENT, CHAI_STRING, CHAI_NUMBER, CHAI_KEYWORD,
22   CHAI_IDENTIFIER, CHAI_OPERATOR, CHAI_ANY
23 };
24
25 /*****************************************************************************/
26
27 %%{
28   machine chaiscript;
29   write data;
30   include common "common.rl";
31
32   # Line counting machine
33
34   action chai_ccallback {
35     switch(entity) {
36     case CHAI_SPACE:
37       ls
38       break;
39     case CHAI_ANY:
40       code
41       break;
42     case INTERNAL_NL:
43       std_internal_newline(CHAI_LANG)
44       break;
45     case NEWLINE:
46       std_newline(CHAI_LANG)
47     }
48   }
49
50   chai_line_comment = '//' @comment nonnewline*;
51   chai_block_comment =
52     '/*' @comment (
53       newline %{ entity = INTERNAL_NL; } %chai_ccallback
54       |
55       ws
56       |
57       (nonnewline - ws) @comment
58     )* :>> '*/';
59   chai_comment = chai_line_comment | chai_block_comment;
60
61   # Does Javascript allow newlines inside strings?
62   # I can't find a definitive answer.
63   chai_sq_str =
64     '\'' @code (
65       escaped_newline %{ entity = INTERNAL_NL; } %chai_ccallback
66       |
67       ws
68       |
69       [^\t '\\] @code
70       |
71       '\\' nonnewline @code
72     )* '\'';
73   chai_dq_str =
74     '"' @code (
75       escaped_newline %{ entity = INTERNAL_NL; } %chai_ccallback
76       |
77       ws
78       |
79       [^\t "\\] @code
80       |
81       '\\' nonnewline @code
82     )* '"';
83   chai_regex_str = '/' [^/*] ([^\r\n\f/\\] | '\\' nonnewline)* '/' @code;
84   chai_string = chai_sq_str | chai_dq_str | chai_regex_str;
85
86   chai_line := |*
87     spaces     ${ entity = CHAI_SPACE; } => chai_ccallback;
88     chai_comment;
89     chai_string;
90     newline    ${ entity = NEWLINE;  } => chai_ccallback;
91     ^space     ${ entity = CHAI_ANY;   } => chai_ccallback;
92   *|;
93
94   # Entity machine
95
96   action chai_ecallback {
97     callback(CHAI_LANG, chai_entities[entity], cint(ts), cint(te), userdata);
98   }
99
100   chai_line_comment_entity = '//' nonnewline*;
101   chai_block_comment_entity = '/*' any* :>> '*/';
102   chai_comment_entity = chai_line_comment_entity | chai_block_comment_entity;
103
104   chai_entity := |*
105     space+            ${ entity = CHAI_SPACE;   } => chai_ecallback;
106     chai_comment_entity ${ entity = CHAI_COMMENT; } => chai_ecallback;
107     # TODO:
108     ^space;
109   *|;
110 }%%
111
112 /* Parses a string buffer with Chaiscript code.
113  *
114  * @param *buffer The string to parse.
115  * @param length The length of the string to parse.
116  * @param count Integer flag specifying whether or not to count lines. If yes,
117  *   uses the Ragel machine optimized for counting. Otherwise uses the Ragel
118  *   machine optimized for returning entity positions.
119  * @param *callback Callback function. If count is set, callback is called for
120  *   every line of code, comment, or blank with 'lcode', 'lcomment', and
121  *   'lblank' respectively. Otherwise callback is called for each entity found.
122  */
123 void parse_chaiscript(char *buffer, int length, int count,
124                       void (*callback) (const char *lang, const char *entity,
125                                         int s, int e, void *udata),
126                       void *userdata
127   ) {
128   init
129
130   %% write init;
131   cs = (count) ? chaiscript_en_chai_line : chaiscript_en_chai_entity;
132   %% write exec;
133
134   // if no newline at EOF; callback contents of last line
135   if (count) { process_last_line(CHAI_LANG) }
136 }
137
138 #endif