000001| (** Abstract state datatype and operations *)
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| (*[643533]*)ST.leq st0.store st1.store && (*[260632]*)EL.leq st0.env st1.env
000015|
000016| (* eq : elem -> elem -> bool *)
000017| let eq st0 st1 =
000018| (*[389312]*)ST.eq st0.store st1.store && (*[389312]*)EL.eq st0.env st1.env
000019|
000020| (* join : elem -> elem -> bool *)
000021| let join st0 st1 =
000022| (*[103460]*){ 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| (*[67332]*){ store = ST.meet st0.store st1.store;
000028| env = EL.meet st0.env st1.env; }
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 = (*[447303]*)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| (*[297722]*)if is_bot slat then ((*[30425]*)bot,[]) else
000121| match bi with
000122| | VL.Error -> ((*[8946]*)bot,[]) (* unreachable *)
000123| | VL.Exit -> ((*[8953]*)bot,[]) (* unreachable *)
000124| | VL.Next ->
000125| (match vlats with
000126| | [] -> ((*[1974]*)bot,[]) (*error*)
000127| | vlat::_ ->
000128| (*[6975]*)if VL.may_be_table vlat then
000129| (*[6729]*)let keys = VL.join VL.nil (* potentially: end of table *)
000130| (ST.lookup_all_keys slat.store vlat) in
000131| (*[6729]*)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| ((*[6729]*)slat,[keys;values]) (* then result cannot be nil *)
000135| else ((*[246]*)bot,[])) (*error*)
000136| | VL.INext ->
000137| (match vlats with
000138| | [] -> ((*[1955]*)bot,[]) (*error*)
000139| | vlat::_ ->
000140| (*[6998]*)if VL.may_be_table vlat
000141| then
000142| (*[6781]*)let keys = ST.lookup_all_keys slat.store vlat in
000143| ((*[6781]*)if VL.may_be_number keys
000144| then
000145| (*[1477]*)let keys = VL.join VL.nil VL.number in (* potentially: end of table *)
000146| (*[1477]*)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| ((*[1477]*)slat,[keys;values])
000149| else
000150| (*[5304]*)let keys,values = VL.nil,VL.nil in (* end of table *)
000151| ((*[5304]*)slat,[keys;values]))
000152| else ((*[217]*)bot,[])) (*error*)
000153| | VL.Pairs ->
000154| (match vlats with
000155| | [] -> ((*[1968]*)bot,[]) (*error*)
000156| | vlat::_ ->
000157| (*[6977]*)let vlat' = VL.only_tables vlat in
000158| (*[6977]*)if VL.is_bot vlat'
000159| then ((*[220]*)bot,[]) (*error*)
000160| else ((*[6757]*)slat,[VL.builtin VL.Next; vlat'; VL.nil]))
000161| | VL.IPairs ->
000162| (match vlats with
000163| | [] -> ((*[2005]*)bot,[]) (*error*)
000164| | vlat::_ ->
000165| (*[6940]*)let vlat' = VL.only_tables vlat in
000166| (*[6940]*)if VL.is_bot vlat'
000167| then ((*[235]*)bot,[]) (*error*)
000168| else ((*[6705]*)slat,[VL.builtin VL.INext; vlat'; VL.number])) (* return iterator, table, 0 *)
000169| | VL.Print -> ((*[7961]*)slat,[VL.nil]) (* no return value specified - Lua2.5 impl returns nil *)
000170| | VL.Write ->
000171| (match vlats with
000172| | [] -> ((*[2949]*)slat, [VL.userdata])
000173| | vlat::vlats ->
000174| (*[17985]*)if (*[17985]*)VL.may_be_number vlat || (*[9044]*)VL.may_be_strings vlat (* may succeed *)
000175| then (*[14971]*)apply_builtin bi slat vlats
000176| else ((*[3014]*)bot, []))
000177| | VL.Tonumber ->
000178| (match vlats with
000179| | [] -> ((*[1999]*)bot,[]) (*error*)
000180| | vlat::_ ->
000181| (*[6946]*)if VL.is_nil vlat then ((*[18]*)bot,[]) (* unreachable *)
000182| else
000183| (*[6928]*)let retval =
000184| if VL.is_number vlat then (*[3]*)VL.number (* number arg (at most) *)
000185| else (*[6925]*)if VL.is_strings vlat then (*[8]*)VL.number_or_nil (* string arg (at most) *)
000186| else (*[6917]*)if VL.may_be_number vlat then (*[3232]*)VL.number_or_nil (* number or other arg *)
000187| else (*[3685]*)if VL.may_be_strings vlat then (*[2297]*)VL.number_or_nil (* string or other arg *)
000188| else (*[1388]*)VL.nil (* no string or number arguments *)
000189| in ((*[6928]*)slat,[retval]))
000190| | VL.Tostring ->
000191| (match vlats with
000192| | [] -> ((*[2013]*)bot,[]) (*error*)
000193| | vlat::_ ->
000194| (*[6940]*)if VL.is_bot vlat then ((*[17]*)bot,[]) (* unreachable *)
000195| else ((*[6923]*)slat,[VL.anystring]))
000196| | VL.Abs
000197| | VL.Ceil
000198| | VL.Floor ->
000199| (match vlats with
000200| | vlat::_ ->
000201| (*[21028]*)if VL.is_bot vlat then ((*[42]*)bot, []) (* unreachable *)
000202| else (*[20986]*)if VL.may_be_number (VL.coerce_tonum vlat) then ((*[13059]*)slat, [VL.number])
000203| else ((*[7927]*)bot, [])
000204| | _ -> ((*[5844]*)bot, []))
000205| | VL.Mod ->
000206| (match vlats with
000207| | vl0::vl1::_ -> (*[6103]*)let res = VL.binop Ast.Mod vl0 vl1 in
000208| (*[6103]*)if res = VL.bot then ((*[3546]*)bot, [VL.bot])
000209| else ((*[2557]*)slat, [res])
000210| | _ -> ((*[2854]*)bot, []))
000211| | VL.Random ->
000212| (match vlats with
000213| | [] -> ((*[588]*)slat,[VL.number])
000214| | vl0::[] -> (*[587]*)if VL.may_be_number (VL.coerce_tonum vl0)
000215| then ((*[408]*)slat,[VL.number])
000216| else ((*[179]*)bot, [])
000217| | vl0::vl1::[] -> (*[587]*)if (*[587]*)VL.may_be_number (VL.coerce_tonum vl0)
000218| && (*[399]*)VL.may_be_number (VL.coerce_tonum vl1)
000219| then ((*[274]*)slat,[VL.number])
000220| else ((*[313]*)bot, [])
000221| | _ -> ((*[4203]*)bot, []))
000222| | VL.Strlen ->
000223| (match vlats with
000224| | [] -> ((*[1959]*)bot,[]) (*error*)
000225| | vlat::_ ->
000226| (*[6985]*)if VL.may_be_strings (VL.coerce_tostring vlat)
000227| then ((*[5563]*)slat,[VL.number])
000228| else ((*[1422]*)bot,[]))
000229| | VL.Strupper ->
000230| (match vlats with
000231| | [] -> ((*[2017]*)bot,[]) (*error*)
000232| | vlat::_ -> ((*[6940]*)slat,[VL.upper vlat]))
000233| | VL.Strlower ->
000234| (match vlats with
000235| | [] -> ((*[1930]*)bot,[]) (*error*)
000236| | vlat::_ -> ((*[7014]*)slat,[VL.lower vlat]))
000237| | VL.Strchar ->
000238| (match vlats with
000239| | [] -> ((*[1814]*)slat, [VL.string ""])
000240| | vlat::vlats ->
000241| (*[12285]*)let vlat' = VL.char vlat in
000242| (*[12285]*)if VL.may_be_strings vlat' (* may succeed *)
000243| then
000244| (*[8160]*)let slat',vlats' = apply_builtin bi slat vlats in (* recurse *)
000245| (match vlats' with
000246| | [] -> ((*[4988]*)bot, []) (* propagate error *)
000247| | vlat''::_ -> ((*[3172]*)slat',[VL.binop Ast.Concat vlat' vlat'']))
000248| else ((*[4125]*)bot, []))
000249| | VL.Strbyte ->
000250| (match vlats with
000251| | [] -> ((*[1624]*)bot, [])
000252| | arg::[] -> (*[557]*)if VL.may_be_strings (VL.coerce_tostring arg)
000253| then ((*[463]*)slat,[VL.number_or_nil])
000254| else ((*[94]*)bot, [])
000255| | arg1::arg2::[] -> (*[598]*)if (*[598]*)VL.may_be_strings (VL.coerce_tostring arg1)
000256| && (*[498]*)VL.may_be_number (VL.coerce_tonum arg2)
000257| then ((*[345]*)slat,[VL.number_or_nil])
000258| else ((*[253]*)bot, [])
000259| | arg1::arg2::arg3::_ -> (*[4170]*)if (*[4170]*)VL.may_be_strings (VL.coerce_tostring arg1)
000260| && (*[3474]*)VL.may_be_number (VL.coerce_tonum arg2)
000261| && (*[2268]*)VL.may_be_number (VL.coerce_tonum arg3)
000262| then (* almost conservative :-) for static strings, length gives a bound *)
000263| ((*[1465]*)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 ((*[2705]*)bot, []))
000266| | VL.Strsub ->
000267| (match vlats with
000268| | [] | [ _ ] -> ((*[2252]*)bot, [])
000269| | arg1::arg2::[] -> (*[591]*)apply_builtin bi slat ([arg1;VL.number;arg2])
000270| | arg1::arg2::arg3::_ ->
000271| (*[4695]*)let arg1' = VL.coerce_tostring arg1 in
000272| (*[4695]*)let arg2' = VL.coerce_tonum arg2 in
000273| (*[4695]*)let arg3' = VL.coerce_tonum arg3 in
000274| (*[4695]*)if (*[4695]*)VL.may_be_strings arg1' && (*[3955]*)VL.may_be_number arg2' && (*[2870]*)VL.may_be_number arg3'
000275| then ((*[1907]*)slat,[VL.anystring])
000276| else ((*[2788]*)bot,[]))
000277| | VL.Sqrt ->
000278| (match vlats with
000279| | [] -> ((*[2018]*)bot,[]) (*error*)
000280| | vlat::_ ->
000281| (*[6935]*)if VL.may_be_number (VL.coerce_tonum vlat)
000282| then ((*[4425]*)slat,[VL.number])
000283| else ((*[2510]*)bot,[]))
000284| | VL.Type ->
000285| (match vlats with
000286| | [] -> ((*[2014]*)bot,[]) (*error*)
000287| | vlat::_ -> ((*[6939]*)slat,[VL.typep vlat]))
000288| | VL.Format ->
000289| (match vlats with
000290| | [] -> ((*[2046]*)bot,[]) (*error*)
000291| | vlat::_ ->
000292| (*[6903]*)if VL.is_nil vlat then ((*[12]*)bot,[]) (*unreachable*)
000293| else (*[6891]*)if VL.may_be_strings vlat then ((*[4365]*)slat,[VL.anystring])
000294| else ((*[2526]*)bot,[]))
000295| | VL.Tblconcat ->
000296| (match vlats with
000297| | [] -> ((*[1609]*)bot,[]) (*error*)
000298| | vlat1::vlats1 ->
000299| (*[5336]*)if VL.may_be_table vlat1
000300| then (match vlats1 with
000301| | [] -> ((*[606]*)slat,[VL.anystring]) (* one arg *)
000302| | vlat2::vlats2 ->
000303| (*[4730]*)if VL.may_be_strings (VL.coerce_tostring vlat2)
000304| then (match vlats2 with
000305| | [] -> ((*[503]*)slat,[VL.anystring]) (* two args *)
000306| | vlat3::vlats3 ->
000307| (*[3458]*)if VL.may_be_number (VL.coerce_tonum vlat3)
000308| then (match vlats3 with
000309| | [] -> ((*[349]*)slat,[VL.anystring]) (* three args *)
000310| | vlat4::_ ->
000311| (*[1859]*)if VL.may_be_number (VL.coerce_tonum vlat4)
000312| then ((*[1221]*)slat,[VL.anystring]) (* four args *)
000313| else ((*[638]*)bot,[]))
000314| else ((*[1250]*)bot,[]))
000315| else ((*[769]*)bot,[]))
000317| | VL.Getmetatable ->
000318| (match vlats with
000319| | [] -> ((*[1960]*)bot,[]) (*error*)
000320| | vlat::_ -> ((*[6993]*)slat,[ST.get_metatable slat.store vlat]))
000321| | VL.Setmetatable ->
000322| (match vlats with
000323| | [] -> ((*[2029]*)bot,[]) (*error*)
000324| | [_] -> ((*[905]*)bot,[]) (*error*)
000325| | vlat::vlat'::_ ->
000326| (*[6018]*)let store' = ST.set_metatable slat.store vlat vlat' in
000327| ((*[6018]*){slat with store = store'},[vlat]))
000328| | VL.Rawget ->
000329| (match vlats with
000330| | [] -> ((*[1992]*)bot,[]) (*error*)
000331| | [_] -> ((*[885]*)bot,[]) (*error*)
000332| | vlat::vlat'::_ -> ((*[6068]*)slat,[ST.raw_get slat.store vlat vlat']))
000333| | VL.Rawset ->
000334| (match vlats with
000335| | [] -> ((*[1988]*)bot,[]) (*error*)
000336| | _::[] -> ((*[825]*)bot,[]) (*error*)
000337| | _::_::[] -> ((*[798]*)bot,[]) (*error*)
000338| | vlat0::vlat1::vlat2::_ ->
000339| (*[5327]*)let store' = ST.raw_set slat.store vlat0 vlat1 vlat2 in
000340| ((*[5327]*){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| (*[64887]*)if (*[64887]*)is_bot slat || (*[63836]*)VL.is_bot vlat
000346| then (*[2072]*)bot
000347| else
000348| (*[62815]*)let store' =
000349| EL.fold (fun (localslab,_) storeacc ->
000350| (*[300425]*)let env = ST.find_label slat.store localslab in
000351| (*[300425]*)let env' = PL.add_local x vlat env in (* strong update *)
000352| (*[300425]*)ST.join (ST.add_label slat.store localslab env') storeacc)
000353| slat.env ST.bot in
000354| (*[62815]*){ 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| (*[66694]*)if is_bot slat
000359| then (*[1198]*)bot
000360| else match (xs,vlats) with
000361| | [], [] -> (*[5802]*)slat
000362| | x::xs,vlat::vlats ->
000363| (*[21338]*)let slat' = add_local slat vlat x in
000364| (*[21338]*)add_local_list slat' vlats xs
000365| | x::xs,[] ->
000366| (*[33549]*)let slat' = add_local slat VL.nil x in (* missing value: assign nil *)
000367| (*[33549]*)add_local_list slat' [] xs
000368| | [], vlat::vlats ->
000369| (*[4807]*)add_local_list slat vlats [] (* missing local: drop excess value *)
000370|
000371| (* enter_scope : SL -> label -> SL *)
000372| let enter_scope slat label =
000373| (*[5000]*)if is_bot slat
000374| then (*[1041]*)bot
000375| else
000376| (*[3959]*){ 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| (*[5000]*)if EL.is_bot scopechain
000382| then (*[1217]*)PL.bot
000383| else
000384| (*[3783]*)EL.fold (fun (i,is) scset -> (*[17349]*)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| (*[5000]*)let rec scope_read envlab scopechain =
000390| (*[21802]*)if ST.is_bot slat.store
000391| then (*[1364]*)VL.bot
000392| else
000393| (*[20438]*)let env = ST.find_label slat.store envlab in
000394| (*[20438]*)if PL.is_bot env
000395| then (*[15101]*)VL.bot
000396| else
000397| (*[5337]*)try
000398| (*[5337]*)let vl,abs = PL.find_exn name env in (* slight hack: direct lookup *)
000399| (*[1373]*)if Abs.eq abs Abs.maybe_absent
000400| then (*[670]*)VL.join vl (continue_read scopechain)
000401| else (*[703]*)vl (* certain entry, don't continue *)
000402| with Not_found -> (*[3964]*)continue_read scopechain
000403| (* continue_read : lab list -> VL *)
000404| and continue_read scopechain = match scopechain with
000405| | [] -> (*[151]*)VL.nil (* not found: return nil *)
000406| | outerenvlab::scopechain' -> (*[4483]*)scope_read outerenvlab scopechain'
000407| in
000408| (*[5000]*)EL.fold (fun (envlab,chain) a -> (*[17319]*)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| (*[8000]*)if (*[8000]*)is_bot slat || (*[7950]*)VL.is_bot vlat
000413| then (*[80]*)bot
000414| else
000415| (* scope_write : lab -> lab list -> SL *)
000416| (*[7920]*)let rec scope_write envlab scopechain =
000417| (*[45261]*)try
000418| (*[45261]*)let env = ST.find_label_exn slat.store envlab in
000419| (*[12240]*)if PL.is_bot env
000420| then (*[981]*)bot
000421| else
000422| (*[11259]*)if PL.mem name env (* slight hack: direct lookup *)
000423| then
000424| (*[3089]*)let _,abs = PL.find_exn name env in (* slight hack: direct lookup *)
000425| (*[3089]*)let env' = PL.add_local name vlat env in (* strong update the local variable *)
000426| (*[3089]*)let store' = ST.add_label slat.store envlab env' in
000427| (*[3089]*)let slat' = { slat with store = store' } in
000428| ((*[3089]*)if Abs.eq abs Abs.maybe_absent
000429| then (*[1672]*)join slat' (continue_write scopechain)
000430| else (*[1417]*)slat')
000431| else (*[8170]*)continue_write scopechain
000432| with Not_found -> (*[33021]*)bot
000433| (* continue_write : list -> SL *)
000434| and continue_write scopechain = match scopechain with