Definition unopDenote (op : unop) (v : val) : val :=
  match op, is_true_dec v with
    | UNeg, left _ => Vint 0
    | UNeg, right _ => Vint 1
  end.Definition binopDenote (op : binop) (v1 v2 : val) :=
  match op, v1, v2 with
    | BAdd, (Vint n), (Vint m) => Vint (n+m)%nat
    | BAdd, (Vptr p), (Vint n) => Vptr (p+n)%nat
    | _, _, _ => Vundef
  end.Fixpoint expr_wellformed (e : expr) : Prop :=
  match e with
    | EVal _ => True
    | EUnop _ e => expr_wellformed e
    | EBinop _ e1 e2 => expr_wellformed e1 /\ expr_wellformed e2
    | EPrim f => G f
  end.Fixpoint exprEval' (e : expr) : W -> option val := fun w =>
  match e with
    | EVal v => Some v
    | EUnop op e' =>
      let v := exprEval' e' w in
        match v with
          | Some v' => Some (unopDenote op v')
          | None => None
        end
    | EBinop op e1 e2 =>
      let v1 := exprEval' e1 w in
      let v2 := exprEval' e2 w in
        match v1, v2 with
          | Some v1', Some v2' => Some (binopDenote op v1' v2')
          | _, _ => None
        end
    | EPrim f => f w
  end.Definition exprEval (e : expr) (w : W) (v : val) :=
  expr_wellformed e /\ exprEval' e w = Some v.Fixpoint pure_expr (e : expr) :=
  match e with
    | EVal v => True
    | EUnop op e' => pure_expr e'
    | EBinop op e1 e2 => pure_expr e1 /\ pure_expr e2
    | EPrim _ => False
  end.

(* Specifications: *)
Lemma pure_exprEval : forall e w w' b1 b2, pure_expr e -> exprEval e w b1 -> exprEval e w' b2 -> b1=b2.
Lemma pure_expr_safe : forall e w, pure_expr e -> exists b, exprEval e w b.
Lemma pure_expr_dec : forall e, {pure_expr e} + {~ pure_expr e}.