1structure Parse_support :> Parse_support =
2struct
3
4type pretype = Pretype.pretype
5type preterm = Preterm.preterm
6type term    = Term.term
7type overload_info = term_grammar.overload_info
8
9open HolKernel GrammarSpecials;
10
11val ERROR = mk_HOL_ERR "Parse_support";
12val ERRORloc = mk_HOL_ERRloc "Parse_support";
13
14(*---------------------------------------------------------------------------
15       Parsing environments
16 ---------------------------------------------------------------------------*)
17
18open Parse_supportENV
19
20fun lookup_fvar(s,({free,...}:env)) = assoc s free;
21fun lookup_bvar(s,({scope,...}:env)) = assoc s scope;
22fun add_free(b,{scope,free,uscore_cnt,ptyE}) =
23    {scope=scope, free=b::free, uscore_cnt = uscore_cnt, ptyE = ptyE}
24fun add_scope(b,{scope,free,uscore_cnt,ptyE}) =
25  {scope=b::scope, free=free, uscore_cnt = uscore_cnt, ptyE = ptyE};
26fun new_uscore {scope,free,uscore_cnt,ptyE} =
27    {scope = scope, free = free, uscore_cnt = uscore_cnt + 1, ptyE = ptyE}
28
29type preterm_in_env = env -> Preterm.preterm * env
30
31(*---------------------------------------------------------------------------*
32 * Denotes a binding occurrence of a variable. These are treated as          *
33 * functions from preterm (the body) to preterm (the abstraction).           *
34 *---------------------------------------------------------------------------*)
35
36type bvar_in_env = env -> (Preterm.preterm -> Preterm.preterm) * env
37
38(*---------------------------------------------------------------------------*
39 * Denotes a variable bound by a binder ("\\" or a constant, e.g.,           *
40 * "!", "?", "@"). Hence, it takes a binder and returns a function from      *
41 * the body to a preterm (plus of course, any changes to the env).           *
42 *---------------------------------------------------------------------------*)
43
44type binder_in_env = string -> bvar_in_env
45
46
47(*---------------------------------------------------------------------------*
48 * Top level parse terms                                                     *
49 *---------------------------------------------------------------------------*)
50
51fun make_preterm (tm_in_e : preterm_in_env) =
52  fn e => let
53    val (pt, env:env) = tm_in_e (fupd_ptyE (K e) empty_env)
54  in
55    errormonad.Some(#ptyE env, pt)
56  end
57
58(*---------------------------------------------------------------------------*
59 *       Antiquotes                                                          *
60 *---------------------------------------------------------------------------*)
61
62fun make_aq l tm (e:env) =
63  let
64    open errormonad
65    fun traverse localbvs t e =
66      case dest_term t of
67          VAR(nm, ty) =>
68          if HOLset.member(localbvs, t) then e
69          else
70            let
71              val pty = Pretype.fromType ty
72            in
73              case assoc1 nm (#scope e) of
74                  NONE =>
75                  (case assoc1 nm (#free e) of
76                       NONE => fupd_free (cons (nm,pty)) e
77                     | SOME (_, pty') =>
78                       case Pretype.unify pty pty' (#ptyE e) of
79                           Some(ptyE', ()) => fupd_ptyE (K ptyE') e
80                         | Error e => raise AQincompat{
81                                       nm = nm, aqty = ty, loc = l, fv = true,
82                                       unify_error = e })
83               | SOME (_, pty') =>
84                 (case Pretype.unify pty pty' (#ptyE e) of
85                      Some(ptyE', ()) => fupd_ptyE (K ptyE') e
86                    | Error e => raise AQincompat {
87                                  nm = nm, aqty = ty, loc = l, fv = false,
88                                  unify_error = e })
89            end
90        | CONST _ => e
91        | COMB(f,x) => traverse localbvs x (traverse localbvs f e)
92        | LAMB(bv, bod) => traverse (HOLset.add(localbvs,bv)) bod e
93  in
94    (Preterm.Antiq{Tm = tm, Locn = l}, traverse empty_tmset tm e)
95  end
96
97(*---------------------------------------------------------------------------*
98 * Generating fresh constant instances                                       *
99 *---------------------------------------------------------------------------*)
100
101fun ptylift (m : 'a Pretype.in_env) (e : env) : 'a * env =
102  let
103    open errormonad
104    val {scope,free,uscore_cnt,ptyE} = e
105  in
106    case m ptyE of
107      Error e => raise typecheck_error.mkExn e
108    | Some (e', a) => (a, {scope=scope,free=free,uscore_cnt=uscore_cnt,ptyE=e'})
109  end
110
111
112fun gen_thy_const l (thy,s) E = let
113  open Term
114  val c = prim_mk_const{Name=s, Thy=thy}
115  val ptym = type_of c |> Pretype.fromType |> Pretype.rename_typevars []
116  val (pty,E') = ptylift ptym E
117in
118  (Preterm.Const {Name=s, Thy=thy, Locn=l, Ty=pty}, E')
119end
120
121(*---------------------------------------------------------------------------
122 * Binding occurrences of variables
123 *---------------------------------------------------------------------------*)
124
125fun make_binding_occ l s E = let
126  open Preterm
127  val (ntv,E') = ptylift Pretype.new_uvar E
128  val E'' = add_scope((s,ntv),E')
129in
130  ((fn b => Abs{Bvar=Var{Name=s, Ty=ntv, Locn=l},Body=b,
131                Locn=locn.near (Preterm.locn b)}), E'')
132end
133
134fun make_aq_binding_occ l aq E = let
135  val (v as (Name,Ty)) = Term.dest_var aq
136  val pty = Pretype.fromType Ty
137  val v' = {Name=Name, Ty=Pretype.fromType Ty, Locn=l}
138  val E' = add_scope ((Name,pty),E)
139  open Preterm
140in
141  ((fn b => Abs{Bvar=Var v', Body=b, Locn=locn.near (Preterm.locn b)}), E')
142end
143
144
145(*---------------------------------------------------------------------------
146 * Free occurrences of variables.
147 *---------------------------------------------------------------------------*)
148
149fun all_uscores s = let
150  fun check i = i < 0 orelse (String.sub(s,i) = #"_" andalso check (i - 1))
151in
152  check (size s - 1)
153end
154
155fun make_free_var l (s,E) = let
156  open Preterm
157  fun fresh (s,E) = let
158    val (tyv, E') = ptylift Pretype.new_uvar E
159  in
160    (Var{Name = s, Ty = tyv, Locn = l}, add_free((s,tyv), E'))
161  end
162in
163  if all_uscores s then fresh ("_"^Int.toString (#uscore_cnt E), new_uscore E)
164  else (Var{Name=s, Ty=lookup_fvar(s,E), Locn=l}, E)
165       handle HOL_ERR _ => fresh(s,E)
166end
167
168(*---------------------------------------------------------------------------
169 * Bound occurrences of variables.
170 *---------------------------------------------------------------------------*)
171
172fun make_bvar l (s,E) = (Preterm.Var{Name=s, Ty=lookup_bvar(s,E), Locn=l}, E);
173
174(* ----------------------------------------------------------------------
175     Treatment of overloaded identifiers
176 ---------------------------------------------------------------------- *)
177
178fun gen_overloaded_const oinfo l s E =
179 let
180   open Overload Pretype
181   val opinfo = valOf (info_for_name oinfo s)
182         handle Option => raise Fail "gen_overloaded_const: invariant failure"
183 in
184  case #actual_ops opinfo of
185    [t] =>
186      if is_const t then let
187          val {Name,Thy,Ty} = dest_thy_const t
188          val (pty, E') = ptylift (rename_typevars [] (fromType Ty)) E
189        in
190          (Preterm.Const{Name=Name, Thy=Thy, Locn=l, Ty = pty}, E')
191        end
192      else let
193          val fvs = free_vars t
194          val tyfvs = List.foldl (fn (t, acc) => Lib.union (type_vars_in_term t)
195                                                           acc)
196                                 []
197                                 fvs
198          val (ptm, E') =
199              ptylift (Preterm.term_to_preterm (map dest_vartype tyfvs) t) E
200        in
201          (Preterm.Pattern{Ptm = ptm, Locn = l}, E')
202        end
203  | otherwise => let
204      val base_pretype0 = fromType (#base_type opinfo)
205      val (new_pretype, E') = ptylift (rename_typevars [] base_pretype0) E
206    in
207      (Preterm.Overloaded{Name = s, Ty = new_pretype, Info = opinfo, Locn = l},
208       E')
209    end
210 end
211
212
213(*---------------------------------------------------------------------------
214 * Identifiers work as follows: look for the string in the scope;
215 * if it's there, put the bound var.
216 * Failing that, check to see if the string is a known constant.
217 *
218 * If so, it will have an "overloading" entry.  Look this up and proceed.
219 *
220 * If not, it might be trying to be a record selection; these are
221 * necessarily constants (and overloaded) so we can complain at this point.
222 *
223 * Otherwise, it might be a string literal.  Try and make one, if this
224 * fails because stringTheory is not loaded, fail.
225 *
226 * If none of the above, then it's a free variable.
227 *
228 * Free vars are placed in the "free" part of the environment; this is a
229 * set. Bound vars are placed at the front of the "scope". When we come out
230 * of an Abs, we return the scope in effect when entering the Abs, but the
231 * "free"s include new ones found in the body of the Abs.
232 *---------------------------------------------------------------------------*)
233
234(*---------------------------------------------------------------------------
235    Making preterm string literals.
236 ---------------------------------------------------------------------------*)
237
238local
239  fun mk_chr ctm tm = mk_comb(ctm, tm)
240  fun mk_string stm (tm1,tm2) = list_mk_comb(stm, [tm1, tm2])
241  fun mk_numeral n =
242      Literal.gen_mk_numeral
243        {mk_comb = mk_comb,
244         ZERO = prim_mk_const{Name = "0", Thy = "num"},
245         ALT_ZERO = prim_mk_const{Name = "ZERO", Thy = "arithmetic"},
246         NUMERAL = prim_mk_const {Name="NUMERAL",Thy="arithmetic"},
247         BIT1 = prim_mk_const {Name="BIT1", Thy="arithmetic"},
248         BIT2 = prim_mk_const {Name="BIT2", Thy="arithmetic"}} n
249  fun fromMLC ctm c = mk_chr ctm (mk_numeral (Arbnum.fromInt (Char.ord c)))
250in
251fun make_string_literal l s =
252    if not (mem "string" (ancestry "-")) andalso
253       current_theory() <> "string"
254    then
255      Raise (ERRORloc "make_string_literal" l
256                      ("String literals not allowed - "^
257                       "load \"stringTheory\" first."))
258    else let
259        val char_ty = mk_thy_type {Tyop = "char", Thy = "string", Args = []}
260        val str_ty = mk_thy_type {Tyop = "list", Thy = "list", Args = [char_ty]}
261        val stm = mk_thy_const {Name = "CONS", Thy = "list",
262                                Ty = char_ty --> str_ty --> str_ty}
263        val ctm = prim_mk_const {Name = "CHR", Thy = "string"}
264        val etm = mk_thy_const{Name = "NIL", Thy = "list",
265                               Ty = str_ty}
266      in
267        Preterm.Antiq {Locn = l,
268                       Tm = Literal.mk_string_lit
269                              {mk_string = mk_string stm,
270                               emptystring = etm,
271                               fromMLchar = fromMLC ctm}
272                              (String.substring(s,1,String.size s - 2))}
273      end
274fun make_char_literal l s =
275    if not (mem "string" (ancestry "-")) andalso
276       current_theory() <> "string"
277    then
278      raise (ERRORloc "make_char_literal" l
279                      "Char literals not allowed - \
280                      \load \"stringTheory\" first.")
281    else let
282        val ctm = prim_mk_const {Name = "CHR", Thy = "string"}
283        val n_t = mk_numeral (Arbnum.fromInt (Char.ord (String.sub(s,2))))
284      in
285        Preterm.Antiq{Locn = l, Tm = mk_chr ctm n_t}
286      end
287end (* local *)
288
289(*---------------------------------------------------------------------------
290    "make_qconst" ignores overloading and visibility information. The
291    idea is that if we ask to make a long identifier, it should be
292    treated as visible.
293 ---------------------------------------------------------------------------*)
294
295fun make_qconst l (p as (thy,s)) = gen_thy_const l p
296
297fun make_atom oinfo l s E =
298 make_bvar l (s,E) handle HOL_ERR _
299  =>
300  if Overload.is_overloaded oinfo s then gen_overloaded_const oinfo l s E
301  else
302    case List.find (fn rfn => String.isPrefix rfn s)
303                   [recsel_special, recupd_special, recfupd_special] of
304      NONE => if Lexis.is_string_literal s then (make_string_literal l s, E)
305              else if Lexis.is_char_literal s then (make_char_literal l s, E)
306              else make_free_var l (s, E)
307    | SOME rfn =>
308        raise ERRORloc "make_atom" l
309                       ("Record field "^String.extract(s, size rfn, NONE)^
310                        " not registered")
311
312(*---------------------------------------------------------------------------
313 * Combs
314 *---------------------------------------------------------------------------*)
315
316fun list_make_comb l (tm1::(rst as (_::_))) E =
317     rev_itlist (fn tm => fn (trm,e) =>
318        let val (tm',e') = tm e
319        in (Preterm.Comb{Rator = trm, Rand = tm', Locn=l}, e') end)     rst (tm1 E)
320  | list_make_comb l _ _ = raise ERRORloc "list_make_comb" l "insufficient args";
321
322(*---------------------------------------------------------------------------
323 * Constraints
324 *---------------------------------------------------------------------------*)
325
326fun make_constrained l tm ty E = let
327  val (tm',E') = tm E
328in
329  (Preterm.Constrained{Ptm = tm', Ty = ty, Locn = l}, E')
330end;
331
332
333(*---------------------------------------------------------------------------
334
335  Abstractions, qualified abstractions, and vstructs.
336
337  The thing to know about parsing abstractions is that an abstraction is
338  a function from the string identifying the binder to an env to a
339  pair. The first member of the pair is a function that will take the
340  body of the abstraction and produce a lambda term, essentially by
341  clapping on whatever variables, or applying whatever constants
342  necessary. The second member of the pair is the environment previous
343  to entering the abstraction plus whatever new free variables were
344  found in the body of the abstraction.
345
346  We could just return (F tm', E), except that we may add free variables
347  found in tm to E.
348 ----------------------------------------------------------------------------*)
349
350fun bind_term _ alist tm (E as {scope=scope0,...}:env) : (preterm*env) = let
351  fun itthis a (e,f) = let
352    val (g,e') = a e
353  in
354    (e', f o g)
355  end
356  val (E',F) = rev_itlist itthis alist (E,I)
357  val (tm',({free=free1,uscore_cnt=uc',ptyE,...}:env)) = tm E'
358in
359  (F tm', {scope=scope0,free=free1,uscore_cnt=uc',ptyE=ptyE})
360end
361
362
363(*---------------------------------------------------------------------------
364 * For restricted binders. Adding a pair "(B,R)" to this list, if "B" is the
365 * name of a binder and "R" is the name of a constant, will enable parsing
366 * of terms with the form
367 *
368 *     B <varstruct list>::<restr>. M
369 *---------------------------------------------------------------------------*)
370
371local val restricted_binders = ref ([] : (string * string) list)
372in
373fun binder_restrictions() = !restricted_binders
374fun associate_restriction l (p as (binder_str,const_name)) =
375  case (Lib.assoc1 binder_str (!restricted_binders)) of
376    NONE => restricted_binders := p :: !restricted_binders
377  | SOME _ =>
378      raise ERRORloc "restrict_binder" l
379        ("Binder "^Lib.quote binder_str^" is already restricted")
380
381fun delete_restriction l binder =
382 restricted_binders :=
383  Lib.set_diff (!restricted_binders)
384         [(binder,Lib.assoc binder(!restricted_binders))]
385  handle HOL_ERR _
386   => raise ERRORloc "delete_restriction" l (Lib.quote binder^" is not restricted")
387end;
388
389fun restr_binder l s =
390   assoc s (binder_restrictions()) handle HOL_ERR _
391   => raise ERRORloc "restr_binder" l
392                      ("no restriction associated with "^Lib.quote s)
393
394fun split ty =
395  case ty of
396    Pretype.Tyop{Thy="pair",Tyop = "prod",Args} => Args
397  | _ => raise ERROR "split" "not a product";
398
399
400local open Preterm
401in
402fun cdom M [] = M
403  | cdom (Abs{Bvar,Body,Locn}) (ty::rst) =
404       Abs{Bvar = Constrained{Ptm=Bvar,Ty=ty,Locn=Locn}, Body = cdom Body rst, Locn = Locn}
405  | cdom (Comb{Rator as Const{Name="UNCURRY",...},Rand,Locn}) (ty::rst) =
406       Comb{Rator=Rator, Rand=cdom Rand (split ty@rst), Locn=Locn}
407  | cdom x y = raise ERRORloc "cdom" (Preterm.locn x) "missing case"
408end;
409
410fun cdomf (f,e) ty = ((fn tm => cdom (f tm) [ty]), e)
411
412fun make_vstruct oinfo l bvl tyo E = let
413  open Preterm
414  fun loop ([v],E) = v E
415    | loop ((v::rst),E) = let
416        val (f,e) = v E
417        val (F,E') = loop(rst,e)
418        val (uc_t, E'') = gen_overloaded_const oinfo l "UNCURRY" E'
419      in
420        ((fn b => Comb{Rator=uc_t, Rand=f(F b),Locn=l}), E'')
421      end
422    | loop _ = raise ERRORloc "make_vstruct" l "impl. error, empty vstruct"
423in
424  case tyo of
425    NONE    => loop(bvl,E)
426  | SOME ty => cdomf (hd bvl E) ty
427end
428
429
430(*---------------------------------------------------------------------------
431 * Let bindings
432 *---------------------------------------------------------------------------*)
433fun make_let oinfo l bindings tm (env:env) = let
434  open Preterm
435  fun itthis (bvs, arg) {body_bvars,args,E} = let
436    val (b,rst) = (hd bvs,tl bvs)
437    val (arg',E') =
438        case rst of [] => arg E | L => bind_term l L arg E
439  in
440    {body_bvars = b::body_bvars, args=arg'::args, E=E'}
441  end
442  val {body_bvars, args, E} =
443      itlist itthis bindings {body_bvars=[], args=[], E=env}
444  val (core,E') = bind_term l body_bvars tm E
445  fun rev_itthis arg (core, E) =
446    let
447      val (let_t, E') = gen_overloaded_const oinfo l "LET" E
448    in
449      (Comb{Rator= Comb{Rator=let_t, Rand=core,Locn=l},Rand=arg,Locn=l},
450       E')
451    end
452in
453  rev_itlist rev_itthis args (core, E')
454end
455    handle HOL_ERR _ => raise ERRORloc "make_let" l "bad let structure";
456
457fun make_set_const oinfo l fname s E =
458 gen_overloaded_const oinfo l s E
459  handle HOL_ERR _
460    => raise ERRORloc fname l ("The theory "^Lib.quote "pred_set"^" is not loaded");
461
462
463(*---------------------------------------------------------------------------
464 * Set abstractions {tm1 | tm2}. The complicated rigamarole at the front is
465 * so that new type variables only get made once per free var, although we
466 * compute the free vars for tm1 and tm2 separately.
467 *
468 * You can't make a set unless the theory of sets is an ancestor.
469 * The calls to make_set_const ensure this.
470 *
471 * Warning: apt not to work if you want to "antiquote in" free variables that
472 * will subsequently get bound in the set abstraction.
473 *---------------------------------------------------------------------------*)
474fun update_ptyE (old:env) = fupd_ptyE (K (#ptyE old))
475
476fun make_set_abs oinfo l (tm1,tm2) (E as {scope=scope0,...}:env) = let
477  val (_,(e1:env)) = tm1 (update_ptyE E empty_env)
478                     (* used to find names of free vars in tm1, but is also
479                        the basis for calculating the bound vars in the final
480                        preterm so we need its pty-env to be accurate *)
481  val (_,(e2:env)) = tm2 empty_env (* only used to get 2nd set of free vars *)
482  val (_,(e3:env)) = tm2 e1 (* link types and get complete set of free vars *)
483  val tm1_fv_names = map fst (#free e1)
484  val tm2_fv_names = map fst (#free e2)
485  val fv_names = if null tm1_fv_names then tm2_fv_names else
486                 if null tm2_fv_names then tm1_fv_names else
487                 intersect tm1_fv_names tm2_fv_names
488  val init_fv = #free e3 (* candidate bound names *)
489in
490  case filter (fn (name,_) => mem name fv_names) init_fv of
491    [] => raise ERRORloc "make_set_abs" l "no free variables in set abstraction"
492  | quants =>
493    let
494      open Preterm
495      val quants' = map
496                      (fn (bnd as (Name,Ty)) =>
497                          fn E =>
498                             ((fn b => Abs{Bvar=Var{Name=Name,Ty=Ty,Locn=l},
499                                           Body=b, Locn=l}),
500                              add_scope(bnd,E)))
501                      (rev quants) (* make_vstruct expects reverse occ. order *)
502      fun comma E = gen_overloaded_const oinfo l "," E
503    in
504      list_make_comb l
505                     [(make_set_const oinfo l "make_set_abs" "GSPEC"),
506                      (bind_term l
507                                 [make_vstruct oinfo l quants' NONE]
508                                 (list_make_comb l [comma,tm1,tm2]))]
509                     (update_ptyE e3 E)
510    end
511end
512
513(* ----------------------------------------------------------------------
514    case arrow
515
516    Free variables in the first should bind in the second
517   ---------------------------------------------------------------------- *)
518
519fun make_case_arrow oinfo loc tm1 tm2 (E : env) = let
520  val (ptm1, e1 : env) = tm1 (fupd_ptyE (K (#ptyE E)) empty_env)
521  val (arr, E') =
522      make_qconst loc
523                  ("bool", GrammarSpecials.case_arrow_special)
524                  (fupd_ptyE (K (#ptyE e1)) E)
525  fun mk_bvar (bv as (n,ty)) E = ((fn t => t), add_scope(bv,E))
526  val qs = map mk_bvar (#free e1)
527  val (ptm2, E'') = bind_term loc qs tm2 E'
528in
529  (Preterm.Comb{Rator = Preterm.Comb{Locn=loc,Rator = arr, Rand = ptm1},
530                Rand = ptm2,
531                Locn = loc}, E'')
532end
533
534
535(*---------------------------------------------------------------------------
536 * Sequence abstractions [| tm1 | tm2 |].
537 *
538 * You can't make a llist unless llistTheory is an ancestor.
539 * The call to make_seq_comp_const ensure this.
540 *---------------------------------------------------------------------------*)
541(*
542fun make_seqComp_const l fname s E =
543 (gen_const l s, E)
544  handle HOL_ERR _
545    => raise ERRORloc fname l ("The theory "^Lib.quote "llist"^" is not loaded");
546
547fun make_seq_abs l (tm1,tm2) (E as {scope=scope0,...}:env) =
548   let val (_,(e1:env)) = tm1 empty_env
549       val (_,(e2:env)) = tm2 empty_env
550       val (_,(e3:env)) = tm2 e1
551       val tm1_fv_names = map fst (#free e1)
552       val tm2_fv_names = map fst (#free e2)
553       val fv_names = if null tm1_fv_names then tm2_fv_names else
554                      if null tm2_fv_names then tm1_fv_names else
555                      intersect tm1_fv_names tm2_fv_names
556       val init_fv = #free e3
557   in
558   case filter (fn (name,_) => mem name fv_names) init_fv
559     of [] => raise ERRORloc "make_seq_abs" l "no free variables in set abstraction"
560      | quants =>
561         let val quants' = map
562                (fn (bnd as (Name,Ty)) =>
563                     (fn (s:string) => fn E =>
564                       ((fn b => Preterm.Abs{Bvar=Preterm.Var{Name=Name,Ty=Ty,Locn=l(*ugh*)},
565                                             Body=b, Locn=l}),
566                                add_scope(bnd,E))))
567               (rev quants) (* make_vstruct expects reverse occ. order *)
568         in list_make_comb l
569               [(make_seqComp_const l "make_seq_abs" "SeqComp"),
570                (bind_term l "\\" [make_vstruct l quants' NONE]
571                          (list_make_comb l [make_const l ",",tm1,tm2]))] E
572         end
573   end;
574*)
575
576end; (* Parse_support *)
577