import .imp_syntax import .imp_common namespace imp namespace interp_nock /- This is an implementation of an interpreter equivalent to the one we defined in `imp_interp.lean`, without the safety checks. The goal is to show that the "safe" version of the interpreter is equivalent to this "optimized" version of the interpreter. -/ def lookup' (s : store) (x : string) : val := match store.lookup x s with | some v := v | none := val.int 0 end def updates' : store → list string → list val → store | s (x :: xs') (v :: vs') := updates' (update x v s) xs' vs' | s _ _ := s def strget' (v : val) (s : string) : val := match v with | val.int i := match s.index i.to_nat with | some c := val.str (string.str "" c) | none := val.int 0 end | _ := val.int 0 end def read' (h : heap) : val → val | (val.addr a) := match heap.read h a with | some v' := v' | _ := val.int 0 end | _ := val.int 0 def alloc' (h : heap) : val → val → heap | (val.int i1) v2 := heap.alloc h i1 v2 | _ _ := h def write' (h : heap) : val → val → heap | (val.addr i1) v2 := match heap.write h i1 v2 with | some h' := h' | _ := h end | _ _ := h def op1 : unary_op → val → val | unary_op.neg (val.int i) := val.int (-i) | unary_op.not (val.bool b) := val.bool (bnot b) | _ _ := val.int 0 section interp_op2 open binary_op open val def op2 : binary_op → val → val → val | add (int i1) (int i2) := val.int (i1 + i2) | add (str s1) (str s2) := val.str (s1 ++ s2) | sub (int i1) (int i2) := int (i1 - i2) | mul (int i1) (int i2) := int (i1 * i2) | div (int i1) (int i2) := int (int.fdiv i1 i2) | mod (int i1) (int i2) := int (int.fmod i1 i2) | eq v1 v2 := bool (v1 = v2) | lt (int i1) (int i2) := bool (i1 < i2) | le (int i1) (int i2) := bool (i1 <= i2) | conj (bool b1) (bool b2) := bool (b1 && b2) | disj (bool b1) (bool b2) := bool (b1 || b2) -- hacks | add (addr i1) (int i2) := addr (1 + i1 + i2) | _ _ _ := val.int 0 end interp_op2 end interp_nock section interp_e open imp.expr val def interp_nock.expr (s : store) (h : heap) : expr → val | (expr.val v) := v | (expr.var x) := interp_nock.lookup' s x | (expr.unary_op op e1) := interp_nock.op1 op (interp_nock.expr e1) | (expr.binary_op op e1 e2) := interp_nock.op2 op (interp_nock.expr e1) (interp_nock.expr e2) | (length e1) := match interp_nock.expr e1 with | (addr a) := interp_nock.read' h (addr a) | (str cs) := int (cs.length) | _ := val.int 0 end | (index e1 e2) := match interp_nock.expr e1 with | (addr a) := interp_nock.read' h (interp_nock.op2 binary_op.add (addr a) (interp_nock.expr e2)) | (str cs) := interp_nock.strget' (interp_nock.expr e2) cs | _ := int 0 end end interp_e namespace interp_nock def seq_expr (s : store) (h : heap) : list imp.expr → list val | [] := [] | (e :: rest) := interp_nock.expr s h e :: seq_expr rest section interp_s open stmt open val def stmt : store → heap → stmt → (store × heap × stmt) | s h nop := (s, h, nop) | s h (set x e) := (update x (expr s h e) s, h, nop) | s h (alloc x e1 e2) := ( update x (addr $ h.length) s , alloc' h (expr s h e1) (expr s h e2) , nop ) | s h (write x e1 e2) := let h' := write' h (op2 binary_op.add (lookup' s x) (expr s h e1)) (expr s h e2) in (s, h', nop) | s h (ifelse e p1 p2) := match expr s h e with | bool bool.ff := (s, h, p2) | _ := (s, h, p1) end | s h (while e p) := match expr s h e with | (bool bool.ff) := (s, h, nop) | _ := (s, h, seq p (while e p)) end | s h (seq p1 p2) := if p1 = imp.stmt.nop then (s, h, p2) else match stmt s h p1 with | (s', h', p1') := (s', h', seq p1' p2) end end interp_s def program : nat → store → heap → imp.stmt → imp.expr → result | 0 s h p ret := result.timeout s h p ret | (n + 1) s h p ret := if p = stmt.nop then result.done h (expr s h ret) else match stmt s h p with | (s', h', p') := program n s' h' p' ret end end interp_nock end imp