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



Statistics:  
kind coverage
binding 20 / 21 (95%)
sequence 0 / 0 (-%)
for 0 / 0 (-%)
if/then 35 / 35 (100%)
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  = (*[208633]*){ 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   = (*[3636]*){ bot with tables  = LabelSet.singleton t }
000096|  
000097| (*  proc : label -> VL  *)
000098| let proc p    = (*[0]*){ bot with funs    = ProcSet.singleton (Funtag p) }
000099|  
000100| (*  builtin : builtin -> VL  *)
000101| let builtin b = (*[13489]*){ bot with funs    = ProcSet.singleton (Builtin b) }
000102|  
000103| (*  eq : VL -> VL -> bool  *)
000104| let eq v1 v2 =
000105|   (*[707613]*)TagSet.equal v1.tags v2.tags
000106|   && (*[707613]*)Num.eq v1.number v2.number
000107|   && (*[707613]*)Str.eq v1.strings v2.strings
000108|   && (*[707613]*)ProcSet.equal v1.funs v2.funs
000109|   && (*[707613]*)LabelSet.equal v1.tables v2.tables
000110|  
000111| (*  leq : VL -> VL -> bool  *)
000112| let leq v1 v2 =
000113|   (*[63008002]*)TagSet.subset v1.tags v2.tags
000114|   && (*[59570913]*)Num.leq v1.number v2.number
000115|   && (*[58642715]*)Str.leq v1.strings v2.strings
000116|   && (*[57943094]*)ProcSet.subset v1.funs v2.funs
000117|   && (*[57328764]*)LabelSet.subset v1.tables v2.tables
000118|  
000119| (*  join : VL -> VL -> VL  *)
000120| let join v1 v2 =
000121|   (*[25409118]*){ 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|   (*[3824609]*){ 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 = (*[5310877]*)leq vlat bot
000144|  
000145| (** Is argument at most nil in lattice order? *)
000146| (*  is_nil : VL -> bool *)
000147| let is_nil vlat = (*[20752]*)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 = (*[210593]*)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|      (*[17047]*)vlat.tags <> (TagSet.singleton Nil)
000157|   || (*[4680]*)vlat.number <> Num.bot
000158|   || (*[3857]*)vlat.strings <> Str.bot
000159|   || (*[3225]*)vlat.funs <> mtprocset 
000160|   || (*[2870]*)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 = (*[11939]*)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 = (*[11939]*)leq userdata vlat
000169|  
000170| (** Is argument at most number in lattice order? *)
000171| (*  is_number : VL -> bool  *)
000172| let is_number vlat = (*[11928]*)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 = (*[488318]*)leq number vlat
000177|  
000178| (** Is argument at most String.top in lattice order? *)
000179| (*  is_strings : VL -> bool  *)
000180| let is_strings vlat = (*[11925]*)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 = (*[69556]*)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|      (*[71024]*)vlat.number <> Num.bot
000190|   || (*[44234]*)vlat.tags <> mttagset
000191|   || (*[20843]*)vlat.funs <> mtprocset 
000192|   || (*[16190]*)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 = (*[19939]*)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 = (*[32838]*)vlat.tables <> mtlabelset
000201|  
000202|  
000203| (** {3 Lattice operations } *)
000204|  
000205| (*  exclude_nil : VL -> VL *)
000206| let exclude_nil lat =
000207|   (*[77824552]*)let tags = TagSet.remove Nil lat.tags in
000208|   (*[77824552]*){ lat with tags = tags }
000209|  
000210| (*  exclude_strings : VL -> VL *)
000211| let exclude_strings lat =
000212|   (*[5963733]*){ lat with strings = Str.bot }
000213|     
000214| (*  exclude_proc : VL -> VL *)
000215| let exclude_proc lat =
000216|   (*[5000]*){ lat with funs = mtprocset }
000217|  
000218| (*  exclude_tables : VL -> VL *)
000219| let exclude_tables lat =
000220|   (*[46718]*){ lat with tables = mtlabelset }
000221|  
000222| (*  only_tables : VL -> VL *)
000223| let only_tables lat =
000224|   (*[24244]*){ bot with tables = lat.tables }
000225|  
000226| (*  coerce_tonum : VL -> VL *)
000227| let coerce_tonum lat =
000228|   (*[164332]*)if may_be_number lat
000229|   then (*[77243]*)number
000230|   else match lat.strings with
000231|     | Str.Top     -> (*[25541]*)number
000232|     | Str.Const s -> ((*[27604]*)try (*[27604]*)let _ = float_of_string (String.trim s) in (*[0]*)number
000233|                       with (Failure _) -> (*[27604]*)bot)
000234|     | Str.Bot     -> (*[33944]*)bot
000235|  
000236| (*  coerce_tostring : VL -> VL *)
000237| let coerce_tostring lat =
000238|   (*[72943]*)if may_be_number lat
000239|   then (*[30116]*)anystring
000240|   else (*[42827]*){ bot with strings = lat.strings }
000241|  
000242| (*  or_join : VL -> VL -> VL *)
000243| let or_join vlat0 vlat1 =
000244|   (*[32259]*)if (*[32259]*)is_bot vlat0 || (*[18724]*)is_bot vlat1 then (*[19212]*)bot else (*FIXED*)
000245|   (*[13047]*)join (if may_be_non_nil vlat0 then ((*[10210]*)exclude_nil vlat0) else (*[2837]*)bot)
000246|        (if may_be_nil vlat0 then (*[8508]*)vlat1 else (*[4539]*)bot)
000247|  
000248| (*  upper : VL -> VL *)
000249| let upper lat =
000250|   (*[11940]*)let lat' = coerce_tostring lat in
000251|   (*[11940]*){ lat' with strings = Str.upper lat'.strings }
000252|  
000253| (*  lower : VL -> VL *)
000254| let lower lat =
000255|   (*[12014]*)let lat' = coerce_tostring lat in
000256|   (*[12014]*){ lat' with strings = Str.lower lat'.strings }
000257|  
000258| (*  char : VL -> VL *)
000259| let char lat =
000260|   (*[17285]*)let lat' = coerce_tonum lat in
000261|   (*[17285]*)if may_be_number lat' (* char of number (or better) is any string *)
000262|   then (*[10542]*)anystring
000263|   else (*[6743]*)bot
000264|  
000265| (*  typep : VL -> VL *)
000266| let typep lat =
000267|   (*[11939]*)join (if may_be_nil lat        then (*[4953]*)string "nil" else (*[6986]*)bot)
000268|    (join (if may_be_bool lat       then (*[4804]*)string "boolean" else (*[7135]*)bot)
000269|      (join (if may_be_number lat     then (*[5000]*)string "number" else (*[6939]*)bot)
000270|         (join (if may_be_userdata lat  then (*[4837]*)string "userdata" else (*[7102]*)bot)
000271|            (join (if may_be_table lat    then (*[10273]*)string "table" else (*[1666]*)bot)
000272|               (join (if may_be_strings lat then (*[6770]*)string "string" else (*[5169]*)bot)
000273|                         (if may_be_proc lat   then (*[10315]*)string "function" else (*[1624]*)bot))))))
000274|  
000275| (*  unop : unop -> VL -> VL  *)
000276| let unop op lat = 
000277|   (*[15000]*)if leq lat bot
000278|   then (*[3062]*)bot (* unary operation over bot is bot *)
000279|   else
000280|     match op with
000281|     | Ast.Uminus ->
000282|       (*[3980]*)let lat' = coerce_tonum lat in
000283|       (*[3980]*)if may_be_number lat' (* unary minus of number (or better) is number *)
000284|       then (*[2370]*)number
000285|       else (*[1610]*)bot
000286|     | Ast.Length ->
000287|       (*[3977]*)if (*[3977]*)may_be_strings lat || (*[1590]*)may_be_table lat
000288|       then (*[3774]*)number
000289|       else (*[203]*)bot    (* length of everything but strings and tables is number *)
000290|     | Ast.Not ->
000291|       (*[3981]*)bool   (* negation of anything is bool *)
000292|  
000293| (*  binop : binop -> VL -> VL -> VL  *)
000294| let binop op lat0 lat1 = 
000295|   (*[139275]*)if (*[139275]*)leq lat0 bot || (*[125973]*)leq lat1 bot
000296|   then (*[26617]*)bot (* binary operation over a bot is bot *)
000297|   else
000298|     match op with
000299|     | Ast.Eq
000300|     | Ast.Ne -> (*[15927]*)bool (* anything can be compared *)
000301|     | Ast.Lt
000302|     | Ast.Gt
000303|     | Ast.Le
000304|     | Ast.Ge -> (*[31816]*)if ((*[31816]*)may_be_number lat0 && (*[14838]*)may_be_number lat1)
000305|                   || ((*[24784]*)Str.nonempty lat0.strings && (*[15596]*)Str.nonempty lat1.strings)
000306|                 then (*[16708]*)bool
000307|                 else (*[15108]*)bot
000308|     | Ast.Plus
000309|     | Ast.Minus
000310|     | Ast.Times
000311|     | Ast.Div
000312|     | Ast.Mod
000313|     | Ast.Pow ->
000314|       (*[53788]*)if (*[53788]*)may_be_number (coerce_tonum lat0) && (*[33838]*)may_be_number (coerce_tonum lat1)
000315|       then (*[21128]*)number
000316|       else (*[32660]*)bot
000317|     | Ast.Concat ->
000318|       (*[11127]*)let lat0' = coerce_tostring lat0 in
000319|       (*[11127]*)let lat1' = coerce_tostring lat1 in
000320|       (*[11127]*){ 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