Merge pull request #41 from blackducksw/ubuntu_14
[ohcount] / src / parsers / python.rl
1 // python.rl written by Mitchell Foral. mitchell<att>caladbolg<dott>net
2
3 /************************* Required for every parser *************************/
4 #ifndef OHCOUNT_PYTHON_PARSER_H
5 #define OHCOUNT_PYTHON_PARSER_H
6
7 #include "../parser_macros.h"
8
9 // the name of the language
10 const char *PYTHON_LANG = LANG_PYTHON;
11
12 // the languages entities
13 const char *python_entities[] = {
14   "space", "comment", "string", "any"
15 };
16
17 // constants associated with the entities
18 enum {
19   PYTHON_SPACE = 0, PYTHON_COMMENT, PYTHON_STRING, PYTHON_ANY
20 };
21
22 /*****************************************************************************/
23
24 %%{
25   machine python;
26   write data;
27   include common "common.rl";
28
29   # Line counting machine
30
31   action python_ccallback {
32     switch(entity) {
33     case PYTHON_SPACE:
34       ls
35       break;
36     case PYTHON_ANY:
37       code
38       break;
39     case INTERNAL_NL:
40       std_internal_newline(PYTHON_LANG)
41       break;
42     case NEWLINE:
43       std_newline(PYTHON_LANG)
44     }
45   }
46
47   python_line_comment = ('#' | '//') @comment nonnewline*;
48   python_block_comment =
49     '/*' @comment (
50       newline %{ entity = INTERNAL_NL; } %python_ccallback
51       |
52       ws
53       |
54       (nonnewline - ws) @comment
55     )* :>> '*/';
56   python_sq_doc_str =
57     '\'\'\'' @comment (
58       newline %{ entity = INTERNAL_NL; } %python_ccallback
59       |
60       ws
61       |
62       (nonnewline - ws) @comment
63     )* :>> '\'\'\'' @comment;
64   python_dq_doc_str =
65     '"""' @comment (
66       newline %{ entity = INTERNAL_NL; } %python_ccallback
67       |
68       ws
69       |
70       (nonnewline - ws) @comment
71     )* :>> '"""' @comment;
72   python_comment = python_line_comment | python_block_comment |
73                    python_sq_doc_str | python_dq_doc_str;
74
75   python_sq_str =
76     '\'' ([^'] | '\'' [^'] @{ fhold; }) @{ fhold; } # make sure it's not '''
77       ([^\r\n\f'\\] | '\\' nonnewline)* '\'';
78   python_dq_str =
79     '"' ([^"] | '"' [^"] @{ fhold; }) @{ fhold; } # make sure it's not """
80       ([^\r\n\f"\\] | '\\' nonnewline)* '"';
81   python_string = (python_sq_str | python_dq_str) @code;
82
83   python_line := |*
84     spaces          ${ entity = PYTHON_SPACE; } => python_ccallback;
85     python_comment;
86     python_string;
87     newline         ${ entity = NEWLINE;      } => python_ccallback;
88     ^space          ${ entity = PYTHON_ANY;   } => python_ccallback;
89   *|;
90
91   # Entity machine
92
93   action python_ecallback {
94     callback(PYTHON_LANG, python_entities[entity], cint(ts), cint(te),
95              userdata);
96   }
97
98   python_line_comment_entity = ('#' | '//') nonnewline*;
99   python_block_comment_entity = '/*' any* :>> '*/';
100   python_sq_doc_str_entity = '\'\'\'' any* :>> '\'\'\'';
101   python_dq_doc_str_entity = '"""' any* :>> '"""';
102   python_comment_entity = python_line_comment_entity |
103     python_block_comment_entity | python_sq_doc_str_entity |
104     python_dq_doc_str_entity;
105
106   python_entity := |*
107     space+                ${ entity = PYTHON_SPACE;   } => python_ecallback;
108     python_comment_entity ${ entity = PYTHON_COMMENT; } => python_ecallback;
109     # TODO:
110     ^space;
111   *|;
112 }%%
113
114 /************************* Required for every parser *************************/
115
116 /* Parses a string buffer with Python 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_python(char *buffer, int length, int count,
128                   void (*callback) (const char *lang, const char *entity, int s,
129                                     int e, void *udata),
130                   void *userdata
131   ) {
132   init
133
134   %% write init;
135   cs = (count) ? python_en_python_line : python_en_python_entity;
136   %% write exec;
137
138   // if no newline at EOF; callback contents of last line
139   if (count) { process_last_line(PYTHON_LANG) }
140 }
141
142 #endif
143
144 /*****************************************************************************/