3e71c5a7b6b8cd4e38b2c5d17409723967f99c6a
[tatoo.git] / src / xpath / ulexer.ml
1 (***********************************************************************)
2 (*                                                                     *)
3 (*                               TAToo                                 *)
4 (*                                                                     *)
5 (*                     Kim Nguyen, LRI UMR8623                         *)
6 (*                   Université Paris-Sud & CNRS                       *)
7 (*                                                                     *)
8 (*  Copyright 2010-2013 Université Paris-Sud and Centre National de la *)
9 (*  Recherche Scientifique. All rights reserved.  This file is         *)
10 (*  distributed under the terms of the GNU Lesser General Public       *)
11 (*  License, with the special exception on linking described in file   *)
12 (*  ../LICENSE.                                                        *)
13 (*                                                                     *)
14 (***********************************************************************)
15
16 (*
17   Time-stamp: <Last modified on 2013-03-10 14:34:41 CET by Kim Nguyen>
18 *)
19
20 open Xpath_internal_parser
21
22 module L = Ulexing
23
24 exception Error of int * int * string
25
26 let error i j s = raise (Error (i,j,s))
27
28 (***********************************************************)
29 (* Buffer for string literals *)
30
31 let string_buff = Buffer.create 1024
32
33 let store_lexeme lexbuf =
34   Buffer.add_string string_buff (Ulexing.utf8_lexeme lexbuf)
35 let store_ascii = Buffer.add_char string_buff
36 let store_code  = Utf8.store string_buff
37 let clear_buff () = Buffer.clear string_buff
38 let get_stored_string () =
39   let s = Buffer.contents string_buff in
40   clear_buff ();
41   Buffer.clear string_buff;
42   s
43
44 (***********************************************************)
45 (* Lexer *)
46
47 let illegal lexbuf =
48   error
49     (L.lexeme_start lexbuf)
50     (L.lexeme_end lexbuf)
51     "Illegal character"
52
53 let return lexbuf tok = (tok, L.loc lexbuf)
54 let return_loc i j tok = (tok, (i,j))
55
56 let regexp ncname_char =
57   xml_letter | xml_digit | [ '-' '_' '.'] | xml_combining_char | xml_extender
58
59 let hexa_digit = function
60   | '0'..'9' as c -> (Char.code c) - (Char.code '0')
61   | 'a'..'f' as c -> (Char.code c) - (Char.code 'a') + 10
62   | 'A'..'F' as c -> (Char.code c) - (Char.code 'A') + 10
63   | _ -> -1
64
65 let regexp ncname = ( xml_letter ncname_char* ) | ('_' ncname_char+)
66 let regexp digit = ['0'-'9']
67 let regexp float = '-'? digit+ ('.' digit+ (['e''E'] digit+)?)?
68
69 let parse_char lexbuf base i =
70   let s = L.latin1_sub_lexeme lexbuf i (L.lexeme_length lexbuf - i - 1) in
71   let r = ref 0 in
72   for i = 0 to String.length s - 1 do
73     let c = hexa_digit s.[i] in
74     if (c >= base) || (c < 0) then
75       error (L.lexeme_start lexbuf) (L.lexeme_end lexbuf) "invalid digit";
76     r := !r * base + c;
77   done;
78   !r
79
80 let keyword_or_tag s =
81      try
82        List.assoc s [
83          "self", AXIS Ast.Self;
84          "descendant", AXIS (Ast.Descendant false);
85          "child", AXIS Ast.Child;
86          "descendant-or-self", AXIS (Ast.Descendant true);
87          "attribute", AXIS Ast.Attribute;
88          "following-sibling", AXIS Ast.FollowingSibling;
89          "preceding-sibling", AXIS Ast.PrecedingSibling;
90          "parent", AXIS Ast.Parent;
91          "ancestor", AXIS (Ast.Ancestor false);
92          "ancestor-or-self", AXIS (Ast.Ancestor true);
93          "preceding", AXIS Ast.Preceding;
94          "following", AXIS Ast.Following;
95          "and", AND;
96          "or" , OR;
97          "div", DIV;
98          "mod", MOD;
99        ]
100      with
101        _ -> TAG s
102
103
104 let rec token = lexer
105  | [' ' '\t' '\n'] -> token lexbuf
106  | "*" -> STAR
107  | "/" -> SLASH
108  | "//" -> SLASHSLASH
109  | "::" -> COLONCOLON
110  | "("  -> LP
111  | ")"  -> RP
112  | "["  -> LB
113  | "]"  -> RB
114  | ","  -> COMMA
115  | "|"  -> PIPE
116  | "+"  -> ADD
117  | "-"  -> SUB
118  | "<"  -> LT
119  | "<=" -> LTE
120  | ">"  -> GT
121  | ">=" -> GTE
122  | "="  -> EQ
123  | "!=" -> NEQ
124  | "node()" -> NODE
125  | "text()" -> TEXT
126  | '@' ncname -> ATTNAME (L.utf8_lexeme lexbuf)
127
128  | ncname -> keyword_or_tag (L.utf8_lexeme lexbuf)
129  | float ->
130      let s = L.utf8_lexeme lexbuf in
131      (try
132        INT (int_of_string s)
133      with
134        _ -> FLOAT (float_of_string s))
135  | '"' | "'" ->
136      let double_quote = L.latin1_lexeme_char lexbuf 0 = '"' in
137      string (L.lexeme_start lexbuf) double_quote lexbuf;
138      let s = get_stored_string () in
139      STRING s
140
141  | eof -> EOF
142  | _ -> illegal lexbuf
143
144 and string start double = lexer
145   | '"' | "'" ->
146       let d = L.latin1_lexeme_char lexbuf 0 = '"' in
147       if d != double then (store_lexeme lexbuf; string start double lexbuf)
148   | '\\' ['\\' '"' '\''] ->
149       store_ascii (L.latin1_lexeme_char lexbuf 1);
150       string start double lexbuf
151   | "\\n" ->
152       store_ascii '\n'; string start double lexbuf
153   | "\\t" ->
154       store_ascii '\t'; string start double lexbuf
155   | "\\r" ->
156       store_ascii '\r'; string start double lexbuf
157   | '\\' ['0'-'9']+ ';' ->
158       store_code (parse_char lexbuf 10 1);
159       string start double lexbuf
160   | '\\' 'x' ['0'-'9' 'a'-'f' 'A'-'F']+ ';' ->
161       store_code (parse_char lexbuf 16 2);
162       string start double lexbuf
163   | '\\' ->
164       illegal lexbuf;
165   | eof ->
166       error start (start+1) "Unterminated string"
167   | _ ->
168       store_lexeme lexbuf;
169       string start double lexbuf