ruby.rl's string and regex literals shouldn't call @code right after '%'.
[ohcount] / ext / ohcount_native / ragel_parsers / javascript.rl
1 // Javascript.rl written by Mitchell Foral. mitchell<att>caladbolg<dott>net.
2
3 /************************* Required for every parser *************************/
4 #ifndef RAGEL_JAVASCRIPT_PARSER
5 #define RAGEL_JAVASCRIPT_PARSER
6
7 #include "ragel_parser_macros.h"
8
9 // the name of the language
10 const char *JS_LANG = "javascript";
11
12 // the languages entities
13 const char *js_entities[] = {
14   "space", "comment", "string", "number", "keyword",
15   "identifier", "operator", "any"
16 };
17
18 // constants associated with the entities
19 enum {
20   JS_SPACE = 0, JS_COMMENT, JS_STRING, JS_NUMBER, JS_KEYWORD,
21   JS_IDENTIFIER, JS_OPERATOR, JS_ANY
22 };
23
24 /*****************************************************************************/
25
26 %%{
27   machine javascript;
28   write data;
29   include common "common.rl";
30
31   # Line counting machine
32
33   action js_ccallback {
34     switch(entity) {
35     case JS_SPACE:
36       ls
37       break;
38     case JS_ANY:
39       code
40       break;
41     case INTERNAL_NL:
42       std_internal_newline(JS_LANG)
43       break;
44     case NEWLINE:
45       std_newline(JS_LANG)
46     }
47   }
48
49   js_line_comment = '//' @comment nonnewline*;
50   js_block_comment =
51     '/*' @comment (
52       newline %{ entity = INTERNAL_NL; } %js_ccallback
53       |
54       ws
55       |
56       (nonnewline - ws) @comment
57     )* :>> '*/';
58   js_comment = js_line_comment | js_block_comment;
59
60   # Does Javascript allow newlines inside strings?
61   # I can't find a definitive answer.
62   js_sq_str =
63     '\'' @code (
64       escaped_newline %{ entity = INTERNAL_NL; } %js_ccallback
65       |
66       ws
67       |
68       [^\t '\\] @code
69       |
70       '\\' nonnewline @code
71     )* '\'';
72   js_dq_str =
73     '"' @code (
74       escaped_newline %{ entity = INTERNAL_NL; } %js_ccallback
75       |
76       ws
77       |
78       [^\t "\\] @code
79       |
80       '\\' nonnewline @code
81     )* '"';
82   js_string = js_sq_str | js_dq_str;
83
84   js_line := |*
85     spaces     ${ entity = JS_SPACE; } => js_ccallback;
86     js_comment;
87     js_string;
88     newline    ${ entity = NEWLINE;  } => js_ccallback;
89     ^space     ${ entity = JS_ANY;   } => js_ccallback;
90   *|;
91
92   # Entity machine
93
94   action js_ecallback {
95     callback(JS_LANG, entity, cint(ts), cint(te));
96   }
97
98   js_entity := 'TODO:';
99 }%%
100
101 /* Parses a string buffer with Javascript code.
102  *
103  * @param *buffer The string to parse.
104  * @param length The length of the string to parse.
105  * @param count Integer flag specifying whether or not to count lines. If yes,
106  *   uses the Ragel machine optimized for counting. Otherwise uses the Ragel
107  *   machine optimized for returning entity positions.
108  * @param *callback Callback function. If count is set, callback is called for
109  *   every line of code, comment, or blank with 'lcode', 'lcomment', and
110  *   'lblank' respectively. Otherwise callback is called for each entity found.
111  */
112 void parse_javascript(char *buffer, int length, int count,
113   void (*callback) (const char *lang, const char *entity, int start, int end)
114   ) {
115   init
116
117   %% write init;
118   cs = (count) ? javascript_en_js_line : javascript_en_js_entity;
119   %% write exec;
120
121   // if no newline at EOF; callback contents of last line
122   if (count) { process_last_line(JS_LANG) }
123 }
124
125 #endif