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