]> matita.cs.unibo.it Git - helm.git/blob - matitaB/components/content_pres/cicNotationParser.ml
Keeping track of locations of disambiguated ids and symbols.
[helm.git] / matitaB / components / content_pres / cicNotationParser.ml
1 (* Copyright (C) 2005, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://helm.cs.unibo.it/
24  *)
25
26 (* $Id$ *)
27
28 open Printf
29
30 module Ast = NotationPt
31 module Env = NotationEnv
32
33 exception Parse_error of string
34 exception Level_not_found of int
35
36 let min_precedence = 0
37 let max_precedence = 100
38
39 type ('a,'b,'c,'d,'e) grammars = {
40   level1_pattern: 'a Grammar.Entry.e;
41   level2_ast: 'b Grammar.Entry.e;
42   level2_ast_grammar : Grammar.g;
43   term: 'b Grammar.Entry.e;
44   ident: 'e Grammar.Entry.e;
45   let_defs: 'c Grammar.Entry.e;
46   located: Stdpp.location Grammar.Entry.e;
47   protected_binder_vars: 'd Grammar.Entry.e;
48   level2_meta: 'b Grammar.Entry.e;
49 }
50
51 type checked_l1_pattern = CL1P of NotationPt.term * int
52
53 let refresh_uri_in_checked_l1_pattern ~refresh_uri_in_term
54      ~refresh_uri_in_reference (CL1P (t,n))
55 =
56  CL1P (NotationUtil.refresh_uri_in_term ~refresh_uri_in_term
57  ~refresh_uri_in_reference t, n)
58
59 type binding =
60   | NoBinding
61   | Binding of string * Env.value_type
62   | Env of (string * Env.value_type) list
63
64 type db = {
65   grammars: 
66     (int -> NotationPt.term, 
67     Ast.term,
68     (Ast.term Ast.capture_variable list *
69       Ast.term Ast.capture_variable * Ast.term * int) list, 
70     Ast.term list * Ast.term option, Env.ident_or_var) grammars;
71   keywords: string list;
72   items: (string * Ast.term * (NotationEnv.t -> Ast.location -> Ast.term)) list
73 }
74
75 let int_of_string s =
76   try
77     Pervasives.int_of_string s
78   with Failure _ ->
79     failwith (sprintf "Lexer failure: string_of_int \"%s\" failed" s)
80
81 (** {2 Grammar extension} *)
82
83 let level_of precedence =
84   if precedence < min_precedence || precedence > max_precedence then
85     raise (Level_not_found precedence);
86   string_of_int precedence 
87
88 let gram_symbol s = 
89   Gramext.srules 
90    [ [ Gramext.Stoken ("SYMBOL",s) ], Gramext.action (fun _ loc -> loc) ]
91  
92 let gram_ident status =
93  Gramext.Snterm (Grammar.Entry.obj
94   (status#notation_parser_db.grammars.ident : 'a Grammar.Entry.e))
95   (*Gramext.Stoken ("IDENT", s)*)
96 let gram_number s = Gramext.Stoken ("NUMBER", s)
97 let gram_keyword s = Gramext.Stoken ("", s)
98 let gram_term status = function
99   | Ast.Self _ -> Gramext.Sself
100   | Ast.Level precedence ->
101       Gramext.Snterml 
102         (Grammar.Entry.obj 
103           (status#notation_parser_db.grammars.term : 'a Grammar.Entry.e), 
104          level_of precedence)
105 ;;
106
107 let gram_of_literal =
108   function
109   | `Symbol s -> gram_symbol s
110   | `Keyword s -> gram_keyword s
111   | `Number s -> gram_number s
112
113 let make_action action bindings =
114   let rec aux (vl : NotationEnv.t) =
115     function
116       [] -> Gramext.action (fun (loc: Ast.location) -> action vl loc)
117     | NoBinding :: tl -> Gramext.action 
118                           (fun (loc: Ast.location) -> 
119                             aux (("",(Env.NoType,Env.LocValue loc))::vl) tl)
120     (* LUCA: DEFCON 3 BEGIN *)
121     | Binding (name, Env.TermType l) :: tl ->
122         Gramext.action
123           (fun (v:Ast.term) ->
124             aux ((name, (Env.TermType l, Env.TermValue v))::vl) tl)
125     | Binding (name, Env.StringType) :: tl ->
126         Gramext.action
127           (fun (v:Env.ident_or_var) ->
128             aux ((name, (Env.StringType, Env.StringValue v)) :: vl) tl)
129     | Binding (name, Env.NumType) :: tl ->
130         Gramext.action
131           (fun (v:string) ->
132             aux ((name, (Env.NumType, Env.NumValue v)) :: vl) tl)
133     | Binding (name, Env.OptType t) :: tl ->
134         Gramext.action
135           (fun (v:'a option) ->
136             aux ((name, (Env.OptType t, Env.OptValue v)) :: vl) tl)
137     | Binding (name, Env.ListType t) :: tl ->
138         Gramext.action
139           (fun (v:'a list) ->
140             aux ((name, (Env.ListType t, Env.ListValue v)) :: vl) tl)
141     | Env _ :: tl ->
142         Gramext.action (fun (v:NotationEnv.t) -> aux (v @ vl) tl)
143     | _ (* Binding (_,NoType) *) -> assert false
144     (* LUCA: DEFCON 3 END *)
145   in
146     aux [] (List.rev bindings)
147
148 let flatten_opt =
149   let rec aux acc =
150     function
151       [] -> List.rev acc
152     | NoBinding :: tl -> aux acc tl
153     | Env names :: tl -> aux (List.rev names @ acc) tl
154     | Binding (name, ty) :: tl -> aux ((name, ty) :: acc) tl
155   in
156   aux []
157
158   (* given a level 1 pattern computes the new RHS of "term" grammar entry *)
159 let extract_term_production status pattern =
160   let rec aux = function
161     | Ast.AttributedTerm (_, t) -> aux t
162     | Ast.Literal l -> aux_literal l
163     | Ast.Layout l -> aux_layout l
164     | Ast.Magic m -> aux_magic m
165     | Ast.Variable v -> aux_variable v
166     | t ->
167         prerr_endline (NotationPp.pp_term status t);
168         assert false
169   and aux_literal =
170     function
171     | `Symbol s -> [NoBinding, gram_symbol s]
172     | `Keyword s ->
173         (* assumption: s will be registered as a keyword with the lexer *)
174         [NoBinding, gram_keyword s]
175     | `Number s -> [NoBinding, gram_number s]
176   and aux_layout = function
177     | Ast.Sub (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\sub "] @ aux p2
178     | Ast.Sup (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\sup "] @ aux p2
179     | Ast.Below (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\below "] @ aux p2
180     | Ast.Above (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\above "] @ aux p2
181     | Ast.Frac (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\frac "] @ aux p2
182     | Ast.InfRule (p1, p2, p3) -> [NoBinding, gram_symbol "\\infrule "] @ aux p1 @ aux p2 @ aux p3
183     | Ast.Atop (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\atop "] @ aux p2
184     | Ast.Over (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\over "] @ aux p2
185     | Ast.Root (p1, p2) ->
186         [NoBinding, gram_symbol "\\root "] @ aux p2
187         @ [NoBinding, gram_symbol "\\of "] @ aux p1
188     | Ast.Sqrt p -> [NoBinding, gram_symbol "\\sqrt "] @ aux p
189     | Ast.Break -> []
190     | Ast.Box (_, pl) -> List.flatten (List.map aux pl)
191     | Ast.Group pl -> List.flatten (List.map aux pl)
192     | Ast.Mstyle (_,pl) -> List.flatten (List.map aux pl)
193     | Ast.Mpadded (_,pl) -> List.flatten (List.map aux pl)
194     | Ast.Maction l -> List.flatten (List.map aux l)
195   and aux_magic magic =
196     match magic with
197     | Ast.Opt p ->
198         let p_bindings, p_atoms, p_names, p_action = inner_pattern p in
199         let action (env_opt : NotationEnv.t option) (loc : Ast.location) =
200           match env_opt with
201           | Some env -> List.map Env.opt_binding_some env
202           | None -> List.map Env.opt_binding_of_name p_names
203         in
204         [ Env (List.map Env.opt_declaration p_names),
205           Gramext.srules
206             [ [ Gramext.Sopt (Gramext.srules [ p_atoms, p_action ]) ],
207               Gramext.action action ] ]
208     | Ast.List0 (p, _)
209     | Ast.List1 (p, _) ->
210         let p_bindings, p_atoms, p_names, p_action = inner_pattern p in
211         let action (env_list : NotationEnv.t list) (loc : Ast.location) =
212           NotationEnv.coalesce_env p_names env_list
213         in
214         let gram_of_list s =
215           match magic with
216           | Ast.List0 (_, None) -> Gramext.Slist0 s
217           | Ast.List1 (_, None) -> Gramext.Slist1 s
218           | Ast.List0 (_, Some l) -> Gramext.Slist0sep (s, gram_of_literal l)
219           | Ast.List1 (_, Some l) -> Gramext.Slist1sep (s, gram_of_literal l)
220           | _ -> assert false
221         in
222         [ Env (List.map Env.list_declaration p_names),
223           Gramext.srules
224             [ [ gram_of_list (Gramext.srules [ p_atoms, p_action ]) ],
225               Gramext.action action ] ]
226     | _ -> assert false
227   and aux_variable =
228     function
229     | Ast.NumVar s -> [Binding (s, Env.NumType), gram_number ""]
230     | Ast.TermVar (s,(Ast.Self level|Ast.Level level as lv)) -> 
231         [Binding (s, Env.TermType level), gram_term status lv]
232     | Ast.IdentVar s -> [Binding (s, Env.StringType), gram_ident status]
233     | Ast.Ascription (p, s) -> assert false (* TODO *)
234     | Ast.FreshVar _ -> assert false
235   and inner_pattern p =
236     let p_bindings, p_atoms = List.split (aux p) in
237     let p_names = flatten_opt p_bindings in
238     let action =
239       make_action (fun (env : NotationEnv.t) (loc : Ast.location) -> env)
240         p_bindings
241     in
242     p_bindings, p_atoms, p_names, action
243   in
244   aux pattern
245
246 type rule_id = Grammar.token Gramext.g_symbol list
247
248 let compare_rule_id x y =
249   let rec aux = function
250     | [],[] -> 0
251     | [],_ -> ~-1
252     | _,[] -> 1
253     | ((s1::tl1) as x),((s2::tl2) as y) ->
254         if Gramext.eq_symbol s1 s2 then aux (tl1,tl2)
255         else Pervasives.compare x y 
256   in
257     aux (x,y)
258
259
260 let check_l1_pattern level1_pattern pponly level associativity =
261   let variables = ref 0 in
262   let symbols = ref 0 in
263   let rec aux = function
264     | Ast.AttributedTerm (att, t) -> Ast.AttributedTerm (att,aux t)
265     | Ast.Literal _ as l -> incr symbols; l
266     | Ast.Layout l -> Ast.Layout (aux_layout l)
267     | Ast.Magic m -> Ast.Magic (aux_magic m)
268     | Ast.Variable v -> (aux_variable v)
269     | t -> assert false
270   and aux_layout = function
271     | Ast.Sub (p1, p2)   -> let p1 = aux p1 in let p2 = aux p2 in Ast.Sub (p1, p2)
272     | Ast.Sup (p1, p2)   -> let p1 = aux p1 in let p2 = aux p2 in Ast.Sup (p1, p2)
273     | Ast.Below (p1, p2) -> let p1 = aux p1 in let p2 = aux p2 in Ast.Below (p1, p2)
274     | Ast.Above (p1, p2) -> let p1 = aux p1 in let p2 = aux p2 in Ast.Above (p1, p2)
275     | Ast.Frac (p1, p2)  -> let p1 = aux p1 in let p2 = aux p2 in Ast.Frac (p1, p2)
276     | Ast.InfRule (p1, p2, p3)  -> let p1 = aux p1 in let p2 = aux p2 in let p3 = aux p3 in Ast.InfRule (p1, p2, p3)
277     | Ast.Atop (p1, p2)  -> let p1 = aux p1 in let p2 = aux p2 in Ast.Atop (p1, p2)
278     | Ast.Over (p1, p2)  -> let p1 = aux p1 in let p2 = aux p2 in Ast.Over (p1, p2)
279     | Ast.Root (p1, p2)  -> let p1 = aux p1 in let p2 = aux p2 in Ast.Root (p1, p2)
280     | Ast.Sqrt p -> Ast.Sqrt (aux p)
281     | Ast.Break as t -> t 
282     | Ast.Box (b, pl) -> Ast.Box(b, List.map aux pl)
283     | Ast.Group pl -> Ast.Group (List.map aux pl)
284     | Ast.Mstyle (l,pl) -> Ast.Mstyle (l, List.map aux pl)
285     | Ast.Mpadded (l,pl) -> Ast.Mpadded (l, List.map aux pl)
286     | Ast.Maction l as t -> 
287         if not pponly then 
288         raise(Parse_error("Maction can be used only in output notations")) 
289         else t
290   and aux_magic magic =
291     match magic with
292     | Ast.Opt p -> Ast.Opt (aux p)
293     | Ast.List0 (p, x) -> Ast.List0 (aux p, x)
294     | Ast.List1 (p, x) -> Ast.List1 (aux p, x)
295     | _ -> assert false
296   and aux_variable =
297     function
298     | Ast.NumVar _ as t -> Ast.Variable t
299     | Ast.TermVar (s,Ast.Self _) when associativity <> Gramext.NonA -> 
300         incr variables; 
301         if !variables > 2 then
302           raise (Parse_error ("Exactly 2 variables must be specified in an "^
303           "associative notation"));
304         (match !variables, associativity with
305         | 1,Gramext.LeftA -> 
306              Ast.Variable (Ast.TermVar (s, Ast.Self level))
307         | 1,Gramext.RightA -> 
308              Ast.Variable (Ast.TermVar (s, Ast.Self (level+1)))
309         | 2,Gramext.LeftA ->
310              Ast.Variable (Ast.TermVar (s, Ast.Self (level+1)))
311         | 2,Gramext.RightA -> 
312              Ast.Variable (Ast.TermVar (s, Ast.Level (level-1)))
313         | _ -> assert false)
314     | Ast.TermVar (s,Ast.Level _) when associativity <> Gramext.NonA -> 
315           raise (Parse_error ("Variables can not be declared with a " ^ 
316             "precedence in an associative notation"))
317        (*avoid camlp5 divergence due to non-Sself recursion at the same level *)
318     | Ast.TermVar (s,Ast.Level l) when l<=level && !variables=0 && !symbols=0-> 
319        raise(Parse_error("Left recursive rule with precedence not greater " ^
320         "than " ^ string_of_int level ^ " is not allowed to avoid divergence"))
321     | Ast.TermVar _ as t -> incr variables; Ast.Variable t
322     | Ast.IdentVar _ as t -> Ast.Variable t
323     | Ast.Ascription _ -> assert false (* TODO *)
324     | Ast.FreshVar _ -> assert false
325   in
326   if associativity <> Gramext.NonA && level = min_precedence then
327     raise (Parse_error ("You can not specify an associative notation " ^
328     "at level "^string_of_int min_precedence ^ "; increase it"));
329   let cp = aux level1_pattern in
330 (*   prerr_endline ("checked_pattern: " ^ NotationPp.pp_term cp); *)
331   if !variables <> 2 && associativity <> Gramext.NonA then
332     raise (Parse_error ("Exactly 2 variables must be specified in an "^
333      "associative notation"));
334   CL1P (cp,level)
335 ;;
336
337 (** {2 Grammar} *)
338
339 let fold_cluster binder terms ty body =
340   List.fold_right
341     (fun term body -> Ast.Binder (binder, (term, ty), body))
342     terms body  (* terms are names: either Ident or FreshVar *)
343
344 let fold_exists terms ty body =
345   List.fold_right
346     (fun term body ->
347       let lambda = Ast.Binder (`Lambda, (term, ty), body) in
348       Ast.Appl [ Ast.Symbol ("exists", None); lambda ])
349     terms body
350
351 let fold_binder binder pt_names body =
352   List.fold_right
353     (fun (names, ty) body -> fold_cluster binder names ty body)
354     pt_names body
355
356 let return_term loc term = Ast.AttributedTerm (`Loc loc, term)
357 let return_term_of_level loc term l = 
358   Ast.AttributedTerm (`Loc loc, term l)
359
360 (** {2 API implementation} *)
361
362 let exc_located_wrapper f =
363   try
364     f ()
365   with
366   | Stdpp.Exc_located (floc, Stream.Error msg) ->
367       raise (HExtlib.Localized (floc, Parse_error msg))
368   | Stdpp.Exc_located (floc, HExtlib.Localized (_,exn)) ->
369       raise (HExtlib.Localized (floc, (Parse_error (Printexc.to_string exn))))
370   | Stdpp.Exc_located (floc, exn) ->
371       raise (HExtlib.Localized (floc, (Parse_error (Printexc.to_string exn))))
372
373 let parse_level1_pattern grammars precedence lexbuf =
374   exc_located_wrapper
375     (fun () -> Grammar.Entry.parse grammars.level1_pattern (Obj.magic lexbuf) precedence)
376
377 let parse_level2_ast grammars lexbuf =
378   exc_located_wrapper
379     (fun () -> Grammar.Entry.parse grammars.level2_ast (Obj.magic lexbuf))
380
381 let parse_level2_meta grammars lexbuf =
382   exc_located_wrapper
383     (fun () -> Grammar.Entry.parse grammars.level2_meta (Obj.magic lexbuf))
384
385   (* create empty precedence level for "term" *)
386 let initialize_grammars grammars =
387   let dummy_action =
388     Gramext.action (fun _ ->
389       failwith "internal error, lexer generated a dummy token")
390   in
391   (* Needed since campl4 on "delete_rule" remove the precedence level if it gets
392    * empty after the deletion. The lexer never generate the Stoken below. *)
393   let dummy_prod = [ [ Gramext.Stoken ("DUMMY", "") ], dummy_action ] in
394   let mk_level_list first last =
395     let rec aux acc = function
396       | i when i < first -> acc
397       | i ->
398           aux
399             ((Some (level_of i), Some Gramext.NonA, dummy_prod)
400              :: acc)
401             (i - 1)
402     in
403     aux [] last
404   in
405   Grammar.extend
406     [ Grammar.Entry.obj (grammars.term: 'a Grammar.Entry.e),
407       None,
408       mk_level_list min_precedence max_precedence ];
409 (* {{{ Grammar for concrete syntax patterns, notation level 1 *)
410   begin
411   let level1_pattern = grammars.level1_pattern in
412 EXTEND
413   GLOBAL: level1_pattern;
414
415   level1_pattern: [ 
416     [ p = l1_pattern; EOI -> fun l -> NotationUtil.boxify (p l) ] 
417   ];
418   l1_pattern: [ 
419     [ p = LIST1 l1_simple_pattern -> 
420         fun l -> List.map (fun x -> x l) p ] 
421   ];
422   literal: [
423     [ s = SYMBOL -> `Symbol s
424     | k = QKEYWORD -> `Keyword k
425     | n = NUMBER -> `Number n
426     ]
427   ];
428   sep:       [ [ "sep";      sep = literal -> sep ] ];
429   l1_magic_pattern: [
430     [ "list0"; p = l1_simple_pattern; sep = OPT sep -> 
431             fun l -> Ast.List0 (p l, sep)
432     | "list1"; p = l1_simple_pattern; sep = OPT sep -> 
433             fun l -> Ast.List1 (p l, sep)
434     | "opt";   p = l1_simple_pattern -> fun l -> Ast.Opt (p l)
435     ]
436   ];
437   l1_pattern_variable: [
438     [ "term"; precedence = NUMBER; id = IDENT -> 
439         Ast.TermVar (id, Ast.Level (int_of_string precedence))
440     | "number"; id = IDENT -> Ast.NumVar id
441     | "ident"; id = IDENT -> Ast.IdentVar id
442     ]
443   ];
444   mstyle: [ 
445     [ id = IDENT; 
446       v = [ IDENT | NUMBER | COLOR | FLOATWITHUNIT ] -> id, v]];
447   mpadded: [ 
448     [ id = IDENT; 
449       v = [ PERCENTAGE ] -> id, v]];
450   l1_simple_pattern:
451     [ "layout" LEFTA
452       [ p1 = SELF; SYMBOL "\\sub "; p2 = SELF ->
453           return_term_of_level loc 
454             (fun l -> Ast.Layout (Ast.Sub (p1 l, p2 l)))
455       | p1 = SELF; SYMBOL "\\sup "; p2 = SELF ->
456           return_term_of_level loc 
457             (fun l -> Ast.Layout (Ast.Sup (p1 l, p2 l)))
458       | p1 = SELF; SYMBOL "\\below "; p2 = SELF ->
459           return_term_of_level loc 
460             (fun l -> Ast.Layout (Ast.Below (p1 l, p2 l)))
461       | p1 = SELF; SYMBOL "\\above "; p2 = SELF ->
462           return_term_of_level loc 
463             (fun l -> Ast.Layout (Ast.Above (p1 l, p2 l)))
464       | p1 = SELF; SYMBOL "\\over "; p2 = SELF ->
465           return_term_of_level loc 
466             (fun l -> Ast.Layout (Ast.Over (p1 l, p2 l)))
467       | p1 = SELF; SYMBOL "\\atop "; p2 = SELF ->
468           return_term_of_level loc 
469             (fun l -> Ast.Layout (Ast.Atop (p1 l, p2 l)))
470       | p1 = SELF; SYMBOL "\\frac "; p2 = SELF ->
471           return_term_of_level loc 
472             (fun l -> Ast.Layout (Ast.Frac (p1 l, p2 l)))
473       | SYMBOL "\\infrule "; p1 = SELF; p2 = SELF; p3 = SELF ->
474           return_term_of_level loc 
475             (fun l -> Ast.Layout (Ast.InfRule (p1 l, p2 l, p3 l)))
476       | SYMBOL "\\sqrt "; p = SELF -> 
477           return_term_of_level loc (fun l -> Ast.Layout (Ast.Sqrt p l))
478       | SYMBOL "\\root "; index = SELF; SYMBOL "\\of "; arg = SELF ->
479           return_term_of_level loc 
480             (fun l -> Ast.Layout (Ast.Root (arg l, index l)))
481       | "hbox"; LPAREN; p = l1_pattern; RPAREN ->
482           return_term_of_level loc 
483             (fun l -> Ast.Layout (Ast.Box ((Ast.H, false, false), p l)))
484       | "vbox"; LPAREN; p = l1_pattern; RPAREN ->
485           return_term_of_level loc 
486             (fun l -> Ast.Layout (Ast.Box ((Ast.V, false, false), p l)))
487       | "hvbox"; LPAREN; p = l1_pattern; RPAREN ->
488           return_term_of_level loc 
489             (fun l -> Ast.Layout (Ast.Box ((Ast.HV, false, false), p l)))
490       | "hovbox"; LPAREN; p = l1_pattern; RPAREN ->
491           return_term_of_level loc 
492             (fun l -> Ast.Layout (Ast.Box ((Ast.HOV, false, false), p l)))
493       | "break" -> return_term_of_level loc (fun _ -> Ast.Layout Ast.Break)
494       | "mstyle"; m = LIST1 mstyle ; LPAREN; t = l1_pattern; RPAREN ->
495           return_term_of_level loc 
496             (fun l -> 
497                Ast.Layout (Ast.Mstyle (m, t l)))
498       | "mpadded"; m = LIST1 mpadded ; LPAREN; t = l1_pattern; RPAREN ->
499           return_term_of_level loc 
500             (fun l -> 
501                Ast.Layout (Ast.Mpadded (m, t l)))
502       | "maction"; m = LIST1 [ LPAREN; l = l1_pattern; RPAREN -> l ] ->
503            return_term_of_level loc 
504             (fun l -> Ast.Layout (Ast.Maction (List.map (fun x ->
505               NotationUtil.group (x l)) m)))
506       | LPAREN; p = l1_pattern; RPAREN ->
507           return_term_of_level loc (fun l -> NotationUtil.group (p l))
508       ]
509     | "simple" NONA
510       [ i = IDENT -> 
511          return_term_of_level loc 
512            (fun l -> Ast.Variable (Ast.TermVar (i,Ast.Self l)))
513       | m = l1_magic_pattern -> 
514              return_term_of_level loc (fun l -> Ast.Magic (m l))
515       | v = l1_pattern_variable -> 
516              return_term_of_level loc (fun _ -> Ast.Variable v)
517       | l = literal -> return_term_of_level loc (fun _ -> Ast.Literal l)
518       ]
519     ];
520   END
521   end;
522 (* }}} *)
523 (* {{{ Grammar for ast magics, notation level 2 *)
524   begin
525   let level2_meta = grammars.level2_meta in
526 EXTEND
527   GLOBAL: level2_meta;
528   l2_variable: [
529     [ "term"; precedence = NUMBER; id = IDENT -> 
530         Ast.TermVar (id,Ast.Level (int_of_string precedence))
531     | "number"; id = IDENT -> Ast.NumVar id
532     | "ident"; id = IDENT -> Ast.IdentVar id
533     | "fresh"; id = IDENT -> Ast.FreshVar id
534     | "anonymous" -> Ast.TermVar ("_",Ast.Self 0) (* is the level relevant?*)
535     | id = IDENT -> Ast.TermVar (id,Ast.Self 0)
536     ]
537   ];
538   l2_magic: [
539     [ "fold"; kind = [ "left" -> `Left | "right" -> `Right ];
540       base = level2_meta; "rec"; id = IDENT; recursive = level2_meta ->
541         Ast.Fold (kind, base, [id], recursive)
542     | "default"; some = level2_meta; none = level2_meta ->
543         Ast.Default (some, none)
544     | "if"; p_test = level2_meta;
545       "then"; p_true = level2_meta;
546       "else"; p_false = level2_meta ->
547         Ast.If (p_test, p_true, p_false)
548     | "fail" -> Ast.Fail
549     ]
550   ];
551   level2_meta: [
552     [ magic = l2_magic -> Ast.Magic magic
553     | var = l2_variable -> Ast.Variable var
554     | blob = UNPARSED_AST ->
555         parse_level2_ast grammars (Ulexing.from_utf8_string blob)
556     ]
557   ];
558 END
559   end;
560 (* }}} *)
561 (* {{{ Grammar for ast patterns, notation level 2 *)
562   begin
563   let level2_ast = grammars.level2_ast in
564   let term = grammars.term in
565   let let_defs = grammars.let_defs in
566   let ident = grammars.ident in
567   let protected_binder_vars = grammars.protected_binder_vars in
568 EXTEND
569   GLOBAL: level2_ast term let_defs protected_binder_vars ident;
570   level2_ast: [ [ p = term -> p ] ];
571   sort: [
572     [ "Prop" -> `Prop
573     | "Set" -> `Set
574     | "Type"; SYMBOL "["; n = [ NUMBER| IDENT ]; SYMBOL "]" -> `NType n
575     | "CProp"; SYMBOL "["; n = [ NUMBER| IDENT ]; SYMBOL "]" -> `NCProp n
576     ]
577   ];
578   meta_subst: [
579     [ s = SYMBOL "_" -> None
580     | p = term -> Some p ]
581   ];
582   meta_substs: [
583     [ SYMBOL "["; substs = LIST0 meta_subst; SYMBOL "]" -> substs ]
584   ];
585   possibly_typed_name: [
586     [ LPAREN; id = single_arg; SYMBOL ":"; typ = term; RPAREN ->
587         id, Some typ
588     | arg = single_arg -> arg, None
589     | id = PIDENT -> Ast.Ident (id, `Ambiguous), None
590     | SYMBOL "_" -> Ast.Ident ("_", `Ambiguous), None
591     | LPAREN; id = PIDENT; SYMBOL ":"; typ = term; RPAREN ->
592         Ast.Ident (id, `Ambiguous), Some typ
593     | LPAREN; SYMBOL "_"; SYMBOL ":"; typ = term; RPAREN ->
594         Ast.Ident ("_", `Ambiguous), Some typ
595     ]
596   ];
597   match_pattern: [
598     [ SYMBOL "_" -> Ast.Wildcard
599     | id = IDENT -> Ast.Pattern (id, None, [])
600     | LPAREN; id = IDENT; vars = LIST1 possibly_typed_name; RPAREN ->
601        Ast.Pattern (id, None, vars)
602     | id = IDENT; vars = LIST1 possibly_typed_name ->
603        Ast.Pattern (id, None, vars)
604     ]
605   ];
606   binder: [
607     [ SYMBOL <:unicode<Pi>>     (* Π *) -> `Pi
608     | SYMBOL <:unicode<forall>> (* ∀ *) -> `Forall
609     | SYMBOL <:unicode<lambda>> (* λ *) -> `Lambda
610     ]
611   ];
612   tident: [
613     [ uri = HREF;
614       id = IDENT;
615       HREFEND -> (id, `Uri uri) ]];
616   gident: [
617     [ fullident = tident -> fullident;
618     | id = IDENT -> (id, `Ambiguous) ]];
619   arg: [
620     [ LPAREN; names = LIST1 gident SEP SYMBOL ",";
621       SYMBOL ":"; ty = term; RPAREN ->
622         List.map (fun (n,u) -> Ast.Ident (n,u)) names, Some ty
623     | (name,uri) = gident -> [Ast.Ident (name,uri)], None
624     | blob = UNPARSED_META ->
625         let meta = parse_level2_meta grammars (Ulexing.from_utf8_string blob) in
626         match meta with
627         | Ast.Variable (Ast.FreshVar _) -> [meta], None
628         | Ast.Variable (Ast.TermVar ("_",_)) -> [Ast.Ident ("_", `Ambiguous)], None
629         | _ -> failwith "Invalid bound name."
630    ]
631   ];
632   single_arg: [
633     [ (name,uri) = gident -> Ast.Ident (name,uri)
634     | blob = UNPARSED_META ->
635         let meta = parse_level2_meta grammars (Ulexing.from_utf8_string blob) in
636         match meta with
637         | Ast.Variable (Ast.FreshVar _)
638         | Ast.Variable (Ast.IdentVar _) -> meta
639         | Ast.Variable (Ast.TermVar ("_",_)) -> Ast.Ident ("_", `Ambiguous)
640         | _ -> failwith "Invalid index name."
641     ]
642   ];
643   ident: [
644     [ name = IDENT -> Env.Ident name
645     | blob = UNPARSED_META ->
646         let meta = parse_level2_meta grammars (Ulexing.from_utf8_string blob) in
647         match meta with
648         | Ast.Variable (Ast.FreshVar _) ->
649            (* it makes sense: extend Env.ident_or_var *)
650             assert false
651         | Ast.Variable (Ast.IdentVar name) -> Env.Var name
652         | Ast.Variable (Ast.TermVar ("_",_)) -> Env.Var "_"
653         | _ -> failwith ("Invalid index name: " ^ blob)
654     ]
655   ];
656   located: [
657     [ s = SYMBOL -> loc ]
658   ];
659   let_defs: [
660     [ defs = LIST1 [
661         name = single_arg;
662         args = LIST1 arg;
663         index_name = OPT [ "on"; id = single_arg -> id ];
664         ty = OPT [ SYMBOL ":" ; p = term -> p ];
665         SYMBOL <:unicode<def>> (* ≝ *); body = term ->
666           let rec position_of name p = function 
667             | [] -> None, p
668             | n :: _ when n = name -> Some p, p
669             | _ :: tl -> position_of name (p + 1) tl
670           in
671           let rec find_arg name n = function 
672             | [] ->
673                 (* CSC: new NCicPp.status is the best I can do here
674                    without changing the return type *)
675                 Ast.fail loc (sprintf "Argument %s not found"
676                   (NotationPp.pp_term (new NCicPp.status) name))
677             | (l,_) :: tl -> 
678                 (match position_of name 0 l with
679                 | None, len -> find_arg name (n + len) tl
680                 | Some where, len -> n + where)
681           in
682           let index = 
683             match index_name with 
684             | None -> 0 
685             | Some index_name -> find_arg index_name 0 args
686           in
687           let args =
688            List.concat
689             (List.map
690              (function (names,ty) -> List.map (function x -> x,ty) names
691              ) args)
692           in
693            args, (name, ty), body, index
694       ] SEP "and" ->
695         defs
696     ]
697   ];
698   binder_vars: [
699     [ vars = [ l =
700         [ l = LIST1 single_arg SEP SYMBOL "," -> l
701         | l = LIST1 [ PIDENT | SYMBOL "_" ] SEP SYMBOL "," -> 
702             List.map (fun x -> Ast.Ident(x,`Ambiguous)) l
703       ] -> l ];
704       typ = OPT [ SYMBOL ":"; t = term -> t ] -> (vars, typ)
705     ]
706   ];
707   protected_binder_vars: [
708     [ LPAREN; vars = binder_vars; RPAREN -> vars 
709     ]
710   ];
711   maybe_protected_binder_vars: [
712     [ vars = binder_vars -> vars
713     | vars = protected_binder_vars -> vars
714     ]
715   ];
716   term: LEVEL "10"
717   [
718     [ "let"; 
719      var = 
720       [ LPAREN; id = single_arg; SYMBOL ":"; typ = term; RPAREN ->
721           id, Some typ
722       | (id,uri) = gident; ty = OPT [ SYMBOL ":"; typ = term -> typ] ->
723           Ast.Ident (id,uri), ty ];
724       SYMBOL <:unicode<def>> (* ≝ *);
725       p1 = term; "in"; p2 = term ->
726         return_term loc (Ast.LetIn (var, p1, p2))
727     | LETCOREC; defs = let_defs; "in";
728       body = term ->
729         return_term loc (Ast.LetRec (`CoInductive, defs, body))
730     | LETREC; defs = let_defs; "in";
731       body = term ->
732         return_term loc (Ast.LetRec (`Inductive, defs, body))
733     ]
734   ];
735   term: LEVEL "20"
736     [
737       [ b = binder; (vars, typ) = maybe_protected_binder_vars; SYMBOL "."; body = term LEVEL "19" ->
738           return_term loc (fold_cluster b vars typ body)
739       ]
740     ];
741   term: LEVEL "70"
742     [
743       [ p1 = term; p2 = term LEVEL "71" ->
744           let rec aux = function
745             | Ast.Appl (hd :: tl)
746             | Ast.AttributedTerm (_, Ast.Appl (hd :: tl)) ->
747                 aux hd @ tl
748             | term -> [term]
749           in
750           return_term loc (Ast.Appl (aux p1 @ [p2]))
751       ]
752     ];
753   term: LEVEL "90"
754     [
755       [ (id,uri) = gident -> return_term loc (Ast.Ident (id,uri))
756       | s = CSYMBOL -> return_term loc (Ast.Symbol (s, None))
757       | u = URI -> return_term loc (Ast.Ident 
758                      (NUri.name_of_uri (NUri.uri_of_string u), `Uri u))
759       | r = NREF -> return_term loc (Ast.NRef (NReference.reference_of_string r))
760       | n = NUMBER -> return_term loc (Ast.Num (n, None))
761       | IMPLICIT -> return_term loc (Ast.Implicit `JustOne)
762       | SYMBOL <:unicode<ldots>> -> return_term loc (Ast.Implicit `Vector)
763       | PLACEHOLDER -> return_term loc Ast.UserInput
764       | m = META -> return_term loc (Ast.Meta (int_of_string m, []))
765       | m = META; s = meta_substs ->
766           return_term loc (Ast.Meta (int_of_string m, s))
767       | s = sort -> return_term loc (Ast.Sort s)
768       | "match"; t = term;
769         indty_ident = OPT [ "in"; id = IDENT -> id, None ];
770         outtyp = OPT [ "return"; ty = term -> ty ];
771         "with"; SYMBOL "[";
772         patterns = LIST0 [
773           lhs = match_pattern; SYMBOL <:unicode<Rightarrow>> (* ⇒ *);
774           rhs = term ->
775             lhs, rhs
776         ] SEP SYMBOL "|";
777         SYMBOL "]" ->
778           return_term loc (Ast.Case (t, indty_ident, outtyp, patterns))
779       | LPAREN; p1 = term; SYMBOL ":"; p2 = term; RPAREN ->
780           return_term loc (Ast.Cast (p1, p2))
781       | LPAREN; p = term; RPAREN -> p
782       | blob = UNPARSED_META ->
783           parse_level2_meta grammars (Ulexing.from_utf8_string blob)
784       ]
785     ];
786 END
787   end;
788 (* }}} *)
789   grammars
790 ;;
791
792 let initial_grammars keywords =
793   let lexers = CicNotationLexer.mk_lexers keywords in
794   let level1_pattern_grammar = 
795     Grammar.gcreate lexers.CicNotationLexer.level1_pattern_lexer in
796   let level2_ast_grammar = 
797     Grammar.gcreate lexers.CicNotationLexer.level2_ast_lexer in
798   let level2_meta_grammar = 
799     Grammar.gcreate lexers.CicNotationLexer.level2_meta_lexer in
800   let level1_pattern =
801     Grammar.Entry.create level1_pattern_grammar "level1_pattern" in
802   let level2_ast = Grammar.Entry.create level2_ast_grammar "level2_ast" in
803   let term = Grammar.Entry.create level2_ast_grammar "term" in
804   let ident = Grammar.Entry.create level2_ast_grammar "ident" in
805   let located = Grammar.Entry.create level2_ast_grammar "located" in
806   let let_defs = Grammar.Entry.create level2_ast_grammar "let_defs" in
807   let protected_binder_vars = 
808     Grammar.Entry.create level2_ast_grammar "protected_binder_vars" in
809   let level2_meta = Grammar.Entry.create level2_meta_grammar "level2_meta" in
810   initialize_grammars { level1_pattern=level1_pattern;
811     level2_ast=level2_ast;
812     term=term;
813     ident=ident;
814     let_defs=let_defs;
815     located=located;
816     protected_binder_vars=protected_binder_vars;
817     level2_meta=level2_meta;
818     level2_ast_grammar=level2_ast_grammar;
819   }
820 ;;
821
822 class type g_status =
823  object
824   method notation_parser_db: db
825  end
826
827 class status0 ~keywords:kwds =
828  object
829   val db = { grammars = initial_grammars kwds; keywords = kwds; items = [] }
830   method notation_parser_db = db
831   method set_notation_parser_db v = {< db = v >}
832   method set_notation_parser_status
833    : 'status. #g_status as 'status -> 'self
834    = fun o -> {< db = o#notation_parser_db >}
835  end
836
837 class virtual status ~keywords:kwds =
838  object
839   inherit NCic.status
840   inherit status0 kwds
841  end
842
843 let extend (status : #status) (CL1P (level1_pattern,precedence)) action =
844         (* move inside constructor XXX *)
845   let add1item status (level, level1_pattern, action) =
846     let p_bindings, p_atoms =
847       List.split (extract_term_production status level1_pattern) in
848     Grammar.extend
849       [ Grammar.Entry.obj 
850         (status#notation_parser_db.grammars.term : 'a Grammar.Entry.e),
851         Some (Gramext.Level level),
852         [ None,
853           Some (*Gramext.NonA*) Gramext.NonA,
854           [ p_atoms, (* concrete l1 syntax *) 
855             (make_action
856               (fun (env: NotationEnv.t) (loc: Ast.location) ->
857                 (action env loc))
858               p_bindings) ]]];
859     status
860   in
861   let current_item = 
862     let level = level_of precedence in
863     level, level1_pattern, action in
864   let keywords = NotationUtil.keywords_of_term level1_pattern @
865     status#notation_parser_db.keywords in
866   let items = current_item :: status#notation_parser_db.items in 
867   let status = status#set_notation_parser_status (new status0 ~keywords) in
868   let status = status#set_notation_parser_db 
869     {status#notation_parser_db with items = items} in
870   List.fold_left add1item status items
871 ;;
872
873
874 let parse_level1_pattern status =
875   parse_level1_pattern status#notation_parser_db.grammars 
876 let parse_level2_ast status =
877   parse_level2_ast status#notation_parser_db.grammars 
878 let parse_level2_meta status =
879   parse_level2_meta status#notation_parser_db.grammars
880
881 let level2_ast_grammar status = 
882   status#notation_parser_db.grammars.level2_ast_grammar
883 let term status = status#notation_parser_db.grammars.term
884 let let_defs status = status#notation_parser_db.grammars.let_defs
885 let protected_binder_vars status = 
886   status#notation_parser_db.grammars.protected_binder_vars
887
888 (** {2 Debugging} *)
889
890 let print_l2_pattern status =
891   Grammar.print_entry Format.std_formatter 
892     (Grammar.Entry.obj status#notation_parser_db.grammars.term);
893   Format.pp_print_flush Format.std_formatter ();
894   flush stdout  
895
896 (* vim:set encoding=utf8 foldmethod=marker: *)