--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/Tools/nbe_codegen.ML Tue Feb 21 16:18:50 2006 +0100
@@ -0,0 +1,372 @@
+(* ID: $Id$
+ Author: Klaus Aehlig, Tobias Nipkow
+*)
+
+(* Global asssumptions:
+ For each function: there is at least one defining eqns and
+ all defining equations have same number of arguments.
+
+FIXME
+fun MLname s = "nbe_" ^ s;
+val quote = quote;
+
+FIXME xtab in theory
+*)
+(*
+structure NBE_Codegen =
+struct
+
+FIXME CodegenThingol names! which "error"?
+*)
+
+val is_constr = NBE_Eval.is_constr;
+val Eval = "NBE_Eval";
+val Eval_register= Eval ^ ".register";
+val Eval_lookup = Eval ^ ".lookup";
+val Eval_apply = Eval ^ ".apply";
+val Eval_Constr = Eval ^ ".Constr";
+val Eval_C = Eval ^ ".C";
+val Eval_AbsN = Eval ^ ".AbsN";
+val Eval_Fun = Eval ^ ".Fun";
+val Eval_BVar = Eval ^ ".BVar";
+val Eval_new_name = Eval ^ ".new_name";
+val Eval_to_term = Eval ^ ".to_term";
+
+fun MLname s = "nbe_" ^ s;
+fun MLvname s = "v_" ^ MLname s;
+fun MLparam n = "p_" ^ string_of_int n;
+fun MLintern s = "i_" ^ MLname s;
+
+fun MLparams n = map MLparam (1 upto n);
+
+structure S =
+struct
+
+val quote = quote; (* FIXME *)
+
+fun app e1 e2 = "(" ^ e1 ^ " " ^ e2 ^ ")";
+fun abs v e = "(fn" ^ v ^ " => " ^ e ^ ")";
+fun tup es = "(" ^ commas es ^ ")";
+fun list es = "[" ^ commas es ^ "]";
+
+fun apps s ss = Library.foldl (uncurry app) (s, ss);
+fun nbe_apps s ss =
+ Library.foldr (fn (s,e) => app (app Eval_apply e) s) (ss,s);
+
+fun eqns name ees =
+ let fun eqn (es,e) = name ^ " " ^ space_implode " " es ^ " = " ^ e
+ in "fun " ^ space_implode "\n | " (map eqn ees) ^ ";\n" end;
+
+
+fun Val v s = "val " ^ v ^ " = " ^ s;
+fun Let ds e = "let\n" ^ (space_implode "\n" ds) ^ " in " ^ e ^ " end"
+
+end
+
+fun mk_nbeFUN(nm,e) =
+ S.app Eval_Fun (S.tup [S.abs(S.list [MLvname nm])e,S.list [],"1",
+ S.abs(S.tup [])(S.Let
+ [S.Val (MLintern "var") (S.app Eval_new_name (S.tup [])),
+ S.Val (MLvname nm) (S.app Eval_BVar (S.tup [(MLintern "var"), S.list []]))]
+ (S.app Eval_AbsN(S.tup[MLintern "var",(S.app Eval_to_term e)])))]);
+
+fun take_last n xs = rev (Library.take(n, rev xs));
+fun drop_last n xs = rev (Library.drop(n, rev xs));
+
+fun selfcall nm ar args =
+ if (ar <= length args) then
+ S.nbe_apps (S.app (MLname nm) (S.list (take_last ar args)))
+ (drop_last ar args)
+ else S.app Eval_Fun (S.tup [MLname nm,S.list args,
+ string_of_int(ar - (length args)),
+ S.abs (S.tup []) (S.app Eval_C
+ (S.quote nm))]);
+
+
+fun mk_rexpr nm ar =
+ let fun mk args t = case t of
+ CodegenThingol.IConst((s,_),_) =>
+ if s=nm then selfcall nm ar args
+ else if is_constr s then S.app Eval_Constr
+ (S.tup [S.quote s,S.list args ])
+ else S.nbe_apps (MLname s) args
+ | CodegenThingol.IVarE(s,_) => S.nbe_apps (MLvname s) args
+ | CodegenThingol.IApp(e1,e2) => mk (args @ [mk [] e2]) e1
+ | CodegenThingol.IAbs(CodegenThingol.IVarE(nm,_), e) =>
+ S.nbe_apps (mk_nbeFUN(nm, mk [] e)) args
+ | _ => sys_error "NBE mkexpr"
+ in mk [] end;
+
+val mk_lexpr =
+ let fun mk args t = case t of
+ CodegenThingol.IConst((s,_),_) =>
+ S.app Eval_Constr (S.tup [S.quote s, S.list args])
+ | CodegenThingol.IVarE(s,_) => if args = [] then MLvname s else
+ sys_error "NBE mk_lexpr illegal higher order pattern"
+ | CodegenThingol.IApp(e1,e2) => mk (args @ [mk [] e2]) e1
+ | _ => sys_error "NBE mk_lexpr illegal pattern"
+ in mk [] end;
+
+fun mk_eqn nm ar (lhs,e) = ([S.list(map mk_lexpr (rev lhs))], mk_rexpr nm ar e);
+
+fun funs_of_expr(CodegenThingol.IConst((s,_),_),fs) = s::fs
+ | funs_of_expr(CodegenThingol.IApp(e1,e2),fs) =
+ funs_of_expr(e1, funs_of_expr(e2, fs))
+ | funs_of_expr(CodegenThingol.IAbs(_, e),fs) = funs_of_expr(e,fs)
+ | funs_of_expr(_,fs) = fs;
+
+fun lookup nm =
+ S.Val (MLname nm) (S.app Eval_lookup (S.quote nm));
+
+fun export thy (nm,CodegenThingol.Fun(eqns,_)) =
+ let
+ val ar = length(fst(hd eqns));
+ val params = S.list (rev (MLparams ar));
+ val funs = Library.flat(map (fn (_,e) => funs_of_expr(e,[])) eqns) \ nm;
+ val globals = map lookup (filter_out is_constr funs);
+ val default_eqn = ([params], S.app Eval_Constr (S.tup[S.quote nm,params]));
+ val code = S.eqns (MLname nm) (map (mk_eqn nm ar) eqns @ [default_eqn])
+ val register = S.app Eval_register
+ (S.tup[S.quote nm, MLname nm, string_of_int ar])
+ in
+ S.Let (globals @ [code]) register
+ end
+ | export _ _ = "\"NBE no op\"";
+
+val use_show = fn s => (writeln ("\n---generated code:\n"^ s);
+ use_text(writeln o enclose "\n---compiler echo:\n" "\n---\n",
+ writeln o enclose "\n--- compiler echo (with error!):\n"
+ "\n---\n")
+ true s);
+
+val dummyIT = CodegenThingol.IType("DUMMY",[]);
+
+use_show(export "" ("append",CodegenThingol.Fun(
+ [([CodegenThingol.IConst(("Nil",dummyIT),[]),
+ CodegenThingol.IVarE("ys",dummyIT)],
+ CodegenThingol.IVarE("ys",dummyIT)),
+ ([CodegenThingol.IApp(
+ CodegenThingol.IApp(
+ CodegenThingol.IConst(("Cons",dummyIT),[]),
+ CodegenThingol.IVarE("x",dummyIT)),
+ CodegenThingol.IVarE("xs",dummyIT)),
+ CodegenThingol.IVarE("ys",dummyIT)],
+ CodegenThingol.IApp(
+ CodegenThingol.IApp(
+ CodegenThingol.IConst(("Cons",dummyIT),[]),
+ CodegenThingol.IVarE("x",dummyIT)),
+ CodegenThingol.IApp(
+ CodegenThingol.IApp(
+ CodegenThingol.IConst(("append",dummyIT),[]),
+ CodegenThingol.IVarE("xs",dummyIT)),
+ CodegenThingol.IVarE("ys",dummyIT))))]
+ ,([],dummyIT))));
+
+
+let
+fun test a b = if a=b then () else error "oops!";
+
+val CNil = Const("Nil",dummyT);
+val CCons = Const("Cons",dummyT);
+val Cappend = Const("append",dummyT);
+val Fx = Free("x",dummyT);
+val Fy = Free("y",dummyT);
+val Fxs = Free("xs",dummyT);
+val Fys = Free("ys",dummyT);
+open NBE_Eval
+in
+test (nbe(CNil)) (C "Nil");
+test (nbe(CCons)) (C "Cons");
+test (nbe(Cappend)) (C "append");
+test (nbe(Cappend $ CNil $ CNil)) (C "Nil");
+test (nbe(Cappend $ Fxs)) (A (C "append", V "xs"));
+test (nbe(Cappend $ Fxs $ Fys)) (A (A (C "append", V "xs"), V "ys"));
+test (nbe(Cappend $ CNil $ Fxs)) (V "xs");
+test (nbe(Cappend $ (CCons $ Fx $ Fxs) $ Fys))
+ (A (A (C "Cons", V "x"), A (A (C "append", V "xs"), V "ys")));
+test (nbe(Cappend $ (CCons $ Fx $ Fxs) $ (CCons $ Fy $ Fys)))
+ (A (A (C "Cons", V "x"), A (A (C "append", V "xs"), A (A (C "Cons", V "y"), V "ys"))));
+test (nbe(Cappend $ (CCons $ Fx $ (CCons $ Fy $ Fxs)) $ (CCons$Fy$Fys)))
+ (A
+ (A (C "Cons", V "x"),
+ A
+ (A (C "Cons", V "y"),
+ A (A (C "append", V "xs"), A (A (C "Cons", V "y"), V "ys")))))
+
+end;
+
+
+use_show(export "" ("app",CodegenThingol.Fun(
+ [
+ ([CodegenThingol.IConst(("Nil",dummyIT),[])],
+ CodegenThingol.IAbs(CodegenThingol.IVarE("ys",dummyIT),
+ CodegenThingol.IVarE("ys",dummyIT))),
+
+ ([CodegenThingol.IApp(
+ CodegenThingol.IApp(
+ CodegenThingol.IConst(("Cons",dummyIT),[]),
+ CodegenThingol.IVarE("x",dummyIT)),
+ CodegenThingol.IVarE("xs",dummyIT))],
+ CodegenThingol.IAbs(CodegenThingol.IVarE("ys",dummyIT),
+ CodegenThingol.IApp(
+ CodegenThingol.IApp(
+ CodegenThingol.IConst(("Cons",dummyIT),[]),
+ CodegenThingol.IVarE("x",dummyIT)),
+ CodegenThingol.IApp(
+ CodegenThingol.IApp(
+ CodegenThingol.IConst(("app",dummyIT),[]),
+ CodegenThingol.IVarE("xs",dummyIT)),
+ CodegenThingol.IVarE("ys",dummyIT)))))]
+ ,([],dummyIT))));
+
+
+let
+fun test a b = if a=b then () else error "oops!";
+
+val CNil = Const("Nil",dummyT);
+val CCons = Const("Cons",dummyT);
+val Cappend = Const("app",dummyT);
+val Fx = Free("x",dummyT);
+val Fy = Free("y",dummyT);
+val Fxs = Free("xs",dummyT);
+val Fys = Free("ys",dummyT);
+open NBE_Eval
+in
+test (nbe(CNil)) (C "Nil");
+test (nbe(CCons)) (C "Cons");
+test (nbe(Cappend)) (C "app");
+test (nbe(Cappend $ CNil)) (AbsN (1, B 1));
+test (nbe(Cappend $ CNil $ CNil)) (C "Nil");
+test (nbe(Cappend $ Fxs)) (A (C "app", V "xs"));
+test (nbe(Cappend $ Fxs $ Fys)) (A (A (C "app", V "xs"), V "ys"));
+test (nbe(Cappend $ CNil $ Fxs)) (V "xs");
+test (nbe(Cappend $ (CCons $ Fx $ Fxs) $ Fys))
+ (A (A (C "Cons", V "x"), A (A (C "app", V "xs"), V "ys")));
+test (nbe(Cappend $ (CCons $ Fx $ Fxs)))
+ (AbsN (1, A (A (C "Cons", V "x"), A (A (C "app", V "xs"), B 1))));
+test (nbe(Cappend $ (CCons $ Fx $ Fxs) $ (CCons $ Fy $ Fys)))
+ (A (A (C "Cons", V "x"), A (A (C "app", V "xs"), A (A (C "Cons", V "y"), V "ys"))));
+test (nbe(Cappend $ (CCons $ Fx $ (CCons $ Fy $ Fxs)) $ (CCons$Fy$Fys)))
+ (A
+ (A (C "Cons", V "x"),
+ A
+ (A (C "Cons", V "y"),
+ A (A (C "app", V "xs"), A (A (C "Cons", V "y"), V "ys")))));
+()
+end;
+
+
+use_show(export "" ("add",CodegenThingol.Fun(
+ [
+ ([CodegenThingol.IConst(("0",dummyIT),[])],
+ CodegenThingol.IAbs(CodegenThingol.IVarE("n",dummyIT),
+ CodegenThingol.IVarE("n",dummyIT))),
+ ([CodegenThingol.IApp(
+ CodegenThingol.IConst(("S",dummyIT),[]),
+ CodegenThingol.IVarE("n",dummyIT))],
+ CodegenThingol.IAbs(CodegenThingol.IVarE("m",dummyIT),
+ CodegenThingol.IApp(
+ CodegenThingol.IConst(("S",dummyIT),[]),
+ CodegenThingol.IApp(
+ CodegenThingol.IApp(
+ CodegenThingol.IConst(("add",dummyIT),[]),
+ CodegenThingol.IVarE("n",dummyIT)),
+ CodegenThingol.IVarE("m",dummyIT)))))]
+ ,([],dummyIT))));
+
+
+let
+fun test a b = if a=b then () else error "oops!";
+
+val C0 = Const("0",dummyT);
+val CS = Const("S",dummyT);
+val Cadd = Const("add",dummyT);
+val Fx = Free("x",dummyT);
+val Fy = Free("y",dummyT);
+open NBE_Eval
+in
+test (nbe(Cadd $ C0)) (AbsN (1, B 1));
+test (nbe(Cadd $ C0 $ C0)) (C "0");
+test (nbe(Cadd $ (CS $ (CS $ (CS $ Fx))) $ (CS $ (CS $ (CS $ Fy)))))
+(A (C "S", A (C "S", A (C "S", A (A (C "add", V "x"), A (C "S", A (C "S", A (C "S", V "y")))))))
+)
+end;
+
+
+
+use_show(export "" ("mul",CodegenThingol.Fun(
+ [
+ ([CodegenThingol.IConst(("0",dummyIT),[])],
+ CodegenThingol.IAbs(CodegenThingol.IVarE("n",dummyIT),
+ CodegenThingol.IConst(("0",dummyIT),[]))),
+ ([CodegenThingol.IApp(
+ CodegenThingol.IConst(("S",dummyIT),[]),
+ CodegenThingol.IVarE("n",dummyIT))],
+ CodegenThingol.IAbs(CodegenThingol.IVarE("m",dummyIT),
+ CodegenThingol.IApp(
+ CodegenThingol.IApp(
+ CodegenThingol.IConst(("add",dummyIT),[]),
+ CodegenThingol.IVarE("m",dummyIT)),
+ CodegenThingol.IApp(
+ CodegenThingol.IApp(
+ CodegenThingol.IConst(("mul",dummyIT),[]),
+ CodegenThingol.IVarE("n",dummyIT)),
+ CodegenThingol.IVarE("m",dummyIT)))))]
+ ,([],dummyIT))));
+
+
+let
+fun test a b = if a=b then () else error "oops!";
+
+val C0 = Const("0",dummyT);
+val CS = Const("S",dummyT);
+val Cmul = Const("mul",dummyT);
+val Fx = Free("x",dummyT);
+val Fy = Free("y",dummyT);
+open NBE_Eval
+in
+test (nbe(Cmul $ C0)) (AbsN (1, C "0"));
+test (nbe(Cmul $ C0 $ Fx)) (C "0");
+test (nbe(Cmul $ (CS $ (CS $ (CS $ C0)))))
+(AbsN (1, A (A (C "add", B 1), A (A (C "add", B 1), A (A (C "add", B 1), C "0")))));
+test (nbe(Cmul $ (CS $ (CS $ (CS $ Fx)))))
+ (AbsN (1, A (A (C "add", B 1), A (A (C "add", B 1),
+ A (A (C "add", B 1), A (A (C "mul", V "x"), B 1))))));
+test (nbe(Cmul $ (CS $ (CS $ Fx)) $ (CS $ (CS $ (CS $ Fy)))))
+(A (C "S", A(C "S",A(C "S",A(A (C "add", V "y"),A(C "S",A(C "S",A(C "S",A
+ (A (C "add", V "y"),A(A (C "mul", V "x"),A(C "S",A(C "S",A(C "S", V"y")))))))))))));
+()
+end;
+
+
+
+
+
+(*
+ | export(nm,Fun(cls,(_,ty)))
+ | export _ = ""
+
+fun top_eval st thy =
+let val t = Sign.read_term thy st
+ val tabs = CodegenPackage.mk_tabs thy;
+ val thy') =
+ CodegenPackage.expand_module NONE (CodegenPackage.codegen_term
+ thy tabs [t]) thy
+ val s = map export diff
+in use s; (* FIXME val thy'' = thy' |> *)
+ Pretty.writeln (Sign.pretty_term thy t');
+ thy'
+end
+
+structure P = OuterParse;
+
+val nbeP =
+ OuterSyntax.command "norm_by_eval" "norm by eval" K.thy_decl
+ (P.term >> (Toplevel.theory o top_eval));
+
+val _ = OuterSyntax.add_parsers [nbeP];
+
+ProofGeneral.write_keywords "nbe";
+(* isar-keywords-nbe.el -> isabelle/etc/
+ Isabelle -k nbe *)
+*)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/Tools/nbe_eval.ML Tue Feb 21 16:18:50 2006 +0100
@@ -0,0 +1,151 @@
+(* ID: $Id$
+ Author: Klaus Aehlig, Tobias Nipkow
+*)
+
+(* ------------------------------ Evaluator ------------------------------ *)
+
+(* Optimizations:
+ int instead of string in Constr
+ xtab as real table
+ treat int via ML ints
+*)
+
+signature NBE_EVAL =
+sig
+(* named terms used for output only *)
+datatype nterm =
+ C of string (* Named Constants *)
+ | V of string (* Free Variable *)
+ | B of int (* Named(!!) Bound Variables *)
+ | A of nterm*nterm (* Application *)
+ | AbsN of int*nterm ; (* Binding of named Variables *)
+
+val nbe: term -> nterm
+
+datatype Univ =
+ Constr of string*(Univ list) (* Named Constructors *)
+ | Var of string*(Univ list) (* Free variables *)
+ | BVar of int*(Univ list) (* Bound named variables *)
+ | Fun of (Univ list -> Univ) * (Univ list) * int * (unit -> nterm);
+ (* Functions *)
+val apply: Univ -> Univ -> Univ;
+val to_term: Univ -> nterm;
+
+val lookup: string -> Univ;
+val is_constr: string -> bool;
+val register: string * (Univ list -> Univ) * int -> unit
+val new_name: unit -> int;
+
+(* For testing
+val eval: term -> (Univ list) -> Univ
+*)
+
+end;
+
+(* FIXME add_funs and relatives should NOT be exported. Eventually it
+should work like for quickcheck: Eval generates code which leaves the
+function values in a public reference variable, the code is executed,
+and the value of the reference variable is added to the internal
+tables, all in one go, w/o interruption. *)
+
+
+structure NBE_Eval:NBE_EVAL =
+struct
+
+datatype nterm =
+ C of string (* Named Constants *)
+ | V of string (* Free Variable *)
+ | B of int (* Named(!!) Variables *)
+ | A of nterm * nterm (* Application *)
+ | AbsN of int * nterm (* Binding of named Variables *);
+
+fun apps t args = foldr (fn (y,x) => A(x,y)) t args;
+
+(* ------------------------------ The semantical universe --------------------- *)
+
+(*
+ Functions are given by their semantical function value. To avoid
+ trouble with the ML-type system, these functions have the most
+ generic type, that is "Univ list -> Univ". The calling convention is
+ that the arguments come as a list, the last argument first. In
+ other words, a function call that usually would look like
+
+ f x_1 x_2 ... x_n or f(x_1,x_2, ..., x_n)
+
+ would be in our convention called as
+
+ f [x_n,..,x_2,x_1]
+
+ Moreover, to handle functions that are still waiting for some
+ arguments we have additionally a list of arguments collected to far
+ and the number of arguments we're still waiting for.
+
+ Finally, it might happen, that a function does not get all the
+ arguments it needs. In this case the function must provide means to
+ present itself as a string. As this might be a heavy-wight
+ operation, we delay it.
+*)
+
+datatype Univ =
+ Constr of string*(Univ list) (* Named Constructors *)
+ | Var of string*(Univ list) (* Free variables *)
+ | BVar of int*(Univ list) (* Bound named variables *)
+ | Fun of (Univ list -> Univ) * (Univ list) * int * (unit -> nterm);
+
+fun to_term (Constr(name, args)) = apps (C name) (map to_term args)
+ | to_term (Var (name, args)) = apps (V name) (map to_term args)
+ | to_term (BVar (name, args)) = apps (B name) (map to_term args)
+ | to_term (Fun(_,args,_,name_thunk)) = apps (name_thunk ()) (map to_term args);
+
+(*
+ A typical operation, why functions might be good for, is
+ application. Moreover, functions are the only values that can
+ reasonably we applied in a semantical way.
+*)
+
+fun apply (Fun(f,xs,1,name)) x = f (x::xs)
+ | apply (Fun(f,xs,n,name)) x = Fun(f,x::xs,n-1,name)
+ | apply (Constr(name,args)) x = Constr(name,x::args)
+ | apply (Var(name,args)) x = Var(name,x::args)
+ | apply (BVar(name,args)) x = BVar(name,x::args);
+
+(* ---------------- table with the meaning of constants -------------------- *)
+
+val xfun_tab: (string * Univ)list ref = ref [];
+fun do_register sx = (xfun_tab := sx :: !xfun_tab);
+fun register(name,v,0) = do_register(name,v [])
+ | register(name,v,n) = do_register(name,Fun(v,[],n, fn () => C name));
+
+fun do_lookup [] s = NONE
+ | do_lookup ((n,v)::xs) s = if (s=n) then SOME v else do_lookup xs s;
+
+fun lookup s = case do_lookup (!xfun_tab) s of
+ SOME x => x
+ | NONE => Constr(s,[]);
+
+fun is_constr s = is_none (do_lookup (!xfun_tab) s);
+
+(* ------------------ evaluation with greetings to Tarski ------------------ *)
+
+(* generation of fresh names *)
+
+val counter = ref 0;
+
+fun new_name() = (counter := !counter +1; !counter);
+
+(* greetings to Tarski *)
+
+fun eval(Const(f,_)) xs = lookup f
+ | eval(Free(x,_)) xs = Var(x,[])
+ | eval(Bound n) xs = List.nth(xs,n)
+ | eval(s $ t) xs = apply (eval s xs) (eval t xs)
+ | eval(Abs(_,_, t)) xs = Fun ((fn [x] => eval t (x::xs)),[],1,
+ fn () => let val var = new_name() in
+ AbsN(var, to_term (eval t ((BVar(var,[]) :: xs)))) end);
+
+
+(* finally... *)
+
+fun nbe t = (counter :=0; to_term(eval t []));
+
+end;