000001| (** Abstract value datatype and operations *)
000002|
000003| module Num = Numberlattice
000004| module Str = Stringlattice
000005|
000006| (** {3 Lattice type and primitives } *)
000007|
000008| type tag =
000009| | Nil
000010| | Bool
000011| | Userdata
000012|
000013| type proc =
000014| | Funtag of int
000015| | Builtin of builtin
000016| and builtin =
000017| | Error
000018| | Exit
000019| | Next
000020| | INext (* internal to IPairs *)
000021| | Pairs
000022| | IPairs
000023| | Print
000024| | Write
000025| | Tonumber
000026| | Tostring
000027| | Abs
000028| | Ceil
000029| | Floor
000030| | Mod
000031| | Random
000032| | Strlen
000033| | Strupper
000034| | Strlower
000035| | Strchar
000036| | Strbyte
000037| | Strsub
000038| | Sqrt
000039| | Type
000040| | Format
000041| | Tblconcat
000042| | Getmetatable
000043| | Setmetatable
000044| | Rawget
000045| | Rawset
000046|
000047| (* TODO: experiment with Patricia trees *)
000048| module TagSet = Set.Make(struct type t = tag
000049| let compare = (*[1]*)Pervasives.compare end)
000050| module ProcSet = Set.Make(struct type t = proc
000051| let compare = (*[1]*)Pervasives.compare end)
000052| module LabelSet = Set.Make(struct type t = int
000053| let compare = (*[1]*)Pervasives.compare end)
000054|
000055| type elem = { tags : TagSet.t;
000056| number : Num.elem;
000057| strings : Str.elem;
000058| funs : ProcSet.t;
000059| tables : LabelSet.t; }
000060|
000061| (* let top = *)
000062|
000063| let mttagset = (*[1]*)TagSet.empty
000064| let mtprocset = (*[1]*)ProcSet.empty
000065| let mtlabelset = (*[1]*)LabelSet.empty
000066|
000067| (* bot : VL *)
000068| let bot = (*[1]*){ tags = mttagset;
000069| number = Num.bot;
000070| strings = Str.bot;
000071| funs = mtprocset;
000072| tables = mtlabelset; }
000073|
000074| let mktagelem t = (*[3]*){ bot with tags = TagSet.singleton t }
000075|
000076| (* nil : VL *)
000077| let nil = (*[1]*)mktagelem Nil
000078|
000079| (* bool : VL *)
000080| let bool = (*[1]*)mktagelem Bool
000081|
000082| (* number : VL *)
000083| let number = (*[1]*){ bot with number = Num.top }
000084|
000085| (* userdata : VL *)
000086| let userdata = (*[1]*)mktagelem Userdata
000087|
000088| (* string : string -> VL *)
000089| let string s = (*[2882]*){ bot with strings = Str.const s }
000090|
000091| (* anystring : VL *)
000092| let anystring = (*[1]*){ bot with strings = Str.top }
000093|
000094| (* table : label -> VL *)
000095| let table t = (*[354]*){ bot with tables = LabelSet.singleton t }
000096|
000097| (* proc : label -> VL *)
000098| let proc p = (*[394]*){ bot with funs = ProcSet.singleton (Funtag p) }
000099|
000100| (* builtin : builtin -> VL *)
000101| let builtin b = (*[49]*){ bot with funs = ProcSet.singleton (Builtin b) }
000102|
000103| (* eq : VL -> VL -> bool *)
000104| let eq v1 v2 =
000105| (*[2]*)TagSet.equal v1.tags v2.tags
000106| && (*[2]*)Num.eq v1.number v2.number
000107| && (*[2]*)Str.eq v1.strings v2.strings
000108| && (*[2]*)ProcSet.equal v1.funs v2.funs
000109| && (*[2]*)LabelSet.equal v1.tables v2.tables
000110|
000111| (* leq : VL -> VL -> bool *)
000112| let leq v1 v2 =
000113| (*[441519]*)TagSet.subset v1.tags v2.tags
000114| && (*[432192]*)Num.leq v1.number v2.number
000115| && (*[425510]*)Str.leq v1.strings v2.strings
000116| && (*[421707]*)ProcSet.subset v1.funs v2.funs
000117| && (*[419517]*)LabelSet.subset v1.tables v2.tables
000118|
000119| (* join : VL -> VL -> VL *)
000120| let join v1 v2 =
000121| (*[6550830]*){ tags = TagSet.union v1.tags v2.tags;
000122| number = Num.join v1.number v2.number;
000123| strings = Str.join v1.strings v2.strings;
000124| funs = ProcSet.union v1.funs v2.funs;
000125| tables = LabelSet.union v1.tables v2.tables; }
000126|
000127| (* meet : VL -> VL -> VL *)
000128| let meet v1 v2 =
000129| (*[475]*){ tags = TagSet.inter v1.tags v2.tags;
000130| number = Num.meet v1.number v2.number;
000131| strings = Str.meet v1.strings v2.strings;
000132| funs = ProcSet.inter v1.funs v2.funs;
000133| tables = LabelSet.inter v1.tables v2.tables; }
000134|
000135| (* number_or_nil : VL *)
000136| let number_or_nil = (*[1]*)join nil number
000137|
000138|
000139| (** {3 Lattice queries } *)
000140|
000141| (** Is argument bot in lattice order? *)
000142| (* is_bot : VL -> bool *)
000143| let is_bot vlat = (*[22203]*)leq vlat bot
000144|
000145| (** Is argument at most nil in lattice order? *)
000146| (* is_nil : VL -> bool *)
000147| let is_nil vlat = (*[42]*)leq vlat nil
000148|
000149| (** Is argument at least nil in lattice order? *)
000150| (* may_be_nil : VL -> bool *)
000151| let may_be_nil vlat = (*[4257]*)leq nil vlat
000152|
000153| (** Can argument be different from nil in lattice order? *)
000154| (* may_be_non_nil : VL -> bool *)
000155| let may_be_non_nil vlat =
000156| (*[85]*)vlat.tags <> (TagSet.singleton Nil)
000157| || (*[14]*)vlat.number <> Num.bot
000158| || (*[14]*)vlat.strings <> Str.bot
000159| || (*[14]*)vlat.funs <> mtprocset
000160| || (*[14]*)vlat.tables <> mtlabelset
000161|
000162| (** Is argument at least bool in lattice order? *)
000163| (* may_be_bool : VL -> bool *)
000164| let may_be_bool vlat = (*[30]*)leq bool vlat
000165|
000166| (** Is argument at least userdata in lattice order? *)
000167| (* may_be_userdata : VL -> bool *)
000168| let may_be_userdata vlat = (*[16]*)leq userdata vlat
000169|
000170| (** Is argument at most number in lattice order? *)
000171| (* is_number : VL -> bool *)
000172| let is_number vlat = (*[34]*)leq vlat number
000173|
000174| (** Is argument at least number in lattice order? *)
000175| (* may_be_number : VL -> bool *)
000176| let may_be_number vlat = (*[2285]*)leq number vlat
000177|
000178| (** Is argument at most String.top in lattice order? *)
000179| (* is_strings : VL -> bool *)
000180| let is_strings vlat = (*[6]*)leq vlat anystring
000181|
000182| (** Is argument strictly greater than String.bot in lattice order? *)
000183| (* may_be_strings : VL -> bool *)
000184| let may_be_strings vlat = (*[105]*)vlat.strings <> Str.bot
000185|
000186| (** Is argument strictly greater then bot for some non-string component in lattice order? *)
000187| (* may_be_non_strings : VL -> bool *)
000188| let may_be_non_strings vlat =
000189| (*[1419]*)vlat.number <> Num.bot
000190| || (*[1117]*)vlat.tags <> mttagset
000191| || (*[1027]*)vlat.funs <> mtprocset
000192| || (*[1011]*)vlat.tables <> mtlabelset
000193|
000194| (** Is argument strictly greater than ProcSet.empty in lattice order? *)
000195| (* may_be_proc : VL -> bool *)
000196| let may_be_proc vlat = (*[2593]*)vlat.funs <> mtprocset
000197|
000198| (** Is argument strictly greater than LabelSet.empty in lattice order? *)
000199| (* may_be_table : VL -> bool *)
000200| let may_be_table vlat = (*[1113]*)vlat.tables <> mtlabelset
000201|
000202|
000203| (** {3 Lattice operations } *)
000204|
000205| (* exclude_nil : VL -> VL *)
000206| let exclude_nil lat =
000207| (*[4404]*)let tags = TagSet.remove Nil lat.tags in
000208| (*[4404]*){ lat with tags = tags }
000209|
000210| (* exclude_strings : VL -> VL *)
000211| let exclude_strings lat =
000212| (*[171]*){ lat with strings = Str.bot }
000213|
000214| (* exclude_proc : VL -> VL *)
000215| let exclude_proc lat =
000216| (*[975]*){ lat with funs = mtprocset }
000217|
000218| (* exclude_tables : VL -> VL *)
000219| let exclude_tables lat =
000220| (*[8]*){ lat with tables = mtlabelset }
000221|
000222| (* only_tables : VL -> VL *)
000223| let only_tables lat =
000224| (*[363]*){ bot with tables = lat.tables }
000225|
000226| (* coerce_tonum : VL -> VL *)
000227| let coerce_tonum lat =
000228| (*[1036]*)if may_be_number lat
000229| then (*[792]*)number
000230| else match lat.strings with
000231| | Str.Top -> (*[12]*)number
000232| | Str.Const s -> ((*[36]*)try (*[36]*)let _ = float_of_string (String.trim s) in (*[36]*)number
000317| | Ast.Concat ->
000318| (*[55]*)let lat0' = coerce_tostring lat0 in
000319| (*[55]*)let lat1' = coerce_tostring lat1 in
000320| (*[55]*){ bot with strings = Str.concat lat0'.strings lat1'.strings }
000321|
000322|
000323| (** {3 Pretty printing routines } *)
000324|
000325| (* pprint_tags : tagset -> unit *)
000326| let pprint_tags ts =
000327| (* pprint_tag : tag -> unit *)
000328| let pprint_tag t = match t with
000329| | Nil -> Format.printf "Nil"
000330| | Bool -> Format.printf "Bool"
000331| | Userdata -> Format.printf "Userdata" in
000332| begin
000333| Format.printf "{ @[<h 1>";
000334| ignore (TagSet.fold (fun t first ->
000335| if first
000336| then (pprint_tag t; false)
000337| else
000338| begin
000339| Format.printf ",";
000340| Format.print_space ();
000341| pprint_tag t;
000342| false
000343| end) ts true);
000344| Format.printf "@] }";
000345| end
000346|
000347| (* pprint_procs : procset -> unit *)
000348| let pprint_procs ts =
000349| (* builtin_name : builtin -> string *)
000350| let builtin_name b = match b with
000351| | Error -> "error"
000352| | Exit -> "exit"
000353| | Next -> "next"
000354| | INext -> "inext"
000355| | Pairs -> "pairs"
000356| | IPairs -> "ipairs"
000357| | Print -> "print"
000358| | Write -> "write"
000359| | Tonumber -> "tonumber"
000360| | Tostring -> "tostring"
000361| | Abs -> "abs"
000362| | Ceil -> "ceil"
000363| | Floor -> "floor"
000364| | Mod -> "mod"
000365| | Random -> "random"
000366| | Strlen -> "strlen"
000367| | Strupper -> "strupper"
000368| | Strlower -> "strlower"
000369| | Strchar -> "strchar"
000370| | Strbyte -> "strbyte"
000371| | Strsub -> "strsub"
000372| | Sqrt -> "sqrt"
000373| | Type -> "type"
000374| | Format -> "format"
000375| | Tblconcat -> "tblconcat"
000376| | Getmetatable -> "getmetatable"
000377| | Setmetatable -> "setmetatable"
000378| | Rawget -> "rawget"
000379| | Rawset -> "rawset" in
000380|
000381| (* pprint_proc : proc -> unit *)
000382| let pprint_proc p = match p with
000383| | Funtag t -> Format.printf "%i" t
000384| | Builtin b -> Format.printf "[builtin:%s]" (builtin_name b) in
000385|
000386| begin
000387| Format.printf "{ @[<h 1>";
000388| ignore (ProcSet.fold (fun t first ->
000389| if first
000390| then (pprint_proc t; false)
000391| else
000392| begin
000393| Format.printf ",";
000394| Format.print_space ();
000395| pprint_proc t;
000396| false
000397| end) ts true);
000398| Format.printf "@] }";
000399| end
000400|
000401| (* pprint_labels : labelset -> unit *)
000402| let pprint_labels ts =
000403| begin
000404| Format.printf "{ @[<h 1>";
000405| ignore (LabelSet.fold (fun t first ->
000406| if first
000407| then (Format.printf "%i" t; false)
000408| else
000409| begin
000410| Format.printf ",";
000411| Format.print_space ();
000412| Format.printf "%i" t;
000413| false
000414| end) ts true);
000415| Format.printf "@] }";
000416| end
000417|
000418| (* pprint : VL -> unit *)
000419| let pprint v =
000420| let () = Format.printf "{ @[<v 0>" in
000421| let funs =
000422| [(fun first -> if v.tags = mttagset then first else
000423| begin
000424| Format.printf "tags: ";
000425| pprint_tags v.tags;
000426| false
000427| end);
000428| (fun first -> if v.number = Num.bot then first else
000429| begin
000430| (if first then () else Format.print_space ());
000431| Format.printf "number: ";
000432| Num.pprint v.number;
000433| false
000434| end);
000435| (fun first -> if v.strings = Str.bot then first else
000436| begin
000437| (if first then () else Format.print_space ());
000438| Format.printf "strings: ";
000439| Str.pprint v.strings;
000440| false
000441| end);
000442| (fun first -> if v.funs = mtprocset then first else
000443| begin
000444| (if first then () else Format.print_space ());
000445| Format.printf "funs: ";
000446| pprint_procs v.funs;
000447| false
000448| end);
000449| (fun first -> if v.tables = mtlabelset then first else
000450| begin
000451| (if first then () else Format.print_space ());
000452| Format.printf "tables: ";
000453| pprint_labels v.tables;
000454| false
000455| end) ] in
000456| let _ = List.fold_left (fun firstacc f -> f firstacc) true funs in
000457| Format.printf "@] }"
000458|
000459| (* to_string : elem -> string *)
000460| let to_string v =
000461| let buf = Buffer.create 64 in
000462| let out,flush = Format.get_formatter_output_functions () in (* save previous outputters *)
000463| begin
000464| Format.set_formatter_output_functions (Buffer.add_substring buf) (fun () -> ());
000465| pprint v;
000466| Format.print_flush ();
000467| Format.set_formatter_output_functions out flush; (* restore previous outputters *)
000468| Buffer.contents buf
000469| end