Statistics: |
|
|
000002|
000003| module Abs = Absencelattice
000004| module VL = Valuelattice
000005| module EL = Envlattice
000006| module PL = Proplattice
000007| module ST = Storelattice
000008|
000009| type elem = { store : ST.elem;
000010| env : EL.elem; }
000011|
000012| (* leq : elem -> elem -> bool *)
000013| let leq st0 st1 =
000014| (*[18513]*)ST.leq st0.store st1.store && (*[5467]*)EL.leq st0.env st1.env
000015|
000016| (* eq : elem -> elem -> bool *)
000017| let eq st0 st1 =
000018| (*[0]*)ST.eq st0.store st1.store && (*[0]*)EL.eq st0.env st1.env
000020| (* join : elem -> elem -> bool *)
000021| let join st0 st1 =
000022| (*[61142]*){ store = ST.join st0.store st1.store;
000023| env = EL.join st0.env st1.env; }
000024|
000025| (* meet : elem -> elem -> bool *)
000026| let meet st0 st1 =
000027| (*[0]*){ store = ST.meet st0.store st1.store;
000029|
000030| (* bot : elem *)
000031| let bot = (*[1]*){ store = ST.bot;
000032| env = EL.bot; }
000033|
000034|
000035| (** {3 Lattice operations } *)
000036|
000037| (* is_bot : SL -> bool *)
000038| let is_bot slat = (*[13711]*)leq slat bot
000039|
000040| (* build_record : (string * VL) list -> PL *)
000041| let build_record bs =
000042| (*[6]*)let props, vls = List.split bs in
000043| (*[6]*)PL.add_all_params props vls PL.mt
000044|
000045| (* init : elem *)
000046| let init =
000047| (*[1]*)let localenvlab = Label.make_res_label() in
000048| (*[1]*)let globallabel = Label.make_res_label() in
000049| (*[1]*)let arglabel = Label.make_res_label() in
000050| (*[1]*)let iolabel = Label.make_res_label() in
000051| (*[1]*)let mathlabel = Label.make_res_label() in
000052| (*[1]*)let oslabel = Label.make_res_label() in
000053| (*[1]*)let stringlabel = Label.make_res_label() in
000054| (*[1]*)let tablelabel = Label.make_res_label() in
000055| (*[1]*)let store = List.fold_left
000056| (fun store (lab,table) -> (*[8]*)ST.add_label store lab table) ST.bot
000057| [ (localenvlab, PL.mt);
000058| (globallabel, build_record
000059| [ ("error", VL.builtin VL.Error);
000060| ("next", VL.builtin VL.Next);
000061| ("pairs", VL.builtin VL.Pairs);
000062| ("ipairs", VL.builtin VL.IPairs);
000063| ("print", VL.builtin VL.Print);
000064| ("tonumber", VL.builtin VL.Tonumber);
000065| ("tostring", VL.builtin VL.Tostring);
000066| (* ("abs", VL.builtin VL.Abs); *) (* from Lua 2.5 *)
000067| (* ("write", VL.builtin VL.Write); *) (* from Lua 2.5 *)
000068| (* ("floor", VL.builtin VL.Floor); *) (* from Lua 2.5 *)
000069| (* ("mod", VL.builtin VL.Mod); *) (* from Lua 2.5 *)
000070| (* ("strlen", VL.builtin VL.Strlen);*) (* from Lua 2.5 *)
000071| (* ("sqrt", VL.builtin VL.Sqrt); *) (* from Lua 2.5 *)
000072| (* ("format", VL.builtin VL.Format);*) (* from Lua 2.5 *)
000073| ("_VERSION", VL.anystring);
000074| ("_G", VL.table globallabel);
000075| ("arg", VL.table arglabel);
000076| ("io", VL.table iolabel);
000077| ("math", VL.table mathlabel);
000078| ("os", VL.table oslabel);
000079| ("string", VL.table stringlabel);
000080| ("table", VL.table tablelabel);
000081| ("type", VL.builtin VL.Type);
000082| ("setmetatable", VL.builtin VL.Setmetatable);
000083| ("getmetatable", VL.builtin VL.Getmetatable);
000084| ("rawget", VL.builtin VL.Rawget);
000085| ("rawset", VL.builtin VL.Rawset);
000086| ]);
000087| (arglabel, PL.add_nonstr_default VL.number VL.anystring PL.mt);
000088| (iolabel, build_record
000089| [ ("write", VL.builtin VL.Write); ]);
000090| (mathlabel, build_record
000091| [ ("abs", VL.builtin VL.Abs);
000092| ("ceil", VL.builtin VL.Ceil);
000093| ("floor", VL.builtin VL.Floor);
000094| ("huge", VL.number);
000095| ("random", VL.builtin VL.Random);
000096| ("sqrt", VL.builtin VL.Sqrt);
000097| ]);
000098| (oslabel, build_record
000099| [ ("exit", VL.builtin VL.Exit); ]);
000100| (stringlabel, build_record
000101| [ ("len", VL.builtin VL.Strlen);
000102| ("upper", VL.builtin VL.Strupper);
000103| ("lower", VL.builtin VL.Strlower);
000104| ("char", VL.builtin VL.Strchar);
000105| ("byte", VL.builtin VL.Strbyte);
000106| ("sub", VL.builtin VL.Strsub);
000107| ("format", VL.builtin VL.Format);
000108| ]);
000109| (tablelabel, build_record
000110| [ ("concat", VL.builtin VL.Tblconcat);
000111| ]);
000112| ] in
000113| (*[1]*)let env = EL.init localenvlab globallabel in
000114| (*[1]*){ store = store;
000115| env = env; }
000116|
000117|
000118| (* apply_builtin : builtin -> SL -> VL list -> SL * VL list *)
000119| let rec apply_builtin bi slat vlats =
000120| (*[658]*)if is_bot slat then ((*[5]*)bot,[]) else
000121| match bi with
000122| | VL.Error -> ((*[12]*)bot,[]) (* unreachable *)
000123| | VL.Exit -> ((*[2]*)bot,[]) (* unreachable *)
000124| | VL.Next ->
000125| (match vlats with
000126| | [] -> ((*[0]*)bot,[]) (*error*)
000128| (*[72]*)if VL.may_be_table vlat then
000129| (*[72]*)let keys = VL.join VL.nil (* potentially: end of table *)
000130| (ST.lookup_all_keys slat.store vlat) in
000131| (*[72]*)let values = VL.join VL.nil (* potentially: end of table *)
000132| (ST.lookup_all_props slat.store vlat) in
000133| (* possible strengthening: if 2nd arg is nil and table is definitely non-empty (has definite entries), *)
000134| ((*[72]*)slat,[keys;values]) (* then result cannot be nil *)
000135| else ((*[0]*)bot,[])) (*error*)
000138| | [] -> ((*[0]*)bot,[]) (*error*)
000140| (*[15]*)if VL.may_be_table vlat
000141| then
000142| (*[15]*)let keys = ST.lookup_all_keys slat.store vlat in
000143| ((*[15]*)if VL.may_be_number keys
000144| then
000145| (*[10]*)let keys = VL.join VL.nil VL.number in (* potentially: end of table *)
000146| (*[10]*)let values = VL.join VL.nil (* potentially: end of table *)
000147| (ST.lookup_all_nonstr_props slat.store vlat) in (* array entries are nonstr *)
000148| ((*[10]*)slat,[keys;values])
000149| else
000150| (*[5]*)let keys,values = VL.nil,VL.nil in (* end of table *)
000151| ((*[5]*)slat,[keys;values]))
000152| else ((*[0]*)bot,[])) (*error*)
000155| | [] -> ((*[0]*)bot,[]) (*error*)
000157| (*[4]*)let vlat' = VL.only_tables vlat in
000158| (*[4]*)if VL.is_bot vlat'
000159| then ((*[0]*)bot,[]) (*error*)
000161| | VL.IPairs ->
000162| (match vlats with
000163| | [] -> ((*[0]*)bot,[]) (*error*)
000165| (*[6]*)let vlat' = VL.only_tables vlat in
000166| (*[6]*)if VL.is_bot vlat'
000167| then ((*[0]*)bot,[]) (*error*)
000169| | VL.Print -> ((*[306]*)slat,[VL.nil]) (* no return value specified - Lua2.5 impl returns nil *)
000170| | VL.Write ->
000171| (match vlats with
000172| | [] -> ((*[7]*)slat, [VL.userdata])
000173| | vlat::vlats ->
000174| (*[14]*)if (*[14]*)VL.may_be_number vlat || (*[7]*)VL.may_be_strings vlat (* may succeed *)
000175| then (*[14]*)apply_builtin bi slat vlats
000176| else ((*[0]*)bot, []))
000179| | [] -> ((*[0]*)bot,[]) (*error*)
000181| (*[34]*)if VL.is_nil vlat then ((*[0]*)bot,[]) (* unreachable *)
000183| (*[34]*)let retval =
000184| if VL.is_number vlat then (*[28]*)VL.number (* number arg (at most) *)
000185| else (*[6]*)if VL.is_strings vlat then (*[4]*)VL.number_or_nil (* string arg (at most) *)
000186| else (*[2]*)if VL.may_be_number vlat then (*[0]*)VL.number_or_nil (* number or other arg *)
000188| else (*[0]*)VL.nil (* no string or number arguments *)
000192| | [] -> ((*[0]*)bot,[]) (*error*)
000194| (*[2]*)if VL.is_bot vlat then ((*[0]*)bot,[]) (* unreachable *)
000196| | VL.Abs
000197| | VL.Ceil
000198| | VL.Floor ->
000199| (match vlats with
000200| | vlat::_ ->
000201| (*[2]*)if VL.is_bot vlat then ((*[0]*)bot, []) (* unreachable *)
000203| else ((*[0]*)bot, [])
000204| | _ -> ((*[0]*)bot, []))
000207| | vl0::vl1::_ -> (*[0]*)let res = VL.binop Ast.Mod vl0 vl1 in
000208| (*[0]*)if res = VL.bot then ((*[0]*)bot, [VL.bot])
000209| else ((*[0]*)slat, [res])
000210| | _ -> ((*[0]*)bot, []))
000213| | [] -> ((*[0]*)slat,[VL.number])
000215| then ((*[2]*)slat,[VL.number])
000216| else ((*[0]*)bot, [])
000218| && (*[2]*)VL.may_be_number (VL.coerce_tonum vl1)
000219| then ((*[2]*)slat,[VL.number])
000220| else ((*[0]*)bot, [])
000221| | _ -> ((*[0]*)bot, []))
000224| | [] -> ((*[0]*)bot,[]) (*error*)
000226| (*[35]*)if VL.may_be_strings (VL.coerce_tostring vlat)
000227| then ((*[33]*)slat,[VL.number])
000228| else ((*[2]*)bot,[]))
000229| | VL.Strupper ->
000230| (match vlats with
000231| | [] -> ((*[0]*)bot,[]) (*error*)
000233| | VL.Strlower ->
000234| (match vlats with
000235| | [] -> ((*[0]*)bot,[]) (*error*)
000237| | VL.Strchar ->
000238| (match vlats with
000239| | [] -> ((*[2]*)slat, [VL.string ""])
000240| | vlat::vlats ->
000241| (*[6]*)let vlat' = VL.char vlat in
000242| (*[6]*)if VL.may_be_strings vlat' (* may succeed *)
000243| then
000244| (*[6]*)let slat',vlats' = apply_builtin bi slat vlats in (* recurse *)
000245| (match vlats' with
000246| | [] -> ((*[0]*)bot, []) (* propagate error *)
000248| else ((*[0]*)bot, []))
000251| | [] -> ((*[0]*)bot, [])
000253| then ((*[2]*)slat,[VL.number_or_nil])
000254| else ((*[0]*)bot, [])
000255| | arg1::arg2::[] -> (*[0]*)if (*[0]*)VL.may_be_strings (VL.coerce_tostring arg1)
000256| && (*[0]*)VL.may_be_number (VL.coerce_tonum arg2)
000257| then ((*[0]*)slat,[VL.number_or_nil])
000258| else ((*[0]*)bot, [])
000260| && (*[2]*)VL.may_be_number (VL.coerce_tonum arg2)
000261| && (*[2]*)VL.may_be_number (VL.coerce_tonum arg3)
000262| then (* almost conservative :-) for static strings, length gives a bound *)
000263| ((*[2]*)slat,[VL.number_or_nil;VL.number_or_nil;VL.number_or_nil;VL.number_or_nil;VL.number_or_nil;
000264| VL.number_or_nil;VL.number_or_nil;VL.number_or_nil;VL.number_or_nil;VL.number_or_nil ])
000265| else ((*[0]*)bot, []))
000268| | [] | [ _ ] -> ((*[0]*)bot, [])
000269| | arg1::arg2::[] -> (*[0]*)apply_builtin bi slat ([arg1;VL.number;arg2])
000271| (*[8]*)let arg1' = VL.coerce_tostring arg1 in
000272| (*[8]*)let arg2' = VL.coerce_tonum arg2 in
000273| (*[8]*)let arg3' = VL.coerce_tonum arg3 in
000274| (*[8]*)if (*[8]*)VL.may_be_strings arg1' && (*[8]*)VL.may_be_number arg2' && (*[8]*)VL.may_be_number arg3'
000275| then ((*[8]*)slat,[VL.anystring])
000276| else ((*[0]*)bot,[]))
000279| | [] -> ((*[0]*)bot,[]) (*error*)
000281| (*[2]*)if VL.may_be_number (VL.coerce_tonum vlat)
000282| then ((*[2]*)slat,[VL.number])
000283| else ((*[0]*)bot,[]))
000286| | [] -> ((*[0]*)bot,[]) (*error*)
000288| | VL.Format ->
000289| (match vlats with
000290| | [] -> ((*[0]*)bot,[]) (*error*)
000292| (*[4]*)if VL.is_nil vlat then ((*[0]*)bot,[]) (*unreachable*)
000294| else ((*[0]*)bot,[]))
000297| | [] -> ((*[0]*)bot,[]) (*error*)
000301| | [] -> ((*[0]*)slat,[VL.anystring]) (* one arg *)
000303| (*[6]*)if VL.may_be_strings (VL.coerce_tostring vlat2)
000304| then (match vlats2 with
000305| | [] -> ((*[2]*)slat,[VL.anystring]) (* two args *)
000306| | vlat3::vlats3 ->
000307| (*[4]*)if VL.may_be_number (VL.coerce_tonum vlat3)
000308| then (match vlats3 with
000309| | [] -> ((*[2]*)slat,[VL.anystring]) (* three args *)
000310| | vlat4::_ ->
000311| (*[2]*)if VL.may_be_number (VL.coerce_tonum vlat4)
000312| then ((*[2]*)slat,[VL.anystring]) (* four args *)
000313| else ((*[0]*)bot,[]))
000314| else ((*[0]*)bot,[]))
000315| else ((*[0]*)bot,[]))
000316| else ((*[0]*)bot,[])) (*unreachable*)
000319| | [] -> ((*[0]*)bot,[]) (*error*)
000321| | VL.Setmetatable ->
000322| (match vlats with
000323| | [] -> ((*[0]*)bot,[]) (*error*)
000324| | [_] -> ((*[0]*)bot,[]) (*error*)
000326| (*[70]*)let store' = ST.set_metatable slat.store vlat vlat' in
000327| ((*[70]*){slat with store = store'},[vlat]))
000328| | VL.Rawget ->
000329| (match vlats with
000330| | [] -> ((*[0]*)bot,[]) (*error*)
000331| | [_] -> ((*[0]*)bot,[]) (*error*)
000333| | VL.Rawset ->
000334| (match vlats with
000335| | [] -> ((*[0]*)bot,[]) (*error*)
000336| | _::[] -> ((*[0]*)bot,[]) (*error*)
000337| | _::_::[] -> ((*[0]*)bot,[]) (*error*)
000339| (*[4]*)let store' = ST.raw_set slat.store vlat0 vlat1 vlat2 in
000340| ((*[4]*){slat with store = store'},[VL.only_tables vlat0]))
000341|
000342|
000343| (* add_local : SL -> VL -> str -> SL *)
000344| let add_local slat vlat x =
000345| (*[813]*)if (*[813]*)is_bot slat || (*[813]*)VL.is_bot vlat
000346| then (*[8]*)bot
000347| else
000348| (*[805]*)let store' =
000349| EL.fold (fun (localslab,_) storeacc ->
000350| (*[883]*)let env = ST.find_label slat.store localslab in
000351| (*[883]*)let env' = PL.add_local x vlat env in (* strong update *)
000352| (*[883]*)ST.join (ST.add_label slat.store localslab env') storeacc)
000353| slat.env ST.bot in
000354| (*[805]*){ slat with store = store' }
000355|
000356| (* add_local_list : SL -> VL list -> str list -> SL *)
000357| let rec add_local_list slat vlats xs =
000358| (*[1599]*)if is_bot slat
000359| then (*[118]*)bot
000360| else match (xs,vlats) with
000361| | [], [] -> (*[660]*)slat
000362| | x::xs,vlat::vlats ->
000363| (*[783]*)let slat' = add_local slat vlat x in
000364| (*[783]*)add_local_list slat' vlats xs
000365| | x::xs,[] ->
000366| (*[30]*)let slat' = add_local slat VL.nil x in (* missing value: assign nil *)
000367| (*[30]*)add_local_list slat' [] xs
000368| | [], vlat::vlats ->
000369| (*[8]*)add_local_list slat vlats [] (* missing local: drop excess value *)
000370|
000371| (* enter_scope : SL -> label -> SL *)
000372| let enter_scope slat label =
000373| (*[778]*)if is_bot slat
000374| then (*[107]*)bot
000375| else
000376| (*[671]*){ store = ST.add_label slat.store label PL.mt;
000377| env = EL.enter_scope slat.env label }
000378|
000379| (* build_prop_chain : EL -> PL *)
000380| let build_prop_chain scopechain =
000381| (*[394]*)if EL.is_bot scopechain
000382| then (*[14]*)PL.bot
000383| else
000384| (*[380]*)EL.fold (fun (i,is) scset -> (*[380]*)PL.add_scopechain scset (i::is)) scopechain PL.mt
000385|
000386| (* read_name : SL -> string -> VL *)
000387| let read_name slat name =
000388| (* scope_read : lab -> lab list -> VL *)
000389| (*[4440]*)let rec scope_read envlab scopechain =
000390| (*[9234]*)if ST.is_bot slat.store
000391| then (*[0]*)VL.bot
000393| (*[9234]*)let env = ST.find_label slat.store envlab in
000394| (*[9234]*)if PL.is_bot env
000395| then (*[24]*)VL.bot
000396| else
000397| (*[9210]*)try
000398| (*[9210]*)let vl,abs = PL.find_exn name env in (* slight hack: direct lookup *)
000399| (*[4525]*)if Abs.eq abs Abs.maybe_absent
000400| then (*[83]*)VL.join vl (continue_read scopechain)
000401| else (*[4442]*)vl (* certain entry, don't continue *)
000402| with Not_found -> (*[4685]*)continue_read scopechain
000403| (* continue_read : lab list -> VL *)
000404| and continue_read scopechain = match scopechain with
000405| | [] -> (*[156]*)VL.nil (* not found: return nil *)
000406| | outerenvlab::scopechain' -> (*[4612]*)scope_read outerenvlab scopechain'
000407| in
000408| (*[4440]*)EL.fold (fun (envlab,chain) a -> (*[4622]*)VL.join (scope_read envlab chain) a) slat.env VL.bot
000409|
000410| (* write_name : SL -> string -> VL -> SL *)
000411| let write_name slat name vlat =
000412| (*[822]*)if (*[822]*)is_bot slat || (*[755]*)VL.is_bot vlat
000413| then (*[67]*)bot
000414| else
000415| (* scope_write : lab -> lab list -> SL *)
000416| (*[755]*)let rec scope_write envlab scopechain =
000417| (*[1120]*)try
000418| (*[1120]*)let env = ST.find_label_exn slat.store envlab in
000419| (*[1120]*)if PL.is_bot env
000420| then (*[0]*)bot
000422| (*[1120]*)if PL.mem name env (* slight hack: direct lookup *)
000423| then
000424| (*[308]*)let _,abs = PL.find_exn name env in (* slight hack: direct lookup *)
000425| (*[308]*)let env' = PL.add_local name vlat env in (* strong update the local variable *)
000426| (*[308]*)let store' = ST.add_label slat.store envlab env' in
000427| (*[308]*)let slat' = { slat with store = store' } in
000428| ((*[308]*)if Abs.eq abs Abs.maybe_absent
000429| then (*[0]*)join slat' (continue_write scopechain)
000432| with Not_found -> (*[0]*)bot
000434| and continue_write scopechain = match scopechain with
000435| | [] -> (*[0]*)failwith "Outside any environment\n";
000437| ((*[522]*)try
000438| (*[522]*)let globalenv = ST.find_label_exn slat.store globallab in
000439| (*[522]*)let globalenv' = PL.add name vlat globalenv in (* strong update: only *one* global env *)
000440| (*[522]*)let store' = ST.add_label slat.store globallab globalenv' in
000441| (*[522]*){ slat with store = store' }
000442| with Not_found -> (*[0]*)bot)
000444| in
000445| (*[755]*)EL.fold
000446| (fun (envlab,chain) slatacc ->
000447| (*try *)(*[830]*)join (scope_write envlab chain) slatacc
000448| (*with Not_found -> (*Printf.printf "Unknown environment label\n";*)
000449| slatacc*)) slat.env bot
000450|
000451| (* write_dyn_prop : SL -> VL -> VL -> VL -> SL *)
000452| let write_dyn_prop slat vlat0 vlat1 vlat =
000453| (*[349]*)let store' = ST.write_dyn_prop slat.store vlat0 vlat1 vlat in
000454| (*[349]*){ slat with store = store' }
000455|
000456| (* getbinhandler : SL -> VL -> VL -> string -> VL *)
000457| let getbinhandler slat vlat0 vlat1 strevent =
000458| (*[299]*)ST.getbinhandler slat.store vlat0 vlat1 strevent
000459|
000460|
000461| (** {3 Pretty printing} *)
000462|
000463| (* pprint : SL -> unit *)
000464| let pprint slat =
000465| begin
000466| Format.printf "{ @[<v 0>store: ";
000467| ST.pprint slat.store;
000468| Format.print_space ();
000469| Format.printf "env: ";
000470| EL.pprint slat.env;
000471| Format.printf "@] }";
000472| end
000473|
000474| (* to_string : elem -> string *)
000475| let to_string s =
000476| let buf = Buffer.create 128 in
000477| let out,flush = Format.get_formatter_output_functions () in (* save previous outputters *)
000478| begin
000479| Format.set_formatter_output_functions (Buffer.add_substring buf) (fun () -> ());
000480| pprint s;
000481| Format.print_flush ();
000482| Format.set_formatter_output_functions out flush; (* restore previous outputters *)
000483| Buffer.contents buf
000484| end