File: src/valuelattice.ml (return to index)



Statistics:  
kind coverage
binding 21 / 21 (100%)
sequence 0 / 0 (-%)
for 0 / 0 (-%)
if/then 30 / 35 (85%)
try 1 / 1 (100%)
while 0 / 0 (-%)
match/function 42 / 43 (97%)
kind coverage
class expression 0 / 0 (-%)
class initializer 0 / 0 (-%)
class method 0 / 0 (-%)
class value 0 / 0 (-%)
toplevel expression 0 / 0 (-%)
lazy operator 31 / 31 (100%)



Source:

fold all unfold all
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
000233|                       with (Failure _) -> (*[0]*)bot)
000234|     | Str.Bot     -> (*[196]*)bot
000235|  
000236| (*  coerce_tostring : VL -> VL *)
000237| let coerce_tostring lat =
000238|   (*[167]*)if may_be_number lat
000239|   then (*[24]*)anystring
000240|   else (*[143]*){ bot with strings = lat.strings }
000241|  
000242| (*  or_join : VL -> VL -> VL *)
000243| let or_join vlat0 vlat1 =
000244|   (*[228]*)if (*[228]*)is_bot vlat0 || (*[31]*)is_bot vlat1 then (*[197]*)bot else (*FIXED*)
000245|   (*[31]*)join (if may_be_non_nil vlat0 then ((*[21]*)exclude_nil vlat0) else (*[10]*)bot)
000246|        (if may_be_nil vlat0 then (*[10]*)vlat1 else (*[21]*)bot)
000247|  
000248| (*  upper : VL -> VL *)
000249| let upper lat =
000250|   (*[2]*)let lat' = coerce_tostring lat in
000251|   (*[2]*){ lat' with strings = Str.upper lat'.strings }
000252|  
000253| (*  lower : VL -> VL *)
000254| let lower lat =
000255|   (*[2]*)let lat' = coerce_tostring lat in
000256|   (*[2]*){ lat' with strings = Str.lower lat'.strings }
000257|  
000258| (*  char : VL -> VL *)
000259| let char lat =
000260|   (*[6]*)let lat' = coerce_tonum lat in
000261|   (*[6]*)if may_be_number lat' (* char of number (or better) is any string *)
000262|   then (*[6]*)anystring
000263|   else (*[0]*)bot
000264|  
000265| (*  typep : VL -> VL *)
000266| let typep lat =
000267|   (*[16]*)join (if may_be_nil lat        then (*[4]*)string "nil" else (*[12]*)bot)
000268|    (join (if may_be_bool lat       then (*[2]*)string "boolean" else (*[14]*)bot)
000269|      (join (if may_be_number lat     then (*[6]*)string "number" else (*[10]*)bot)
000270|         (join (if may_be_userdata lat  then (*[0]*)string "userdata" else (*[16]*)bot)
000271|            (join (if may_be_table lat    then (*[2]*)string "table" else (*[14]*)bot)
000272|               (join (if may_be_strings lat then (*[2]*)string "string" else (*[14]*)bot)
000273|                         (if may_be_proc lat   then (*[4]*)string "function" else (*[12]*)bot))))))
000274|  
000275| (*  unop : unop -> VL -> VL  *)
000276| let unop op lat = 
000277|   (*[19]*)if leq lat bot
000278|   then (*[1]*)bot (* unary operation over bot is bot *)
000279|   else
000280|     match op with
000281|     | Ast.Uminus ->
000282|       (*[2]*)let lat' = coerce_tonum lat in
000283|       (*[2]*)if may_be_number lat' (* unary minus of number (or better) is number *)
000284|       then (*[2]*)number
000285|       else (*[0]*)bot
000286|     | Ast.Length ->
000287|       (*[4]*)if (*[4]*)may_be_strings lat || (*[2]*)may_be_table lat
000288|       then (*[4]*)number
000289|       else (*[0]*)bot    (* length of everything but strings and tables is number *)
000290|     | Ast.Not ->
000291|       (*[12]*)bool   (* negation of anything is bool *)
000292|  
000293| (*  binop : binop -> VL -> VL -> VL  *)
000294| let binop op lat0 lat1 = 
000295|   (*[515]*)if (*[515]*)leq lat0 bot || (*[467]*)leq lat1 bot
000296|   then (*[50]*)bot (* binary operation over a bot is bot *)
000297|   else
000298|     match op with
000299|     | Ast.Eq
000300|     | Ast.Ne -> (*[82]*)bool (* anything can be compared *)
000301|     | Ast.Lt
000302|     | Ast.Gt
000303|     | Ast.Le
000304|     | Ast.Ge -> (*[131]*)if ((*[131]*)may_be_number lat0 && (*[129]*)may_be_number lat1)
000305|                   || ((*[4]*)Str.nonempty lat0.strings && (*[2]*)Str.nonempty lat1.strings)
000306|                 then (*[127]*)bool
000307|                 else (*[4]*)bot
000308|     | Ast.Plus
000309|     | Ast.Minus
000310|     | Ast.Times
000311|     | Ast.Div
000312|     | Ast.Mod
000313|     | Ast.Pow ->
000314|       (*[197]*)if (*[197]*)may_be_number (coerce_tonum lat0) && (*[197]*)may_be_number (coerce_tonum lat1)
000315|       then (*[197]*)number
000316|       else (*[0]*)bot
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

Legend:
   some code - line containing no point
   some code - line containing only visited points
   some code - line containing only unvisited points
   some code - line containing both visited and unvisited points