aboutsummaryrefslogtreecommitdiffstats
path: root/interpreter.v
blob: c701b42ae79761d69881f55c6ff6622235cf34f8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
Require Import Coq.Strings.String.
From stdpp Require Import fin_maps.
From mininix Require Import binop expr maptools matching.

Open Scope string_scope.

Definition eval1 (go : bool → expr → option value)
  (uf : bool) (d : expr) : option value :=
    match d with
    | X_Id _ => None
    | X_Force e => go true e
    | X_Closed e => go uf e
    | X_Placeholder x e => go uf e
    | X_V (V_Attrset bs) =>
        if uf
        then vs'map_mapM (go true) bs;
             Some (V_Attrset (X_V <$> vs'))
        else Some (V_Attrset bs)
    | X_V v => Some v
    | X_Attrset bs => go uf (V_Attrset (rec_subst bs))
    | X_LetBinding bs e =>
      let e' := subst (closed (rec_subst bs)) e
      in go uf e'
    | X_Select e (Ne_Cons x ys) =>
      v' ← go false e;
      bs ← maybe V_Attrset v';
      e'' ← bs !! x;
      match ys with
      | [] => go uf e''
      | y :: ys => go uf (X_Select e'' (Ne_Cons y ys))
      end
    | X_SelectOr e (Ne_Cons x ys) or =>
      v' ← go false e;
      bs ← maybe V_Attrset v';
      match bs !! x with
      | Some e'' =>
          match ys with
          | [] => go uf e''
          | y :: ys => go uf (X_SelectOr e'' (Ne_Cons y ys) or)
          end
      | None => go uf or
      end
    | X_Apply e1 e2 =>
      v1' ← go false e1;
      match v1' with
      | V_Fn x e =>
          let e' := subst {[x := X_Closed e2]} e
          in go uf e'
      | V_AttrsetFn m e =>
          v2' ← go false e2;
          bs ← maybe V_Attrset v2';
          bs' ← matches m bs;
          go uf (X_LetBinding bs' e)
      | V_Attrset bs =>
          f ← bs !! "__functor";
          go uf (X_Apply (X_Apply f (V_Attrset bs)) e2)
      | _ => None
      end
    | X_Cond e1 e2 e3 =>
      v1' ← go false e1;
      b ← maybe V_Bool v1';
      go uf (if b : bool then e2 else e3)
    | X_Incl e1 e2 =>
      v1' ← go false e1;
      match v1' with
      | V_Attrset bs => go uf (subst (placeholders bs) e2)
      | _ => go uf e2
      end
    | X_Op op e1 e2 =>
      e1' ← go false e1;
      e2' ← go false e2;
      v' ← binop_eval op e1' e2';
      go uf (X_V v')
    | X_HasAttr e x =>
      v' ← go false e;
      Some $ V_Bool $
        match v' with
        | V_Attrset bs =>
            bool_decide (is_Some (bs !! x))
        | _ => false
        end
    | X_Assert e1 e2 =>
      v1' ← go false e1;
      match v1' with
      | V_Bool true => go uf e2
      | _ => None
      end
    end.

Fixpoint eval (n : nat) (uf : bool) (e : expr) : option value :=
  match n with
  | O => None
  | S n => eval1 (eval n) uf e
  end.

(* Don't automatically 'simplify' eval: this can lead to very complicated
   assumptions and goals. Instead, we define our own lemma which can be used
   to unfold eval once. This allows us to write proofs in a much more
   controlled manner, and we can still leverage tactics like simplify_option_eq
   without everything blowing up uncontrollably *)
Global Opaque eval.
Lemma eval_S n : eval (S n) = eval1 (eval n).
Proof. done. Qed.