package kdl
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file lexer.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256open Parser open Printf let error msg = raise @@ Err.CustomLexingError msg (* [Compl] doesn't seem to work *) let space_chars = [%sedlex.regexp? '\t' (* Character Tabulation U+0009 *) | ' ' (* Space U+0020 *) | 0x00A0 (* No-Break-Space U+00A0 *) | 0x1680 (* Ogham Space Mark U+1680 *) | 0x2000 (* En Quad U+2000 *) | 0x2001 (* Em Quad U+2001 *) | 0x2002 (* En Space U+2002 *) | 0x2003 (* Em Space U+2003 *) | 0x2004 (* Three-Per-Em Space U+2004 *) | 0x2005 (* Four-Per-Em Space U+2005 *) | 0x2006 (* Six-Per-Em Space U+2006 *) | 0x2007 (* Figure Space U+2007 *) | 0x2008 (* Punctuation Space U+2008 *) | 0x2009 (* Thin Space U+2009 *) | 0x200A (* Hair Space U+200A *) | 0x202F (* Narrow No-Break Space U+202F *) | 0x205F (* Medium Mathematical Space U+205F *) | 0x3000 (* Ideographic Space U+3000 *) | 0xFEFF (* BOM U+FEFF *) ] let ws = [%sedlex.regexp? Plus space_chars] let newline_chars = [%sedlex.regexp? '\r' (* CR Carriage Return U+000D *) | '\n' (* LF Line Feed U+000A *) | 0x0085 (* NEL Next Line U+0085 *) | 0x000C (* FF Form Feed U+000C *) | 0x2028 (* LS Line Separator U+2028 *) | 0x2029 (* PS Paragraph Separator U+2029 *) ] let newline = [%sedlex.regexp? "\r\n" | newline_chars] (* With this defined as [%sedlex.regexp? ascii_hex_digit], the [(integer | float) identchar+] case surprisingly doesn't work correctly *) let hex_digit = [%sedlex.regexp? Chars "0123456789abcdefABCDEF"] let sign = [%sedlex.regexp? Chars "-+"] let decimal_nat = [%sedlex.regexp? '0'..'9', Star ('0'..'9' | '_')] let exponent = [%sedlex.regexp? Chars "eE", Opt sign, decimal_nat] let decimal_int = [%sedlex.regexp? Opt sign, decimal_nat] let decimal_float = [%sedlex.regexp? Opt sign, decimal_nat, ('.', decimal_nat, Opt exponent | exponent) ] let hex = [%sedlex.regexp? Opt sign, "0x", hex_digit, Star (hex_digit | '_')] let octal = [%sedlex.regexp? Opt sign, "0o", '0'..'7', Star ('0'..'7' | '_')] let binary = [%sedlex.regexp? Opt sign, "0b", Chars "01", Star (Chars "01_")] let integer = [%sedlex.regexp? decimal_int | hex | octal | binary] let float = [%sedlex.regexp? decimal_float] (* Disallowed: Any codepoint with hexadecimal value 0x20 or below Any codepoint with hexadecimal value higher than 0x10FFFF Any of {| \/(){}<>;[]=," |} *) let disallowed_chars = [%sedlex.regexp? Chars "\\/(){}<>;[]=,\"" | 0 .. 0x20 | space_chars | newline_chars] let identchar = [%sedlex.regexp? Sub (any, disallowed_chars)] let startident = [%sedlex.regexp? Sub (identchar, '0'..'9')] let[@inline] new_line lexbuf = let lexeme = Sedlexing.Utf8.lexeme lexbuf in if lexeme <> "\n" && lexeme <> "\r\n" then Sedlexing.new_line lexbuf let string_buffer = Buffer.create 256 let string_start_pos = ref Lexing.dummy_pos let[@inline] set_string_start lexbuf = let start_pos, _ = Sedlexing.lexing_positions lexbuf in string_start_pos := start_pos (* let[@inline] recover_string_location lexbuf = Sedlexing.mark lexbuf 0x1000; Sedlexing.set_position lexbuf !string_start_pos; Sedlexing.start lexbuf; ignore @@ Sedlexing.backtrack lexbuf *) let rec comment depth lexbuf = match%sedlex lexbuf with | newline -> new_line lexbuf; comment depth lexbuf | "/*" -> comment (depth + 1) lexbuf | "*/" -> if depth <= 0 then () else comment (depth - 1) lexbuf | eof -> error "Unterminated comment" | any -> comment depth lexbuf | _ -> assert false let rec line_comment lexbuf = match%sedlex lexbuf with | newline -> new_line lexbuf | eof -> () | any -> line_comment lexbuf | _ -> assert false let rec raw_string hashlen lexbuf = match%sedlex lexbuf with | newline -> new_line lexbuf; Buffer.add_string string_buffer (Sedlexing.Utf8.lexeme lexbuf); raw_string hashlen lexbuf | '"', Star '#' -> let hashes = Sedlexing.Utf8.sub_lexeme lexbuf 1 (Sedlexing.lexeme_length lexbuf - 1) in let hashlen' = String.length hashes in if hashlen = hashlen' then RAW_STRING (Buffer.contents string_buffer) else begin Buffer.add_string string_buffer (Sedlexing.Utf8.lexeme lexbuf); raw_string hashlen lexbuf end | eof -> error "Unterminated raw string" | any -> Buffer.add_string string_buffer (Sedlexing.Utf8.lexeme lexbuf); raw_string hashlen lexbuf | _ -> assert false let rec string lexbuf = match%sedlex lexbuf with | newline -> new_line lexbuf; Buffer.add_string string_buffer (Sedlexing.Utf8.lexeme lexbuf); string lexbuf | "\\n" -> Buffer.add_char string_buffer '\n'; string lexbuf | "\\r" -> Buffer.add_char string_buffer '\r'; string lexbuf | "\\t" -> Buffer.add_char string_buffer '\t'; string lexbuf | "\\\\" -> Buffer.add_char string_buffer '\\'; string lexbuf | "\\/" -> Buffer.add_char string_buffer '/'; string lexbuf | "\\\"" -> Buffer.add_char string_buffer '"'; string lexbuf | "\\b" -> Buffer.add_char string_buffer '\b'; string lexbuf | "\\f" -> Buffer.add_char string_buffer '\012'; string lexbuf | "\\u{", Rep (hex_digit, 1 .. 6), '}' -> let code_str = Sedlexing.Utf8.sub_lexeme lexbuf 3 (Sedlexing.lexeme_length lexbuf - 4) in let code = int_of_string @@ "0x" ^ code_str in if code > 0x10FFFF then error "Invalid unicode code point, cannot be greater than 10FFFF"; if not @@ Uchar.is_valid code then error "Invalid unicode code point"; Buffer.add_utf_8_uchar string_buffer (Uchar.unsafe_of_int code); string lexbuf | '"' -> STRING (Buffer.contents string_buffer) | eof -> error "Unterminated string" | any -> Buffer.add_string string_buffer (Sedlexing.Utf8.lexeme lexbuf); string lexbuf | _ -> assert false let rec line_cont lexbuf = match%sedlex lexbuf with | ws -> line_cont lexbuf | newline -> new_line lexbuf | "//" -> line_comment lexbuf | "/*" -> comment 0 lexbuf; line_cont lexbuf | eof -> error "Unexpected EOF after the '\\' line continuation" | any -> error @@ sprintf "Illegal character '%s' after the '\\' line continuation" (Sedlexing.Utf8.lexeme lexbuf) | _ -> assert false let rec main lexbuf = match%sedlex lexbuf with | ws -> main lexbuf | newline -> new_line lexbuf; NEWLINE | "//" -> line_comment lexbuf; NEWLINE | "/*" -> comment 0 lexbuf; main lexbuf | '\\' -> line_cont lexbuf; main lexbuf | "/-" -> DISABLE | ';' -> SEMI | '(' -> LPAREN | ')' -> RPAREN | '{' -> LBRACE | '}' -> RBRACE | '=' -> EQ | "true" -> TRUE | "false" -> FALSE | "null" -> NULL | integer -> INTEGER (Sedlexing.Utf8.lexeme lexbuf) | float -> let float_str = Sedlexing.Utf8.lexeme lexbuf in begin match float_of_string_opt float_str with | Some f -> FLOAT f | None -> error @@ sprintf "Invalid float literal %s" float_str end | (integer | float), Plus identchar -> error @@ sprintf "Invalid number literal %s" (Sedlexing.Utf8.lexeme lexbuf) | 'r', Star '#', '"' -> let hashes = Sedlexing.Utf8.sub_lexeme lexbuf 1 (Sedlexing.lexeme_length lexbuf - 2) in Buffer.reset string_buffer; set_string_start lexbuf; raw_string (String.length hashes) lexbuf | '"' -> Buffer.reset string_buffer; set_string_start lexbuf; string lexbuf | '-', startident, Star identchar -> IDENT (Sedlexing.Utf8.lexeme lexbuf) | '-' -> IDENT "-" | Sub (startident, '-'), Star identchar -> IDENT (Sedlexing.Utf8.lexeme lexbuf) | eof -> EOF | any -> error @@ sprintf "Illegal character '%s'" (Sedlexing.Utf8.lexeme lexbuf) | _ -> assert false (** This function should be used instead of [Sedlexing.with_tokenizer main] *) let main_tokenizer lexbuf = let lexer () = let token = main lexbuf in let start_pos', end_pos = Sedlexing.lexing_positions lexbuf in let start_pos = match token with | STRING _ | RAW_STRING _ -> !string_start_pos | _ -> start_pos' in token, start_pos, end_pos in lexer (* let query_identchar = [%sedlex.regexp? Sub (identchar, Chars "+~|^$*")] let query_startident = [%sedlex.regexp? Sub (query_identchar, '0'..'9')] (* Lexical analyzer for the KDL Query Language *) let rec query lexbuf = match%sedlex lexbuf with | ws -> query lexbuf | newline -> new_line lexbuf; query lexbuf | '[' -> LBRACKET | ']' -> RBRACKET | '>' -> GT | ">=" -> GTE | '<' -> LT | "<=" -> LTE | '+' -> PLUS | '~' -> TILDE | "||" -> PARALLEL | "^=" -> CARET_EQ | "$=" -> DOLLAR_EQ | "*=" -> STAR_EQ | '-', query_startident, Star query_identchar -> IDENT (Sedlexing.Utf8.lexeme lexbuf) | '-' -> IDENT "-" | Sub (query_startident, '-'), Star query_identchar -> IDENT (Sedlexing.Utf8.lexeme lexbuf) | any -> error @@ sprintf "Illegal character '%s'" (Sedlexing.Utf8.lexeme lexbuf) | _ -> assert false *)