aab642282749c6d9294a08a40d1028df1a2d78e6
[tatoo.git] / src / xPath.ml
1 (***********************************************************************)
2 (*                                                                     *)
3 (*                               TAToo                                 *)
4 (*                                                                     *)
5 (*                     Kim Nguyen, LRI UMR8623                         *)
6 (*                   Université Paris-Sud & CNRS                       *)
7 (*                                                                     *)
8 (*  Copyright 2010-2012 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 module Ast =
16 struct
17
18   type path = single_path list
19   and single_path = Absolute of step list | Relative of step list
20   and step = axis * test * expr list
21   and axis = Self | Attribute | Child | Descendant | DescendantOrSelf | FollowingSibling
22              | Parent | Ancestor | AncestorOrSelf | PrecedingSibling | Preceding | Following
23
24   and test = QNameSet.t
25
26   and binop = Eq | Neq | Lt | Gt | Lte | Gte | Or | And | Add | Sub | Mult | Div | Mod
27   and unop =  Neg
28   and expr =
29     | Number of [ `Int of int | `Float of float ]
30     | String of string
31     | Fun_call of QName.t * expr list
32     | Path of path
33     | Binop of expr * binop * expr
34     | Unop of unop * expr
35
36
37   type t = path
38
39
40   let text = QNameSet.singleton QName.text
41   let node = QNameSet.any
42   let star =
43     QNameSet.complement (
44       QNameSet.from_list [ QName.text;
45                          QName.document;
46                          QName.cdata_section;
47                          QName.comment])
48
49
50
51   let pp fmt e = Format.fprintf fmt e
52
53   let prio e = match e with
54   | Unop (Neg, _) -> 11
55   | Path _ -> 10
56   | Number _ | String _ | Fun_call _ -> 9
57   | Binop (_,op,_) -> begin match op with
58     | Lt | Lte | Gt | Gte -> 7
59     | Neq | Eq -> 6
60     | And -> 5
61     | Or -> 4
62     | Mult | Div | Mod -> 3
63     | Add | Sub -> 2
64   end
65
66   let print_binop fmt o =
67     pp fmt "%s" begin match o with
68     | Eq -> "="
69     | Neq -> "!="
70     | Lt -> "<"
71     | Gt -> ">"
72     | Lte -> "<="
73     | Gte -> ">="
74     | Or -> "or"
75     | And -> "and"
76     | Add -> "+"
77     | Sub -> "-"
78     | Mult -> "*"
79     | Div -> "div"
80     | Mod -> "mod"
81     end
82   let print_unop fmt o =
83     pp fmt "%s" begin match o with
84     | Neg -> "-"
85     end
86
87   let rec print_path fmt p =
88     Pretty.print_list ~sep:" | " print_single_path fmt p
89
90   and print_single_path fmt p =
91     let l = match p with
92       | Absolute l -> pp fmt "/"; l
93       | Relative l -> l
94     in
95       Pretty.print_list ~sep:"/" print_step fmt l
96
97   and print_step fmt (axis, test, expr) =
98     pp fmt "%a::%a" print_axis axis print_test test;
99     match expr with
100       [] -> ()
101     | l -> pp fmt "[ ";
102         Pretty.print_list ~sep:" ][ " print_expr fmt l;
103         pp fmt " ]"
104
105   and print_axis fmt a = pp fmt "%s" (match a with
106       Self -> "self"
107     | Child -> "child"
108     | Descendant -> "descendant"
109     | DescendantOrSelf -> "descendant-or-self"
110     | FollowingSibling -> "following-sibling"
111     | Attribute -> "attribute"
112     | Ancestor -> "ancestor"
113     | AncestorOrSelf -> "ancestor-or-self"
114     | PrecedingSibling -> "preceding-sibling"
115     | Parent -> "parent"
116     | Preceding -> "preceding"
117     | Following -> "following"
118   )
119   and print_test fmt ts =
120     try
121       pp fmt "%s" (List.assoc ts
122                      [ text,"text()";
123                        node,"node()";
124                        star, "*" ] )
125     with
126       Not_found -> pp fmt "%s"
127         (if QNameSet.is_finite ts
128          then QName.to_string (QNameSet.choose ts)
129          else "<INFINITE>"
130         )
131
132   and print_expr fmt = function
133     | Number (`Int(i)) -> pp fmt "%i" i
134     | Number (`Float(f)) -> pp fmt "%f" f
135     | String s -> pp fmt "'%S'" s
136     | Fun_call (n, args) ->
137         pp fmt "%a(" QName.print n;
138         Pretty.print_list ~sep:", " print_expr fmt args;
139         pp fmt ")"
140     | Path p -> print_path fmt p
141     | Binop (e1, op, e2) as e ->
142         let pe = prio e in
143         let need_par1 = prio e1 < pe in
144         if need_par1 then pp fmt "(";
145         pp fmt "%a" print_expr e1;
146         if need_par1 then pp fmt ")";
147         pp fmt " %a "  print_binop op;
148         let need_par2 = prio e2 < pe in
149         if need_par2 then pp fmt "(";
150         pp fmt "%a" print_expr e2;
151         if need_par2 then pp fmt ")"
152     | Unop (op, e0) as e ->
153         let need_par0 = prio e0 < prio e in
154         print_unop fmt op;
155         if need_par0 then pp fmt "(";
156         print_expr fmt e0;
157         if need_par0 then pp fmt ")"
158
159 end