]> matita.cs.unibo.it Git - fireball-separation.git/blob - ocaml_new/lambda4.ml
git status! separation problem seems now undecidable git status!
[fireball-separation.git] / ocaml_new / lambda4.ml
1 open Util
2 open Util.Vars
3 open Pure
4 open Num
5
6 (* exceptions *)
7 exception Pacman
8 exception Bottom
9 exception Lambda
10 exception Backtrack of string
11
12 (* verbosity *)
13 let _very_verbose = true;;
14 (** Display measure of every term when printing problem *)
15 let _measure_of_terms = false;;
16
17 let verbose s =
18  if _very_verbose then prerr_endline s
19 ;;
20
21 type problem =
22  { freshno: int
23  ; div: i_var
24  ; conv: i_var list (* the inerts that must converge *)
25  ; sigma: (int * nf) list (* the computed substitution *)
26  ; initialSpecialK: int
27  ; label : string
28  ; var_names : string list (* names of the original free variables *)
29 } ;;
30
31 let label_of_problem {label} = label;;
32
33 let string_of_var l x =
34  try
35   List.nth l x
36  with Failure "nth" -> "`" ^ string_of_int x
37 ;;
38 let string_of_term p t = print ~l:p.var_names (t :> nf);;
39
40
41 let first args p var f =
42  let rec aux k = function
43  | [] ->
44    raise (Backtrack ("no more alternatives for " ^ string_of_var p.var_names var))
45  | i::is as ii -> try
46     f p i k
47    with Backtrack s ->
48 prerr_endline (">>>>>> BACKTRACK (reason: " ^ s ^") measure=$ ");
49 (* prerr_endline("Now trying var="^string_of_var p.var_names var^" i="^string_of_int (i+1)); *)
50      if k = 0 then aux p.initialSpecialK is else aux (k-1) ii
51  in aux p.initialSpecialK args
52
53 let all_terms p = p.div :: p.conv ;;
54
55 let measure_of_term, measure_of_terms =
56  let rec aux = function
57  | `Bottom | `Pacman -> 0
58  | `Var(_,ar) -> if ar = min_int then 0 else max 0 ar (*assert (ar >= 0); ar*)
59  | `Lam(_,t) -> aux t
60  | `I(v,args) -> aux (`Var v) + aux_many (Listx.to_list args :> nf list)
61  and aux_many tms = List.fold_right ((+) ++ aux) tms 0 in
62  (fun t -> aux (t :> nf)), (fun l -> aux_many (l :> nf list))
63 ;;
64
65 let sum_arities p = measure_of_terms (all_terms p)
66
67 let problem_measure p = sum_arities p;;
68 let string_of_measure = string_of_int;;
69
70 let string_of_problem label ({freshno; div; conv} as p) =
71  let aux_measure_terms t = if _measure_of_terms then "(" ^ string_of_int (measure_of_term t) ^ ") " else "" in
72  let l = p.var_names in
73  String.concat "\n" ([
74   "";
75   "# DISPLAY PROBLEM (" ^ label ^ ") " ^ "measure=" ^ string_of_measure (problem_measure p);
76   "#";
77   "$" ^ p.label;
78   "D " ^ aux_measure_terms div ^ print ~l (div :> nf);
79   ]
80   @ List.map (fun t -> "C " ^ aux_measure_terms t ^ print ~l (t :> nf)) conv
81   @ [""])
82 ;;
83
84
85 let failwithProblem p reason =
86  print_endline (string_of_problem "FAIL" p);
87  failwith reason
88 ;;
89
90 let make_fresh_var p arity =
91  let freshno = p.freshno + 1 in
92  {p with freshno}, `Var(freshno,arity)
93 ;;
94
95 let make_fresh_vars p arities =
96  List.fold_right
97   (fun arity (p, vars) -> let p, var = make_fresh_var p arity in p, var::vars)
98   arities
99   (p, [])
100 ;;
101
102
103 let fixpoint f =
104  let rec aux x = let x' = f x in if x <> x' then aux x' else x in aux
105 ;;
106
107
108 let subst_in_problem x inst ({div; conv} as p) =
109 prerr_endline ("# INST0: " ^ string_of_var p.var_names x ^ " := " ^ string_of_term p inst);
110  let div = subst false false x inst (div :> nf) in
111  let conv = List.map (subst false false x inst) (conv :> nf list) in
112  let conv = Util.filter_map (function `Lam _ | `Pacman -> None | `Bottom -> raise (Backtrack "bottom in conv") | #i_var as t -> Some t) conv in
113  match div with
114   | `Lam _ | `Pacman | `Var _ -> raise (Backtrack "lam in div")
115   | `Bottom -> `Finished p
116   | `I _ as div -> `Continue {p with div; conv}
117 ;;
118
119 exception Dangerous;;
120
121 let arity_of arities hd =
122  let pos,_,nargs = List.find (fun (_,hd',_) -> hd=hd') arities in
123  nargs + if pos = -1 then - 1 else 0
124 ;;
125
126 (* let rec dangerous arities showstoppers =
127  function
128     `N _
129   | `Var _
130   | `Lam _
131   | `Pacman -> ()
132   | `Match(t,_,liftno,bs,args) ->
133       (* CSC: XXX partial dependency on the encoding *)
134       (match t with
135           `N _ -> List.iter (dangerous arities showstoppers) args
136         | `Match _ as t -> dangerous arities showstoppers t ; List.iter (dangerous arities showstoppers) args
137         | `Var(x,_) -> dangerous_inert arities showstoppers x args 2
138         | `I((x,_),args') -> dangerous_inert arities showstoppers x (Listx.to_list args' @ args) 2
139       )
140   | `I((k,_),args) -> dangerous_inert arities showstoppers k (Listx.to_list args) 0
141
142 and dangerous_inert arities showstoppers k args more_args =
143  List.iter (dangerous arities showstoppers) args ;
144  if List.mem k showstoppers then raise Dangerous else
145  try
146   let arity = arity_of arities k in
147   if List.length args + more_args > arity then raise Dangerous else ()
148  with
149   Not_found -> ()
150
151 (* cut & paste from above *)
152 let rec dangerous_conv p arities showstoppers =
153  function
154   | `N _
155   | `Var _
156   | `Lam _
157   | `Pacman -> ()
158   | `Match(t,_,liftno,bs,args) -> (
159       (* CSC: XXX partial dependency on the encoding *)
160        try (match t with
161         | `N _ -> List.iter (dangerous_conv p arities showstoppers) args
162         | `Match _ as t -> dangerous_conv p arities showstoppers t; List.iter (dangerous_conv p arities showstoppers) args
163         | `Var(x,_) -> dangerous_inert_conv p arities showstoppers x [] args 2
164         | `I((x,_),args') -> dangerous_inert_conv p arities showstoppers x (Listx.to_list args') args 2
165         ) with TriggerMatchReduction x -> (
166            match Util.find_opt (fun (n, t) -> if hd_of (List.nth p.ps n) = Some x then Some t else None) !bs with
167             | None -> ()
168             | Some t -> (
169                match t with
170                 | `Bottom -> raise Dangerous
171                 | #nf_nob as t -> dangerous_conv p arities showstoppers t
172                )
173            )
174        )
175   | `I((k,_),args) -> dangerous_inert_conv p arities showstoppers k (Listx.to_list args) [] 0
176
177 and dangerous_inert_conv p arities showstoppers k args match_args more_args =
178  let all_args = args @ match_args in
179  List.iter (dangerous_conv p arities showstoppers) all_args;
180  let all_args = (all_args :> nf list) in
181  if List.mem k showstoppers then raise Dangerous else
182   try
183    let arity = arity_of arities k in
184 prerr_endline ("dangerous_inert_conv: ar=" ^ string_of_int arity ^ " k="^string_of_var p.var_names k ^ " listlenargs=" ^ (string_of_int (List.length args)) ^ " more_args=" ^ string_of_int more_args);
185    if more_args > 0 (* match argument*) && List.length args = arity then raise (TriggerMatchReduction k)
186     else if List.length all_args + more_args > arity then raise Dangerous else ()
187   with
188    Not_found -> ()
189
190 (* inefficient algorithm *)
191 let rec edible p arities showstoppers =
192  let rec aux f showstoppers tms = function
193    | [] -> showstoppers
194    | x::xs when List.exists (fun y -> hd_of x = Some y) showstoppers ->
195       (* se la testa di x e' uno show-stopper *)
196       let new_showstoppers = sort_uniq (showstoppers @ free_vars (x :> nf)) in
197       (* aggiungi tutte le variabili libere di x *)
198       if List.length showstoppers <> List.length new_showstoppers then
199        aux f new_showstoppers tms tms
200       else
201        aux f showstoppers tms xs
202    | x::xs ->
203       match hd_of x with
204          None -> aux f showstoppers tms xs
205        | Some h ->
206           try
207            f showstoppers (x :> nf_nob) ;
208            aux f showstoppers tms xs
209           with
210            Dangerous ->
211             aux f (sort_uniq (h::showstoppers)) tms tms
212   in
213    let showstoppers = sort_uniq (aux (dangerous arities) showstoppers p.ps p.ps) in
214    let dangerous_conv = sort_uniq (aux (dangerous_conv p arities) showstoppers p.conv p.conv) in
215
216 (* prerr_endline ("dangerous_conv lenght:" ^ string_of_int (List.length dangerous_conv));
217 List.iter (fun l -> prerr_endline (String.concat " " (List.map (string_of_var p.var_names) l))) dangerous_conv; *)
218
219     let showstoppers' = showstoppers @ dangerous_conv in
220     let showstoppers' = sort_uniq (match p.div with
221      | None -> showstoppers'
222      | Some div ->
223        if List.exists ((=) (hd_of_i_var div)) showstoppers'
224        then showstoppers' @ free_vars (div :> nf) else showstoppers') in
225     if showstoppers <> showstoppers' then edible p arities showstoppers' else showstoppers', dangerous_conv
226 ;;
227
228 let precompute_edible_data {ps; div} xs =
229  let aux t = match t with `Var _ -> 0 | `I(_, args) -> Listx.length args | `N _ -> assert false in
230  (fun l -> match div with
231   | None -> l
232   | Some div -> (-1, hd_of_i_var div, aux div) :: l)
233   (List.map (fun hd ->
234    let i, tm = Util.findi (fun y -> hd_of y = Some hd) ps in
235     i, hd, aux tm
236    ) xs)
237 ;;
238
239 (** Returns (p, showstoppers_step, showstoppers_eat) where:
240     - showstoppers_step are the heads occurring twice
241       in the same discriminating set
242     - showstoppers_eat are the heads in ps having different number
243       of arguments *)
244 let critical_showstoppers p =
245   let p = super_simplify p in
246   let hd_of_div = match p.div with None -> [] | Some t -> [hd_of_i_var t] in
247   let showstoppers_step =
248   concat_map (fun bs ->
249     let heads = List.map (fun (i,_) -> List.nth p.ps i) !bs in
250     let heads = List.sort compare (hd_of_div @ filter_map hd_of heads) in
251     snd (split_duplicates heads)
252     ) p.deltas @
253      if List.exists (fun t -> [hd_of t] = List.map (fun x -> Some x) hd_of_div) p.conv
254      then hd_of_div else [] in
255   let showstoppers_step = sort_uniq showstoppers_step in
256   let showstoppers_eat =
257    let heads_and_arities =
258     List.sort (fun (k,_) (h,_) -> compare k h)
259      (filter_map (function `Var(k,_) -> Some (k,0) | `I((k,_),args) -> Some (k,Listx.length args) | _ -> None ) p.ps) in
260    let rec multiple_arities =
261     function
262        []
263      | [_] -> []
264      | (x,i)::(y,j)::tl when x = y && i <> j ->
265          x::multiple_arities tl
266      | _::tl -> multiple_arities tl in
267    multiple_arities heads_and_arities in
268
269   let showstoppers_eat = sort_uniq showstoppers_eat in
270   let showstoppers_eat = List.filter
271     (fun x -> not (List.mem x showstoppers_step))
272     showstoppers_eat in
273   List.iter (fun v -> prerr_endline ("DANGEROUS STEP: " ^ (string_of_var p.var_names) v)) showstoppers_step;
274   List.iter (fun v -> prerr_endline ("DANGEROUS EAT: " ^ (string_of_var p.var_names) v)) showstoppers_eat;
275   p, showstoppers_step, showstoppers_eat
276   ;;
277
278 let eat p =
279   let ({ps} as p), showstoppers_step, showstoppers_eat = critical_showstoppers p in
280   let showstoppers = showstoppers_step @ showstoppers_eat in
281   let heads = List.sort compare (filter_map hd_of ps) in
282   let arities = precompute_edible_data p (uniq heads) in
283   let inedible, showstoppers_conv = edible p arities showstoppers in
284   let l = List.filter (fun (_,hd,_) -> not (List.mem hd inedible)) arities in
285   let p =
286   List.fold_left (fun p (pos,hd,nargs) -> if pos = -1 then p else
287    let v = `N pos in
288    let inst = make_lams v nargs in
289 prerr_endline ("# [INST_IN_EAT] eating: " ^ string_of_var p.var_names hd ^ " := " ^ string_of_term p inst);
290    { p with sigma = p.sigma @ [hd,inst] }
291    ) p l in
292   (* to avoid applied numbers in safe positions that
293      trigger assert failures subst_in_problem x inst p*)
294  let ps =
295   List.map (fun t ->
296    try
297     let j,_,_ = List.find (fun (_,hd,_) -> hd_of t = Some hd) l in
298     `N j
299    with Not_found -> t
300   ) ps in
301  let p = match p.div with
302   | None -> p
303   | Some div ->
304    if List.mem (hd_of_i_var div) inedible
305    then p
306    else
307     let n = match div with `I(_,args) -> Listx.length args | `Var _ -> 0 in
308     let x = hd_of_i_var div in
309     let inst = make_lams `Bottom n in
310     subst_in_problem x inst p in
311 (*let dangerous_conv = showstoppers_conv in
312 prerr_endline ("dangerous_conv lenght:" ^ string_of_int (List.length dangerous_conv));
313 List.iter (fun l -> prerr_endline (String.concat " " (List.map (string_of_var p.var_names) l))) dangerous_conv; *)
314  let conv =
315    List.map (function t ->
316     try
317      if let hd = hd_of t in hd <> None && not (List.mem (Util.option_get hd) showstoppers_conv) then t else (
318      (match t with | `Var _ -> raise Not_found | _ -> ());
319      let _ = List.find (fun h -> hd_of t = Some h) inedible in
320       t)
321     with Not_found -> match hd_of t with
322      | None -> assert (t = convergent_dummy); t
323      | Some h ->
324       prerr_endline ("FREEZING " ^ string_of_var p.var_names h);
325       convergent_dummy
326    ) p.conv in
327  List.iter
328   (fun bs ->
329     bs :=
330      List.map
331       (fun (n,t as res) ->
332         match List.nth ps n with
333            `N m -> m,t
334          | _ -> res
335       ) !bs
336   ) p.deltas ;
337  let old_conv = p.conv in
338  let p = { p with ps; conv } in
339  if l <> [] || old_conv <> conv
340   then prerr_endline (string_of_problem "eat" p);
341  if List.for_all (function `N _ -> true | _ -> false) ps && p.div = None then
342   `Finished p
343  else
344   `Continue p
345
346
347 let safe_arity_of_var p x =
348  (* Compute the minimum number of arguments when x is in head
349     position at p.div or p.ps *)
350  let aux = function
351  | `Var(y,_) -> if x = y then 0 else max_int
352  | `I((y,_),args) -> if x = y then Listx.length args else max_int
353  | _ -> max_int in
354  let tms = ((match p.div with None -> [] | Some t -> [(t :> i_n_var)]) @ p.ps) in
355  List.fold_left (fun acc t -> Pervasives.min acc (aux t)) max_int tms
356 ;; *)
357
358 let instantiate p x perm n =
359  (* let n = (prerr_endline ("WARNING: using constant initialSpecialK=" ^ string_of_int p.initialSpecialK)); p.initialSpecialK in *)
360  let arities = Array.to_list (Array.make (n+1) min_int) in
361  let p,vars = make_fresh_vars p arities in
362  (* manual lifting of vars by perm in next line *)
363  let vars = List.map (function `Var (n,ar) -> `Var (n+perm,ar)) vars in
364  (* other_vars are the variables which are delayed and re-applied to the match *)
365  let other_vars = Array.mapi (fun n () -> `Var(n+1,min_int)) (Array.make (perm-1) ()) in
366  let other_vars = Array.to_list other_vars in
367  (* 666, since it will be replaced anyway during subst: *)
368  (* let inst = `Match(`I((0,min_int),args),(x,-666),perm,bs,other_vars) in *)
369  let inst = `I((0,min_int),Listx.from_list (vars @ other_vars)) in (* FIXME *)
370  (* Add a number of 'perm' leading lambdas *)
371  let inst = Array.fold_left (fun t () -> `Lam(false, t)) inst (Array.make perm ()) in
372  let p = {p with sigma=(x,inst)::p.sigma} in
373  subst_in_problem x inst p
374 ;;
375
376 let compute_special_k tms =
377  let rec aux k (t: nf) = Pervasives.max k (match t with
378  | `Lam(b,t) -> aux (k + if b then 1 else 0) t
379  | `I(n, tms) -> Listx.max (Listx.map (aux 0) (tms :> nf Listx.listx))
380  | `Bottom
381  | `Pacman
382  | `Var _ -> 0
383  ) in
384  let rec aux' top t = match t with
385  | `Lam(_,t) -> aux' false t
386  | `I((_,ar), tms) -> max ar
387      (Listx.max (Listx.map (aux' false) (tms :> nf Listx.listx)))
388  | `Bottom
389  | `Pacman
390  | `Var _ -> 0 in
391  Listx.max (Listx.map (aux 0) tms) + Listx.max (Listx.map (aux' true) tms)
392 ;;
393
394 (* let choose_step p =
395  let p, showstoppers_step, showstoppers_eat = critical_showstoppers p in
396  let x =
397   match showstoppers_step, showstoppers_eat with
398   | [], y::_ ->
399      prerr_endline ("INSTANTIATING (critical eat) : " ^ string_of_var p.var_names y); y
400   | x::_, _ ->
401      prerr_endline ("INSTANTIATING (critical step): " ^ string_of_var p.var_names x); x
402   | [], [] ->
403      let heads =
404       (* Choose only variables still alive (with arity > 0) *)
405       List.sort compare (filter_map (
406        fun t -> match t with `Var _ -> None | x -> if arity_of_hd x <= 0 then None else hd_of x
407       ) ((match p.div with Some t -> [(t :> i_n_var)] | _ -> []) @ p.ps)) in
408      (match heads with
409       | [] ->
410          (try
411            fst (List.find (((<) 0) ++ snd) (concat_map free_vars' (p.conv :> nf list)))
412           with
413            Not_found -> assert false)
414       | x::_ ->
415          prerr_endline ("INSTANTIATING TO EAT " ^ string_of_var p.var_names x);
416          x) in
417  let arity_of_x = Util.option_get (max_arity_tms x (all_terms p)) in
418  let safe_arity_of_x = safe_arity_of_var p x in
419  x, min arity_of_x safe_arity_of_x
420 ;; *)
421
422 let intersect l1 l2 =
423  let rec aux n l1 l2 = match l1, l2 with
424  | [], _ -> []
425  | _, [] -> assert false
426  | x::xs, y::ys -> if x <> y then n :: aux (n+1) xs ys else aux (n+1) xs ys
427  in aux 1 (Listx.to_list l1) (Listx.to_list l2);;
428
429 exception Difference of int list;;
430 let eat p =
431  let hd, args, n = match p.div with `Var _ -> assert false | `I((x,_), l) -> x, l, Listx.length l in
432  let rec aux = function
433  | `Var _ | `Lam _ -> ()
434  | `Pacman | `Bottom -> assert false
435  | `I((x,_),args') ->
436      if x = hd then
437       if Listx.length args' >= n then
438        (let diff = intersect args args' in
439        raise (if diff = [] then Backtrack "div in conv" else Difference diff));
440      List.iter aux ((Listx.to_list args') :> nf list) in
441  try
442   List.iter aux (p.conv :> nf list) ;
443   `Finished {p with sigma=(hd,make_lams `Bottom n)::p.sigma}
444  with
445   Difference l -> `Continue (hd, l)
446 ;;
447
448 let rec auto_eat p =
449  prerr_endline (string_of_problem "auto_eat" p);
450  (* prerr_endline "{{{{{{{{ Computing measure before auto_instantiate }}}}}}"; *)
451  match eat p with
452  | `Finished p -> prerr_endline "finished"; p
453  | `Continue (x,positions) ->
454  let m = problem_measure p in
455  first positions p x (fun p j k ->
456   match instantiate p x j k with
457   `Continue p ->
458   (* prerr_endline "{{{{{{{{ Computing measure inafter auto_instantiate }}}}}}"; *)
459   let delta = problem_measure p - m in
460   if delta >= 0
461    then
462     (prerr_endline
463     ("Measure did not decrease (+=" ^ string_of_int delta ^ ")"))
464    else prerr_endline ("$ Measure decreased: " ^ string_of_int delta);
465    auto_eat p
466   | `Finished p -> p)
467 ;;
468
469 (******************************************************************************)
470 let env_of_sigma freshno sigma =
471  let rec aux n =
472   if n > freshno then
473    []
474   else
475    let e = aux (n+1) in
476    (try
477     e,Pure.lift (-n-1) (snd (List.find (fun (i,_) -> i = n) sigma)),[]
478    with
479     Not_found -> ([],Pure.V n,[]))::e
480  in aux 0
481 ;;
482 (* ************************************************************************** *)
483
484 type response = [
485  | `CompleteSeparable of string
486  | `CompleteUnseparable of string
487  | `Uncomplete
488 ]
489
490 type result = [
491  `Complete | `Uncomplete
492 ] * [
493  | `Separable of (int * Num.nf) list
494  | `Unseparable of string
495 ]
496
497
498 let run p =
499  Console.print_hline();
500  prerr_endline (string_of_problem "main" p);
501  let p_finale = auto_eat p in
502  let freshno,sigma = p_finale.freshno, p_finale.sigma in
503  prerr_endline ("------- <DONE> ------ measure=. \n ");
504  List.iter (fun (x,inst) -> prerr_endline (string_of_var p_finale.var_names x ^ " := " ^ string_of_term p_finale inst)) sigma;
505
506  prerr_endline "---------<PURE>---------";
507  let scott_of_nf t = ToScott.scott_of_nf (t :> nf) in
508  let div = scott_of_nf p.div in
509  let conv = List.map scott_of_nf p.conv in
510
511  let sigma' = List.map (fun (x,inst) -> x, ToScott.scott_of_nf inst) sigma in
512  let e' = env_of_sigma freshno sigma' in
513
514  prerr_endline "--------<REDUCE>---------";
515  (* print_endline (Pure.print div); *)
516  let t = Pure.mwhd (e',div,[]) in
517  prerr_endline ("*:: " ^ (Pure.print t));
518  assert (t = Pure.B);
519  List.iter (fun n ->
520    (* verbose ("_::: " ^ (Pure.print n)); *)
521    let t = Pure.mwhd (e',n,[]) in
522    verbose ("_:: " ^ (Pure.print t));
523    assert (t <> Pure.B)
524  ) conv ;
525  prerr_endline "-------- </DONE> --------";
526  p_finale.sigma
527 ;;
528
529 let solve (p, todo) =
530  let completeness, to_run =
531   match todo with
532    | `CompleteUnseparable s -> `Complete, `False s
533    | `CompleteSeparable _ -> `Complete, `True
534    | `Uncomplete -> `Uncomplete, `True in
535  completeness, match to_run with
536   | `False s -> `Unseparable s
537   | `True ->
538       try
539        `Separable (run p)
540       with
541        Backtrack _ -> `Unseparable "backtrack"
542 ;;
543
544 let no_bombs_pacmans p =
545     not (List.exists (eta_subterm `Bottom) p.conv)
546  && not (eta_subterm `Pacman p.div)
547 ;;
548
549 let check p =
550  if not (List.exists (eta_subterm p.div) p.conv) && no_bombs_pacmans p
551   then `CompleteSeparable "no bombs, pacmans and div"
552   (* il check seguente e' spostato nel parser e lancia un ParsingError *)
553  (* else if false (* TODO bombs or div fuori da lambda in ps@conv *)
554   then `CompleteUnseparable "bombs or div fuori da lambda in ps@conv" *)
555  else `Uncomplete
556 ;;
557
558 let problem_of (label, div, conv, var_names) =
559  (* TODO: replace div with bottom in problem??? *)
560  let all_tms = div :: conv in
561  if all_tms = [] then failwith "problem_of: empty problem";
562  let initialSpecialK = compute_special_k (Listx.from_list (all_tms :> nf list)) in
563  let freshno = List.length var_names in
564  let sigma = [] in
565  let p = {freshno; div; conv; sigma; initialSpecialK; var_names; label} in
566  p, check p
567 ;;