~james/remy

feat(frontend): prove parsed expressions preserve lexical scope

commit
7d99400a08ffdfae7e1b35205b55350ef711c303 browse tree
parent
72b2edbe209a48353896277c3695fd72e27facac
author
james <j@cpl0.zip>
signature
Verified ~james signed with a key registered by ~james
date
2026-09-16 11:00 UTC

1 files changed, +27 −3

src/Frontend.thy modified

@@ -26,6 +26,9 @@ fun lookup :: "string \<Rightarrow> string list \<Rightarrow> nat option" where
2626 "lookup name [] = None"
2727 | "lookup name (x # xs) = (if name = x then Some 0 else map_option Suc (lookup name xs))"
2828
29+lemma lookup_bound: "lookup name names = Some i \<Longrightarrow> i < length names"
30+ by (induction names arbitrary: i) (auto split: if_splits option.splits)
31+
2932 fun operator :: "string \<Rightarrow> operator option" where
3033 "operator s = (if s = ''+'' then Some Add else if s = ''-'' then Some Sub else if s = ''*'' then Some Mul
3134 else if s = ''and'' then Some And else if s = ''or'' then Some Or else if s = ''xor'' then Some Xor
@@ -36,10 +39,16 @@ definition atom :: "string list \<Rightarrow> string \<Rightarrow> expression op
3639 if s = ''x'' then Some (Input X) else if s = ''y'' then Some (Input Y) else if s = ''t'' then Some (Input T)
3740 else map_option (Literal \<circ> word_of_nat) (number s))"
3841
42+lemma atom_scoped: "atom names s = Some e \<Longrightarrow> scoped (length names) e"
43+ by (auto simp: atom_def split: option.splits if_splits dest: lookup_bound)
44+
3945 fun close :: "expression \<Rightarrow> string list \<Rightarrow> (expression \<times> string list) option" where
4046 "close e (s # rest) = (if s = '')'' then Some (e,rest) else None)"
4147 | "close e [] = None"
4248
49+lemma close_expression: "close e tokens = Some (a,rest) \<Longrightarrow> a = e"
50+ by (cases tokens) (auto split: if_splits)
51+
4352 function parse :: "nat \<Rightarrow> string list \<Rightarrow> string list \<Rightarrow> (expression \<times> string list) option" where
4453 "parse fuel names tokens = (if fuel = 0 then None else case tokens of [] \<Rightarrow> None | s # rest \<Rightarrow>
4554 if s \<noteq> ''('' then map_option (\<lambda>e. (e,rest)) (atom names s)
@@ -58,20 +67,35 @@ function parse :: "nat \<Rightarrow> string list \<Rightarrow> string list \<Rig
5867 by pat_completeness auto
5968 termination by (relation "measure (\<lambda>(fuel,names,tokens). fuel)") auto
6069
70+declare parse.simps [simp del]
71+
72+theorem parse_scoped:
73+ "parse fuel names tokens = Some (e,rest) \<Longrightarrow> scoped (length names) e"
74+proof (induction fuel arbitrary: names tokens e rest)
75+ case 0
76+ then show ?case by (subst (asm) parse.simps) auto
77+next
78+ case (Suc fuel)
79+ from Suc.prems show ?case
80+ by (subst (asm) parse.simps)
81+ (auto simp del: operator.simps dest: atom_scoped split: list.splits if_splits bind_splits option.splits prod.splits;
82+ drule close_expression; auto dest: Suc.IH)
83+qed
84+
6185 definition prepare :: "string \<Rightarrow> expression option" where
6286 "prepare s = (if \<not> list_all (\<lambda>c. nat_of_char c < 128) s then None else
6387 Option.bind (parse 128 [] (lex s [] [])) (\<lambda>(e,rest).
64- if rest = [] \<and> scoped 0 e \<and> nodes e \<le> 4096 then
88+ if rest = [] \<and> nodes e \<le> 4096 then
6589 let code = compile (optimise e) [] in
6690 if check code 0 = Some 1 \<and> demand (optimise e) \<le> 512 \<and> list_all encodable (native code)
6791 then Some e else None else None))"
6892
6993 lemma prepare_scoped: "prepare s = Some e \<Longrightarrow> scoped 0 e"
70- by (auto simp: prepare_def Let_def split: if_splits bind_splits prod.splits)
94+ by (auto simp: prepare_def Let_def dest: parse_scoped split: if_splits bind_splits prod.splits)
7195
7296 lemma prepare_bounded:
7397 "prepare s = Some e \<Longrightarrow> bounded 512 (compile (optimise e) []) 0"
74- by (auto simp: prepare_def Let_def closed_demand optimise_scoped split: if_splits bind_splits prod.splits)
98+ by (auto simp: prepare_def Let_def closed_demand optimise_scoped dest: parse_scoped split: if_splits bind_splits prod.splits)
7599
76100 lemma prepare_encodable:
77101 "prepare s = Some e \<Longrightarrow> list_all encodable (native (compile (optimise e) []))"