feat(encoding): prove decoder progress and consumed byte bounds
1 files changed, +47 −0
- src/Encoding.thy modified +47 −0
src/Encoding.thy modified
| @@ -176,6 +176,53 @@ theorem encode_injective: | ||
| 176 | 176 | using decode_encode[of a "[]"] decode_encode[of b "[]"] |
| 177 | 177 | by (metis append_Nil option.inject prod.inject) |
| 178 | 178 | |
| 179 | +lemma push_nonempty [simp]: "pushcode r \<noteq> []" | |
| 180 | + by (cases r) auto | |
| 181 | + | |
| 182 | +lemma pop_nonempty [simp]: "popcode r \<noteq> []" | |
| 183 | + by (cases r) auto | |
| 184 | + | |
| 185 | +lemma arithmetic_nonempty [simp]: "arithmetic op \<noteq> []" | |
| 186 | + by (cases op) auto | |
| 187 | + | |
| 188 | +lemma encode_nonempty [simp]: "encode op \<noteq> []" | |
| 189 | + by (cases op) (auto simp: movecode_def) | |
| 190 | + | |
| 191 | +lemma fixed_decode: | |
| 192 | + "List.find (\<lambda>op. take (length (encode op)) bs = encode op) fixed = Some op \<Longrightarrow> | |
| 193 | + 0 < length (encode op) \<and> length (encode op) \<le> length bs \<and> | |
| 194 | + list_all (\<lambda>b. b < 256) (take (length (encode op)) bs)" | |
| 195 | + using encode_bytes[of op] | |
| 196 | + by (auto simp: find_Some_iff list_all_iff dest: arg_cong[where f=length]) | |
| 197 | + | |
| 198 | +theorem decode_progress: | |
| 199 | + "decode bs = Some (op,rest) \<Longrightarrow> length rest < length bs" | |
| 200 | + unfolding decode_def | |
| 201 | + apply (auto simp: Let_def dest: fixed_decode split: if_splits option.splits) | |
| 202 | + apply (drule fixed_decode) | |
| 203 | + apply auto | |
| 204 | + by (cases bs) auto | |
| 205 | + | |
| 206 | +theorem decode_consumed: | |
| 207 | + "decode bs = Some (op,rest) \<Longrightarrow> list_all (\<lambda>b. b < 256) bs \<Longrightarrow> | |
| 208 | + \<exists>prefix. bs = prefix @ rest \<and> prefix \<noteq> [] \<and> list_all (\<lambda>b. b < 256) prefix" | |
| 209 | +proof - | |
| 210 | + assume decoded: "decode bs = Some (op,rest)" | |
| 211 | + and input: "list_all (\<lambda>b. b < 256) bs" | |
| 212 | + have drop: "rest = drop (length bs - length rest) bs" | |
| 213 | + using decoded unfolding decode_def | |
| 214 | + apply (auto simp: Let_def split: if_splits option.splits) | |
| 215 | + apply (drule fixed_decode) | |
| 216 | + by auto | |
| 217 | + have bytes: "list_all (\<lambda>b. b < 256) (take (length bs - length rest) bs)" | |
| 218 | + using input by (auto simp: list_all_iff dest: in_set_takeD) | |
| 219 | + have decomposition: "bs = take (length bs - length rest) bs @ rest" | |
| 220 | + using drop append_take_drop_id[of "length bs - length rest" bs] by metis | |
| 221 | + show ?thesis | |
| 222 | + using decomposition bytes decode_progress[OF decoded] | |
| 223 | + by (intro exI[where x="take (length bs - length rest) bs"]) auto | |
| 224 | +qed | |
| 225 | + | |
| 179 | 226 | fun recover :: "nat \<Rightarrow> nat list \<Rightarrow> (opcode list \<times> nat list) option" where |
| 180 | 227 | "recover 0 bs = Some ([],bs)" |
| 181 | 228 | | "recover (Suc n) bs = Option.bind (decode bs) (\<lambda>(op,tail). |