OTWO-1213 Works around lost encoding in Ruby/C binding layer
[ohcount] / src / parsers / haskell.rl
1 // haskell.rl written by Mitchell Foral. mitchell<att>caladbolg<dott>net
2
3 /************************* Required for every parser *************************/
4 #ifndef OHCOUNT_HASKELL_PARSER_H
5 #define OHCOUNT_HASKELL_PARSER_H
6
7 #include "../parser_macros.h"
8
9 // the name of the language
10 const char *HASKELL_LANG = LANG_HASKELL;
11
12 // the languages entities
13 const char *haskell_entities[] = {
14   "space", "comment", "string", "any"
15 };
16
17 // constants associated with the entities
18 enum {
19   HASKELL_SPACE = 0, HASKELL_COMMENT, HASKELL_STRING, HASKELL_ANY
20 };
21
22 /*****************************************************************************/
23
24 %%{
25   machine haskell;
26   write data;
27   include common "common.rl";
28
29   # Line counting machine
30
31   action haskell_ccallback {
32     switch(entity) {
33     case HASKELL_SPACE:
34       ls
35       break;
36     case HASKELL_ANY:
37       code
38       break;
39     case INTERNAL_NL:
40       std_internal_newline(HASKELL_LANG)
41       break;
42     case NEWLINE:
43       std_newline(HASKELL_LANG)
44     }
45   }
46
47   action haskell_comment_nc_res { nest_count = 0; }
48   action haskell_comment_nc_inc { nest_count++; }
49   action haskell_comment_nc_dec { nest_count--; }
50
51   # TODO: |-- is not a comment
52   haskell_line_comment = '--' [^>] @{ fhold; } @comment nonnewline*;
53   haskell_nested_block_comment =
54     '{-' >haskell_comment_nc_res @comment (
55       newline %{ entity = INTERNAL_NL; } %haskell_ccallback
56       |
57       ws
58                         |
59                         '{-' @haskell_comment_nc_inc @comment
60                         |
61                         '-}' @haskell_comment_nc_dec @comment
62       |
63       (nonnewline - ws) @comment
64     )* :>> ('-}' when { nest_count == 0 }) @comment;
65   haskell_comment = haskell_line_comment | haskell_nested_block_comment;
66
67   haskell_char = '\'' @code ([^\r\n\f'\\] | '\\' nonnewline) '\'';
68   haskell_dq_str =
69     '"' @code (
70       escaped_newline %{ entity = INTERNAL_NL; } %haskell_ccallback
71       |
72       ws
73       |
74       [^\t "\\] @code
75       |
76       '\\' nonnewline @code
77     )* '"';
78   haskell_string = haskell_char | haskell_dq_str;
79
80   haskell_line := |*
81     spaces           ${ entity = HASKELL_SPACE; } => haskell_ccallback;
82     haskell_comment;
83     haskell_string;
84     newline          ${ entity = NEWLINE;       } => haskell_ccallback;
85     ^space           ${ entity = HASKELL_ANY;   } => haskell_ccallback;
86   *|;
87
88   # Entity machine
89
90   action haskell_ecallback {
91     callback(HASKELL_LANG, haskell_entities[entity], cint(ts), cint(te),
92              userdata);
93   }
94
95   haskell_line_comment_entity = '--' [^>] @{ fhold; } nonnewline*;
96   haskell_block_comment_entity = '{-' >haskell_comment_nc_res (
97     '{-' @haskell_comment_nc_inc
98     |
99     '-}' @haskell_comment_nc_dec
100     |
101     any
102   )* :>> ('-}' when { nest_count == 0 });
103   haskell_comment_entity =
104     haskell_line_comment_entity | haskell_block_comment_entity;
105
106   haskell_entity := |*
107     space+                 ${ entity = HASKELL_SPACE;   } => haskell_ecallback;
108     haskell_comment_entity ${ entity = HASKELL_COMMENT; } => haskell_ecallback;
109     # TODO:
110     ^space;
111   *|;
112 }%%
113
114 /************************* Required for every parser *************************/
115
116 /* Parses a string buffer with Haskell code.
117  *
118  * @param *buffer The string to parse.
119  * @param length The length of the string to parse.
120  * @param count Integer flag specifying whether or not to count lines. If yes,
121  *   uses the Ragel machine optimized for counting. Otherwise uses the Ragel
122  *   machine optimized for returning entity positions.
123  * @param *callback Callback function. If count is set, callback is called for
124  *   every line of code, comment, or blank with 'lcode', 'lcomment', and
125  *   'lblank' respectively. Otherwise callback is called for each entity found.
126  */
127 void parse_haskell(char *buffer, int length, int count,
128                    void (*callback) (const char *lang, const char *entity,
129                                      int s, int e, void *udata),
130                    void *userdata
131   ) {
132   init
133
134   int nest_count = 0;
135
136   %% write init;
137   cs = (count) ? haskell_en_haskell_line : haskell_en_haskell_entity;
138   %% write exec;
139
140   // if no newline at EOF; callback contents of last line
141   if (count) { process_last_line(HASKELL_LANG) }
142 }
143
144 #endif
145
146 /*****************************************************************************/