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