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