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