| @@ -104,24 +104,45 @@ next |
| 104 | 104 | drule close_expression; auto dest: Suc.IH) |
| 105 | 105 | qed |
| 106 | 106 | |
| 107 | | -definition prepare :: "string \<Rightarrow> expression option" where |
| 108 | | - "prepare s = (if \<not> list_all (\<lambda>c. nat_of_char c < 128) s then None else |
| 109 | | - Option.bind (parse 128 [] (lex s [] [])) (\<lambda>(e,rest). |
| 110 | | - if rest = [] \<and> nodes e \<le> 4096 then |
| 107 | +record limits = |
| 108 | + depth_budget :: nat |
| 109 | + node_budget :: nat |
| 110 | + stack_budget :: nat |
| 111 | + |
| 112 | +definition defaults :: limits where |
| 113 | + "defaults = \<lparr>depth_budget = 128, node_budget = 4096, stack_budget = 512\<rparr>" |
| 114 | + |
| 115 | +definition valid_limits :: "limits \<Rightarrow> bool" where |
| 116 | + "valid_limits lim = (depth_budget lim \<le> 128 \<and> node_budget lim \<le> 4096 \<and> stack_budget lim \<le> 512)" |
| 117 | + |
| 118 | +definition prepare_with :: "limits \<Rightarrow> string \<Rightarrow> expression option" where |
| 119 | + "prepare_with lim s = (if \<not> valid_limits lim \<or> \<not> list_all (\<lambda>c. nat_of_char c < 128) s then None else |
| 120 | + Option.bind (parse (depth_budget lim) [] (lex s [] [])) (\<lambda>(e,rest). |
| 121 | + if rest = [] \<and> nodes e \<le> node_budget lim then |
| 111 | 122 | let code = compile (optimise e) [] in |
| 112 | | - if check code 0 = Some 1 \<and> demand (optimise e) \<le> 512 \<and> list_all encodable (native code) |
| 123 | + if check code 0 = Some 1 \<and> demand (optimise e) \<le> stack_budget lim \<and> list_all encodable (native code) |
| 113 | 124 | then Some e else None else None))" |
| 114 | 125 | |
| 126 | +definition prepare :: "string \<Rightarrow> expression option" where |
| 127 | + "prepare = prepare_with defaults" |
| 128 | + |
| 129 | +lemma prepare_with_scoped: "prepare_with lim s = Some e \<Longrightarrow> scoped 0 e" |
| 130 | + by (auto simp: prepare_with_def Let_def dest: parse_scoped split: if_splits bind_splits prod.splits) |
| 131 | + |
| 132 | +lemma prepare_with_bounded: |
| 133 | + "prepare_with lim s = Some e \<Longrightarrow> bounded (stack_budget lim) (compile (optimise e) []) 0" |
| 134 | + by (auto simp: prepare_with_def Let_def closed_demand optimise_scoped dest: parse_scoped split: if_splits bind_splits prod.splits) |
| 135 | + |
| 115 | 136 | lemma prepare_scoped: "prepare s = Some e \<Longrightarrow> scoped 0 e" |
| 116 | | - by (auto simp: prepare_def Let_def dest: parse_scoped split: if_splits bind_splits prod.splits) |
| 137 | + unfolding prepare_def using prepare_with_scoped by blast |
| 117 | 138 | |
| 118 | 139 | lemma prepare_bounded: |
| 119 | 140 | "prepare s = Some e \<Longrightarrow> bounded 512 (compile (optimise e) []) 0" |
| 120 | | - by (auto simp: prepare_def Let_def closed_demand optimise_scoped dest: parse_scoped split: if_splits bind_splits prod.splits) |
| 141 | + using prepare_with_bounded[where lim=defaults] by (simp add: prepare_def defaults_def) |
| 121 | 142 | |
| 122 | 143 | lemma prepare_encodable: |
| 123 | 144 | "prepare s = Some e \<Longrightarrow> list_all encodable (native (compile (optimise e) []))" |
| 124 | | - by (auto simp: prepare_def Let_def split: if_splits bind_splits prod.splits) |
| 145 | + by (auto simp: prepare_def prepare_with_def Let_def split: if_splits bind_splits prod.splits) |
| 125 | 146 | |
| 126 | 147 | theorem prepared_correct: |
| 127 | 148 | "prepare source = Some e \<Longrightarrow> |
| @@ -195,22 +216,33 @@ termination by (relation "measure (\<lambda>(fuel,names,tokens,pos). fuel)") aut |
| 195 | 216 | |
| 196 | 217 | declare diagnose.simps [simp del] |
| 197 | 218 | |
| 198 | | -definition source_error :: "string \<Rightarrow> string" where |
| 199 | | - "source_error s = (if \<not> list_all (\<lambda>c. nat_of_char c < 128) s then ''source must contain ASCII'' @ newline else |
| 200 | | - case diagnose 128 [] (lex s [] []) 0 of |
| 219 | +definition source_error_with :: "limits \<Rightarrow> string \<Rightarrow> string" where |
| 220 | + "source_error_with lim s = (if \<not> valid_limits lim then ''limits exceed compiler bounds'' @ newline else if \<not> list_all (\<lambda>c. nat_of_char c < 128) s then ''source must contain ASCII'' @ newline else |
| 221 | + case diagnose (depth_budget lim) [] (lex s [] []) 0 of |
| 201 | 222 | Failed (Unexpected pos) \<Rightarrow> ''syntax error at token '' @ decimal pos @ newline |
| 202 | 223 | | Failed (Exhausted pos) \<Rightarrow> ''parse depth limit exceeded at token '' @ decimal pos @ newline |
| 203 | 224 | | Parsed (e,rest,pos) \<Rightarrow> if rest \<noteq> [] then ''syntax error at token '' @ decimal pos @ newline |
| 204 | | - else if nodes e > 4096 then ''program exceeds 4096 nodes'' @ newline |
| 205 | | - else if demand (optimise e) > 512 then ''evaluation stack exceeds 512 words'' @ newline |
| 225 | + else if nodes e > node_budget lim then ''program exceeds '' @ decimal (node_budget lim) @ '' nodes'' @ newline |
| 226 | + else if demand (optimise e) > stack_budget lim then ''evaluation stack exceeds '' @ decimal (stack_budget lim) @ '' words'' @ newline |
| 206 | 227 | else ''native validation failed'' @ newline)" |
| 207 | 228 | |
| 208 | | -definition artifact :: "string \<Rightarrow> (bool \<times> string) \<times> string" where |
| 209 | | - "artifact s = (case prepare s of None \<Rightarrow> ((False,[]), source_error s) |
| 229 | +definition artifact_with :: "limits \<Rightarrow> string \<Rightarrow> (bool \<times> string) \<times> string" where |
| 230 | + "artifact_with lim s = (case prepare_with lim s of None \<Rightarrow> ((False,[]), source_error_with lim s) |
| 210 | 231 | | Some e \<Rightarrow> let opt = optimise e; bytes = executable e in |
| 211 | 232 | ((True, map char_of_nat bytes), decimal (nodes e) @ '' nodes -> '' @ decimal (nodes opt) @ |
| 212 | 233 | '' nodes, '' @ decimal (length bytes) @ '' bytes, '' @ decimal (demand opt) @ '' stack words'' @ newline))" |
| 213 | 234 | |
| 235 | +definition source_error :: "string \<Rightarrow> string" where |
| 236 | + "source_error = source_error_with defaults" |
| 237 | + |
| 238 | +definition artifact :: "string \<Rightarrow> (bool \<times> string) \<times> string" where |
| 239 | + "artifact = artifact_with defaults" |
| 240 | + |
| 241 | +definition configured :: "string \<Rightarrow> string \<Rightarrow> string \<Rightarrow> string \<Rightarrow> (bool \<times> string) \<times> string" where |
| 242 | + "configured depth count stacktext source = (case (number depth, number count, number stacktext) of |
| 243 | + (Some d,Some n,Some k) \<Rightarrow> artifact_with \<lparr>depth_budget=d, node_budget=n, stack_budget=k\<rparr> source |
| 244 | + | _ \<Rightarrow> ((False,[]),''invalid resource limits'' @ newline))" |
| 245 | + |
| 214 | 246 | definition boundary :: "nat list" where |
| 215 | 247 | "boundary = [0,1,63,64,65,127,255,256,2 ^ 31,2 ^ 32,2 ^ 63,2 ^ 64 - 1]" |
| 216 | 248 | |