| 
 | 1 | +-- Programming Language Technology DAT151/DIT231  | 
 | 2 | +-- 2024-12-17 Agda (version ≥2.6.0)  | 
 | 3 | +-- From Dependent Types to Verified Compilation  | 
 | 4 | + | 
 | 5 | +-- A correct compiler for Hutton's Razor to a stack machine  | 
 | 6 | + | 
 | 7 | +-- Similar to an early pen-and-paper proof (register machine):  | 
 | 8 | +--  | 
 | 9 | +--   John McCarthy and James Painter, 1967  | 
 | 10 | +--   Correctness of a Compiler for Arithmetic Expressions  | 
 | 11 | +--   http://jmc.stanford.edu/articles/mcpain/mcpain.pdf  | 
 | 12 | + | 
 | 13 | +open import Relation.Binary.PropositionalEquality  | 
 | 14 | +open ≡-Reasoning  | 
 | 15 | + | 
 | 16 | +-- Data types and pattern matching  | 
 | 17 | +---------------------------------------------------------------------------  | 
 | 18 | + | 
 | 19 | +-- Example of a data type.  | 
 | 20 | + | 
 | 21 | +data List (A : Set) : Set where  | 
 | 22 | +  []  : List A  | 
 | 23 | +  _∷_ : (x : A) (xs : List A) → List A   -- \ : :   A → List A → List A  | 
 | 24 | + | 
 | 25 | +-- Natural numbers in unary notation.  | 
 | 26 | + | 
 | 27 | +data Nat : Set where  | 
 | 28 | +  zero : Nat  | 
 | 29 | +  suc : (n : Nat) → Nat  | 
 | 30 | + | 
 | 31 | +{-# BUILTIN NATURAL Nat #-}  | 
 | 32 | + | 
 | 33 | +-- NATURAL gives us decimal notation for Nat.  | 
 | 34 | + | 
 | 35 | +five = suc 4  | 
 | 36 | + | 
 | 37 | +infixl 10 _+_  | 
 | 38 | +infixr  6 _∷_  | 
 | 39 | + | 
 | 40 | +-- Addition.  | 
 | 41 | + | 
 | 42 | +_+_ : (n m : Nat) → Nat  | 
 | 43 | +zero + m = m  | 
 | 44 | +suc n + m = suc (n + m)  | 
 | 45 | + | 
 | 46 | +{-  | 
 | 47 | +data Empty : Set where  | 
 | 48 | +
  | 
 | 49 | +inh : Empty  | 
 | 50 | +inh = error "hoo"  | 
 | 51 | +-}  | 
 | 52 | + | 
 | 53 | +plus-0 : (n : Nat) → n + zero ≡ n    --  \ = =  | 
 | 54 | +plus-0 zero = refl {x = 0}  | 
 | 55 | +plus-0 (suc n) = cong suc (plus-0 n)  | 
 | 56 | + | 
 | 57 | +-- Indexed types: Fin, Vec  | 
 | 58 | +---------------------------------------------------------------------------  | 
 | 59 | + | 
 | 60 | +-- Bounded numbers: Fin n = { m | m < n }.  | 
 | 61 | + | 
 | 62 | +data Fin : Nat → Set where  | 
 | 63 | +  zero : {n : Nat} → Fin (suc n)  | 
 | 64 | +  suc  : {n : Nat} (i : Fin n) → Fin (suc n)  | 
 | 65 | + | 
 | 66 | +-- Example with hidden arguments.  | 
 | 67 | + | 
 | 68 | +three : Fin 5  | 
 | 69 | +three = suc {n = 4} (suc (suc zero))  | 
 | 70 | + | 
 | 71 | +-- Vectors (length-indexed lists).  | 
 | 72 | +-- Vec : Set → Nat → Set  | 
 | 73 | + | 
 | 74 | +data Vec (A : Set) : Nat → Set where  | 
 | 75 | +  []  : Vec A zero  | 
 | 76 | +  _∷_ : {n : Nat} (x : A) (xs : Vec A n) → Vec A (suc n)  | 
 | 77 | + | 
 | 78 | +-- Automatic quantification over hidden arguments.  | 
 | 79 | + | 
 | 80 | +variable  | 
 | 81 | +  n : Nat  | 
 | 82 | +  A : Set  | 
 | 83 | + | 
 | 84 | +-- Reading an element of a vector.  | 
 | 85 | + | 
 | 86 | +lookup : {n : Nat} {A : Set} (i : Fin n) (xs : Vec A n) → A  | 
 | 87 | +lookup zero    (x ∷ xs) = x  | 
 | 88 | +lookup (suc i) (x ∷ xs) = lookup i xs  | 
 | 89 | + | 
 | 90 | +-- Expressions and interpretation: "Hutton's razor"  | 
 | 91 | +---------------------------------------------------------------------------  | 
 | 92 | + | 
 | 93 | +-- We have a single type of (natural) numbers.  | 
 | 94 | + | 
 | 95 | +Num = Nat  | 
 | 96 | + | 
 | 97 | +-- Expressions over n variables.  | 
 | 98 | + | 
 | 99 | +-- A variable is denoted by its number x < n.  | 
 | 100 | + | 
 | 101 | +data Exp (n : Nat) : Set where  | 
 | 102 | +  var  : (x : Fin n)    → Exp n  | 
 | 103 | +  num  : (w : Num)      → Exp n  | 
 | 104 | +  plus : (e e' : Exp n) → Exp n  | 
 | 105 | + | 
 | 106 | +-- (x + 3) + y  | 
 | 107 | +ex1 : Exp 2  | 
 | 108 | +ex1 = plus (plus (var zero) (num 3)) (var (suc zero))  | 
 | 109 | + | 
 | 110 | +-- An environment maps each variable to its value.  | 
 | 111 | + | 
 | 112 | +Value = Num  | 
 | 113 | +Env   = Vec Num  | 
 | 114 | + | 
 | 115 | +-- Interpretation of expressions.  | 
 | 116 | + | 
 | 117 | +eval : (e : Exp n) (γ : Env n) → Value  | 
 | 118 | +eval (var x) γ = lookup x γ  | 
 | 119 | +eval (num w) γ = w  | 
 | 120 | +eval (plus e e₁) γ = eval e γ + eval e₁ γ  | 
 | 121 | + | 
 | 122 | +v1 = eval ex1 (15 ∷ 1 ∷ [])  | 
 | 123 | + | 
 | 124 | +-- A fragment of JVM  | 
 | 125 | +---------------------------------------------------------------------------  | 
 | 126 | + | 
 | 127 | +StackSize = Nat  -- Current stack size  | 
 | 128 | +StoreSize = Nat  -- Local variable store limit  | 
 | 129 | +Addr = Fin       -- Local variable address  | 
 | 130 | +Word = Nat       -- Word (should be 32bit signed int, but we use Nat here)  | 
 | 131 | + | 
 | 132 | +-- JVM instructions.  | 
 | 133 | +--  | 
 | 134 | +-- n  = number of local variables  | 
 | 135 | +-- m  = stack size before instruction  | 
 | 136 | +-- m' = stack size after instruction  | 
 | 137 | + | 
 | 138 | +variable  | 
 | 139 | +  k l m m' : StackSize  | 
 | 140 | + | 
 | 141 | +data Ins (n : StoreSize) : (m m' : StackSize) → Set where  | 
 | 142 | +  load  : (a : Addr n) → Ins n m       (1 + m)  -- Load variable onto stack.  | 
 | 143 | +  add   :                Ins n (2 + m) (1 + m)  -- Add top stack elements.  | 
 | 144 | +  ldc   : (w : Word)   → Ins n m       (1 + m)  -- Load constant onto stack.  | 
 | 145 | +  pop   :                Ins n (1 + m) m        -- Remove top stack element.  | 
 | 146 | + | 
 | 147 | +-- Instruction sequences.  | 
 | 148 | +-- Note that for instruction concatenation, the index "l" has to match.  | 
 | 149 | + | 
 | 150 | +data Inss (n : StoreSize) (m : StackSize) : (m' : StackSize) → Set where  | 
 | 151 | +  []  : Inss n m m  | 
 | 152 | +  ins : Ins n m l → Inss n m l  | 
 | 153 | +  _∙_ : (i : Inss n m l) (is : Inss n l k) → Inss n m k  | 
 | 154 | + | 
 | 155 | +infixr 10 _∙_  | 
 | 156 | + | 
 | 157 | +-- Compilation of expressions  | 
 | 158 | +---------------------------------------------------------------------------  | 
 | 159 | + | 
 | 160 | +-- The code for an expression leaves one additional value on the stack.  | 
 | 161 | + | 
 | 162 | +compile : (e : Exp n) → Inss n m (suc m)  | 
 | 163 | +compile (var x)     = ins (load x)  | 
 | 164 | +compile (num w)     = ins (ldc w)  | 
 | 165 | +compile (plus e e') = compile e ∙ compile e' ∙ ins add  | 
 | 166 | + | 
 | 167 | +ss1 : Inss 2 0 1  | 
 | 168 | +ss1 = compile ex1  | 
 | 169 | + | 
 | 170 | +-- JVM small-step semantics  | 
 | 171 | +---------------------------------------------------------------------------  | 
 | 172 | + | 
 | 173 | +-- JVM machine state (simplified).  | 
 | 174 | + | 
 | 175 | +Store = Env  | 
 | 176 | +Stack = Vec Word  | 
 | 177 | + | 
 | 178 | +record State (n : StoreSize) (m : StackSize) : Set where  | 
 | 179 | +  constructor state  | 
 | 180 | +  field  | 
 | 181 | +    V  : Store n  | 
 | 182 | +    S  : Stack m  | 
 | 183 | +open State  | 
 | 184 | + | 
 | 185 | +-- Executing a JVM instruction.  | 
 | 186 | + | 
 | 187 | +step : (i : Ins n m m') (s : State n m) → State n m'  | 
 | 188 | +step (load a) (state V S)           = state V (lookup a V ∷ S)  | 
 | 189 | +step add      (state V (v ∷ w ∷ S)) = state V (w + v ∷ S)  | 
 | 190 | +step (ldc w)  (state V S)           = state V (w ∷ S)  | 
 | 191 | +step pop      (state V (_ ∷ S))     = state V S  | 
 | 192 | + | 
 | 193 | +-- Compiler correctness  | 
 | 194 | +---------------------------------------------------------------------------  | 
 | 195 | + | 
 | 196 | +-- Executing a series of JVM instructions.  | 
 | 197 | + | 
 | 198 | +steps : (is : Inss n m m') (s : State n m) → State n m'  | 
 | 199 | +steps (ins i)    s = step i s  | 
 | 200 | +steps []         s = s  | 
 | 201 | +steps (is ∙ is') s = steps is' (steps is s)  | 
 | 202 | + | 
 | 203 | +r1 = steps ss1 (state (15 ∷ 1 ∷ []) [])  | 
 | 204 | + | 
 | 205 | +-- Pushing a word onto the stack.  | 
 | 206 | + | 
 | 207 | +push : Word → State n m → State n (suc m)  | 
 | 208 | +push w (state V S) = state V (w ∷ S)  | 
 | 209 | + | 
 | 210 | +push-eval : (e : Exp n) (s : State n m) → State n (suc m)  | 
 | 211 | +push-eval e (state V S) = state V (eval e V ∷ S)  | 
 | 212 | + | 
 | 213 | + | 
 | 214 | +-- Compiler correctness theorem.  | 
 | 215 | + | 
 | 216 | +-- Running the instructions for an expression e  | 
 | 217 | +-- leaves the value of e on top of the stack.  | 
 | 218 | + | 
 | 219 | +sound : (e : Exp n) (s : State n m) →  | 
 | 220 | + | 
 | 221 | +  steps (compile e) s ≡ push-eval e s  | 
 | 222 | + | 
 | 223 | +-- Case: variables  | 
 | 224 | +sound (var x)     s = refl  | 
 | 225 | + | 
 | 226 | +-- Case: number literals.  | 
 | 227 | +sound (num w)     s = refl  | 
 | 228 | + | 
 | 229 | +-- Case: addition expression.  | 
 | 230 | +sound (plus e e') s = begin  | 
 | 231 | +  steps (compile (plus e e')) s                       ≡⟨ refl ⟩  | 
 | 232 | +  steps (compile e ∙ compile e' ∙ ins add) s          ≡⟨ refl ⟩  | 
 | 233 | +  steps (compile e' ∙ ins add) (steps (compile e) s)  ≡⟨ cong (steps _) (sound e s) ⟩  | 
 | 234 | +  steps (compile e' ∙ ins add) s'                     ≡⟨ refl  ⟩  | 
 | 235 | +  steps (ins add) (steps (compile e') s')             ≡⟨ cong (steps _) (sound e' s) ⟩  | 
 | 236 | +  steps (ins add) (push-eval e' s')                   ≡⟨ {!   !} ⟩  | 
 | 237 | +  push-eval (plus e e') s  | 
 | 238 | +  ∎  | 
 | 239 | +  where s' = push-eval e s  | 
 | 240 | + | 
 | 241 | +-- steps (compile (plus e e') s)  | 
 | 242 | +--   = steps (compile e ∙ compile e' ∙ ins add) s  | 
 | 243 | +--   = steps (compile e' ∙ ins add) (steps (compile e) s)  -- by ind.hyp.  | 
 | 244 | +--   = steps (compile e' ∙ ins add) (push-eval e s)  | 
 | 245 | +--   = steps (ins add) (steps (compile e') (push-eval e s))  | 
 | 246 | +--   = steps (ins add) (push-eval e' (push-eval e s))  | 
 | 247 | +--   = step add (push-eval e' (push-eval e s))  | 
 | 248 | +--   = step add (push-eval e' (push-eval e (state V S)))   -- s =: state V S  | 
 | 249 | +--   = step add (push-eval e' (state V (eval e V ∷ S)))  | 
 | 250 | +--   = step add (state V (eval e' V ∷ eval e V ∷ S))  | 
 | 251 | +--   = state V ((eval e V + eval e' V) ∷ S)  | 
 | 252 | +--   = state V (eval (plus e e') V ∷ S)  | 
 | 253 | +--   = push-eval (plus e e') (state V S)  | 
 | 254 | +--   = push-eval (plus e e') s  | 
 | 255 | + | 
 | 256 | +-- -}  | 
 | 257 | +-- -}  | 
 | 258 | +-- -}  | 
 | 259 | +-- -}  | 
 | 260 | +-- -}  | 
 | 261 | +-- -}  | 
 | 262 | +-- -}  | 
 | 263 | +-- -}  | 
 | 264 | +-- -}  | 
 | 265 | +-- -}  | 
 | 266 | +-- -}  | 
 | 267 | +-- -}  | 
 | 268 | +-- -}  | 
 | 269 | +-- -}  | 
 | 270 | +-- -}  | 
 | 271 | +-- -}  | 
 | 272 | +-- -}  | 
0 commit comments