comparison src/scriptcheck.sml @ 2064:3dd041b00087

Extend ScriptCheck to take RPCs into account
author Adam Chlipala <adam@chlipala.net>
date Sun, 24 Aug 2014 11:43:49 -0400
parents a9159911c3ba
children 25874084bf1f
comparison
equal deleted inserted replaced
2063:83bdb52962c9 2064:3dd041b00087
1 (* Copyright (c) 2009, Adam Chlipala 1 (* Copyright (c) 2009, 2014, Adam Chlipala
2 * All rights reserved. 2 * All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met: 5 * modification, are permitted provided that the following conditions are met:
6 * 6 *
27 27
28 structure ScriptCheck :> SCRIPT_CHECK = struct 28 structure ScriptCheck :> SCRIPT_CHECK = struct
29 29
30 open Mono 30 open Mono
31 31
32 structure SM = BinaryMapFn(struct
33 type ord_key = string
34 val compare = String.compare
35 end)
32 structure SS = BinarySetFn(struct 36 structure SS = BinarySetFn(struct
33 type ord_key = string 37 type ord_key = string
34 val compare = String.compare 38 val compare = String.compare
35 end) 39 end)
36 structure IS = IntBinarySet 40 structure IS = IntBinarySet
37 41
38 val pushBasis = SS.addList (SS.empty, 42 val pushBasis = SS.addList (SS.empty,
39 ["new_channel", 43 ["new_channel",
40 "self"]) 44 "self"])
41 45
46 datatype rpcmap =
47 Rpc of int (* ID of function definition *)
48 | Module of rpcmap SM.map
49
50 fun lookup (r : rpcmap, k : string) =
51 let
52 fun lookup' (r, ks) =
53 case r of
54 Rpc x => SOME x
55 | Module m =>
56 case ks of
57 [] => NONE
58 | k :: ks' =>
59 case SM.find (m, k) of
60 NONE => NONE
61 | SOME r' => lookup' (r', ks')
62 in
63 lookup' (r, String.tokens (fn ch => ch = #"/") k)
64 end
65
66 fun insert (r : rpcmap, k : string, v) =
67 let
68 fun insert' (r, ks) =
69 case r of
70 Rpc _ => Rpc v
71 | Module m =>
72 case ks of
73 [] => Rpc v
74 | k :: ks' =>
75 let
76 val r' = case SM.find (m, k) of
77 NONE => Module SM.empty
78 | SOME r' => r'
79 in
80 Module (SM.insert (m, k, insert' (r', ks')))
81 end
82 in
83 insert' (r, String.tokens (fn ch => ch = #"/") k)
84 end
85
86 fun dump (r : rpcmap) =
87 case r of
88 Rpc _ => print "ROOT\n"
89 | Module m => (print "<Module>\n";
90 SM.appi (fn (k, r') => (print (k ^ ":\n");
91 dump r')) m;
92 print "</Module>\n")
93
42 fun classify (ds, ps) = 94 fun classify (ds, ps) =
43 let 95 let
44 val proto = Settings.currentProtocol () 96 val proto = Settings.currentProtocol ()
45 97
46 fun inString {needle, haystack} = String.isSubstring needle haystack 98 fun inString {needle, haystack} = String.isSubstring needle haystack
47 99
48 fun hasClient {basis, funcs, push} = 100 fun hasClient {basis, rpcs, funcs, push} =
49 MonoUtil.Exp.exists {typ = fn _ => false, 101 MonoUtil.Exp.exists {typ = fn _ => false,
50 exp = fn ERecv _ => push 102 exp = fn ERecv _ => push
51 | EFfiApp ("Basis", x, _) => SS.member (basis, x) 103 | EFfiApp ("Basis", x, _) => SS.member (basis, x)
52 | EJavaScript _ => not push 104 | EJavaScript _ => not push
53 | ENamed n => IS.member (funcs, n) 105 | ENamed n => IS.member (funcs, n)
106 | EServerCall (e, _, _, _) =>
107 let
108 fun head (e : exp) =
109 case #1 e of
110 EStrcat (e1, _) => head e1
111 | EPrim (Prim.String (_, s)) => SOME s
112 | _ => NONE
113 in
114 case head e of
115 NONE => true
116 | SOME fcall =>
117 case lookup (rpcs, fcall) of
118 NONE => true
119 | SOME n => IS.member (funcs, n)
120 end
54 | _ => false} 121 | _ => false}
122
123 fun decl ((d, _), rpcs) =
124 case d of
125 DExport (Mono.Rpc _, fcall, n, _, _, _) =>
126 insert (rpcs, fcall, n)
127 | _ => rpcs
128
129 val rpcs = foldl decl (Module SM.empty) ds
55 130
56 fun decl ((d, _), (pull_ids, push_ids)) = 131 fun decl ((d, _), (pull_ids, push_ids)) =
57 let 132 let
58 val hasClientPull = hasClient {basis = SS.empty, funcs = pull_ids, push = false} 133 val hasClientPull = hasClient {basis = SS.empty, rpcs = rpcs, funcs = pull_ids, push = false}
59 val hasClientPush = hasClient {basis = pushBasis, funcs = push_ids, push = true} 134 val hasClientPush = hasClient {basis = pushBasis, rpcs = rpcs, funcs = push_ids, push = true}
60 in 135 in
61 case d of 136 case d of
62 DVal (_, n, _, e, _) => (if hasClientPull e then 137 DVal (_, n, _, e, _) => (if hasClientPull e then
63 IS.add (pull_ids, n) 138 IS.add (pull_ids, n)
64 else 139 else
65 pull_ids, 140 pull_ids,
66 if hasClientPush e then 141 if hasClientPush e then
67 IS.add (push_ids, n) 142 IS.add (push_ids, n)
68 else 143 else
69 push_ids) 144 push_ids)
70 | DValRec xes => (if List.exists (fn (_, _, _, e, _) => hasClientPull e) xes then 145 | DValRec xes => (if List.exists (fn (_, _, _, e, _) => hasClientPull e) xes then
71 foldl (fn ((_, n, _, _, _), pull_ids) => IS.add (pull_ids, n)) 146 foldl (fn ((_, n, _, _, _), pull_ids) => IS.add (pull_ids, n))
72 pull_ids xes 147 pull_ids xes
73 else 148 else
74 pull_ids, 149 pull_ids,
75 if List.exists (fn (_, _, _, e, _) => hasClientPush e) xes then 150 if List.exists (fn (_, _, _, e, _) => hasClientPush e) xes then
76 foldl (fn ((_, n, _, _, _), push_ids) => IS.add (push_ids, n)) 151 foldl (fn ((_, n, _, _, _), push_ids) => IS.add (push_ids, n))
77 push_ids xes 152 push_ids xes