Skip to content

Instantly share code, notes, and snippets.

@xuanruiqi
Created February 5, 2019 17:01
Show Gist options
  • Select an option

  • Save xuanruiqi/3df52612b87867f4b5731fd5efe9c38a to your computer and use it in GitHub Desktop.

Select an option

Save xuanruiqi/3df52612b87867f4b5731fd5efe9c38a to your computer and use it in GitHub Desktop.
Old version of Semantics.v that cause stack overflows
Require Coq.Bool.Bool. Open Scope bool.
Require Import String.
Require Import Coq.Strings.Ascii. Open Scope char_scope.
Require Coq.Arith.PeanoNat. Open Scope nat_scope.
Require Coq.Lists.List. Open Scope list_scope.
Require Import BinInt.
Require Extraction.
Set Implicit Arguments.
Unset Elimination Schemes.
(* TODO: code cleanup
* - shadow instead of prime, esp with u_gen
* - indent 2 spaces
* - naming reconsiderations?
* - more...
*)
Module Util.
Section ListUtil.
Fixpoint update_nth {A : Type} (n : nat) (xs : list A) (f : A -> A) :=
match (n, xs) with
| (_, nil) => nil
| (0, cons x xs) => cons (f x) xs
| (S n, cons x xs) => cons x (update_nth n xs f)
end.
Fixpoint _findmapi {A B : Type} (i : nat) (xs : list A) (f : nat -> A -> option B) : option(B) :=
match xs with
| nil => None
| cons x xs =>
match f i x with
| (Some b) as result => result
| None =>
_findmapi (i + 1) xs f
end
end.
Definition findmapi {A B : Type} (xs : list A) (f : nat -> A -> option B) : option(B) :=
_findmapi 0 xs f.
Fixpoint zip_eq {A B : Type} (xs : list A) (ys : list B) : option(list (A * B)) :=
match (xs, ys) with
| (nil, nil) => Some nil
| (cons x xs, cons y ys) =>
match zip_eq xs ys with
| None => None
| Some tail => Some (cons (x, y) tail)
end
| (cons _ _, nil) => None
| (nil, cons _ _) => None
end.
Fixpoint unzip {A B : Type} (xs : list (A * B)) : (list A * list B) :=
match xs with
| nil => (nil, nil)
| cons (x, y) xys =>
let (xs, ys) := unzip xys in
(cons x xs, cons y ys)
end.
End ListUtil.
Section StringUtil.
Definition str_eqb (s1 s2 : Coq.Strings.String.string) : bool :=
if Coq.Strings.String.string_dec s1 s2 then true else false.
Definition char_le_b (ch1 ch2 : Coq.Strings.Ascii.ascii) : bool :=
Nat.leb (Coq.Strings.Ascii.nat_of_ascii ch1) (Coq.Strings.Ascii.nat_of_ascii ch2).
Definition char_eq_b (ch1 ch2 : Coq.Strings.Ascii.ascii) : bool :=
Nat.eqb (Coq.Strings.Ascii.nat_of_ascii ch1) (Coq.Strings.Ascii.nat_of_ascii ch2).
Definition char_in_range_b (ch s e : Coq.Strings.Ascii.ascii) : bool :=
(char_le_b s ch) && (char_le_b ch e).
End StringUtil.
(* Finite maps over nats, used in various places (e.g. MetaVarMap below) *)
Module Type NATMAP.
Parameter t : Type -> Type.
Parameter empty : forall (A : Type), t A.
Parameter extend : forall (A : Type), t A -> nat * A -> t A.
Parameter drop : forall A : Type, t A -> nat -> option (t A * A).
Parameter union : forall (A : Type), t A -> t A -> t A.
Parameter lookup : forall (A : Type), t A -> nat -> option A.
Parameter insert_or_update : forall (A : Type), t A -> nat * A -> t A.
Parameter insert_or_map : forall (A : Type), t A -> nat -> (unit -> A) -> (A -> A) -> A * t A.
Parameter map : forall (A B : Type), (A -> B) -> t A -> t B.
Parameter update_with : forall (A : Type), (A -> A) -> nat -> t A -> A -> (A * t A).
Parameter length : forall (A : Type), t A -> nat.
Parameter to_list : forall (A : Type), t A -> list (nat * A).
Parameter fold : forall (A B : Type), t A -> (B -> (nat * A) -> B) -> B -> B.
End NATMAP.
Module NatMap <: NATMAP.
Definition t (A : Type) := list (nat * A).
Definition empty {A : Type} : t A := nil.
Definition extend {A : Type} (delta : t A) (x : nat * A)
: t A := cons x delta.
Fixpoint drop {A : Type} (delta : t A) (n : nat) : option (t A * A) :=
match delta with
| nil => None
| cons (y, a) delta' =>
match Nat.eqb n y with
| true => Some (delta', a)
| false => drop delta' n
end
end.
Definition union {A : Type} (delta1 : t A) (delta2 : t A) : t A := delta1 ++ delta2.
Fixpoint lookup {A : Type} (delta : t A) (x : nat) : option A :=
match delta with
| nil => None
| cons (y, a) delta' =>
match Nat.eqb x y with
| true => Some a
| false => lookup delta' x
end
end.
Fixpoint insert_or_update {A : Type} (delta : t A) (x : nat * A) : t A :=
let (u, a) := x in
match delta with
| nil => cons x delta
| cons (u', a') delta' =>
match Nat.eqb u u' with
| true => cons (u', a) delta'
| false => cons (u', a') (insert_or_update delta' x)
end
end.
Fixpoint insert_or_map {A : Type} (delta : t A) (u : nat)
(a0 : unit -> A) (f : A -> A) : A * t A :=
match delta with
| nil =>
let a0 := a0 tt in
(a0, cons (u, a0) delta)
| cons (u', a) delta' =>
if Nat.eqb u u' then
let a' := f a in
(a', cons (u', a') delta')
else
let (a', delta'') := insert_or_map delta' u a0 f in
(a', cons (u', a) delta'')
end.
Fixpoint map {A B : Type} (f : A -> B) (delta : t A) : t B :=
match delta with
| nil => nil
| cons (u, a) delta' => cons (u, f a) (map f delta')
end.
Fixpoint update_with {A : Type} (f : A -> A) (u : nat) (delta : t A) (u_nil : A) : (A * t A) :=
match delta with
| nil => (u_nil, delta)
| cons (u', a) delta' =>
match Nat.eqb u u' with
| true =>
let a' := f a in
(a', cons (u', a') delta')
| false =>
let (a', delta'') := update_with f u delta' u_nil in
(a', cons (u', a) delta'')
end
end.
Definition length {A : Type} (delta : t A) := List.length delta.
Definition to_list {A : Type} (delta : t A) := delta.
Definition fold {A B : Type} (delta : t A) (f : (B -> (nat * A) -> B)) (b : B) : B :=
List.fold_left f delta b.
End NatMap.
End Util.
(* Fuel is used to work around Coq's limited termination check for now.
* During extraction, it is rewritten to unit so it has no run-time cost. *)
Module Fuel.
Inductive t : Type :=
| More : t -> t
| Kicked : t.
End Fuel.
(* Debugging aids that are implemented on the OCaml side *)
Module Type DEBUG.
Parameter log_nat : nat -> nat.
Parameter log_string : Coq.Strings.String.string -> Coq.Strings.String.string.
Parameter string_of_nat : nat -> Coq.Strings.String.string.
Parameter log_path : forall A : Type, (list(nat) * A) -> (list(nat) * A).
Parameter log_natlist : list(nat) -> list(nat).
Parameter log_a : forall A : Type, nat -> A -> A.
End DEBUG.
(* The Debug parameter is provided in SemanticsCore.re *)
Module FCore(Debug : DEBUG).
Module NatMap := Util.NatMap.
Module Var.
Definition t := Coq.Strings.String.string.
Definition eq (x : t) (y : t) : bool := Util.str_eqb x y.
(* is_valid_internal s = true iff s is a string valid as the suffix of a variable *)
Fixpoint is_valid_suffix (s : t) : bool :=
match s with
| Coq.Strings.String.EmptyString => true
| Coq.Strings.String.String ch rest =>
(
(Util.char_eq_b ch "_") ||
(Util.char_in_range_b ch "a" "z") ||
(Util.char_in_range_b ch "A" "Z") ||
(Util.char_in_range_b ch "0" "9") ||
(Util.char_eq_b ch "'")
) && is_valid_suffix rest
end.
(* is_valid s = true iff s is a valid variable *)
(* should be equivalent to the OCaml rules: "[_a-z][_a-zA-Z0-9']*" *)
Definition is_valid (s : t) : bool :=
match s with
| Coq.Strings.String.EmptyString => false
| Coq.Strings.String.String first_char suffix =>
((Util.char_eq_b first_char "_") || (Util.char_in_range_b first_char "a" "z")) &&
is_valid_suffix suffix
end.
(* helper function for guarding options with is_valid *)
Definition check_valid {A : Type}
(s : t)
(result : option(A))
: option(A) :=
if is_valid s then result else None.
End Var.
(* TODO turn this into Util.StringMap ala NatMap *)
(* Module Type VARMAP.
Parameter t : Type -> Type.
Parameter empty : forall (a : Type), t a.
Parameter extend : forall (a : Type), t a -> Var.t * a -> t a.
Parameter lookup : forall (a : Type), t a -> Var.t -> option a.
Parameter map : forall (a b : Type), (Var.t * a -> b) -> t a -> t b.
Parameter length : forall (a : Type), t a -> nat.
Parameter to_list : forall (a : Type), t a -> list (Var.t * a).
End VARMAP. *)
Module VarMap.
Definition t_ (a : Type) := list (Var.t * a).
Definition empty {a : Type} : t_ a := nil.
Definition is_empty {a : Type} (ctx : t_ a) : bool :=
match ctx with
| nil => true
| _ => false
end.
(* Fixpoint update {a : Type} (ctx : t a) (x : Var.t) (elt : a) : option (t a) :=
match ctx with
| nil => None
| cons (y, elt') ctx' =>
match Var.eq x y with
| true => Some (cons (y, elt) ctx')
| false =>
match update ctx' x elt with
| Some ctx' => Some (cons (y, elt') ctx')
| None => None
end
end
end. *)
Fixpoint drop {a : Type} (ctx : t_ a) (x : Var.t) : t_ a :=
match ctx with
| nil => ctx
| cons (y, elt) ctx' =>
match Var.eq x y with
| true => ctx'
| false => cons (y, elt) (drop ctx' x)
end
end.
Definition extend {a : Type} (ctx : t_ a) (xa : Var.t * a)
: t_ a :=
let (x, elt) := xa in
cons xa (drop ctx x).
Definition union {a : Type} (ctx1 : t_ a) (ctx2 : t_ a) : t_ a :=
List.fold_left extend ctx2 ctx1.
Fixpoint lookup {a : Type} (ctx : t_ a) (x : Var.t) : option a :=
match ctx with
| nil => None
| cons (y, elt) ctx' =>
match Var.eq x y with
| true => Some elt
| false => lookup ctx' x
end
end.
Definition contains {a : Type} (ctx : t_ a) (x : Var.t) : bool :=
match lookup ctx x with
| None => false
| Some _ => true
end.
Definition map {a b : Type} (f : Var.t * a -> b) (xs : t_ a) :=
Coq.Lists.List.map (fun (xa : Var.t * a) =>
let (x, _) := xa in
(x, f xa)) xs.
Fixpoint length {a : Type} (ctx : t_ a) : nat :=
match ctx with
| nil => O
| cons _ ctx' => S (length ctx')
end.
Definition to_list {a : Type} (ctx : t_ a) : list(Var.t * a) := ctx.
End VarMap.
(* Metavariables, a.k.a. hole names *)
Module MetaVar.
Definition t := nat.
Fixpoint eq (x : t) (y : t) : bool := Nat.eqb x y.
End MetaVar.
(* A simple metavariable generator *)
Module MetaVarGen.
Definition t : Type := MetaVar.t.
Definition init : MetaVarGen.t := 0.
Definition next (x : t) : MetaVar.t * MetaVarGen.t :=
let n := S(x) in (x, n).
End MetaVarGen.
Module MetaVarMap := Util.NatMap.
Inductive in_hole_reason : Type :=
| TypeInconsistent : in_hole_reason
| WrongLength : in_hole_reason.
Inductive err_status : Type :=
| NotInHole : err_status
| InHole : in_hole_reason -> MetaVar.t -> err_status.
Inductive var_err_status : Type :=
| NotInVHole : var_err_status
| InVHole : MetaVar.t -> var_err_status.
Module OperatorSeq.
Inductive opseq (tm : Type) (op : Type) : Type :=
| ExpOpExp : tm -> op -> tm -> opseq tm op
| SeqOpExp : opseq tm op -> op -> tm -> opseq tm op.
(* concatenates two opseqs *)
Fixpoint seq_op_seq {tm op : Type}
(seq1 : opseq tm op) (op1 : op) (seq2 : opseq tm op)
: opseq tm op :=
match seq2 with
| ExpOpExp e1 op2 e2 => SeqOpExp (SeqOpExp seq1 op1 e1) op2 e2
| SeqOpExp seq2' op2 ue' =>
SeqOpExp (seq_op_seq seq1 op1 seq2') op2 ue'
end.
(* prepends an expression to seq *)
Fixpoint exp_op_seq {tm op : Type}
(e1 : tm) (op1 : op) (seq : opseq tm op)
: opseq tm op :=
match seq with
| ExpOpExp e2 op2 e3 =>
SeqOpExp (ExpOpExp e1 op1 e2) op2 e3
| SeqOpExp seq' op' e' =>
SeqOpExp (exp_op_seq e1 op1 seq') op' e'
end.
(* returns number of expressions in seq (not ops) *)
Fixpoint seq_length {tm op : Type}
(seq : opseq tm op) : nat :=
match seq with
| ExpOpExp _ _ _ => 2
| SeqOpExp seq' _ _ => S(seq_length seq')
end.
(* nth expression in seq, if it exists *)
Fixpoint seq_nth {tm op : Type}
(n : nat) (seq : opseq tm op) : option(tm) :=
match (n, seq) with
| (O, ExpOpExp e1 _ _) => Some e1
| (S O, ExpOpExp _ _ e2) => Some e2
| (_, ExpOpExp _ _ _) => None
| (_, SeqOpExp seq' _ e) =>
let len := seq_length seq' in
if Nat.eqb n len then Some e else seq_nth n seq'
end.
(* update the nth expression in seq, if it exists *)
Fixpoint seq_update_nth {tm op : Type}
(n : nat) (seq : opseq tm op) (e : tm) : option(opseq tm op) :=
match (n, seq) with
| (O, ExpOpExp _ op e2) => Some (ExpOpExp e op e2)
| (S O, ExpOpExp e1 op _) => Some (ExpOpExp e1 op e)
| (_, ExpOpExp _ _ _) => None
| (_, SeqOpExp seq' op e') =>
let len := seq_length seq' in
if Nat.eqb n len then Some (SeqOpExp seq' op e)
else match seq_update_nth n seq' e with
| Some seq'' => Some (SeqOpExp seq'' op e')
| None => None
end
end.
Inductive opseq_surround (tm : Type) (op : Type) : Type :=
(* set up this way to enforce the requirement that there be at least one op *)
(* if the prefix is empty, there must be a non-empty suffix *)
| EmptyPrefix : opseq_suffix tm op -> opseq_surround tm op
(* if the suffix is empty, there must be a non-empty prefix *)
| EmptySuffix : opseq_prefix tm op -> opseq_surround tm op
(* both can be non-empty *)
| BothNonEmpty : opseq_prefix tm op -> opseq_suffix tm op -> opseq_surround tm op
with opseq_prefix (tm : Type) (op : Type) : Type :=
(* a non-empty prefix is either one that contains a single expression *)
| ExpPrefix : tm -> op -> opseq_prefix tm op
(* or one that contains two or more expressions, i.e. another opseq *)
| SeqPrefix : opseq tm op -> op -> opseq_prefix tm op
with opseq_suffix (tm : Type) (op : Type) : Type :=
(* analagous to opseq_prefix *)
| ExpSuffix : op -> tm -> opseq_suffix tm op
| SeqSuffix : op -> opseq tm op -> opseq_suffix tm op.
(* append an exp to a prefix *)
Definition prefix_append_exp {tm op : Type}
(prefix : opseq_prefix tm op)
(e : tm)
(op2 : op)
: opseq_prefix tm op :=
match prefix with
| ExpPrefix e1 op1 =>
SeqPrefix (OperatorSeq.ExpOpExp e1 op1 e) op2
| SeqPrefix seq1 op1 =>
SeqPrefix (OperatorSeq.SeqOpExp seq1 op1 e) op2
end.
(* prepend an exp to a suffix *)
Definition suffix_prepend_exp {tm op : Type}
(suffix : opseq_suffix tm op)
(op1 : op)
(e : tm)
: opseq_suffix tm op :=
match suffix with
| ExpSuffix op2 e' =>
SeqSuffix op1 (OperatorSeq.ExpOpExp e op2 e')
| SeqSuffix op2 seq' =>
SeqSuffix op1 (OperatorSeq.exp_op_seq e op2 seq')
end.
(* append an exp to a suffix *)
Definition suffix_append_exp {tm op : Type}
(suffix : opseq_suffix tm op)
(op2 : op)
(e : tm)
: opseq_suffix tm op :=
match suffix with
| ExpSuffix op1 e' =>
SeqSuffix op1 (OperatorSeq.ExpOpExp e' op2 e)
| SeqSuffix op1 seq =>
SeqSuffix op1 (OperatorSeq.SeqOpExp seq op2 e)
end.
(* append an exp to the suffix of a surround *)
Definition surround_suffix_append_exp {tm op : Type}
(surround : opseq_surround tm op)
(op1 : op)
(e : tm)
: opseq_surround tm op :=
match surround with
| EmptyPrefix suffix =>
let suffix' := suffix_append_exp suffix op1 e in
EmptyPrefix suffix'
| EmptySuffix prefix =>
let suffix' := ExpSuffix op1 e in
BothNonEmpty prefix suffix'
| BothNonEmpty prefix suffix =>
let suffix' := suffix_append_exp suffix op1 e in
BothNonEmpty prefix suffix'
end.
Fixpoint split {tm op : Type}
(n : nat) (seq : opseq tm op)
: option(tm * opseq_surround tm op) :=
match (n, seq) with
| (O, OperatorSeq.ExpOpExp e1 op e2) =>
Some (e1, EmptyPrefix (ExpSuffix op e2))
| (S O, OperatorSeq.ExpOpExp e1 op e2) =>
Some (e2, EmptySuffix (ExpPrefix e1 op))
| (_, OperatorSeq.ExpOpExp _ _ _) =>
None
| (_, OperatorSeq.SeqOpExp seq' op e) =>
let length' := OperatorSeq.seq_length seq' in
if Nat.ltb n length' then
match split n seq' with
| Some (e', surround) =>
let surround' := surround_suffix_append_exp surround op e in
Some (e', surround')
| None => None
end
else if Nat.eqb n length' then
let prefix' := SeqPrefix seq' op in
let surround' := EmptySuffix prefix' in
Some (e, surround')
else None
end.
Fixpoint split0 {tm op : Type}
(seq : opseq tm op)
: tm * opseq_suffix tm op :=
match seq with
| OperatorSeq.ExpOpExp e1 op e2 =>
(e1, ExpSuffix op e2)
| OperatorSeq.SeqOpExp seq' op e =>
let (e0, suffix') := split0 seq' in
(e0, suffix_append_exp suffix' op e)
end.
Definition split_tail {tm op : Type}
(seq : opseq tm op) : tm * opseq_prefix tm op :=
match seq with
| OperatorSeq.ExpOpExp e1 op e2 =>
(e2, ExpPrefix e1 op)
| OperatorSeq.SeqOpExp seq' op e =>
(e, SeqPrefix seq' op)
end.
Definition prefix_length {tm op : Type}
(prefix : opseq_prefix tm op) : nat :=
match prefix with
| ExpPrefix _ _ => 1
| SeqPrefix seq _ => OperatorSeq.seq_length seq
end.
Definition surround_prefix_length {tm op : Type}
(surround : opseq_surround tm op)
: nat :=
match surround with
| EmptyPrefix _ => O
| EmptySuffix prefix
| BothNonEmpty prefix _ => prefix_length prefix
end.
Definition suffix_length {tm op : Type}
(suffix : opseq_suffix tm op) : nat :=
match suffix with
| ExpSuffix _ _ => 1
| SeqSuffix _ seq => OperatorSeq.seq_length seq
end.
Definition surround_suffix_length {tm op : Type}
(surround : opseq_surround tm op)
: nat :=
match surround with
| EmptySuffix _ => O
| EmptyPrefix suffix
| BothNonEmpty _ suffix => suffix_length suffix
end.
Definition opseq_of_exp_and_surround {tm op : Type}
(e : tm)
(surround : opseq_surround tm op)
: opseq tm op :=
match surround with
| EmptyPrefix suffix =>
match suffix with
| ExpSuffix op e2 => OperatorSeq.ExpOpExp e op e2
| SeqSuffix op seq => OperatorSeq.exp_op_seq e op seq
end
| EmptySuffix prefix =>
match prefix with
| ExpPrefix e1 op => OperatorSeq.ExpOpExp e1 op e
| SeqPrefix seq op => OperatorSeq.SeqOpExp seq op e
end
| BothNonEmpty prefix suffix =>
match (prefix, suffix) with
| (ExpPrefix e1 op1, ExpSuffix op2 e2) =>
OperatorSeq.SeqOpExp
(OperatorSeq.ExpOpExp e1 op1 e)
op2 e2
| (ExpPrefix e1 op1, SeqSuffix op2 seq2) =>
OperatorSeq.seq_op_seq
(OperatorSeq.ExpOpExp e1 op1 e)
op2 seq2
| (SeqPrefix seq1 op1, ExpSuffix op2 e2) =>
OperatorSeq.SeqOpExp
(OperatorSeq.SeqOpExp seq1 op1 e) op2 e2
| (SeqPrefix seq1 op1, SeqSuffix op2 seq2) =>
OperatorSeq.seq_op_seq
(OperatorSeq.SeqOpExp seq1 op1 e) op2 seq2
end
end.
End OperatorSeq.
Module Skel.
Inductive t (op : Type) : Type :=
| Placeholder : nat -> t op
| BinOp : err_status -> op -> t op -> t op -> t op.
Fixpoint leftmost_op {op : Type} (skel : t op) : option(op) :=
match skel with
| Placeholder _ _ => None
| BinOp _ op skel1 _ =>
match leftmost_op skel1 with
| (Some op) as result => result
| None => Some op
end
end.
Fixpoint rightmost_op {op : Type} (skel : t op) : option(op) :=
match skel with
| Placeholder _ _ => None
| BinOp _ op _ skel2 =>
match rightmost_op skel2 with
| (Some op) as result => result
| None => Some op
end
end.
End Skel.
Module HTyp.
(* types with holes *)
Inductive t : Type :=
| Hole : t
| Unit : t
| Num : t
| Bool : t
| Arrow : t -> t -> t
| Prod : t -> t -> t
| Sum : t -> t -> t
| List : t -> t.
(* eqity *)
Fixpoint eq (ty1 : t) (ty2 : t) : bool :=
match (ty1, ty2) with
| (Hole, Hole) => true
| (Hole, _) => false
| (Unit, Unit) => true
| (Unit, _) => false
| (Num, Num) => true
| (Num, _) => false
| (Bool, Bool) => true
| (Bool, _) => false
| (Arrow ty1 ty2, Arrow ty1' ty2') =>
andb (eq ty1 ty1') (eq ty2 ty2')
| (Arrow _ _, _) => false
| (Prod ty1 ty2, Prod ty1' ty2') =>
andb (eq ty1 ty1') (eq ty2 ty2')
| (Prod _ _, _) => false
| (Sum ty1 ty2, Sum ty1' ty2') =>
andb (eq ty1 ty1') (eq ty2 ty2')
| (Sum _ _, _) => false
| (List ty, List ty') =>
eq ty ty'
| (List _, _) => false
end.
(* type consistency *)
Fixpoint consistent (x y : t) : bool :=
match (x, y) with
| (Hole, _)
| (_, Hole) => true
| (Unit, Unit) => true
| (Unit, _) => false
| (Num, Num) => true
| (Num, _) => false
| (Bool, Bool) => true
| (Bool, _) => false
| (Arrow ty1 ty2, Arrow ty1' ty2')
| (Prod ty1 ty2, Prod ty1' ty2')
| (Sum ty1 ty2, Sum ty1' ty2') =>
(consistent ty1 ty1') && (consistent ty2 ty2')
| (Arrow _ _, _) => false
| (Prod _ _, _) => false
| (Sum _ _, _) => false
| (List ty, List ty') =>
consistent ty ty'
| (List _, _) => false
end.
Definition inconsistent (ty1 : t) (ty2 : t) : bool :=
negb (consistent ty1 ty2).
(* Theorem eq_implies_consistent : forall x y : t,
((eq x y) = true) -> ((consistent x y) = true).
Proof.
intuition.
unfold consistent.
destruct x;
repeat rewrite -> H;
simpl;
reflexivity.
Qed. *)
(* matched arrow types *)
Definition matched_arrow (ty : t) : option (t * t) :=
match ty with
| Arrow ty1 ty2 => Some (ty1, ty2)
| Hole => Some (Hole, Hole)
| _ => None
end.
Definition has_matched_arrow (ty : t) : bool :=
match ty with
| Arrow _ _ => true
| Hole => true
| _ => false
end.
(* matched product types *)
Definition matched_prod (ty : t) : option (t * t) :=
match ty with
| Prod ty1 ty2 => Some (ty1, ty2)
| Hole => Some (Hole, Hole)
| _ => None
end.
Definition has_matched_prod (ty : t) : bool :=
match ty with
| Prod _ _ => true
| Hole => true
| _ => false
end.
Fixpoint get_tuple
(ty1 : HTyp.t)
(ty2 : HTyp.t)
: list(HTyp.t) :=
match ty2 with
| HTyp.Prod ty21 ty22 =>
cons ty1 (get_tuple ty21 ty22)
| _ =>
cons ty1 (cons ty2 nil)
end.
Fixpoint make_tuple
(tys : list HTyp.t)
: HTyp.t :=
match tys with
| cons ty1 (cons ty2 nil) => Prod ty1 ty2
| cons ty1 nil => ty1
| cons ty1 tys =>
let ty2 := make_tuple tys in
Prod ty1 ty2
| nil => Unit
end.
Fixpoint zip_with_skels
{op : Type}
(skels : list(Skel.t op))
(types : list(t))
: (list(Skel.t op * t) * list(Skel.t op)) :=
match (skels, types) with
| (nil, nil) => (nil, nil)
| (cons skel skels, cons ty tys) =>
let (tail, remainder) := zip_with_skels skels tys in
(cons (skel, ty) tail, remainder)
| (cons _ _, nil) => (nil, skels)
| (nil, cons _ _) => (nil, nil)
end.
(* matched sum types *)
Definition matched_sum (ty : t) : option (t * t) :=
match ty with
| Sum tyL tyR => Some (tyL, tyR)
| Hole => Some (Hole, Hole)
| _ => None
end.
Definition has_matched_sum (ty : t) : bool :=
match ty with
| Sum tyL tyR => true
| Hole => true
| _ => false
end.
(* matched sum types *)
Definition matched_list (ty : t) : option t :=
match ty with
| List ty => Some ty
| Hole => Some Hole
| _ => None
end.
Definition has_matched_list (ty : t) : bool :=
match ty with
| List ty => true
| Hole => true
| _ => false
end.
(* complete (i.e. does not have any holes) *)
Fixpoint complete (ty : t) : bool :=
match ty with
| Hole => false
| Unit => true
| Num => true
| Bool => true
| Arrow ty1 ty2
| Prod ty1 ty2
| Sum ty1 ty2
=> andb (complete ty1) (complete ty2)
| List ty => complete ty
end.
Fixpoint join ty1 ty2 :=
match (ty1, ty2) with
| (_, Hole) => Some ty1
| (Hole, _) => Some ty2
| (Unit, Unit) => Some ty1
| (Unit, _) => None
| (Num, Num) => Some ty1
| (Num, _) => None
| (Bool, Bool) => Some ty1
| (Bool, _) => None
| (Arrow ty1 ty2, Arrow ty1' ty2') =>
match (join ty1 ty1', join ty2 ty2') with
| (Some ty1, Some ty2) => Some (Arrow ty1 ty2)
| _ => None
end
| (Arrow _ _, _) => None
| (Prod ty1 ty2, Prod ty1' ty2') =>
match (join ty1 ty1', join ty2 ty2') with
| (Some ty1, Some ty2) => Some (Prod ty1 ty2)
| _ => None
end
| (Prod _ _, _) => None
| (Sum ty1 ty2, Sum ty1' ty2') =>
match (join ty1 ty1', join ty2 ty2') with
| (Some ty1, Some ty2) => Some (Sum ty1 ty2)
| _ => None
end
| (Sum _ _, _) => None
| (List ty, List ty') =>
match join ty ty' with
| Some ty => Some (List ty)
| None => None
end
| (List ty, _) => None
end.
End HTyp.
Module UHTyp.
Inductive op : Type :=
| Arrow : op
| Prod : op
| Sum : op.
Definition skel_t : Type := Skel.t op.
Inductive t : Type :=
| Parenthesized : t -> t
| Hole : t
| Unit : t
| Num : t
| Bool : t
| List : t -> t
| OpSeq : skel_t -> OperatorSeq.opseq t op -> t.
Definition opseq : Type := OperatorSeq.opseq t op.
Definition bidelimited (uty : t) : bool :=
match uty with
| Hole
| Unit
| Num
| Bool
| Parenthesized _ => true
| List ty => true
| OpSeq _ _ => false
end.
Fixpoint well_formed (fuel : Fuel.t) (uty : t) : bool :=
match fuel with
| Fuel.Kicked => false
| Fuel.More fuel =>
match uty with
| Hole => true
| Unit => true
| Num => true
| Bool => true
| Parenthesized uty1 => well_formed fuel uty1
| List uty1 => well_formed fuel uty1
| OpSeq skel seq =>
(* NOTE: does not check that skel is the valid parse of seq *)
well_formed_skel fuel skel seq
end
end
with well_formed_skel (fuel : Fuel.t) (skel : skel_t) (seq : opseq) : bool :=
match fuel with
| Fuel.Kicked => false
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| Some uty_n =>
bidelimited uty_n && well_formed fuel uty_n
| None => false
end
| Skel.BinOp NotInHole _ skel1 skel2 =>
well_formed_skel fuel skel1 seq
&& well_formed_skel fuel skel2 seq
| Skel.BinOp (InHole TypeInconsistent _) _ _ _ => false (* no type-level non-empty holes *)
| Skel.BinOp (InHole WrongLength _) _ _ _ => false (* the type is assumed to be the true length *)
end
end.
(* TODO fix this to only parenthesize when necessary *)
Fixpoint contract (ty : HTyp.t) : t :=
let mk_opseq (op' : op) (a b : t) :=
let ph n := Skel.Placeholder op n in
let skel :=
(Skel.BinOp NotInHole op' (ph 0) (ph 1))
in
Parenthesized
(OpSeq skel (OperatorSeq.ExpOpExp a op' b))
(* Save it for another day
match (a, b) with
| (OpSeq skelA opseqA, OpSeq skelB opseqB) =>
| (OpSeq skelA opseqA, _) =>
| (_, OpSeq skelB opseqB) =>
| (_, _) =>
OpSeq (Skel.BinOp NotInHole op' ?? ??) (OperatorSeq.ExpOpExp a op' b)
end
*)
in
match ty with
| HTyp.Hole => Hole
| HTyp.Unit => Unit
| HTyp.Num => Num
| HTyp.Bool => Bool
| HTyp.Arrow ty1 ty2 => mk_opseq Arrow (contract ty1) (contract ty2)
| HTyp.Prod ty1 ty2 => mk_opseq Prod (contract ty1) (contract ty2)
| HTyp.Sum ty1 ty2 => mk_opseq Sum (contract ty1) (contract ty2)
| HTyp.List ty1 => List (contract ty1)
end.
Fixpoint expand (fuel : Fuel.t) (uty : t) : HTyp.t :=
match fuel with
| Fuel.Kicked => HTyp.Hole
| Fuel.More fuel =>
match uty with
| Hole => HTyp.Hole
| Unit => HTyp.Unit
| Num => HTyp.Num
| Bool => HTyp.Bool
| Parenthesized uty1 => expand fuel uty1
| List uty1 => HTyp.List (expand fuel uty1)
| OpSeq skel seq => expand_skel fuel skel seq
end
end
with expand_skel (fuel : Fuel.t) (skel : skel_t) (seq : opseq) :=
match fuel with
| Fuel.Kicked => HTyp.Hole
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| Some uty_n => expand fuel uty_n
| None => HTyp.Hole (* should never happen *)
end
| Skel.BinOp _ Arrow skel1 skel2 =>
let uty1 := expand_skel fuel skel1 seq in
let uty2 := expand_skel fuel skel2 seq in
HTyp.Arrow uty1 uty2
| Skel.BinOp _ Prod skel1 skel2 =>
let uty1 := expand_skel fuel skel1 seq in
let uty2 := expand_skel fuel skel2 seq in
HTyp.Prod uty1 uty2
| Skel.BinOp _ Sum skel1 skel2 =>
let uty1 := expand_skel fuel skel1 seq in
let uty2 := expand_skel fuel skel2 seq in
HTyp.Sum uty1 uty2
end
end.
End UHTyp.
Module PaletteName.
Definition t := Coq.Strings.String.string.
Definition eq (x : t) (y : t) : bool := Util.str_eqb x y.
Fixpoint _is_valid_internal (s : t) : bool :=
Var.is_valid s.
Definition is_valid (s : t) : bool :=
(* should be equivalent to the OCaml rules: "[_a-z][_a-zA-Z0-9']*" *)
match s with
| Coq.Strings.String.EmptyString => false
| Coq.Strings.String.String first_char rest =>
(Util.char_eq_b first_char "$") &&
_is_valid_internal rest
end.
Definition check_valid {A : Type}
(s : t)
(result : option(A))
: option(A) :=
if is_valid s then result else None.
End PaletteName.
Module PaletteSerializedModel.
Definition t : Type := Coq.Strings.String.string.
End PaletteSerializedModel.
Module VarCtx.
Definition t := VarMap.t_ (HTyp.t).
Include VarMap.
End VarCtx.
Inductive inj_side : Type :=
| L : inj_side
| R : inj_side.
Definition pick_side {A : Type} (side : inj_side) (l : A) (r : A) : A :=
match side with
| L => l
| R => r
end.
Module UHPat.
Inductive op : Type :=
| Comma : op
| Space : op
| Cons : op.
Definition is_Space op :=
match op
| Space => true
| _ => false
end.
Definition skel_t : Type := Skel.t op.
Inductive t : Type :=
| Pat : err_status -> t' -> t
| Parenthesized : t -> t
with t' : Type :=
| EmptyHole : MetaVar.t -> t'
| Wild : t'
| Var : Var.t -> t'
| NumLit : nat -> t'
| BoolLit : bool -> t'
| Inj : inj_side -> t -> t'
| ListNil : t'
(* | ListLit : list(t) -> t' *)
| OpSeq : skel_t -> OperatorSeq.opseq t op -> t'.
Definition opseq : Type := OperatorSeq.opseq t op.
Fixpoint get_tuple
(skel1 : skel_t)
(skel2 : skel_t)
: list(skel_t) :=
match skel2 with
| Skel.BinOp _ Comma skel21 skel22 =>
cons skel1 (get_tuple skel21 skel22)
| Skel.BinOp _ _ _ _
| Skel.Placeholder _ _ =>
cons skel1 (cons skel2 nil)
end.
Fixpoint make_tuple
(err : err_status)
(skels : list(skel_t))
: option(skel_t) :=
match skels with
| cons skel1 (cons skel2 nil) =>
Some (Skel.BinOp err Comma skel1 skel2)
| cons skel1 skels =>
match make_tuple NotInHole skels with
| None => None
| Some skel2 => Some (Skel.BinOp err Comma skel1 skel2)
end
| nil => None
end.
(* bidelimited patterns are those that don't have
* sub-patterns at their outer left or right edge
* in the concrete syntax *)
Definition bidelimited (p : t) : bool :=
match p with
| Pat _ (EmptyHole _)
| Pat _ Wild
| Pat _ (Var _)
| Pat _ (NumLit _)
| Pat _ (BoolLit _)
| Pat _ (Inj _ _)
| Pat _ ListNil
(* | Pat _ (ListLit _) *)
| Parenthesized _ => true
| Pat _ (OpSeq _ _) => false
end.
(* if p is not bidelimited, bidelimit e parenthesizes it *)
Definition bidelimit (p : t) :=
if bidelimited p then p else Parenthesized p.
(* helper function for constructing a new empty hole *)
Definition new_EmptyHole (u_gen : MetaVarGen.t) : t * MetaVarGen.t :=
let (u, u_gen) := MetaVarGen.next u_gen in
(Pat NotInHole (EmptyHole u), u_gen).
Definition is_EmptyHole p :=
match p with
| Pat _ (EmptyHole _) => true
| _ => false
end.
Fixpoint set_inconsistent (u : MetaVar.t) (p : t) :=
match p with
| Pat _ p' => Pat (InHole TypeInconsistent u) p'
| Parenthesized p1 => Parenthesized (set_inconsistent u p1)
end.
(* put p in a new hole, if it is not already in a hole *)
Fixpoint make_inconsistent (u_gen : MetaVarGen.t) (p : t) :=
match p with
| Pat NotInHole p'
| Pat (InHole WrongLength _) p' =>
let (u, u_gen) := MetaVarGen.next u_gen in
(Pat (InHole TypeInconsistent u) p', u_gen)
| Pat (InHole TypeInconsistent _) _ => (p, u_gen)
| Parenthesized p1 =>
match make_inconsistent u_gen p1 with
| (p1, u_gen) => (Parenthesized p1, u_gen)
end
end.
End UHPat.
Module UHExp. (* unassociated H-expressions *)
Inductive op : Type :=
| Plus : op
| Times : op
| LessThan : op
| Space : op
| Comma : op
| Cons : op.
Definition is_Space op :=
match op with
| Space => true
| _ => false
end.
Definition skel_t := Skel.t op.
Inductive t : Type :=
| Tm : err_status -> t' -> t
| Parenthesized : t -> t
with t' : Type :=
| Asc : t -> UHTyp.t -> t'
| Var : var_err_status -> Var.t -> t'
| Let : UHPat.t -> option(UHTyp.t) -> t -> t -> t'
| Lam : UHPat.t -> option(UHTyp.t) -> t -> t'
| NumLit : nat -> t'
| BoolLit : bool -> t'
| Inj : inj_side -> t -> t'
| Case : t -> list(rule) -> t'
| ListNil : t'
(* | ListCons : list(t) -> t' *)
| EmptyHole : MetaVar.t -> t'
| OpSeq : skel_t -> OperatorSeq.opseq t op -> t' (* invariant: skeleton is consistent with opseq *)
| ApPalette : PaletteName.t ->
PaletteSerializedModel.t ->
(nat * Util.NatMap.t(HTyp.t * t)) (* = PaletteHoleData.t *) ->
t'
with rule : Type :=
| Rule : UHPat.t -> t -> rule.
Definition rules : Type := list(rule).
Fixpoint get_tuple
(skel1 : skel_t)
(skel2 : skel_t)
: list(skel_t) :=
match skel2 with
| Skel.BinOp _ Comma skel21 skel22 =>
cons skel1 (get_tuple skel21 skel22)
| Skel.BinOp _ _ _ _
| Skel.Placeholder _ _ =>
cons skel1 (cons skel2 nil)
end.
Fixpoint make_tuple
(err : err_status)
(skels : list(skel_t))
: option(skel_t) :=
match skels with
| cons skel1 (cons skel2 nil) =>
Some (Skel.BinOp err Comma skel1 skel2)
| cons skel1 skels =>
match make_tuple NotInHole skels with
| None => None
| Some skel2 => Some (Skel.BinOp err Comma skel1 skel2)
end
| nil => None
end.
(* helper function for constructing a new empty hole *)
Definition new_EmptyHole (u_gen : MetaVarGen.t) : t * MetaVarGen.t :=
let (u', u_gen') := MetaVarGen.next u_gen in
(Tm NotInHole (EmptyHole u'), u_gen').
Definition is_EmptyHole e :=
match e with
| Tm _ (EmptyHole _) => true
| _ => false
end.
Definition empty_rule (u_gen : MetaVarGen.t) : rule * MetaVarGen.t :=
let (rule_p, u_gen) := UHPat.new_EmptyHole u_gen in
let (rule_e, u_gen) := UHExp.new_EmptyHole u_gen in
let rule := UHExp.Rule rule_p rule_e in
(rule, u_gen).
Module PaletteHoleData.
Local Open Scope string_scope.
Definition hole_ref_lbl : Type := nat.
Definition hole_map : Type := NatMap.t(HTyp.t * t).
Definition t : Type := (hole_ref_lbl * hole_map).
Definition empty : t := (0, NatMap.empty).
Definition mk_hole_ref_var_name (lbl : hole_ref_lbl) : Var.t :=
Coq.Strings.String.append "__hole_ref_"
(Coq.Strings.String.append (Debug.string_of_nat lbl) "__").
Definition next_ref_lbl (x : hole_ref_lbl) := S(x).
Definition new_hole_ref
(u_gen : MetaVarGen.t)
(hd : t)
(ty : HTyp.t) : (hole_ref_lbl * t * MetaVarGen.t) :=
let (cur_ref_lbl, cur_map) := hd in
let next_ref_lbl := next_ref_lbl(cur_ref_lbl) in
let (initial_exp, u_gen) := UHExp.new_EmptyHole u_gen in
let next_map := NatMap.extend cur_map (cur_ref_lbl, (ty, initial_exp)) in
(cur_ref_lbl, (next_ref_lbl, next_map), u_gen).
Definition extend_ctx_with_hole_map
{A : Type}
(ctx : VarCtx.t * A)
(hm : hole_map)
: VarCtx.t * A :=
let (gamma, palette_ctx) := ctx in
let gamma' :=
NatMap.fold hm
(fun gamma hole_mapping =>
let (id, v) := hole_mapping in
let (htyp, _) := v in
let var_name := mk_hole_ref_var_name id in
VarCtx.extend gamma (var_name, htyp)
)
gamma
in
(gamma', palette_ctx).
End PaletteHoleData.
Module Type HOLEREFS.
Parameter hole_ref : Type.
Parameter lbl_of : hole_ref -> PaletteHoleData.hole_ref_lbl.
Parameter type_of : hole_ref -> HTyp.t.
Parameter m_hole_ref : Type -> Type.
Parameter new_hole_ref : HTyp.t -> m_hole_ref(hole_ref).
Parameter bind : forall (A B : Type), m_hole_ref(A) -> (A -> m_hole_ref(B)) -> m_hole_ref(B).
Parameter ret : forall (A : Type), A -> m_hole_ref(A).
Parameter exec : forall (A : Type), m_hole_ref(A) ->
PaletteHoleData.t ->
MetaVarGen.t ->
A * PaletteHoleData.t * MetaVarGen.t.
End HOLEREFS.
Module HoleRefs : HOLEREFS.
Definition hole_ref : Type := (PaletteHoleData.hole_ref_lbl * HTyp.t).
Definition lbl_of (hr : hole_ref) :=
let (lbl, _) := hr in lbl.
Definition type_of (hr : hole_ref) :=
let (_, ty) := hr in ty.
(* cant define m_hole_ref using Inductive due to Coq limitation *)
Inductive m_hole_ref' : Type -> Type :=
| NewHoleRef : HTyp.t -> m_hole_ref'(hole_ref)
| Bnd : forall (A B : Type), m_hole_ref'(A) -> (A -> m_hole_ref'(B)) -> m_hole_ref'(B)
| Ret : forall (A : Type), A -> m_hole_ref'(A).
Definition m_hole_ref := m_hole_ref'.
Definition new_hole_ref := NewHoleRef.
Definition bind := Bnd.
Definition ret := Ret.
Fixpoint exec {A : Type}
(mhr : m_hole_ref(A))
(phd : UHExp.PaletteHoleData.t)
(u_gen : MetaVarGen.t)
: (A * UHExp.PaletteHoleData.t * MetaVarGen.t) :=
match mhr with
| NewHoleRef ty =>
let (q, u_gen') := UHExp.PaletteHoleData.new_hole_ref u_gen phd ty in
let (lbl, phd') := q in
((lbl, ty), phd', u_gen')
| Bnd mhra f =>
let (q, u_gen') := exec mhra phd u_gen in
let (x, phd') := q in
let mhrb := f x in
exec mhrb phd' u_gen'
| Ret x => (x, phd, u_gen)
end.
End HoleRefs.
Module PaletteDefinition.
Record t : Type := MkPalette {
expansion_ty : HTyp.t;
initial_model : HoleRefs.m_hole_ref(PaletteSerializedModel.t);
to_exp : PaletteSerializedModel.t -> UHExp.t;
}.
End PaletteDefinition.
Module PaletteCtx.
Definition t := VarMap.t_ (PaletteDefinition.t).
Include VarMap.
End PaletteCtx.
Module Contexts.
Definition t : Type := VarCtx.t * PaletteCtx.t.
Definition gamma (ctx : t) : VarCtx.t :=
let (gamma, _) := ctx in gamma.
Definition extend_gamma (contexts : t) (binding : Var.t * HTyp.t) : t :=
let (x, ty) := binding in
let (gamma, palette_ctx) := contexts in
let gamma' := VarCtx.extend gamma (x, ty) in
(gamma', palette_ctx).
Definition gamma_union (contexts : t) (gamma' : VarCtx.t) : t :=
let (gamma, palette_ctx) := contexts in
let gamma'' := VarCtx.union gamma gamma' in
(gamma'', palette_ctx).
Definition gamma_contains (contexts : t) (x : Var.t) : bool :=
VarCtx.contains (gamma contexts) x.
End Contexts.
Definition opseq := OperatorSeq.opseq t op.
(* bidelimited expressions are those that don't have
* sub-expressions at their outer left or right edge
* in the concrete syntax *)
Definition bidelimited (e : t) :=
match e with
(* bidelimited cases *)
| Tm _ (EmptyHole _)
| Tm _ (Var _ _)
| Tm _ (NumLit _)
| Tm _ (BoolLit _)
| Tm _ (Inj _ _)
| Tm _ (Case _ _)
| Tm _ ListNil
(* | Tm _ (ListLit _) *)
| Tm _ (ApPalette _ _ _)
| Parenthesized _ => true
(* non-bidelimited cases *)
| Tm _ (Asc _ _)
| Tm _ (Let _ _ _ _)
| Tm _ (Lam _ _ _)
| Tm _ (OpSeq _ _) => false
end.
(* if e is not bidelimited, bidelimit e parenthesizes it *)
Definition bidelimit (e : t) :=
if bidelimited e then e else Parenthesized e.
(* put e in the specified hole *)
Fixpoint set_inconsistent (u : MetaVar.t) (e : t) :=
match e with
| Tm _ e' => Tm (InHole TypeInconsistent u) e'
| Parenthesized e' => Parenthesized (set_inconsistent u e')
end.
(* put e in a new hole, if it is not already in a hole *)
Fixpoint make_inconsistent (u_gen : MetaVarGen.t) (e : t) :=
match e with
| Tm NotInHole e'
| Tm (InHole WrongLength _) e' =>
let (u, u_gen') := MetaVarGen.next u_gen in
(Tm (InHole TypeInconsistent u) e', u_gen')
| Tm (InHole TypeInconsistent _) _ => (e, u_gen)
| Parenthesized e1 =>
match make_inconsistent u_gen e1 with
| (e1', u_gen') => (Parenthesized e1', u_gen')
end
end.
(* put skel in a new hole, if it is not already in a hole *)
Definition make_skel_inconsistent (u_gen : MetaVarGen.t) (skel : skel_t) (seq : opseq) :=
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| Some en =>
let (en', u_gen') := make_inconsistent u_gen en in
match OperatorSeq.seq_update_nth n seq en' with
| Some seq' => Some (skel, seq', u_gen')
| None => None
end
| None => None
end
| Skel.BinOp (InHole TypeInconsistent _) _ _ _ => Some (skel, seq, u_gen)
| Skel.BinOp NotInHole op skel1 skel2
| Skel.BinOp (InHole WrongLength _) op skel1 skel2 =>
let (u', u_gen') := MetaVarGen.next u_gen in
Some (Skel.BinOp (InHole TypeInconsistent u') op skel1 skel2, seq, u_gen')
end.
Fixpoint drop_outer_parentheses (e : t) : t :=
match e with
| Tm _ _ => e
| Parenthesized e' => drop_outer_parentheses e'
end.
(* see syn_skel and ana_skel below *)
Inductive type_mode : Type :=
| AnalyzedAgainst : HTyp.t -> type_mode
| Synthesized : HTyp.t -> type_mode.
Definition combine_modes (mode1 : option(type_mode)) (mode2 : option(type_mode)) : option(type_mode) :=
match (mode1, mode2) with
| (Some _, _) => mode1
| (_, Some _) => mode2
| (None, None) => None
end.
Fixpoint syn_pat
(fuel : Fuel.t)
(ctx : Contexts.t)
(p : UHPat.t)
: option(HTyp.t * Contexts.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match p with
| UHPat.Pat (InHole TypeInconsistent _) p'
| UHPat.Pat (InHole WrongLength _)
((UHPat.OpSeq (Skel.BinOp (InHole WrongLength _) UHPat.Comma _ _) _) as p') =>
match syn_pat' fuel ctx p' with
| None => None
| Some (_, gamma) => Some(HTyp.Hole, gamma)
end
| UHPat.Pat (InHole WrongLength _) _ => None
| UHPat.Pat NotInHole p' =>
syn_pat' fuel ctx p'
| UHPat.Parenthesized p =>
syn_pat fuel ctx p
end
end
with syn_pat'
(fuel : Fuel.t)
(ctx : Contexts.t)
(p : UHPat.t')
: option(HTyp.t * Contexts.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match p with
| UHPat.EmptyHole _ => Some (HTyp.Hole, ctx)
| UHPat.Wild => Some (HTyp.Hole, ctx)
| UHPat.Var x =>
Var.check_valid x (
Some (HTyp.Hole,
Contexts.extend_gamma ctx (x, HTyp.Hole)))
| UHPat.NumLit _ => Some (HTyp.Num, ctx)
| UHPat.BoolLit _ => Some (HTyp.Bool, ctx)
| UHPat.Inj side p1 =>
match syn_pat fuel ctx p1 with
| None => None
| Some (ty1, ctx) =>
let ty :=
match side with
| L => HTyp.Sum ty1 HTyp.Hole
| R => HTyp.Sum HTyp.Hole ty1
end in
Some (ty, ctx)
end
| UHPat.ListNil => Some (HTyp.List HTyp.Hole, ctx)
(* | UHPat.ListLit ps =>
List.fold_left (fun opt_result elt =>
match opt_result with
| None => None
| Some (ty, ctx) =>
match syn_pat fuel ctx elt with
| None => None
| Some (ty_elt, ctx) =>
match HTyp.join ty ty_elt with
| Some ty => Some (ty, ctx)
| None => None
end
end
end) ps (Some (HTyp.Hole, ctx)) *)
| UHPat.OpSeq skel seq =>
match syn_skel_pat fuel ctx skel seq None with
| None => None
| Some (ty, ctx, _) => Some (ty, ctx)
end
end
end
with syn_skel_pat
(fuel : Fuel.t)
(ctx : Contexts.t)
(skel : UHPat.skel_t)
(seq : UHPat.opseq)
(monitor : option(nat))
: option(HTyp.t * Contexts.t * option(type_mode)) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| None => None
| Some pn =>
match UHPat.bidelimited pn with
| false => None
| true =>
match syn_pat fuel ctx pn with
| None => None
| Some (ty, ctx) =>
let mode :=
match monitor with
| None => None
| Some n' =>
if Nat.eqb n n'
then Some (Synthesized ty)
else None
end in
Some (ty, ctx, mode)
end
end
end
| Skel.BinOp (InHole TypeInconsistent u) op skel1 skel2
| Skel.BinOp (InHole WrongLength u) (UHPat.Comma as op) skel1 skel2 =>
let skel_not_in_hole := Skel.BinOp NotInHole op skel1 skel2 in
match syn_skel_pat fuel ctx skel_not_in_hole seq monitor with
| None => None
| Some (_, ctx, mode) => Some (HTyp.Hole, ctx, mode)
end
| Skel.BinOp (InHole WrongLength u) _ _ _ => None
| Skel.BinOp NotInHole UHPat.Comma skel1 skel2 =>
match syn_skel_pat fuel ctx skel1 seq monitor with
| None => None
| Some (ty1, ctx, mode1) =>
match syn_skel_pat fuel ctx skel2 seq monitor with
| None => None
| Some (ty2, ctx, mode2) =>
let ty := HTyp.Prod ty1 ty2 in
let mode := combine_modes mode1 mode2 in
Some (ty, ctx, mode)
end
end
| Skel.BinOp NotInHole UHPat.Space skel1 skel2 =>
match syn_skel_pat fuel ctx skel1 seq monitor with
| None => None
| Some (ty1, ctx, mode1) =>
match syn_skel_pat fuel ctx skel2 seq monitor with
| None => None
| Some (ty2, ctx, mode2) =>
let ty := HTyp.Hole in
let mode := combine_modes mode1 mode2 in
Some (ty, ctx, mode)
end
end
| Skel.BinOp NotInHole UHPat.Cons skel1 skel2 =>
match syn_skel_pat fuel ctx skel1 seq monitor with
| None => None
| Some (ty1, ctx, mode1) =>
let ty := HTyp.List ty1 in
match ana_skel_pat fuel ctx skel2 seq ty monitor with
| None => None
| Some (ctx, mode2) =>
let mode := combine_modes mode1 mode2 in
Some (ty, ctx, mode)
end
end
end
end
with ana_pat
(fuel : Fuel.t)
(ctx : Contexts.t)
(p : UHPat.t)
(ty : HTyp.t)
: option(Contexts.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match p with
| UHPat.Pat (InHole TypeInconsistent _) p' =>
match syn_pat' fuel ctx p' with
| None => None
| Some (_, ctx) => Some ctx
end
| UHPat.Pat (InHole WrongLength _) ((UHPat.OpSeq (Skel.BinOp (InHole WrongLength _) UHPat.Comma _ _) _) as p')
| UHPat.Pat NotInHole p' =>
ana_pat' fuel ctx p' ty
| UHPat.Pat (InHole WrongLength _) _ => None
| UHPat.Parenthesized p =>
ana_pat fuel ctx p ty
end
end
with ana_pat'
(fuel : Fuel.t)
(ctx : Contexts.t)
(p : UHPat.t')
(ty : HTyp.t)
: option(Contexts.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match p with
| UHPat.Var x =>
Var.check_valid x (
Some (Contexts.extend_gamma ctx (x, ty)))
| UHPat.EmptyHole _
| UHPat.Wild => Some ctx
| UHPat.NumLit _
| UHPat.BoolLit _ =>
match syn_pat' fuel ctx p with
| None => None
| Some (ty', ctx) =>
match HTyp.consistent ty ty' with
| true => Some ctx
| false => None
end
end
| UHPat.Inj side p1 =>
match HTyp.matched_sum ty with
| None => None
| Some (tyL, tyR) =>
let ty1 := pick_side side tyL tyR in
ana_pat fuel ctx p1 ty1
end
| UHPat.ListNil =>
match HTyp.matched_list ty with
| None => None
| Some _ => Some ctx
end
(* | UHPat.ListLit ps =>
match HTyp.matched_list ty with
| None => None
| Some ty_elts =>
List.fold_left (fun optctx p =>
match optctx with
| None => None
| Some ctx => ana_pat fuel ctx p ty_elts
end) ps (Some ctx)
end *)
| UHPat.OpSeq skel seq =>
match ana_skel_pat fuel ctx skel seq ty None with
| None => None
| Some (ctx, _) => Some ctx
end
end
end
with ana_skel_pat
(fuel : Fuel.t)
(ctx : Contexts.t)
(skel : UHPat.skel_t)
(seq : UHPat.opseq)
(ty : HTyp.t)
(monitor : option(nat))
: option(Contexts.t * option(type_mode)) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| None => None
| Some pn =>
match UHPat.bidelimited pn with
| false => None
| true =>
match ana_pat fuel ctx pn ty with
| None => None
| Some ctx =>
let mode :=
match monitor with
| None => None
| Some n' =>
if Nat.eqb n n'
then Some (AnalyzedAgainst ty)
else None
end in
Some (ctx, mode)
end
end
end
| Skel.BinOp (InHole TypeInconsistent u) op skel1 skel2 =>
let skel_not_in_hole := Skel.BinOp NotInHole op skel1 skel2 in
match syn_skel_pat fuel ctx skel_not_in_hole seq monitor with
| None => None
| Some (_, ctx, mode) => Some (ctx, mode)
end
| Skel.BinOp NotInHole UHPat.Comma skel1 skel2 =>
match ty with
| HTyp.Hole =>
match ana_skel_pat fuel ctx skel1 seq HTyp.Hole monitor with
| None => None
| Some (ctx, mode1) =>
match ana_skel_pat fuel ctx skel2 seq HTyp.Hole monitor with
| None => None
| Some (ctx, mode2) =>
let mode := combine_modes mode1 mode2 in
Some (ctx, mode)
end
end
| HTyp.Prod ty1 ty2 =>
let types := HTyp.get_tuple ty1 ty2 in
let skels := UHPat.get_tuple skel1 skel2 in
match Util.zip_eq skels types with
| None => None
| Some zipped =>
List.fold_left (fun opt_result (skel_ty : UHPat.skel_t * HTyp.t) =>
match opt_result with
| None => None
| Some (ctx, mode) =>
let (skel, ty) := skel_ty in
match ana_skel_pat fuel ctx skel seq ty monitor with
| None => None
| Some (ctx, mode') =>
let mode := combine_modes mode mode' in
Some (ctx, mode)
end
end) zipped (Some (ctx, None))
end
| _ => None
end
| Skel.BinOp (InHole WrongLength u) (UHPat.Comma as op) skel1 skel2 =>
match ty with
| HTyp.Prod ty1 ty2 =>
let types := HTyp.get_tuple ty1 ty2 in
let skels := UHPat.get_tuple skel1 skel2 in
let n_types := List.length types in
let n_skels := List.length skels in
match Nat.eqb n_types n_skels with
| true => None (* make sure the lengths are actually different *)
| false =>
let (zipped, remainder) := HTyp.zip_with_skels skels types in
let ana_zipped : option (Contexts.t * option(type_mode)) :=
List.fold_left (fun opt_result (skel_ty : UHPat.skel_t * HTyp.t) =>
match opt_result with
| None => None
| Some (ctx, mode) =>
let (skel, ty) := skel_ty in
match ana_skel_pat fuel ctx skel seq ty monitor with
| None => None
| Some (ctx, mode') =>
let mode := combine_modes mode mode' in
Some (ctx, mode)
end
end) zipped (Some (ctx, None)) in
match ana_zipped with
| None => None
| Some (ctx, mode) =>
List.fold_left (fun opt_result skel =>
match opt_result with
| None => None
| Some (ctx, mode) =>
match syn_skel_pat fuel ctx skel seq monitor with
| None => None
| Some (_, ctx, mode') =>
let mode := combine_modes mode mode' in
Some (ctx, mode)
end
end) remainder (Some (ctx, mode))
end
end
| _ => None
end
| Skel.BinOp (InHole WrongLength _) _ _ _ => None
| Skel.BinOp NotInHole UHPat.Space skel1 skel2 =>
None
| Skel.BinOp NotInHole UHPat.Cons skel1 skel2 =>
match HTyp.matched_list ty with
| None => None
| Some ty_elt =>
match ana_skel_pat fuel ctx skel1 seq ty_elt monitor with
| None => None
| Some (ctx, mode1) =>
let ty_list := HTyp.List ty_elt in
match ana_skel_pat fuel ctx skel2 seq ty_list monitor with
| None => None
| Some (ctx, mode2) =>
let mode := combine_modes mode1 mode2 in
Some (ctx, mode)
end
end
end
end
end.
Definition ctx_for_let
(ctx : Contexts.t)
(p : UHPat.t)
(ty1 : HTyp.t)
(e1 : UHExp.t)
: Contexts.t :=
match (p, e1) with
| (UHPat.Pat _ (UHPat.Var x),
Tm _ (Lam _ _ _)) =>
match HTyp.matched_arrow ty1 with
| Some _ => Contexts.extend_gamma ctx (x, ty1)
| None => ctx
end
| _ => ctx
end.
(* returns recursive ctx + name of recursively defined var *)
Definition ctx_for_let'
(ctx : Contexts.t)
(p : UHPat.t)
(ty1 : HTyp.t)
(e1 : UHExp.t)
: Contexts.t * option(Var.t) :=
match (p, e1) with
| (UHPat.Pat _ (UHPat.Var x),
Tm _ (Lam _ _ _)) =>
match HTyp.matched_arrow ty1 with
| Some _ => (Contexts.extend_gamma ctx (x, ty1), Some x)
| None => (ctx, None)
end
| _ => (ctx, None)
end.
(* synthesize a type, if possible, for e *)
Fixpoint syn
(fuel : Fuel.t)
(ctx : Contexts.t)
(e : UHExp.t)
: option(HTyp.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match e with
| Tm (InHole TypeInconsistent _) e'
| Tm (InHole WrongLength _) ((UHExp.OpSeq (Skel.BinOp (InHole WrongLength _) UHExp.Comma _ _) _) as e') =>
match syn' fuel ctx e' with
| Some _ => Some HTyp.Hole
| None => None
end
| Tm (InHole WrongLength _) _ => None
| Tm NotInHole e' => syn' fuel ctx e'
| Parenthesized e1 => syn fuel ctx e1
end
end
with syn'
(fuel : Fuel.t)
(ctx : Contexts.t)
(e : UHExp.t')
: option(HTyp.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match e with
| EmptyHole u => Some HTyp.Hole
| Asc e1 uty =>
let ty := UHTyp.expand fuel uty in
if bidelimited e1 then
match ana fuel ctx e1 ty with
| None => None
| Some _ => Some ty
end
else None
| Var NotInVHole x =>
let (gamma, _) := ctx in
VarMap.lookup gamma x
| Var (InVHole _) _ =>
Some (HTyp.Hole)
| Lam p ann e1 =>
let ty1 :=
match ann with
| Some uty => UHTyp.expand fuel uty
| None => HTyp.Hole
end in
match ana_pat fuel ctx p ty1 with
| None => None
| Some ctx =>
match syn fuel ctx e1 with
| Some ty2 => Some (HTyp.Arrow ty1 ty2)
| None => None
end
end
| Inj side e1 =>
match syn fuel ctx e1 with
| None => None
| Some ty1 =>
match side with
| L => Some (HTyp.Sum ty1 HTyp.Hole)
| R => Some (HTyp.Sum HTyp.Hole ty1)
end
end
| Let p ann e1 e2 =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
let ctx1 := ctx_for_let ctx p ty1 e1 in
match ana fuel ctx1 e1 ty1 with
| None => None
| Some _ =>
match ana_pat fuel ctx p ty1 with
| None => None
| Some ctx2 => syn fuel ctx2 e2
end
end
| None =>
match syn fuel ctx e1 with
| None => None
| Some ty1 =>
match ana_pat fuel ctx p ty1 with
| None => None
| Some ctx2 => syn fuel ctx2 e2
end
end
end
| NumLit _ => Some HTyp.Num
| BoolLit _ => Some HTyp.Bool
| ListNil => Some (HTyp.List HTyp.Hole)
(* | ListLit es =>
List.fold_left (fun opt_result elt =>
match opt_result with
| None => None
| Some ty =>
match syn fuel ctx elt with
| None => None
| Some ty_elt => HTyp.join ty ty_elt
end
end) es (Some HTyp.Hole) *)
| OpSeq skel seq =>
(* NOTE: doesn't check if skel is the correct parse of seq!!! *)
match syn_skel fuel ctx skel seq None with
| Some (ty, _) => Some ty
| None => None
end
| Case _ _ => None
| ApPalette name serialized_model hole_data =>
let (_, palette_ctx) := ctx in
match (VarMap.lookup palette_ctx name) with
| Some palette_defn =>
match (ana_hole_data fuel ctx hole_data) with
| None => None
| Some _ =>
let expansion_ty := PaletteDefinition.expansion_ty palette_defn in
let to_exp := PaletteDefinition.to_exp palette_defn in
let expansion := to_exp serialized_model in
let (_, hole_map) := hole_data in
let expansion_ctx := PaletteHoleData.extend_ctx_with_hole_map ctx hole_map in
match ana fuel expansion_ctx expansion expansion_ty with
| Some _ =>
Some expansion_ty
| None => None
end
end
| None => None
end
end
end
with ana_hole_data
(fuel : Fuel.t)
(ctx : Contexts.t)
(hole_data : PaletteHoleData.t)
: option(unit) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
let (_, hole_map) := hole_data in
NatMap.fold hole_map (fun c v =>
let (_, ty_e) := v in
let (ty, e) := ty_e in
match c with
| None => None
| Some _ => ana fuel ctx e ty
end) (Some tt)
end
with ana
(fuel : Fuel.t)
(ctx : Contexts.t)
(e : UHExp.t)
(ty : HTyp.t)
: option(unit) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match e with
| Tm (InHole TypeInconsistent _) e' =>
match syn' fuel ctx e' with
| Some _ => Some tt (* this is a consequence of subsumption and hole universality *)
| None => None
end
| Tm (InHole WrongLength _) ((UHExp.OpSeq (Skel.BinOp (InHole WrongLength _) UHExp.Comma _ _) _) as e')
| Tm NotInHole e' =>
ana' fuel ctx e' ty
| Tm (InHole WrongLength _) _ => None
| Parenthesized e1 => ana fuel ctx e1 ty
end
end
with ana'
(fuel : Fuel.t)
(ctx : Contexts.t)
(e : UHExp.t')
(ty : HTyp.t)
: option(unit) :=
match fuel with
| Fuel.More fuel =>
match e with
| Let p ann e1 e2 =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
let ctx1 := ctx_for_let ctx p ty1 e1 in
match ana fuel ctx1 e1 ty1 with
| None => None
| Some _ =>
match ana_pat fuel ctx p ty1 with
| None => None
| Some ctx2 => ana fuel ctx2 e2 ty
end
end
| None =>
match syn fuel ctx e1 with
| None => None
| Some ty1 =>
match ana_pat fuel ctx p ty1 with
| None => None
| Some ctx2 => ana fuel ctx2 e2 ty
end
end
end
| Lam p ann e1 =>
match HTyp.matched_arrow ty with
| None => None
| Some (ty1_given, ty2) =>
match ann with
| Some uty1 =>
let ty1_ann := UHTyp.expand fuel uty1 in
match HTyp.consistent ty1_ann ty1_given with
| false => None
| true =>
match ana_pat fuel ctx p ty1_ann with
| None => None
| Some ctx => ana fuel ctx e1 ty2
end
end
| None =>
match ana_pat fuel ctx p ty1_given with
| None => None
| Some ctx => ana fuel ctx e1 ty2
end
end
end
| Inj side e' =>
match HTyp.matched_sum ty with
| None => None
| Some (ty1, ty2) =>
ana fuel ctx e' (pick_side side ty1 ty2)
end
| ListNil =>
match HTyp.matched_list ty with
| None => None
| Some _ => Some tt
end
(* | ListLit es =>
match HTyp.matched_list ty with
| None => None
| Some ty_elt =>
List.fold_left (fun optresult elt =>
match optresult with
| None => None
| Some _ => ana fuel ctx elt ty_elt
end) es (Some tt)
end *)
| Case e1 rules =>
match syn fuel ctx e1 with
| None => None
| Some ty1 =>
ana_rules fuel ctx rules ty1 ty
end
| OpSeq skel seq =>
match ana_skel fuel ctx skel seq ty None with
| None => None
| Some _ => Some tt
end
| EmptyHole _
| Asc _ _
| Var _ _
| NumLit _
| BoolLit _
| ApPalette _ _ _ =>
match syn' fuel ctx e with
| Some ty' =>
if HTyp.consistent ty ty' then (Some tt) else None
| None => None
end
end
| Fuel.Kicked => None
end
with ana_rules
(fuel : Fuel.t)
(ctx : Contexts.t)
(rules : list(UHExp.rule))
(pat_ty : HTyp.t)
(clause_ty : HTyp.t)
: option(unit) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
List.fold_left (fun b r =>
match b with
| None => None
| Some _ => ana_rule fuel ctx r pat_ty clause_ty
end) rules (Some tt)
end
with ana_rule
(fuel : Fuel.t)
(ctx : Contexts.t)
(rule : UHExp.rule)
(pat_ty : HTyp.t)
(clause_ty : HTyp.t)
: option(unit) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
let (p, e) := rule in
match ana_pat fuel ctx p pat_ty with
| None => None
| Some ctx => ana fuel ctx e clause_ty
end
end
with syn_skel
(fuel : Fuel.t)
(ctx : Contexts.t)
(skel : skel_t)
(seq : opseq)
(monitor : option(nat))
: option(HTyp.t * option(type_mode)) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| Some en =>
if bidelimited en then
match syn fuel ctx en with
| Some ty =>
let mode :=
match monitor with
| Some n' =>
if Nat.eqb n n' then Some (Synthesized ty)
else None
| None => None
end in
Some (ty, mode)
| None => None
end
else None
| None => None
end
| Skel.BinOp (InHole TypeInconsistent u) op skel1 skel2
| Skel.BinOp (InHole WrongLength u) (UHExp.Comma as op) skel1 skel2 =>
let skel_not_in_hole := Skel.BinOp NotInHole op skel1 skel2 in
match syn_skel fuel ctx skel_not_in_hole seq monitor with
| None => None
| Some (ty, mode) => Some (HTyp.Hole, mode)
end
| Skel.BinOp (InHole WrongLength _) _ _ _ => None
| Skel.BinOp NotInHole UHExp.Plus skel1 skel2
| Skel.BinOp NotInHole UHExp.Times skel1 skel2 =>
match ana_skel fuel ctx skel1 seq HTyp.Num monitor with
| Some mode1 =>
match ana_skel fuel ctx skel2 seq HTyp.Num monitor with
| Some mode2 =>
Some (HTyp.Num, combine_modes mode1 mode2)
| None => None
end
| None => None
end
| Skel.BinOp NotInHole UHExp.LessThan skel1 skel2 =>
match ana_skel fuel ctx skel1 seq HTyp.Num monitor with
| Some mode1 =>
match ana_skel fuel ctx skel2 seq HTyp.Num monitor with
| Some mode2 =>
Some (HTyp.Bool, combine_modes mode1 mode2)
| None => None
end
| None => None
end
| Skel.BinOp NotInHole UHExp.Space skel1 skel2 =>
match syn_skel fuel ctx skel1 seq monitor with
| Some (ty1, mode1) =>
match HTyp.matched_arrow ty1 with
| None => None
| Some (ty2, ty) =>
match ana_skel fuel ctx skel2 seq ty2 monitor with
| Some mode2 =>
Some (ty, combine_modes mode1 mode2)
| None => None
end
end
| None => None
end
| Skel.BinOp NotInHole UHExp.Comma skel1 skel2 =>
match syn_skel fuel ctx skel1 seq monitor with
| None => None
| Some (ty1, mode1) =>
match syn_skel fuel ctx skel2 seq monitor with
| None => None
| Some (ty2, mode2) =>
let mode := combine_modes mode1 mode2 in
let ty := HTyp.Prod ty1 ty2 in
Some (ty, mode)
end
end
| Skel.BinOp NotInHole UHExp.Cons skel1 skel2 =>
match syn_skel fuel ctx skel1 seq monitor with
| None => None
| Some (ty1, mode1) =>
let ty := HTyp.List ty1 in
match ana_skel fuel ctx skel2 seq ty monitor with
| None => None
| Some mode2 =>
Some (ty, combine_modes mode1 mode2)
end
end
end
end
with ana_skel
(fuel : Fuel.t)
(ctx : Contexts.t)
(skel : skel_t)
(seq : opseq)
(ty : HTyp.t)
(monitor : option(nat))
: option(option(type_mode)) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| Some en =>
if bidelimited en then
match ana fuel ctx en ty with
| Some _ =>
match monitor with
| Some n' =>
if Nat.eqb n n' then
Some (Some (AnalyzedAgainst ty))
else Some (None)
| None => Some (None)
end
| None => None
end
else None
| None => None
end
| Skel.BinOp NotInHole UHExp.Comma skel1 skel2 =>
match ty with
| HTyp.Hole =>
match ana_skel fuel ctx skel1 seq HTyp.Hole monitor with
| None => None
| Some mode1 =>
match ana_skel fuel ctx skel2 seq HTyp.Hole monitor with
| None => None
| Some mode2 =>
let mode := combine_modes mode1 mode2 in
Some mode
end
end
| HTyp.Prod ty1 ty2 =>
let types := HTyp.get_tuple ty1 ty2 in
let skels := UHExp.get_tuple skel1 skel2 in
match Util.zip_eq skels types with
| None => None
| Some zipped =>
List.fold_left (fun opt_result (skel_ty : UHExp.skel_t * HTyp.t) =>
match opt_result with
| None => None
| Some mode =>
let (skel, ty) := skel_ty in
match ana_skel fuel ctx skel seq ty monitor with
| None => None
| Some mode' =>
let mode := combine_modes mode mode' in
Some mode
end
end) zipped (Some None)
end
| _ => None
end
| Skel.BinOp (InHole WrongLength u) (UHExp.Comma as op) skel1 skel2 =>
match ty with
| HTyp.Prod ty1 ty2 =>
let types := HTyp.get_tuple ty1 ty2 in
let skels := UHExp.get_tuple skel1 skel2 in
let n_types := List.length types in
let n_skels := List.length skels in
match Nat.eqb n_types n_skels with
| true => None (* make sure the lengths are actually different *)
| false =>
let (zipped, remainder) := HTyp.zip_with_skels skels types in
let ana_zipped : option(option(type_mode)) :=
List.fold_left (fun opt_result (skel_ty : UHExp.skel_t * HTyp.t) =>
match opt_result with
| None => None
| Some (mode) =>
let (skel, ty) := skel_ty in
match ana_skel fuel ctx skel seq ty monitor with
| None => None
| Some mode' =>
let mode := combine_modes mode mode' in
Some (mode)
end
end) zipped (Some None) in
match ana_zipped with
| None => None
| Some mode =>
List.fold_left (fun opt_result skel =>
match opt_result with
| None => None
| Some mode =>
match syn_skel fuel ctx skel seq monitor with
| None => None
| Some (_, mode') =>
let mode := combine_modes mode mode' in
Some mode
end
end) remainder (Some mode)
end
end
| _ => None
end
| Skel.BinOp (InHole WrongLength _) _ _ _ => None
| Skel.BinOp NotInHole UHExp.Cons skel1 skel2 =>
match HTyp.matched_list ty with
| None => None
| Some ty_elt =>
match ana_skel fuel ctx skel1 seq ty_elt monitor with
| None => None
| Some mode1 =>
let ty_list := HTyp.List ty_elt in
match ana_skel fuel ctx skel2 seq ty_list monitor with
| None => None
| Some mode2 =>
Some (combine_modes mode1 mode2)
end
end
end
| Skel.BinOp (InHole TypeInconsistent _) _ _ _
| Skel.BinOp NotInHole UHExp.Plus _ _
| Skel.BinOp NotInHole UHExp.Times _ _
| Skel.BinOp NotInHole UHExp.LessThan _ _
| Skel.BinOp NotInHole UHExp.Space _ _ =>
match syn_skel fuel ctx skel seq monitor with
| Some (ty', mode) =>
if HTyp.consistent ty ty' then Some mode else None
| None => None
end
end
end.
Fixpoint syn_pat_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(p : UHPat.t)
: option(UHPat.t * HTyp.t * Contexts.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match p with
| UHPat.Pat _ p' =>
match syn_pat_fix_holes' fuel ctx u_gen renumber_empty_holes p' with
| None => None
| Some (p', ty, ctx, u_gen) => Some(UHPat.Pat NotInHole p', ty, ctx, u_gen)
end
| UHPat.Parenthesized p =>
match syn_pat_fix_holes fuel ctx u_gen renumber_empty_holes p with
| None => None
| Some (p, ty, ctx, u_gen) => Some (UHPat.Parenthesized p, ty, ctx, u_gen)
end
end
end
with syn_pat_fix_holes'
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(p : UHPat.t')
: option(UHPat.t' * HTyp.t * Contexts.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match p with
| UHPat.EmptyHole u =>
if renumber_empty_holes then
let (u, u_gen) := MetaVarGen.next u_gen in
Some (UHPat.EmptyHole u, HTyp.Hole, ctx, u_gen)
else
Some (p, HTyp.Hole, ctx, u_gen)
| UHPat.Wild => Some (p, HTyp.Hole, ctx, u_gen)
| UHPat.Var x =>
Var.check_valid x (
let ctx := Contexts.extend_gamma ctx (x, HTyp.Hole) in
Some (p, HTyp.Hole, ctx, u_gen))
| UHPat.NumLit _ => Some (p, HTyp.Num, ctx, u_gen)
| UHPat.BoolLit _ => Some (p, HTyp.Bool, ctx, u_gen)
| UHPat.ListNil => Some (p, HTyp.List HTyp.Hole, ctx, u_gen)
(* | UHPat.ListLit ps =>
let opt_result := List.fold_left (fun opt_result p =>
match opt_result with
| None => None
| Some (ps, ty, ctx, u_gen) =>
match syn_pat_fix_holes fuel ctx u_gen renumber_empty_holes p with
| Some (p, ty', ctx, u_gen) =>
match HTyp.join ty ty' with
| Some ty_joined => Some (cons p ps, ty_joined, ctx, u_gen)
| None =>
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes p ty with
| None => None
| Some (p, ctx, u_gen) => Some (cons p ps, ty, ctx, u_gen)
end
end
| None =>
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes p ty with
| None => None
| Some (p, ctx, u_gen) => Some (cons p ps, ty, ctx, u_gen)
end
end
end) ps (Some (nil, HTyp.Hole, ctx, u_gen)) in
match opt_result with
| None => None
| Some (ps, ty, ctx, u_gen) =>
Some (UHPat.ListLit ps, HTyp.List ty, ctx, u_gen)
end *)
| UHPat.Inj side p1 =>
match syn_pat_fix_holes fuel ctx u_gen renumber_empty_holes p1 with
| None => None
| Some (p1, ty1, ctx, u_gen) =>
let ty :=
match side with
| L => HTyp.Sum ty1 HTyp.Hole
| R => HTyp.Sum HTyp.Hole ty1
end in
Some (UHPat.Inj side p1, ty, ctx, u_gen)
end
| UHPat.OpSeq skel seq =>
match syn_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel seq with
| None => None
| Some (skel, seq, ty, ctx, u_gen) =>
Some (UHPat.OpSeq skel seq, ty, ctx, u_gen)
end
end
end
with syn_skel_pat_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(skel : UHPat.skel_t)
(seq : UHPat.opseq)
: option(UHPat.skel_t * UHPat.opseq * HTyp.t * Contexts.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| None => None
| Some pn =>
match UHPat.bidelimited pn with
| false => None
| true =>
match syn_pat_fix_holes fuel ctx u_gen renumber_empty_holes pn with
| None => None
| Some (pn, ty, ctx, u_gen) =>
match OperatorSeq.seq_update_nth n seq pn with
| None => None
| Some seq =>
Some (skel, seq, ty, ctx, u_gen)
end
end
end
end
| Skel.BinOp _ UHPat.Comma skel1 skel2 =>
match syn_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq with
| None => None
| Some (skel1, seq, ty1, ctx, u_gen) =>
match syn_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq with
| None => None
| Some (skel2, seq, ty2, ctx, u_gen) =>
let skel := Skel.BinOp NotInHole UHPat.Comma skel1 skel2 in
let ty := HTyp.Prod ty1 ty2 in
Some (skel, seq, ty, ctx, u_gen)
end
end
| Skel.BinOp _ UHPat.Space skel1 skel2 =>
match syn_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq with
| None => None
| Some (skel1, seq, ty1, ctx, u_gen) =>
match syn_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq with
| None => None
| Some (skel2, seq, ty2, ctx, u_gen) =>
let skel := Skel.BinOp NotInHole UHPat.Comma skel1 skel2 in
let ty := HTyp.Hole in
Some (skel, seq, ty, ctx, u_gen)
end
end
| Skel.BinOp _ UHPat.Cons skel1 skel2 =>
match syn_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq with
| None => None
| Some (skel1, seq, ty_elt, ctx, u_gen) =>
let ty := HTyp.List ty_elt in
match ana_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq ty with
| None => None
| Some (skel2, seq, ctx, u_gen) =>
let skel := Skel.BinOp NotInHole UHPat.Cons skel1 skel2 in
Some (skel, seq, ty, ctx, u_gen)
end
end
end
end
with ana_pat_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(p : UHPat.t)
(ty : HTyp.t)
: option(UHPat.t * Contexts.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match p with
| UHPat.Pat _ p' =>
match ana_pat_fix_holes' fuel ctx u_gen renumber_empty_holes p' ty with
| None => None
| Some (err_status, p', ctx, u_gen) =>
Some (UHPat.Pat err_status p', ctx, u_gen)
end
| UHPat.Parenthesized p =>
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes p ty with
| None => None
| Some (p, ctx, u_gen) =>
Some (UHPat.Parenthesized p, ctx, u_gen)
end
end
end
with ana_pat_fix_holes'
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(p : UHPat.t')
(ty : HTyp.t)
: option(err_status * UHPat.t' * Contexts.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match p with
| UHPat.Wild => Some (NotInHole, p, ctx, u_gen)
| UHPat.Var x =>
Var.check_valid x (
let ctx := Contexts.extend_gamma ctx (x, ty) in
Some (NotInHole, p, ctx, u_gen))
| UHPat.EmptyHole _
| UHPat.NumLit _
| UHPat.BoolLit _ =>
match syn_pat_fix_holes' fuel ctx u_gen renumber_empty_holes p with
| None => None
| Some (p', ty', ctx, u_gen) =>
match HTyp.consistent ty ty' with
| true => Some (NotInHole, p', ctx, u_gen)
| false =>
let (u, u_gen) := MetaVarGen.next u_gen in
Some (InHole TypeInconsistent u, p', ctx, u_gen)
end
end
| UHPat.Inj side p1 =>
match HTyp.matched_sum ty with
| Some (tyL, tyR) =>
let ty1 := pick_side side tyL tyR in
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes p1 ty1 with
| None => None
| Some (p1, ctx, u_gen) =>
Some (NotInHole, UHPat.Inj side p1, ctx, u_gen)
end
| None =>
match syn_pat_fix_holes fuel ctx u_gen renumber_empty_holes p1 with
| None => None
| Some (p1, ty, ctx, u_gen) =>
let (u, u_gen) := MetaVarGen.next u_gen in
Some (InHole TypeInconsistent u, UHPat.Inj side p1, ctx, u_gen)
end
end
| UHPat.ListNil =>
match HTyp.matched_list ty with
| Some _ => Some (NotInHole, p, ctx, u_gen)
| None =>
let (u, u_gen) := MetaVarGen.next u_gen in
Some (InHole TypeInconsistent u, p, ctx, u_gen)
end
(* | UHPat.ListLit ps =>
match HTyp.matched_list ty with
| Some ty_elt =>
let ps_result :=
List.fold_left (fun opt_result elt =>
match opt_result with
| None => None
| Some (ps, ctx, u_gen) =>
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes elt ty_elt with
| None => None
| Some (elt, ctx, u_gen) =>
Some (cons elt ps, ctx, u_gen)
end
end) ps (Some (nil, ctx, u_gen)) in
match ps_result with
| None => None
| Some (ps, ctx, u_gen) =>
Some (NotInHole, UHPat.ListLit ps, ctx, u_gen)
end
| None => None (* TODO should return InHole *)
end *)
| UHPat.OpSeq skel seq =>
match ana_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel seq ty with
| None => None
| Some (Skel.Placeholder _ _, _, _, _) => None
| Some ((Skel.BinOp err _ _ _) as skel, seq, ctx, u_gen) =>
let p := UHPat.OpSeq skel seq in
Some (err, p, ctx, u_gen)
end
end
end
with ana_skel_pat_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(skel : UHPat.skel_t)
(seq : UHPat.opseq)
(ty : HTyp.t)
: option(UHPat.skel_t * UHPat.opseq * Contexts.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| None => None
| Some pn =>
match UHPat.bidelimited pn with
| false => None
| true =>
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes pn ty with
| None => None
| Some (pn, ctx, u_gen) =>
match OperatorSeq.seq_update_nth n seq pn with
| Some seq => Some (skel, seq, ctx, u_gen)
| None => None
end
end
end
end
| Skel.BinOp _ UHPat.Comma skel1 skel2 =>
match ty with
| HTyp.Hole =>
match ana_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq HTyp.Hole with
| None => None
| Some (skel1, seq, ctx, u_gen) =>
match ana_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq HTyp.Hole with
| None => None
| Some (skel2, seq, ctx, u_gen) =>
let skel := Skel.BinOp NotInHole UHPat.Comma skel1 skel2 in
Some (skel, seq, ctx, u_gen)
end
end
| HTyp.Prod ty1 ty2 =>
let types := HTyp.get_tuple ty1 ty2 in
let skels := UHPat.get_tuple skel1 skel2 in
match Util.zip_eq skels types with
| Some zipped =>
let fixed :=
List.fold_right (fun (skel_ty : UHPat.skel_t * HTyp.t) opt_result =>
match opt_result with
| None => None
| Some (skels, seq, ctx, u_gen) =>
let (skel, ty) := skel_ty in
match ana_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel seq ty with
| None => None
| Some (skel, seq, ctx, u_gen) =>
Some (cons skel skels, seq, ctx, u_gen)
end
end) (Some (nil, seq, ctx, u_gen)) zipped in
match fixed with
| None => None
| Some (skels, seq, ctx, u_gen) =>
match UHPat.make_tuple NotInHole skels with
| None => None
| Some skel => Some (skel, seq, ctx, u_gen)
end
end
| None =>
let (zipped, remainder) := HTyp.zip_with_skels skels types in
let fixed1 :=
List.fold_right (fun (skel_ty : UHPat.skel_t * HTyp.t) opt_result =>
match opt_result with
| None => None
| Some (skels, seq, ctx, u_gen) =>
let (skel, ty) := skel_ty in
match ana_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel seq ty with
| None => None
| Some (skel, seq, ctx, u_gen) =>
Some (cons skel skels, seq, ctx, u_gen)
end
end) (Some (nil, seq, ctx, u_gen)) zipped in
match fixed1 with
| None => None
| Some (skels1, seq, ctx, u_gen) =>
let fixed2 :=
List.fold_right (fun (skel : UHPat.skel_t) opt_result =>
match opt_result with
| None => None
| Some (skels, seq, ctx, u_gen) =>
match syn_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel seq with
| None => None
| Some (skel, seq, ty, ctx, u_gen) =>
Some (cons skel skels, seq, ctx, u_gen)
end
end) (Some (nil, seq, ctx, u_gen)) remainder in
match fixed2 with
| None => None
| Some (skels2, seq, ctx, u_gen) =>
let skels := skels1 ++ skels2 in
let (u, u_gen) := MetaVarGen.next u_gen in
match UHPat.make_tuple (InHole WrongLength u) skels with
| None => None
| Some skel => Some (skel, seq, ctx, u_gen)
end
end
end
end
| _ =>
match syn_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq with
| None => None
| Some (skel1, seq, _, ctx, u_gen) =>
match syn_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq with
| None => None
| Some (skel2, seq, _, ctx, u_gen) =>
let (u, u_gen) := MetaVarGen.next u_gen in
let skel := Skel.BinOp (InHole TypeInconsistent u) UHPat.Comma skel1 skel2 in
Some (skel, seq, ctx, u_gen)
end
end
end
| Skel.BinOp _ UHPat.Space skel1 skel2 =>
match syn_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq with
| None => None
| Some (skel1, seq, _, ctx, u_gen) =>
match syn_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq with
| None => None
| Some (skel2, seq, _, ctx, u_gen) =>
let (u, u_gen) := MetaVarGen.next u_gen in
let skel := Skel.BinOp (InHole TypeInconsistent u) UHPat.Space skel1 skel2 in
Some (skel, seq, ctx, u_gen)
end
end
| Skel.BinOp _ UHPat.Cons skel1 skel2 =>
match HTyp.matched_list ty with
| Some ty_elt =>
match ana_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq ty_elt with
| None => None
| Some (skel1, seq, ctx, u_gen) =>
let ty_list := HTyp.List ty_elt in
match ana_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq ty_list with
| None => None
| Some (skel2, seq, ctx, u_gen) =>
let skel := Skel.BinOp NotInHole UHPat.Cons skel1 skel2 in
Some (skel, seq, ctx, u_gen)
end
end
| None =>
match syn_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq with
| None => None
| Some (skel1, seq, ty_elt, ctx, u_gen) =>
let ty_list := HTyp.List ty_elt in
match ana_skel_pat_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq ty_list with
| None => None
| Some (skel2, seq, ctx, u_gen) =>
let (u, u_gen) := MetaVarGen.next u_gen in
let skel := Skel.BinOp (InHole TypeInconsistent u) UHPat.Cons skel1 skel2 in
Some (skel, seq, ctx, u_gen)
end
end
end
end
end.
Fixpoint ana_rule_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(rule : UHExp.rule)
(pat_ty : HTyp.t)
(clause_ty : HTyp.t)
: option(UHExp.rule * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match rule with
| Rule pat e =>
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes pat pat_ty with
| None => None
| Some ((pat', ctx), u_gen) =>
match ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes e clause_ty with
| None => None
| Some (e', u_gen) => Some(Rule pat' e', u_gen)
end
end
end
end
with ana_rules_fix_holes_internal
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(rules : list(UHExp.rule))
(pat_ty : HTyp.t)
(clause_ty : HTyp.t)
: option(list(UHExp.rule) * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
List.fold_right (fun r b =>
match b with
| None => None
| Some (rules, u_gen) =>
match ana_rule_fix_holes fuel ctx u_gen renumber_empty_holes r pat_ty clause_ty with
| None => None
| Some (r, u_gen) => Some (cons r rules, u_gen)
end
end) (Some (nil, u_gen)) rules
end
(* If renumber_empty_holes is true, then the metavars in empty holes will be assigned
* new values in the same namespace as non-empty holes. Non-empty holes are renumbered
* regardless.
*)
with syn_fix_holes_internal
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(e : t)
: option(t * HTyp.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match e with
| Tm _ e' =>
match syn_fix_holes' fuel ctx u_gen renumber_empty_holes e' with
| Some (e'', ty, u_gen') =>
Some (Tm NotInHole e'', ty, u_gen')
| None => None
end
| Parenthesized e1 =>
match syn_fix_holes_internal fuel ctx u_gen renumber_empty_holes e1 with
| Some (e1', ty, u_gen') =>
Some (Parenthesized e1', ty, u_gen')
| None => None
end
end
end
with syn_fix_holes'
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(e : t')
: option(t' * HTyp.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match e with
| EmptyHole u =>
if renumber_empty_holes then
let (u', u_gen'') := MetaVarGen.next u_gen in
Some (EmptyHole u', HTyp.Hole, u_gen'')
else
Some (EmptyHole u, HTyp.Hole, u_gen)
| Asc e1 uty =>
if bidelimited e1 then
let ty := UHTyp.expand fuel uty in
match ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes e1 ty with
| Some (e1', u_gen') => Some (Asc e1' uty, ty, u_gen')
| None => None
end
else None
| Var var_err_status x =>
let (gamma, _) := ctx in
match VarMap.lookup gamma x with
| Some ty => Some (Var NotInVHole x, ty, u_gen)
| None =>
match var_err_status with
| InVHole u => Some (e, HTyp.Hole, u_gen)
| NotInVHole =>
let (u, u_gen) := MetaVarGen.next u_gen in
Some (Var (InVHole u) x, HTyp.Hole, u_gen)
end
end
| Lam p ann e1 =>
let ty1 :=
match ann with
| Some uty1 => UHTyp.expand fuel uty1
| None => HTyp.Hole
end in
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes p ty1 with
| None => None
| Some (p, ctx1, u_gen) =>
match syn_fix_holes_internal fuel ctx1 u_gen renumber_empty_holes e1 with
| None => None
| Some (e1, ty2, u_gen) =>
Some (Lam p ann e1, HTyp.Arrow ty1 ty2, u_gen)
end
end
| Let p ann e1 e2 =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
let ctx1 := ctx_for_let ctx p ty1 e1 in
match ana_fix_holes_internal fuel ctx1 u_gen renumber_empty_holes e1 ty1 with
| None => None
| Some (e1, u_gen) =>
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes p ty1 with
| None => None
| Some (p, ctx, u_gen) =>
match syn_fix_holes_internal fuel ctx u_gen renumber_empty_holes e2 with
| Some (e2, ty, u_gen) =>
Some (Let p ann e1 e2, ty, u_gen)
| None => None
end
end
end
| None =>
match syn_fix_holes_internal fuel ctx u_gen renumber_empty_holes e1 with
| Some (e1, ty1, u_gen) =>
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes p ty1 with
| None => None
| Some (p, ctx, u_gen) =>
match syn_fix_holes_internal fuel ctx u_gen renumber_empty_holes e2 with
| Some (e2, ty, u_gen) =>
Some (Let p ann e1 e2, ty, u_gen)
| None => None
end
end
| None => None
end
end
| NumLit i => Some (e, HTyp.Num, u_gen)
| BoolLit b => Some (e, HTyp.Bool, u_gen)
| ListNil => Some (e, HTyp.List HTyp.Hole, u_gen)
(* | ListLit es =>
let opt_result := List.fold_left (fun opt_result e =>
match opt_result with
| None => None
| Some (es, ty, u_gen) =>
match syn_fix_holes_internal fuel ctx u_gen renumber_empty_holes e with
| Some (e, ty', u_gen) =>
match HTyp.join ty ty' with
| Some ty_joined => Some (cons e es, ty_joined, u_gen)
| None =>
match ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes e ty with
| None => None
| Some (e, u_gen) => Some (cons e es, ty, u_gen)
end
end
| None =>
match ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes e ty with
| None => None
| Some (e, u_gen) => Some (cons e es, ty, u_gen)
end
end
end) es (Some (nil, HTyp.Hole, u_gen)) in
match opt_result with
| None => None
| Some (es, ty, u_gen) =>
Some (UHExp.ListLit es, HTyp.List ty, u_gen)
end *)
| OpSeq skel seq =>
match syn_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel seq with
| None => None
| Some (Skel.Placeholder _ _, _, _, _) => None
| Some (skel, seq, ty, u_gen) =>
Some (OpSeq skel seq, ty, u_gen)
end
| Inj side e1 =>
match syn_fix_holes_internal fuel ctx u_gen renumber_empty_holes e1 with
| Some (e1', ty1, u_gen') =>
let e' := Inj side e1' in
let ty' :=
match side with
| L => HTyp.Sum ty1 HTyp.Hole
| R => HTyp.Sum HTyp.Hole ty1
end in
Some (e', ty', u_gen')
| None => None
end
| Case _ _ => None
| ApPalette name serialized_model hole_data =>
let (_, palette_ctx) := ctx in
match (VarMap.lookup palette_ctx name) with
| None => None
| Some palette_defn =>
match (ana_fix_holes_hole_data fuel ctx u_gen renumber_empty_holes hole_data) with
| None => None
| Some (hole_data', u_gen') =>
let expansion_ty := PaletteDefinition.expansion_ty palette_defn in
let to_exp := PaletteDefinition.to_exp palette_defn in
let expansion := to_exp serialized_model in
let (_, hole_map) := hole_data in
let expansion_ctx := PaletteHoleData.extend_ctx_with_hole_map ctx hole_map in
match ana fuel expansion_ctx expansion expansion_ty with
| Some _ =>
Some (ApPalette name serialized_model hole_data', expansion_ty, u_gen')
| None => None
end
end
end
end
end
with ana_fix_holes_hole_data
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(hole_data : PaletteHoleData.t)
: option(PaletteHoleData.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
let (next_ref, hole_map) := hole_data in
let init : (PaletteHoleData.hole_map * MetaVarGen.t) := (NatMap.empty, u_gen) in
let hole_map_opt' := NatMap.fold hole_map (fun (c : option(PaletteHoleData.hole_map * MetaVarGen.t)) v =>
let (i, ty_e) := v in
let (ty, e) := ty_e in
match c with
| None => None
| Some (xs, u_gen) =>
match (ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes e ty) with
| Some (e', u_gen') =>
let xs' := NatMap.extend xs (i, (ty, e')) in
Some (xs', u_gen')
| None => None
end
end) (Some init) in
match hole_map_opt' with
| Some (hole_map', u_gen') => Some ((next_ref, hole_map'), u_gen')
| None => None
end
end
with ana_fix_holes_internal
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(e : t)
(ty : HTyp.t)
: option(t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match e with
| Tm _ e1 =>
match ana_fix_holes' fuel ctx u_gen renumber_empty_holes e1 ty with
| Some (err_status, e1, u_gen) =>
Some (Tm err_status e1, u_gen)
| None => None
end
| Parenthesized e1 =>
match ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes e1 ty with
| Some (e1, u_gen) =>
Some (Parenthesized e1, u_gen)
| None => None
end
end
end
with ana_fix_holes'
(fuel : Fuel.t) (ctx : Contexts.t) (u_gen : MetaVarGen.t) (renumber_empty_holes : bool)
(e : t') (ty : HTyp.t)
: option(err_status * t' * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match e with
| Let p ann e1 e2 =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
let ctx1 := ctx_for_let ctx p ty1 e1 in
match ana_fix_holes_internal fuel ctx1 u_gen renumber_empty_holes e1 ty1 with
| None => None
| Some (e1, u_gen) =>
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes p ty1 with
| None => None
| Some (p, ctx, u_gen) =>
match ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes e2 ty with
| Some (e2, u_gen) =>
Some (NotInHole, Let p ann e1 e2, u_gen)
| None => None
end
end
end
| None =>
match syn_fix_holes_internal fuel ctx u_gen renumber_empty_holes e1 with
| Some (e1, ty1, u_gen) =>
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes p ty1 with
| None => None
| Some (p, ctx, u_gen) =>
match ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes e2 ty with
| Some (e2, u_gen) =>
Some (NotInHole, Let p ann e1 e2, u_gen)
| None => None
end
end
| None => None
end
end
| Lam p ann e1 =>
match HTyp.matched_arrow ty with
| Some (ty1_given, ty2) =>
match ann with
| Some uty1 =>
let ty1_ann := UHTyp.expand fuel uty1 in
match HTyp.consistent ty1_ann ty1_given with
| true =>
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes p ty1_ann with
| None => None
| Some (p, ctx, u_gen) =>
match ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes e1 ty2 with
| None => None
| Some (e1, u_gen) =>
Some (NotInHole, Lam p ann e1, u_gen)
end
end
| false =>
match syn_fix_holes' fuel ctx u_gen renumber_empty_holes e with
| None => None
| Some (e, ty, u_gen) =>
let (u, u_gen) := MetaVarGen.next u_gen in
Some (InHole TypeInconsistent u, e, u_gen)
end
end
| None =>
match ana_pat_fix_holes fuel ctx u_gen renumber_empty_holes p ty1_given with
| None => None
| Some (p, ctx, u_gen) =>
match ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes e1 ty2 with
| Some (e1, u_gen) =>
Some (NotInHole, Lam p ann e1, u_gen)
| None => None
end
end
end
| None =>
match syn_fix_holes' fuel ctx u_gen renumber_empty_holes e with
| None => None
| Some (e, ty', u_gen) =>
let (u, u_gen) := MetaVarGen.next u_gen in
Some (InHole TypeInconsistent u, e, u_gen)
end
end
| Inj side e1 =>
match HTyp.matched_sum ty with
| Some (ty1, ty2) =>
match ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes e1 (pick_side side ty1 ty2) with
| Some (e1', u_gen') =>
Some (NotInHole, Inj side e1', u_gen')
| None => None
end
| None =>
match syn_fix_holes' fuel ctx u_gen renumber_empty_holes e with
| Some (e', ty', u_gen') =>
if HTyp.consistent ty ty' then
Some (NotInHole, e', u_gen')
else
let (u, u_gen'') := MetaVarGen.next u_gen' in
Some (InHole TypeInconsistent u, e', u_gen'')
| None => None
end
end
| ListNil =>
match HTyp.matched_list ty with
| Some _ => Some (NotInHole, e, u_gen)
| None =>
let (u, u_gen) := MetaVarGen.next u_gen in
Some (InHole TypeInconsistent u, e, u_gen)
end
(* | ListLit es =>
match HTyp.matched_list ty with
| Some ty_elt =>
let opt_es := List.fold_left (fun opt_result elt =>
match opt_result with
| None => None
| Some (es, u_gen) =>
match ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes elt ty_elt with
| None => None
| Some (elt, u_gen) =>
Some (cons elt es, u_gen)
end
end) es (Some (nil, u_gen)) in
match opt_es with
| None => None
| Some (es, u_gen) => Some (NotInHole, ListLit es, u_gen)
end
| None => None (* TODO put in hole if not a list *)
end *)
| Case e1 rules =>
match syn_fix_holes_internal fuel ctx u_gen renumber_empty_holes e1 with
| None => None
| Some (e1', ty1, u_gen) =>
match ana_rules_fix_holes_internal fuel ctx u_gen renumber_empty_holes rules ty1 ty
with
| None => None
| Some (rules', u_gen) =>
Some (NotInHole, Case e1' rules', u_gen)
end
end
| OpSeq skel seq =>
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel seq ty with
| None => None
| Some (Skel.Placeholder _ _, _, _) => None
| Some ((Skel.BinOp err _ _ _) as skel, seq, u_gen) =>
match err with
| NotInHole =>
Some (err, OpSeq skel seq, u_gen)
| (InHole WrongLength _) =>
Some (err, OpSeq skel seq, u_gen)
| (InHole _ _) =>
Some (err, OpSeq skel seq, u_gen)
end
end
| EmptyHole _
| Asc _ _
| Var _ _
| NumLit _
| BoolLit _
| ApPalette _ _ _ =>
match syn_fix_holes' fuel ctx u_gen renumber_empty_holes e with
| Some (e', ty', u_gen') =>
if HTyp.consistent ty ty' then
Some (NotInHole, e', u_gen')
else
let (u, u_gen'') := MetaVarGen.next u_gen' in
Some (InHole TypeInconsistent u, e', u_gen'')
| None => None
end
end
end
with syn_skel_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(skel : skel_t)
(seq : opseq)
: option(skel_t * opseq * HTyp.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| None => None
| Some en =>
match bidelimited en with
| false => None
| true =>
match syn_fix_holes_internal fuel ctx u_gen renumber_empty_holes en with
| None => None
| Some (en, ty, u_gen) =>
match OperatorSeq.seq_update_nth n seq en with
| None => None
| Some seq =>
Some (skel, seq, ty, u_gen)
end
end
end
end
| Skel.BinOp _ (UHExp.Plus as op) skel1 skel2
| Skel.BinOp _ (UHExp.Times as op) skel1 skel2 =>
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq HTyp.Num with
| Some (skel1, seq, u_gen) =>
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq HTyp.Num with
| Some (skel2, seq, u_gen) =>
Some (Skel.BinOp NotInHole op skel1 skel2, seq, HTyp.Num, u_gen)
| None => None
end
| None => None
end
| Skel.BinOp _ (UHExp.LessThan as op) skel1 skel2 =>
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq HTyp.Num with
| Some (skel1, seq, u_gen) =>
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq HTyp.Num with
| Some (skel2, seq, u_gen) =>
Some (Skel.BinOp NotInHole op skel1 skel2, seq, HTyp.Bool, u_gen)
| None => None
end
| None => None
end
| Skel.BinOp _ UHExp.Space skel1 skel2 =>
match syn_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq with
| Some (skel1', seq1, ty1, u_gen1) =>
match HTyp.matched_arrow ty1 with
| Some (ty2, ty) =>
match ana_skel_fix_holes fuel ctx u_gen1 renumber_empty_holes skel2 seq1 ty2 with
| Some (skel2', seq2, u_gen2) =>
Some (Skel.BinOp NotInHole Space skel1' skel2', seq2, ty, u_gen2)
| None => None
end
| None =>
match ana_skel_fix_holes fuel ctx u_gen1 renumber_empty_holes skel2 seq1 HTyp.Hole with
| Some (skel2', seq2, u_gen2) =>
match UHExp.make_skel_inconsistent u_gen2 skel1' seq2 with
| Some (skel1'', seq3, u_gen3) =>
Some (Skel.BinOp NotInHole Space skel1'' skel2', seq3, HTyp.Hole, u_gen3)
| None => None
end
| None => None
end
end
| None => None
end
| Skel.BinOp _ UHExp.Comma skel1 skel2 =>
match syn_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq with
| None => None
| Some (skel1, seq, ty1, u_gen) =>
match syn_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq with
| None => None
| Some (skel2, seq, ty2, u_gen) =>
let skel := Skel.BinOp NotInHole Comma skel1 skel2 in
let ty := HTyp.Prod ty1 ty2 in
Some (skel, seq, ty, u_gen)
end
end
| Skel.BinOp _ UHExp.Cons skel1 skel2 =>
match syn_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq with
| None => None
| Some (skel1, seq, ty_elt, u_gen) =>
let ty := HTyp.List ty_elt in
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq ty with
| None => None
| Some (skel2, seq, u_gen) =>
let skel := Skel.BinOp NotInHole Cons skel1 skel2 in
Some (skel, seq, ty, u_gen)
end
end
end
end
with ana_skel_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(skel : skel_t)
(seq : opseq)
(ty : HTyp.t)
: option(skel_t * opseq * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| None => None
| Some en =>
match bidelimited en with
| false => None
| true =>
match ana_fix_holes_internal fuel ctx u_gen renumber_empty_holes en ty with
| None => None
| Some (en, u_gen) =>
match OperatorSeq.seq_update_nth n seq en with
| Some seq => Some (skel, seq, u_gen)
| None => None
end
end
end
end
| Skel.BinOp _ UHExp.Comma skel1 skel2 =>
match ty with
| HTyp.Hole =>
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq HTyp.Hole with
| None => None
| Some (skel1, seq, u_gen) =>
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq HTyp.Hole with
| None => None
| Some (skel2, seq, u_gen) =>
let skel := Skel.BinOp NotInHole UHExp.Comma skel1 skel2 in
Some (skel, seq, u_gen)
end
end
| HTyp.Prod ty1 ty2 =>
let types := HTyp.get_tuple ty1 ty2 in
let skels := UHExp.get_tuple skel1 skel2 in
let num_types := List.length types in
let num_skels := List.length skels in
match Util.zip_eq skels types with
| Some zipped =>
let fixed :=
List.fold_right (fun (skel_ty : UHExp.skel_t * HTyp.t) opt_result =>
match opt_result with
| None => None
| Some (skels, seq, u_gen) =>
let (skel, ty) := skel_ty in
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel seq ty with
| None => None
| Some (skel, seq, u_gen) =>
Some (cons skel skels, seq, u_gen)
end
end) (Some (nil, seq, u_gen)) zipped in
match fixed with
| None => None
| Some (skels, seq, u_gen) =>
match UHExp.make_tuple NotInHole skels with
| None => None
| Some skel => Some (skel, seq, u_gen)
end
end
| None =>
let (zipped, remainder) := HTyp.zip_with_skels skels types in
let fixed1 :=
List.fold_right (fun (skel_ty : UHExp.skel_t * HTyp.t) opt_result =>
match opt_result with
| None => None
| Some (skels, seq, u_gen) =>
let (skel, ty) := skel_ty in
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel seq ty with
| None => None
| Some (skel, seq, u_gen) =>
Some (cons skel skels, seq, u_gen)
end
end) (Some (nil, seq, u_gen)) zipped in
match fixed1 with
| None => None
| Some (skels1, seq, u_gen) =>
let fixed2 :=
List.fold_right (fun (skel : UHExp.skel_t) opt_result =>
match opt_result with
| None => None
| Some (skels, seq, u_gen) =>
match syn_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel seq with
| None => None
| Some (skel, seq, ty, u_gen) =>
Some (cons skel skels, seq, u_gen)
end
end) (Some (nil, seq, u_gen)) remainder in
match fixed2 with
| None => None
| Some (skels2, seq, u_gen) =>
let skels := skels1 ++ skels2 in
let (u, u_gen) := MetaVarGen.next u_gen in
match UHExp.make_tuple (InHole WrongLength u) skels with
| None => None
| Some skel => Some (skel, seq, u_gen)
end
end
end
end
| _ =>
match syn_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq with
| None => None
| Some (skel1, seq, _, u_gen) =>
match syn_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq with
| None => None
| Some (skel2, seq, _, u_gen) =>
let (u, u_gen) := MetaVarGen.next u_gen in
let skel := Skel.BinOp (InHole TypeInconsistent u) UHExp.Comma skel1 skel2 in
Some (skel, seq, u_gen)
end
end
end
| Skel.BinOp _ UHExp.Cons skel1 skel2 =>
match HTyp.matched_list ty with
| Some ty_elt =>
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq ty_elt with
| None => None
| Some (skel1, seq, u_gen) =>
let ty_list := HTyp.List ty_elt in
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq ty_list with
| None => None
| Some (skel2, seq, u_gen) =>
let skel := Skel.BinOp NotInHole Cons skel1 skel2 in
Some (skel, seq, u_gen)
end
end
| None =>
match syn_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel1 seq with
| None => None
| Some (skel1, seq, ty_elt, u_gen) =>
let ty_list := HTyp.List ty_elt in
match ana_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel2 seq ty_list with
| None => None
| Some (skel2, seq, u_gen) =>
let (u, u_gen) := MetaVarGen.next u_gen in
let skel := Skel.BinOp (InHole TypeInconsistent u) Cons skel1 skel2 in
Some (skel, seq, u_gen)
end
end
end
| Skel.BinOp _ UHExp.Plus _ _
| Skel.BinOp _ UHExp.Times _ _
| Skel.BinOp _ UHExp.LessThan _ _
| Skel.BinOp _ UHExp.Space _ _ =>
match syn_skel_fix_holes fuel ctx u_gen renumber_empty_holes skel seq with
| Some (skel', seq', ty', u_gen') =>
if HTyp.consistent ty ty' then Some (skel', seq', u_gen')
else
make_skel_inconsistent u_gen' skel' seq'
| None => None
end
end
end.
Definition syn_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(e : t)
: option(t * HTyp.t * MetaVarGen.t) :=
syn_fix_holes_internal fuel ctx u_gen false e.
Definition ana_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(e : t)
(ty : HTyp.t)
: option(t * MetaVarGen.t) :=
ana_fix_holes_internal fuel ctx u_gen false e ty.
Definition ana_rules_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(renumber_empty_holes : bool)
(rules : list(UHExp.rule))
(pat_ty : HTyp.t)
(clause_ty : HTyp.t) :=
ana_rules_fix_holes_internal fuel ctx u_gen renumber_empty_holes rules pat_ty clause_ty.
(* Only to be used on top-level expressions, as it starts hole renumbering at 0 *)
Definition fix_and_renumber_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(e : t)
: option(t * HTyp.t * MetaVarGen.t) :=
syn_fix_holes_internal fuel ctx MetaVarGen.init true e.
End UHExp.
Module Contexts := UHExp.Contexts.
Module PaletteCtx := UHExp.PaletteCtx.
Inductive cursor_side : Type :=
| Before : cursor_side
| After : cursor_side
| In : nat -> cursor_side.
Module ZList.
Definition t (Z A : Type) : Type := list(A) * Z * list(A).
Definition singleton {A Z : Type} (z : Z) : t Z A :=
(nil, z, nil).
Fixpoint split_at {A : Type} (n : nat) (xs : list A) : option(t A A) :=
match (n, xs) with
| (_, nil) => None
| (0, cons x xs) =>
let prefix := nil in
let suffix := xs in
Some ((prefix, x), suffix)
| (S n', cons x xs) =>
match split_at n' xs with
| None => None
| Some ((prefix, z), suffix) =>
let prefix' := cons x prefix in
Some ((prefix', z), suffix)
end
end.
Fixpoint replace_z {A Z : Type}
(zs : t Z A)
(z : Z)
: t Z A :=
match zs with
| ((prefix, _), suffix) => ((prefix, z), suffix)
end.
Fixpoint optmap_z {A Z1 Z2 : Type}
(f : Z1 -> option(Z2))
(zs : t Z1 A)
: option(t Z2 A) :=
match zs with
| ((prefix, z), suffix) =>
match f z with
| None => None
| Some z' => Some ((prefix, z'), suffix)
end
end.
Definition prj_prefix {Z A : Type} (zxs : t Z A) : list(A) :=
let (az, _) := zxs in
let (prefix, _) := az in
prefix.
Definition prefix_length {Z A : Type} (zxs : t Z A) : nat :=
List.length (prj_prefix zxs).
Definition prj_z {Z A : Type} (zxs : t Z A) : Z :=
let (az, _) := zxs in
let (_, z) := az in
z.
Definition prj_suffix {Z A : Type} (zxs : t Z A) : list(A) :=
let (_, suffix) := zxs in
suffix.
Definition erase {Z A : Type} (xs : t Z A) (erase_z : Z -> A) :=
let (az, xs_after) := xs in
let (xs_before, z) := az in
let a := erase_z z in
xs_before ++ (a :: xs_after).
End ZList.
(* Zippered finite map over nats, used with Z expressions
* i.e. there is a selected element of type Z and the rest is a nat map of type A *)
Module ZNatMap.
Definition t (A Z : Type) : Type := NatMap.t(A) * (nat * Z).
Definition new {A Z : Type} (m : NatMap.t(A)) (nz : nat * Z) : option(t A Z) :=
let (n, z) := nz in
match NatMap.lookup m n with
| Some _ => None
| None => Some (m, nz)
end.
End ZNatMap.
Module ZTyp.
Definition cursor_side : Type := cursor_side.
Inductive t : Type :=
| CursorT : cursor_side -> UHTyp.t -> t
| ParenthesizedZ : t -> t
| ListZ : t -> t
| OpSeqZ : UHTyp.skel_t -> t -> OperatorSeq.opseq_surround UHTyp.t UHTyp.op -> t.
Definition opseq_surround : Type :=
OperatorSeq.opseq_surround UHTyp.t UHTyp.op.
Definition opseq_prefix : Type :=
OperatorSeq.opseq_prefix UHTyp.t UHTyp.op.
Definition opseq_suffix : Type :=
OperatorSeq.opseq_suffix UHTyp.t UHTyp.op.
Definition place_Before (uty : UHTyp.t) : t :=
match uty with
| UHTyp.Hole
| UHTyp.Parenthesized _
| UHTyp.Unit
| UHTyp.Num
| UHTyp.Bool
| UHTyp.List _ => CursorT Before uty
| UHTyp.OpSeq skel seq =>
let (uty0, suffix) := OperatorSeq.split0 seq in
let surround := OperatorSeq.EmptyPrefix suffix in
OpSeqZ skel (CursorT Before uty0) surround
end.
Definition place_After (uty : UHTyp.t) : t :=
match uty with
| UHTyp.Hole
| UHTyp.Parenthesized _
| UHTyp.Unit
| UHTyp.Num
| UHTyp.Bool
| UHTyp.List _ => CursorT After uty
| UHTyp.OpSeq skel seq =>
let (uty0, prefix) := OperatorSeq.split_tail seq in
let surround := OperatorSeq.EmptySuffix prefix in
OpSeqZ skel (CursorT After uty0) surround
end.
(* |_ -> _ *)
Definition ZHole_Arrow_Hole : t :=
OpSeqZ
(Skel.BinOp NotInHole UHTyp.Arrow
(Skel.Placeholder _ O)
(Skel.Placeholder _ 1))
(CursorT Before UHTyp.Hole)
(OperatorSeq.EmptyPrefix
(OperatorSeq.ExpSuffix UHTyp.Arrow UHTyp.Hole)).
(* |_ + _ *)
Definition ZHole_Sum_Hole : t :=
OpSeqZ
(Skel.BinOp NotInHole UHTyp.Sum
(Skel.Placeholder _ O)
(Skel.Placeholder _ 1))
(CursorT Before UHTyp.Hole)
(OperatorSeq.EmptyPrefix
(OperatorSeq.ExpSuffix UHTyp.Sum UHTyp.Hole)).
Fixpoint erase (zty : t) : UHTyp.t :=
match zty with
| CursorT _ ty => ty
| ParenthesizedZ zty1 => UHTyp.Parenthesized (erase zty1)
| ListZ zty1 => UHTyp.List (erase zty1)
| OpSeqZ skel zty1 surround =>
let uty1 := erase zty1 in
UHTyp.OpSeq skel
(OperatorSeq.opseq_of_exp_and_surround uty1 surround)
end.
End ZTyp.
Module ZPat.
Definition cursor_side : Type := cursor_side.
Inductive t : Type :=
| CursorP : cursor_side -> UHPat.t -> t
| ParenthesizedZ : t -> t
| Deeper : err_status -> t' -> t
with t' : Type :=
| InjZ : inj_side -> t -> t'
(* | ListLitZ : ZList.t t UHPat.t -> t' *)
| OpSeqZ : UHPat.skel_t -> t -> OperatorSeq.opseq_surround UHPat.t UHPat.op -> t'.
Definition opseq_surround : Type := OperatorSeq.opseq_surround UHPat.t UHPat.op.
Definition opseq_prefix : Type := OperatorSeq.opseq_prefix UHPat.t UHPat.op.
Definition opseq_suffix : Type := OperatorSeq.opseq_suffix UHPat.t UHPat.op.
Definition bidelimit zp :=
match zp with
| CursorP cursor_side p =>
CursorP cursor_side (UHPat.bidelimit p)
| ParenthesizedZ _
| Deeper _ (InjZ _ _)
(* | Deeper _ (ListLitZ _) *)
=> zp
| Deeper _ (OpSeqZ _ _ _) => ParenthesizedZ zp
end.
(* helper function for constructing a new empty hole *)
Definition new_EmptyHole (u_gen : MetaVarGen.t) : t * MetaVarGen.t :=
let (hole, u_gen) := UHPat.new_EmptyHole u_gen in
(CursorP Before hole, u_gen).
Fixpoint set_inconsistent
(u : MetaVar.t)
(zp : t)
: t :=
match zp with
| CursorP cursor_side p =>
let p := UHPat.set_inconsistent u p in
(CursorP cursor_side p)
| Deeper _ zp' =>
Deeper (InHole TypeInconsistent u) zp'
| ParenthesizedZ zp1 =>
ParenthesizedZ (set_inconsistent u zp1)
end.
Fixpoint make_inconsistent
(u_gen : MetaVarGen.t)
(zp : t)
: (t * MetaVarGen.t) :=
match zp with
| CursorP cursor_side p =>
let (p, u_gen) := UHPat.make_inconsistent u_gen p in
(CursorP cursor_side p, u_gen)
| Deeper (InHole TypeInconsistent _) _ =>
(zp, u_gen)
| Deeper _ zp' =>
let (u, u_gen) := MetaVarGen.next u_gen in
(Deeper (InHole TypeInconsistent u) zp', u_gen)
| ParenthesizedZ zp1 =>
let (zp1, u_gen) := make_inconsistent u_gen zp1 in
(ParenthesizedZ zp1, u_gen)
end.
Fixpoint erase (zp : ZPat.t) : UHPat.t :=
match zp with
| ZPat.CursorP _ p => p
| ZPat.Deeper err_status zp' => UHPat.Pat err_status (erase' zp')
| ZPat.ParenthesizedZ zp => UHPat.Parenthesized (erase zp)
end
with erase' (zp' : ZPat.t') : UHPat.t' :=
match zp' with
| ZPat.InjZ side zp1 => UHPat.Inj side (erase zp1)
(* | ZPat.ListLitZ zps => UHPat.ListLit (ZList.erase zps erase) *)
| ZPat.OpSeqZ skel zp1 surround =>
let p1 := erase zp1 in
UHPat.OpSeq skel (OperatorSeq.opseq_of_exp_and_surround p1 surround)
end.
Definition place_Before (p : UHPat.t) : t :=
match p with
| UHPat.Parenthesized _
| UHPat.Pat _ (UHPat.EmptyHole _)
| UHPat.Pat _ UHPat.Wild
| UHPat.Pat _ (UHPat.Var _)
| UHPat.Pat _ (UHPat.NumLit _)
| UHPat.Pat _ (UHPat.BoolLit _)
| UHPat.Pat _ (UHPat.Inj _ _)
(* | UHPat.Pat _ (UHPat.ListLit _) => *)
| UHPat.Pat _ UHPat.ListNil =>
CursorP Before p
| UHPat.Pat err (UHPat.OpSeq skel seq) =>
let (p0, suffix) := OperatorSeq.split0 seq in
let surround := OperatorSeq.EmptyPrefix suffix in
Deeper err (OpSeqZ skel (CursorP Before p0) surround)
end.
Definition place_After (p : UHPat.t) : t :=
match p with
| UHPat.Parenthesized _
| UHPat.Pat _ (UHPat.EmptyHole _)
| UHPat.Pat _ UHPat.Wild
| UHPat.Pat _ (UHPat.Var _)
| UHPat.Pat _ (UHPat.NumLit _)
| UHPat.Pat _ (UHPat.BoolLit _)
| UHPat.Pat _ (UHPat.Inj _ _)
(* | UHPat.Pat _ (UHPat.ListLit _) *)
| UHPat.Pat _ UHPat.ListNil => CursorP After p
| UHPat.Pat err (UHPat.OpSeq skel seq) =>
let (p0, prefix) := OperatorSeq.split_tail seq in
let surround := OperatorSeq.EmptySuffix prefix in
Deeper err (OpSeqZ skel (CursorP After p0) surround)
end.
End ZPat.
Module ZExp.
Definition cursor_side : Type := cursor_side.
Inductive t : Type :=
| CursorE : cursor_side -> UHExp.t -> t
(* | CursorPalette : PaletteName.t -> PaletteSerializedModel.t -> hole_ref -> t -> t *)
| Deeper : err_status -> t' -> t
| ParenthesizedZ : t -> t
with t' : Type :=
| AscZ1 : t -> UHTyp.t -> t'
| AscZ2 : UHExp.t -> ZTyp.t -> t'
| LetZP : ZPat.t -> option(UHTyp.t) -> UHExp.t -> UHExp.t -> t'
| LetZA : UHPat.t -> ZTyp.t -> UHExp.t -> UHExp.t -> t'
| LetZE1 : UHPat.t -> option(UHTyp.t) -> t -> UHExp.t -> t'
| LetZE2 : UHPat.t -> option(UHTyp.t) -> UHExp.t -> t -> t'
| LamZP : ZPat.t -> option(UHTyp.t) -> UHExp.t -> t'
| LamZA : UHPat.t -> ZTyp.t -> UHExp.t -> t'
| LamZE : UHPat.t -> option(UHTyp.t) -> t -> t'
| InjZ : inj_side -> t -> t'
(* | ListLitZ : ZList.t t UHExp.t -> t' *)
| CaseZE : t -> list(UHExp.rule) -> t'
| CaseZR : UHExp.t -> ZList.t zrule UHExp.rule -> t'
| OpSeqZ : UHExp.skel_t -> t -> OperatorSeq.opseq_surround UHExp.t UHExp.op -> t'
| ApPaletteZ : PaletteName.t ->
PaletteSerializedModel.t ->
(UHExp.PaletteHoleData.hole_ref_lbl * ZNatMap.t (HTyp.t * UHExp.t) (HTyp.t * t)) -> (* = ZPaletteHoleData.t *)
t'
with zrule : Type :=
| RuleZP : ZPat.t -> UHExp.t -> zrule
| RuleZE : UHPat.t -> t -> zrule.
Definition zrules : Type := ZList.t zrule UHExp.rule.
Module ZPaletteHoleData.
Definition z_hole_map : Type := ZNatMap.t (HTyp.t * t) (HTyp.t * ZExp.t).
Definition t : Type := (UHExp.PaletteHoleData.hole_ref_lbl *
ZNatMap.t (HTyp.t * UHExp.t) (HTyp.t * ZExp.t)).
End ZPaletteHoleData.
Definition opseq_surround : Type := OperatorSeq.opseq_surround UHExp.t UHExp.op.
Definition opseq_prefix : Type := OperatorSeq.opseq_prefix UHExp.t UHExp.op.
Definition opseq_suffix : Type := OperatorSeq.opseq_suffix UHExp.t UHExp.op.
Definition bidelimit ze :=
match ze with
| CursorE cursor_side e =>
CursorE cursor_side (UHExp.bidelimit e)
| ParenthesizedZ _
| Deeper _ (InjZ _ _)
| Deeper _ (ApPaletteZ _ _ _)
| Deeper _ (CaseZE _ _)
| Deeper _ (CaseZR _ _)
(* | Deeper _ (ListLitZ _) *)
=> ze
| Deeper _ (AscZ1 _ _)
| Deeper _ (AscZ2 _ _)
| Deeper _ (LetZP _ _ _ _)
| Deeper _ (LetZA _ _ _ _)
| Deeper _ (LetZE1 _ _ _ _)
| Deeper _ (LetZE2 _ _ _ _)
| Deeper _ (LamZP _ _ _)
| Deeper _ (LamZA _ _ _)
| Deeper _ (LamZE _ _ _)
| Deeper _ (OpSeqZ _ _ _) =>
ParenthesizedZ ze
end.
Fixpoint set_inconsistent
(u : MetaVar.t)
(ze : t)
: t :=
match ze with
| CursorE cursor_side e =>
let e' := UHExp.set_inconsistent u e in
(CursorE cursor_side e')
| Deeper _ ze' =>
Deeper (InHole TypeInconsistent u) ze'
| ParenthesizedZ ze1 =>
ParenthesizedZ (set_inconsistent u ze1)
end.
Fixpoint make_inconsistent
(u_gen : MetaVarGen.t)
(ze : t)
: (t * MetaVarGen.t) :=
match ze with
| CursorE cursor_side e =>
let (e', u_gen') := UHExp.make_inconsistent u_gen e in
(CursorE cursor_side e', u_gen')
| Deeper (InHole TypeInconsistent _) _ =>
(ze, u_gen)
| Deeper _ ze' =>
let (u', u_gen') := MetaVarGen.next u_gen in
(Deeper (InHole TypeInconsistent u') ze', u_gen')
| ParenthesizedZ ze1 =>
let (ze1', u_gen') := make_inconsistent u_gen ze1 in
(ParenthesizedZ ze1, u_gen')
end.
Definition new_EmptyHole (u_gen : MetaVarGen.t) :=
let (e, u_gen) := UHExp.new_EmptyHole u_gen in
(CursorE Before e, u_gen).
Fixpoint cursor_on_outer_expr (ze : t) : option(UHExp.t * cursor_side) :=
match ze with
| CursorE side e => Some ((UHExp.drop_outer_parentheses e), side)
| ParenthesizedZ ze' => cursor_on_outer_expr ze'
| Deeper _ _ => None
end.
Definition empty_zrule (u_gen : MetaVarGen.t) : zrule * MetaVarGen.t:=
let (zp, u_gen) := ZPat.new_EmptyHole u_gen in
let (rule_e, u_gen) := UHExp.new_EmptyHole u_gen in
let zrule := ZExp.RuleZP zp rule_e in
(zrule, u_gen).
Fixpoint erase (ze : t) : UHExp.t :=
match ze with
| CursorE _ e => e
| Deeper err_state ze' =>
let e' := erase' ze' in
UHExp.Tm err_state e'
| ParenthesizedZ ze1 =>
UHExp.Parenthesized (erase ze1)
end
with erase' (ze : t') : UHExp.t' :=
match ze with
| AscZ1 ze' ty => (UHExp.Asc (erase ze') ty)
| AscZ2 e' zty => UHExp.Asc e' (ZTyp.erase zty)
| LetZP zp ann e1 e2 => UHExp.Let (ZPat.erase zp) ann e1 e2
| LetZA p zann e1 e2 => UHExp.Let p (Some (ZTyp.erase zann)) e1 e2
| LetZE1 p ann ze e => UHExp.Let p ann (erase ze) e
| LetZE2 p ann e ze => UHExp.Let p ann e (erase ze)
| LamZP zp ann e1 => UHExp.Lam (ZPat.erase zp) ann e1
| LamZA p zann e1 => UHExp.Lam p (Some (ZTyp.erase zann)) e1
| LamZE p ann ze1 => UHExp.Lam p ann (erase ze1)
| InjZ side ze => UHExp.Inj side (erase ze)
(* | ListLitZ zes => UHExp.ListLit (ZList.erase zes erase) *)
| CaseZE ze1 rules => UHExp.Case (erase ze1) rules
| CaseZR e1 zrules => UHExp.Case e1 (ZList.erase zrules erase_rule)
| OpSeqZ skel ze' surround =>
let e := erase ze' in
UHExp.OpSeq skel (OperatorSeq.opseq_of_exp_and_surround e surround)
| ApPaletteZ palette_name serialized_model zhole_data =>
let (next_hole_ref, zholemap) := zhole_data in
let (holemap, z) := zholemap in
let (hole_ref, tz) := z in
let (ty, ze) := tz in
let holemap' := NatMap.extend holemap (hole_ref, (ty, erase ze)) in
let hole_data' := (next_hole_ref, holemap') in
UHExp.ApPalette palette_name serialized_model hole_data'
end
with erase_rule (zr : zrule) : UHExp.rule :=
match zr with
| RuleZP zp e => UHExp.Rule (ZPat.erase zp) e
| RuleZE p ze => UHExp.Rule p (erase ze)
end.
Inductive cursor_mode :=
(* cursor in analytic position *)
| AnaOnly : HTyp.t -> cursor_mode
| AnaAnnotatedLambda : HTyp.t -> HTyp.t -> cursor_mode
| AnaTypeInconsistent : HTyp.t -> HTyp.t -> cursor_mode
| AnaWrongLength :
nat (* expected length *) -> nat (* got length *)
-> HTyp.t (* expected type *) -> cursor_mode
| AnaFree : HTyp.t -> cursor_mode
| AnaSubsumed : HTyp.t -> HTyp.t -> cursor_mode
(* cursor in synthetic position *)
| SynOnly : HTyp.t -> cursor_mode
| SynFree : cursor_mode
| SynErrorArrow : HTyp.t (* expected *) -> HTyp.t (* got *) -> cursor_mode
| SynMatchingArrow : HTyp.t -> HTyp.t -> cursor_mode
| SynFreeArrow : HTyp.t -> cursor_mode
(* cursor in type position *)
| TypePosition : cursor_mode
(* cursor in analytic pattern position *)
| PatAnaOnly : HTyp.t -> cursor_mode
| PatAnaTypeInconsistent : HTyp.t -> HTyp.t -> cursor_mode
| PatAnaWrongLength :
nat (* expected length *) -> nat (* got length *)
-> HTyp.t (* expected type *) -> cursor_mode
| PatAnaSubsumed : HTyp.t -> HTyp.t -> cursor_mode
(* cursor in synthetic pattern position *)
| PatSynOnly : HTyp.t -> cursor_mode.
Inductive cursor_sort :=
| IsExpr : UHExp.t -> cursor_sort
| IsPat : UHPat.t -> cursor_sort
| IsType : cursor_sort.
Record cursor_info : Type := mk_cursor_info {
mode : cursor_mode;
sort : cursor_sort;
side : cursor_side;
ctx : Contexts.t
}.
Definition update_sort (ci : cursor_info) (sort : cursor_sort) : cursor_info :=
let mode := mode ci in
let side := side ci in
let ctx := ctx ci in
mk_cursor_info mode sort side ctx.
Fixpoint ana_pat_cursor_found
(fuel : Fuel.t)
(ctx : Contexts.t)
(p : UHPat.t)
(ty : HTyp.t)
(side : cursor_side)
: option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match p with
| UHPat.Parenthesized p1 =>
match ana_pat_cursor_found fuel ctx p1 ty side with
| None => None
| Some ci =>
Some (update_sort ci (IsPat p))
end
| UHPat.Pat (InHole TypeInconsistent _) p' =>
match UHExp.syn_pat' fuel ctx p' with
| None => None
| Some (ty', _) =>
Some
(mk_cursor_info
(PatAnaTypeInconsistent ty ty')
(IsPat p)
side
ctx)
end
| UHPat.Pat NotInHole (UHPat.EmptyHole _) =>
Some
(mk_cursor_info
(PatAnaSubsumed ty HTyp.Hole)
(IsPat p)
side
ctx)
| UHPat.Pat NotInHole UHPat.Wild
| UHPat.Pat NotInHole (UHPat.Var _) =>
Some
(mk_cursor_info
(PatAnaOnly ty)
(IsPat p)
side
ctx)
| UHPat.Pat NotInHole (UHPat.NumLit _) =>
Some
(mk_cursor_info
(PatAnaSubsumed ty HTyp.Num)
(IsPat p)
side
ctx)
| UHPat.Pat NotInhole (UHPat.BoolLit _) =>
Some
(mk_cursor_info
(PatAnaSubsumed ty HTyp.Bool)
(IsPat p)
side
ctx)
| UHPat.Pat NotInHole (UHPat.Inj _ _) =>
Some
(mk_cursor_info
(PatAnaOnly ty)
(IsPat p)
side
ctx)
| UHPat.Pat NotInHole UHPat.ListNil =>
Some
(mk_cursor_info
(PatAnaOnly ty)
(IsPat p)
side
ctx)
(* | UHPat.Pat NotInHole (UHPat.ListLit _) =>
Some
(mk_cursor_info
(PatAnaOnly ty)
(IsPat p)
side
ctx) *)
| UHPat.Pat NotInHole (UHPat.OpSeq (Skel.BinOp NotInHole Comma skel1 skel2) seq) =>
Some
(mk_cursor_info
(PatAnaOnly ty)
(IsPat p)
side
ctx)
| UHPat.Pat (InHole WrongLength _) (UHPat.OpSeq (Skel.BinOp (InHole WrongLength _) Comma skel1 skel2) _) =>
match ty with
| HTyp.Prod ty1 ty2 =>
let n_elts := List.length (UHPat.get_tuple skel1 skel2) in
let n_types := List.length (HTyp.get_tuple ty1 ty2) in
Some
(mk_cursor_info
(PatAnaWrongLength n_types n_elts ty)
(IsPat p)
side
ctx)
| _ => None
end
| UHPat.Pat (InHole WrongLength _) _ => None
| UHPat.Pat NotInHole (UHPat.OpSeq (Skel.BinOp (InHole _ _) Comma skel1 skel2) seq) => None
| UHPat.Pat NotInHole (UHPat.OpSeq (Skel.Placeholder _ _) _) => None
end
end.
Fixpoint syn_pat_cursor_info
(fuel : Fuel.t)
(ctx : Contexts.t)
(zp : ZPat.t)
: option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match zp with
| ZPat.CursorP side p =>
match UHExp.syn_pat fuel ctx p with
| None => None
| Some (ty, _) =>
Some
(mk_cursor_info
(PatSynOnly ty)
(IsPat p)
side
ctx)
end
| ZPat.Deeper _ zp' =>
syn_pat_cursor_info' fuel ctx zp'
| ZPat.ParenthesizedZ zp1 =>
syn_pat_cursor_info fuel ctx zp1
end
end
with syn_pat_cursor_info'
(fuel : Fuel.t)
(ctx : Contexts.t)
(zp' : ZPat.t')
: option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match zp' with
| ZPat.InjZ side zp1 => syn_pat_cursor_info fuel ctx zp1
(* | ZPat.ListLitZ ((prefix, zp), _) =>
match prefix with
| nil => syn_pat_cursor_info fuel ctx zp
| cons _ _ =>
let opt_result := List.fold_left (fun opt_result p =>
match opt_result with
| None => None
| Some (ty, ctx) =>
match UHExp.syn_pat fuel ctx p with
| Some (ty', ctx) =>
match HTyp.join ty ty' with
| Some ty_joined => Some (ty_joined, ctx)
| None =>
match UHExp.ana_pat fuel ctx p ty with
| None => None
| Some ctx => Some (ty, ctx)
end
end
| None =>
match UHExp.ana_pat fuel ctx p ty with
| None => None
| Some ctx => Some (ty, ctx)
end
end
end) prefix (Some (HTyp.Hole, ctx)) in
match opt_result with
| None => None
| Some (ty, ctx) => ana_pat_cursor_info fuel ctx zp ty
end
end *)
| ZPat.OpSeqZ skel zp1 surround =>
let p1 := ZPat.erase zp1 in
let seq := OperatorSeq.opseq_of_exp_and_surround p1 surround in
let n := OperatorSeq.surround_prefix_length surround in
syn_skel_pat_cursor_info fuel ctx skel seq n zp1
end
end
with syn_skel_pat_cursor_info
(fuel : Fuel.t)
(ctx : Contexts.t)
(skel : UHPat.skel_t)
(seq : UHPat.opseq)
(n : nat)
(zp1 : ZPat.t)
: option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n' =>
if Nat.eqb n n' then
syn_pat_cursor_info fuel ctx zp1
else None
| Skel.BinOp _ UHPat.Comma skel1 skel2 =>
match syn_skel_pat_cursor_info fuel ctx skel1 seq n zp1 with
| (Some _) as result => result
| None => syn_skel_pat_cursor_info fuel ctx skel2 seq n zp1
end
| Skel.BinOp _ UHPat.Space skel1 skel2 =>
match syn_skel_pat_cursor_info fuel ctx skel1 seq n zp1 with
| (Some _) as result => result
| None => syn_skel_pat_cursor_info fuel ctx skel2 seq n zp1
end
| Skel.BinOp _ UHPat.Cons skel1 skel2 =>
match syn_skel_pat_cursor_info fuel ctx skel1 seq n zp1 with
| (Some _) as result => result
| None =>
match UHExp.syn_skel_pat fuel ctx skel1 seq None with
| None => None
| Some (ty_elt, ctx, _) =>
let list_ty := HTyp.List ty_elt in
ana_skel_pat_cursor_info fuel ctx skel2 seq n zp1 list_ty
end
end
end
end
with ana_pat_cursor_info
(fuel : Fuel.t)
(ctx : Contexts.t)
(zp : ZPat.t)
(ty : HTyp.t)
: option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match zp with
| ZPat.CursorP side p =>
ana_pat_cursor_found fuel ctx p ty side
| ZPat.Deeper (InHole TypeInconsistent u) zp' =>
syn_pat_cursor_info' fuel ctx zp'
| ZPat.Deeper NotInHole zp'
| ZPat.Deeper (InHole WrongLength _) ((ZPat.OpSeqZ (Skel.BinOp _ UHPat.Comma _ _) _ _) as zp') =>
ana_pat_cursor_info' fuel ctx zp' ty
| ZPat.Deeper (InHole WrongLength _) _ => None
| ZPat.ParenthesizedZ zp =>
ana_pat_cursor_info fuel ctx zp ty
end
end
with ana_pat_cursor_info'
(fuel : Fuel.t)
(ctx : Contexts.t)
(zp' : ZPat.t')
(ty : HTyp.t)
: option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match zp' with
| ZPat.InjZ side zp1 =>
match HTyp.matched_sum ty with
| None => None
| Some (tyL, tyR) =>
let ty1 := pick_side side tyL tyR in
ana_pat_cursor_info fuel ctx zp1 ty1
end
(* | ZPat.ListLitZ zps =>
match HTyp.matched_list ty with
| None => None
| Some ty_elt =>
let zp := ZList.prj_z zps in
ana_pat_cursor_info fuel ctx zp ty_elt
end *)
| ZPat.OpSeqZ skel zp1 surround =>
let p1 := ZPat.erase zp1 in
let seq := OperatorSeq.opseq_of_exp_and_surround p1 surround in
let n := OperatorSeq.surround_prefix_length surround in
ana_skel_pat_cursor_info fuel ctx skel seq n zp1 ty
end
end
with ana_skel_pat_cursor_info
(fuel : Fuel.t)
(ctx : Contexts.t)
(skel : UHPat.skel_t)
(seq : UHPat.opseq)
(n : nat)
(zp1 : ZPat.t)
(ty : HTyp.t)
: option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n' =>
if Nat.eqb n n' then
ana_pat_cursor_info fuel ctx zp1 ty
else None
| Skel.BinOp (InHole TypeInconsistent _) _ skel1 skel2 =>
syn_skel_pat_cursor_info fuel ctx skel seq n zp1
| Skel.BinOp NotInHole UHPat.Comma skel1 skel2 =>
match ty with
| HTyp.Hole =>
match ana_skel_pat_cursor_info fuel ctx skel1 seq n zp1 HTyp.Hole with
| (Some _) as result => result
| None => ana_skel_pat_cursor_info fuel ctx skel2 seq n zp1 HTyp.Hole
end
| HTyp.Prod ty1 ty2 =>
let types := HTyp.get_tuple ty1 ty2 in
let skels := UHPat.get_tuple skel1 skel2 in
match Util.zip_eq skels types with
| None => None
| Some zipped =>
List.fold_left (fun opt_result (skel_ty : UHPat.skel_t * HTyp.t) =>
match opt_result with
| (Some _) as result => result
| None =>
let (skel, ty) := skel_ty in
ana_skel_pat_cursor_info fuel ctx skel seq n zp1 ty
end) zipped None
end
| _ => None
end
| Skel.BinOp (InHole WrongLength _) UHPat.Comma skel1 skel2 =>
match ty with
| HTyp.Prod ty1 ty2 =>
let types := HTyp.get_tuple ty1 ty2 in
let skels := UHPat.get_tuple skel1 skel2 in
let (zipped, remainder) := HTyp.zip_with_skels skels types in
let ana_zipped :=
List.fold_left (fun opt_result (skel_ty : UHPat.skel_t * HTyp.t) =>
match opt_result with
| (Some _) as result => result
| None =>
let (skel, ty) := skel_ty in
ana_skel_pat_cursor_info fuel ctx skel seq n zp1 ty
end) zipped None in
match ana_zipped with
| (Some _) as result => result
| None =>
List.fold_left (fun opt_result skel =>
match opt_result with
| (Some _) as result => result
| None => syn_skel_pat_cursor_info fuel ctx skel seq n zp1
end) remainder None
end
| _ => None
end
| Skel.BinOp (InHole WrongLength _) _ _ _ => None
| Skel.BinOp NotInHole UHPat.Cons skel1 skel2 =>
match HTyp.matched_list ty with
| None => None
| Some ty_elt =>
match ana_skel_pat_cursor_info fuel ctx skel1 seq n zp1 ty_elt with
| (Some _) as result => result
| None =>
let ty_list := HTyp.List ty_elt in
ana_skel_pat_cursor_info fuel ctx skel2 seq n zp1 ty_list
end
end
| Skel.BinOp NotInHole UHPat.Space _ _ =>
syn_skel_pat_cursor_info fuel ctx skel seq n zp1
end
end.
Fixpoint ana_cursor_found
(fuel : Fuel.t) (ctx : Contexts.t)
(e : UHExp.t) (ty : HTyp.t)
(side : cursor_side)
: option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match e with
| UHExp.Parenthesized e' =>
match ana_cursor_found fuel ctx e' ty side with
| None => None
| Some ci =>
Some (update_sort ci (IsExpr e))
end
| UHExp.Tm (InHole TypeInconsistent _) (UHExp.OpSeq (Skel.BinOp _ op skel1 skel2) surround) =>
let e' := UHExp.OpSeq (Skel.BinOp NotInHole op skel1 skel2) surround in
match UHExp.syn' fuel ctx e' with
| None => None
| Some ty' =>
Some
(mk_cursor_info
(AnaTypeInconsistent ty ty')
(IsExpr e)
side
ctx)
end
| UHExp.Tm (InHole TypeInconsistent _) e' =>
match UHExp.syn' fuel ctx e' with
| None => None
| Some ty' =>
Some (
mk_cursor_info
(AnaTypeInconsistent ty ty')
(IsExpr e)
side
ctx
)
end
| UHExp.Tm _ (UHExp.Var (InVHole _) _) =>
Some (
mk_cursor_info
(AnaFree ty)
(IsExpr e)
side
ctx
)
| UHExp.Tm NotInHole (UHExp.Let _ _ _ _)
| UHExp.Tm NotInHole (UHExp.Case _ _)
| UHExp.Tm NotInHole UHExp.ListNil
(* | UHExp.Tm NotInHole (UHExp.ListLit _) *) =>
Some (
mk_cursor_info
(AnaOnly ty)
(IsExpr e)
side
ctx
)
| UHExp.Tm NotInHole (UHExp.OpSeq (Skel.BinOp NotInHole UHExp.Comma _ _) surround)
| UHExp.Tm NotInHole (UHExp.OpSeq (Skel.BinOp NotInHole UHExp.Cons _ _) surround) =>
Some
(mk_cursor_info
(AnaOnly ty)
(IsExpr e)
side
ctx)
| UHExp.Tm (InHole WrongLength _) (UHExp.OpSeq (Skel.BinOp (InHole WrongLength _) UHExp.Comma skel1 skel2) _) =>
match ty with
| HTyp.Prod ty1 ty2 =>
let n_elts := List.length (UHExp.get_tuple skel1 skel2) in
let n_types := List.length (HTyp.get_tuple ty1 ty2) in
Some (mk_cursor_info
(AnaWrongLength n_types n_elts ty)
(IsExpr e)
side
ctx)
| _ => None
end
| UHExp.Tm (InHole WrongLength _) _ => None
| UHExp.Tm NotInHole (UHExp.OpSeq (Skel.BinOp (InHole WrongLength _) _ _ _) _) => None
| UHExp.Tm NotInHole (UHExp.OpSeq (Skel.BinOp NotInHole UHExp.Plus _ _) _)
| UHExp.Tm NotInHole (UHExp.OpSeq (Skel.BinOp NotInHole UHExp.Times _ _) _)
| UHExp.Tm NotInHole (UHExp.OpSeq (Skel.BinOp NotInHole UHExp.LessThan _ _) _)
| UHExp.Tm NotInHole (UHExp.OpSeq (Skel.BinOp NotInHole UHExp.Space _ _) _)
| UHExp.Tm NotInHole (UHExp.EmptyHole _)
| UHExp.Tm NotInHole (UHExp.Asc _ _)
| UHExp.Tm NotInHole (UHExp.Var NotInVHole _)
| UHExp.Tm NotInHole (UHExp.NumLit _)
| UHExp.Tm NotInHole (UHExp.BoolLit _)
| UHExp.Tm NotInHole (UHExp.ApPalette _ _ _) =>
match UHExp.syn fuel ctx e with
| Some ty' =>
if HTyp.consistent ty ty' then
Some (
mk_cursor_info
(AnaSubsumed ty ty')
(IsExpr e)
side
ctx
)
else None
| None => None
end
| UHExp.Tm NotInHole (UHExp.Lam _ ann _) =>
match HTyp.matched_arrow ty with
| None => None
| Some (ty1_given, ty2) =>
match ann with
| Some uty1 =>
let ty1_ann := UHTyp.expand fuel uty1 in
match HTyp.consistent ty1_ann ty1_given with
| false => None
| true =>
Some
(mk_cursor_info
(AnaAnnotatedLambda
ty
(HTyp.Arrow ty1_ann ty2))
(IsExpr e)
side
ctx)
end
| None =>
Some
(mk_cursor_info
(AnaOnly ty)
(IsExpr e)
side
ctx)
end
end
| UHExp.Tm NotInHole (UHExp.Inj _ _) =>
match ty with
| HTyp.Sum _ _ =>
Some (
mk_cursor_info
(AnaOnly ty)
(IsExpr e)
side
ctx
)
| _ => None
end
| UHExp.Tm NotInHole (UHExp.OpSeq (Skel.BinOp (InHole TypeInconsistent _) _ _ _) surround) => None
| UHExp.Tm NotInHole (UHExp.OpSeq (Skel.Placeholder _ _) surround) => None
end
end.
Fixpoint syn_cursor_info
(fuel : Fuel.t) (ctx : Contexts.t)
(ze : t) : option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match ze with
| CursorE side (UHExp.Tm _ (UHExp.Var (InVHole _) _) as e) =>
Some (
mk_cursor_info
SynFree
(IsExpr e)
side
ctx
)
| CursorE side e =>
match UHExp.syn fuel ctx e with
| Some ty =>
Some (
mk_cursor_info
(SynOnly ty)
(IsExpr e)
side
ctx
)
| None => None
end
| ParenthesizedZ ze1 =>
syn_cursor_info fuel ctx ze1
| Deeper _ ze1' =>
syn_cursor_info' fuel ctx ze1'
end
end
with ana_cursor_info
(fuel : Fuel.t) (ctx : Contexts.t)
(ze : t) (ty : HTyp.t) : option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match ze with
| CursorE side e =>
ana_cursor_found fuel ctx e ty side
| ParenthesizedZ ze1 =>
ana_cursor_info fuel ctx ze1 ty
| Deeper (InHole TypeInconsistent u) ze1' =>
syn_cursor_info' fuel ctx ze1'
| Deeper (InHole WrongLength _) ((ZExp.OpSeqZ (Skel.BinOp _ UHExp.Comma _ _) _ _) as ze1')
| Deeper NotInHole ze1' =>
ana_cursor_info' fuel ctx ze1' ty
| Deeper (InHole WrongLength _) _ => None
end
end
with syn_cursor_info'
(fuel : Fuel.t) (ctx : Contexts.t)
(ze : t') : option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match ze with
| AscZ1 ze1 uty =>
let ty := UHTyp.expand fuel uty in
let e1 := erase ze1 in
if UHExp.bidelimited e1 then
ana_cursor_info fuel ctx ze1 ty
else None
| AscZ2 e1 zty =>
Some
(mk_cursor_info
TypePosition
IsType
Before (* TODO fix this once we use cursor info in type position! *)
ctx)
| LetZP zp ann e1 e2 =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
ana_pat_cursor_info fuel ctx zp ty1
| None =>
match UHExp.syn fuel ctx e1 with
| None => None
| Some ty1 => ana_pat_cursor_info fuel ctx zp ty1
end
end
| LetZA p zann e1 e2 =>
Some
(mk_cursor_info
TypePosition
IsType
Before (* TODO fix this once we use cursor info in type position! *)
ctx)
| LetZE1 p ann ze1 e2 =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
let ctx1 := UHExp.ctx_for_let ctx p ty1 (erase ze1) in
ana_cursor_info fuel ctx1 ze1 ty1
| None => syn_cursor_info fuel ctx ze1
end
| LetZE2 p ann e1 ze2 =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
match UHExp.ana_pat fuel ctx p ty1 with
| None => None
| Some ctx2 =>
syn_cursor_info fuel ctx2 ze2
end
| None =>
match UHExp.syn fuel ctx e1 with
| None => None
| Some ty1 =>
match UHExp.ana_pat fuel ctx p ty1 with
| None => None
| Some ctx2 =>
syn_cursor_info fuel ctx2 ze2
end
end
end
| LamZP zp ann _ =>
let ty1 :=
match ann with
| Some uty1 => UHTyp.expand fuel uty1
| None => HTyp.Hole
end in
ana_pat_cursor_info fuel ctx zp ty1
| LamZA _ zann _ =>
Some
(mk_cursor_info
TypePosition
IsType
Before (* TODO fix this once we use cursor info in type position *)
ctx)
| LamZE p ann ze1 =>
let ty1 :=
match ann with
| Some uty1 => UHTyp.expand fuel uty1
| None => HTyp.Hole
end in
match UHExp.ana_pat fuel ctx p ty1 with
| None => None
| Some ctx1 =>
syn_cursor_info fuel ctx1 ze1
end
| InjZ side ze1 =>
syn_cursor_info fuel ctx ze1
(* | ListLitZ ((prefix, ze), _) =>
match prefix with
| nil => syn_cursor_info fuel ctx ze
| cons _ _ =>
let opt_result := List.fold_left (fun opt_result e =>
match opt_result with
| None => None
| Some ty =>
match UHExp.syn fuel ctx e with
| None => None
| Some ty' =>
match HTyp.join ty ty' with
| Some ty_joined => Some ty_joined
| None =>
match UHExp.ana fuel ctx e ty with
| None => None
| Some _ => Some ty
end
end
end
end) prefix (Some HTyp.Hole) in
match opt_result with
| None => None
| Some ty => ana_cursor_info fuel ctx ze ty
end
end *)
| CaseZE _ _
| CaseZR _ _ => None
| OpSeqZ skel ze0 surround =>
let e0 := erase ze0 in
let seq := OperatorSeq.opseq_of_exp_and_surround e0 surround in
let n := OperatorSeq.surround_prefix_length surround in
syn_skel_cursor_info fuel ctx skel seq n ze0
| ApPaletteZ _ _ zholedata =>
let (_, zholemap) := zholedata in
let (_, tz) := zholemap in
let (_, tz') := tz in
let (ty, ze) := tz' in
ana_cursor_info fuel ctx ze ty
end
end
with ana_cursor_info'
(fuel : Fuel.t) (ctx : Contexts.t)
(ze : t') (ty : HTyp.t) : option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match ze with
| LetZP zp ann e1 e2 =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
ana_pat_cursor_info fuel ctx zp ty1
| None =>
match UHExp.syn fuel ctx e1 with
| None => None
| Some ty1 =>
ana_pat_cursor_info fuel ctx zp ty1
end
end
| LetZA _ zann e1 e2 =>
Some
(mk_cursor_info
TypePosition
IsType
Before (* TODO fix this once we use cursor info in type position! *)
ctx)
| LetZE1 p ann ze1 e2 =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
let ctx1 := UHExp.ctx_for_let ctx p ty1 (erase ze1) in
ana_cursor_info fuel ctx1 ze1 ty1
| None => syn_cursor_info fuel ctx ze1
end
| LetZE2 p ann e1 ze2 =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
match UHExp.ana_pat fuel ctx p ty1 with
| None => None
| Some ctx2 =>
ana_cursor_info fuel ctx2 ze2 ty
end
| None =>
match UHExp.syn fuel ctx e1 with
| None => None
| Some ty1 =>
match UHExp.ana_pat fuel ctx p ty1 with
| None => None
| Some ctx2 =>
ana_cursor_info fuel ctx2 ze2 ty
end
end
end
| LamZP p ann e =>
match HTyp.matched_arrow ty with
| None => None
| Some (ty1_given, ty2) =>
let ty1 :=
match ann with
| Some uty1 => UHTyp.expand fuel uty1
| None => ty1_given
end in
ana_pat_cursor_info fuel ctx p ty1
end
| LamZA _ zann _ =>
Some
(mk_cursor_info
TypePosition
IsType
Before (* TODO fix this once we use cursor info in type position *)
ctx)
| LamZE p ann ze1 =>
match HTyp.matched_arrow ty with
| None => None
| Some (ty1_given, ty2) =>
let ty1 :=
match ann with
| Some uty1 => UHTyp.expand fuel uty1
| None => ty1_given
end in
match UHExp.ana_pat fuel ctx p ty1 with
| None => None
| Some ctx =>
ana_cursor_info fuel ctx ze1 ty2
end
end
| InjZ side ze1 =>
match HTyp.matched_sum ty with
| None => None
| Some (ty1, ty2) =>
ana_cursor_info fuel ctx ze1
(pick_side side ty1 ty2)
end
(* | ListLitZ zes =>
match HTyp.matched_list ty with
| None => None
| Some ty_elt =>
let ze0 := ZList.prj_z zes in
ana_cursor_info fuel ctx ze0 ty_elt
end *)
| CaseZE ze1 rules =>
syn_cursor_info fuel ctx ze1
| CaseZR e1 zrules =>
match UHExp.syn fuel ctx e1 with
| None => None
| Some ty1 =>
let zrule := ZList.prj_z zrules in
ana_rule_cursor_info fuel ctx zrule ty1 ty
end
| OpSeqZ skel ze0 surround =>
let e0 := erase ze0 in
let seq := OperatorSeq.opseq_of_exp_and_surround e0 surround in
let n := OperatorSeq.surround_prefix_length surround in
ana_skel_cursor_info fuel ctx skel seq n ze0 ty
| AscZ1 _ _
| AscZ2 _ _
| ApPaletteZ _ _ _ =>
syn_cursor_info' fuel ctx ze
end
end
with ana_rule_cursor_info
(fuel : Fuel.t)
(ctx : Contexts.t)
(zrule : ZExp.zrule)
(pat_ty : HTyp.t)
(clause_ty : HTyp.t)
: option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match zrule with
| RuleZP zp e =>
ana_pat_cursor_info fuel ctx zp pat_ty
| RuleZE p ze =>
match UHExp.ana_pat fuel ctx p pat_ty with
| None => None
| Some ctx =>
ana_cursor_info fuel ctx ze clause_ty
end
end
end
with syn_skel_cursor_info
(fuel : Fuel.t) (ctx : Contexts.t)
(skel : UHExp.skel_t) (seq : UHExp.opseq)
(n : nat) (ze_n : ZExp.t) : option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n' =>
if Nat.eqb n n' then
syn_cursor_info fuel ctx ze_n
else None
| Skel.BinOp _ UHExp.Plus skel1 skel2
| Skel.BinOp _ UHExp.Times skel1 skel2
| Skel.BinOp _ UHExp.LessThan skel1 skel2 =>
match ana_skel_cursor_info fuel ctx skel1 seq n ze_n HTyp.Num with
| (Some _) as result => result
| None =>
match ana_skel_cursor_info fuel ctx skel2 seq n ze_n HTyp.Num with
| (Some _) as result => result
| None => None
end
end
| Skel.BinOp _ UHExp.Space ((Skel.Placeholder _ n') as skel1) skel2 =>
if Nat.eqb n n' then
match cursor_on_outer_expr ze_n with
| Some ((UHExp.Tm (InHole TypeInconsistent u) e_n') as e_n, side) =>
match UHExp.syn' fuel ctx e_n' with
| Some ty => Some
(mk_cursor_info
(SynErrorArrow (HTyp.Arrow HTyp.Hole HTyp.Hole) ty)
(IsExpr e_n)
side
ctx)
| None => None
end
| Some (((UHExp.Tm _ (UHExp.Var (InVHole _) _)) as e_n), side) =>
Some
(mk_cursor_info
(SynFreeArrow (HTyp.Arrow HTyp.Hole HTyp.Hole))
(IsExpr e_n)
side
ctx)
| Some (e_n, side) =>
match UHExp.syn fuel ctx e_n with
| Some ty =>
match HTyp.matched_arrow ty with
| Some (ty1, ty2) =>
Some
(mk_cursor_info
(SynMatchingArrow ty (HTyp.Arrow ty1 ty2))
(IsExpr e_n)
side
ctx)
| None => None
end
| None => None
end
| None =>
syn_cursor_info fuel ctx ze_n
end
else
match UHExp.syn_skel fuel ctx skel1 seq None with
| None => None
| Some (ty, _) =>
match HTyp.matched_arrow ty with
| Some (ty1, ty2) =>
ana_skel_cursor_info fuel ctx skel2 seq n ze_n ty1
| None => None
end
end
| Skel.BinOp _ UHExp.Space skel1 skel2 =>
match syn_skel_cursor_info fuel ctx skel1 seq n ze_n with
| (Some _) as result => result
| None =>
match UHExp.syn_skel fuel ctx skel1 seq None with
| None => None
| Some (ty, _) =>
match HTyp.matched_arrow ty with
| None => None
| Some (ty1, ty2) =>
ana_skel_cursor_info fuel ctx skel2 seq n ze_n ty2
end
end
end
| Skel.BinOp _ UHExp.Comma skel1 skel2 =>
match syn_skel_cursor_info fuel ctx skel1 seq n ze_n with
| (Some _) as result => result
| None => syn_skel_cursor_info fuel ctx skel2 seq n ze_n
end
| Skel.BinOp _ UHExp.Cons skel1 skel2 =>
match syn_skel_cursor_info fuel ctx skel1 seq n ze_n with
| (Some _) as result => result
| None =>
match UHExp.syn_skel fuel ctx skel1 seq None with
| None => None
| Some (ty_elt, _) =>
let ty_list := HTyp.List ty_elt in
ana_skel_cursor_info fuel ctx skel2 seq n ze_n ty_list
end
end
end
end
with ana_skel_cursor_info
(fuel : Fuel.t) (ctx : Contexts.t)
(skel : UHExp.skel_t) (seq : UHExp.opseq)
(n : nat) (ze_n : t) (ty : HTyp.t) : option(cursor_info) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n' =>
if Nat.eqb n n' then
ana_cursor_info fuel ctx ze_n ty
else None
| Skel.BinOp (InHole TypeInconsistent _) _ _ _ =>
syn_skel_cursor_info fuel ctx skel seq n ze_n
| Skel.BinOp NotInHole UHExp.Comma skel1 skel2 =>
match ty with
| HTyp.Hole =>
match ana_skel_cursor_info fuel ctx skel1 seq n ze_n HTyp.Hole with
| (Some _) as result => result
| None => ana_skel_cursor_info fuel ctx skel2 seq n ze_n HTyp.Hole
end
| HTyp.Prod ty1 ty2 =>
let types := HTyp.get_tuple ty1 ty2 in
let skels := UHExp.get_tuple skel1 skel2 in
match Util.zip_eq skels types with
| None => None
| Some zipped =>
List.fold_left (fun opt_result (skel_ty : UHExp.skel_t * HTyp.t) =>
match opt_result with
| (Some _) as result => result
| None =>
let (skel, ty) := skel_ty in
ana_skel_cursor_info fuel ctx skel seq n ze_n ty
end) zipped None
end
| _ => None
end
| Skel.BinOp (InHole WrongLength _) UHExp.Comma skel1 skel2 =>
match ty with
| HTyp.Prod ty1 ty2 =>
let types := HTyp.get_tuple ty1 ty2 in
let skels := UHExp.get_tuple skel1 skel2 in
let (zipped, remainder) := HTyp.zip_with_skels skels types in
let ana_zipped :=
List.fold_left (fun opt_result (skel_ty : UHExp.skel_t * HTyp.t) =>
match opt_result with
| (Some _) as result => result
| None =>
let (skel, ty) := skel_ty in
ana_skel_cursor_info fuel ctx skel seq n ze_n ty
end) zipped None in
match ana_zipped with
| (Some _) as result => result
| None =>
List.fold_left (fun opt_result skel =>
match opt_result with
| (Some _) as result => result
| None => syn_skel_cursor_info fuel ctx skel seq n ze_n
end) remainder None
end
| _ => None
end
| Skel.BinOp (InHole WrongLength _) _ _ _ => None
| Skel.BinOp NotInHole UHExp.Cons skel1 skel2 =>
match HTyp.matched_list ty with
| None => None
| Some ty_elt =>
match ana_skel_cursor_info fuel ctx skel1 seq n ze_n ty_elt with
| (Some _) as result => result
| None =>
let ty_list := HTyp.List ty_elt in
ana_skel_cursor_info fuel ctx skel2 seq n ze_n ty_list
end
end
| Skel.BinOp _ UHExp.Plus _ _
| Skel.BinOp _ UHExp.Times _ _
| Skel.BinOp _ UHExp.LessThan _ _
| Skel.BinOp _ UHExp.Space _ _ =>
syn_skel_cursor_info fuel ctx skel seq n ze_n
end
end.
End ZExp.
Module Path.
Definition t : Type := list(nat) * ZExp.cursor_side.
Definition cons' (step : nat) (r : t) : t :=
match r with (steps, side) => (cons step steps, side) end.
Fixpoint of_ztyp (zty : ZTyp.t) : t :=
match zty with
| ZTyp.CursorT cursor_side _ => (nil, cursor_side)
| ZTyp.ParenthesizedZ zty1 => cons' O (of_ztyp zty1)
| ZTyp.ListZ zty1 => cons' O (of_ztyp zty1)
| ZTyp.OpSeqZ _ zty1 surround =>
let n := OperatorSeq.surround_prefix_length surround in
cons' n (of_ztyp zty1)
end.
Fixpoint of_zpat (zp : ZPat.t) : t :=
match zp with
| ZPat.CursorP cursor_side _ => (nil, cursor_side)
| ZPat.Deeper _ zp' => of_zpat' zp'
| ZPat.ParenthesizedZ zp1 => cons' 0 (of_zpat zp1)
end
with of_zpat' (zp' : ZPat.t') : t :=
match zp' with
| ZPat.InjZ _ zp1 => cons' 0 (of_zpat zp1)
(* | ZPat.ListLitZ zps =>
let prefix_length := ZList.prefix_length zps in
let zp0 := ZList.prj_z zps in
cons' prefix_length (of_zpat zp0) *)
| ZPat.OpSeqZ _ zp1 surround =>
let n := OperatorSeq.surround_prefix_length surround in
cons' n (of_zpat zp1)
end.
Fixpoint of_zexp (ze : ZExp.t) : t :=
match ze with
| ZExp.CursorE cursor_side _ => (nil, cursor_side)
| ZExp.Deeper _ ze' => of_zexp' ze'
| ZExp.ParenthesizedZ ze1 => cons' O (of_zexp ze1)
end
with of_zexp' (ze : ZExp.t') : t :=
match ze with
| ZExp.AscZ1 ze' _ => cons' O (of_zexp ze')
| ZExp.AscZ2 _ zty => cons' 1 (of_ztyp zty)
| ZExp.LetZP zp _ _ _ => cons' O (of_zpat zp)
| ZExp.LetZA _ zann _ _ => cons' 1 (of_ztyp zann)
| ZExp.LetZE1 _ _ ze1 _ => cons' 2 (of_zexp ze1)
| ZExp.LetZE2 _ _ _ ze2 => cons' 3 (of_zexp ze2)
| ZExp.LamZP zp _ _ => cons' O (of_zpat zp)
| ZExp.LamZA _ zann _ => cons' 1 (of_ztyp zann)
| ZExp.LamZE _ ann ze' => cons' 2 (of_zexp ze')
| ZExp.InjZ _ ze' => cons' O (of_zexp ze')
(* | ZExp.ListLitZ zes =>
let prefix_length := ZList.prefix_length zes in
let ze0 := ZList.prj_z zes in
cons' prefix_length (of_zexp ze0) *)
| ZExp.CaseZE ze1 _ => cons' O (of_zexp ze1)
| ZExp.CaseZR _ zrules =>
let prefix_len := List.length (ZList.prj_prefix zrules) in
let zrule := ZList.prj_z zrules in
cons' (S prefix_len) (of_zrule zrule)
| ZExp.OpSeqZ _ ze' surround =>
let n := OperatorSeq.surround_prefix_length surround in
cons' n (of_zexp ze')
| ZExp.ApPaletteZ _ _ zholedata =>
let (_, zholemap) := zholedata in
let (_, tz) := zholemap in
let (n, tz') := tz in
let (_, ze') := tz' in
cons' n (of_zexp ze')
end
with of_zrule (zrule : ZExp.zrule) : t :=
match zrule with
| ZExp.RuleZP zp _ => cons' O (of_zpat zp)
| ZExp.RuleZE _ ze => cons' 1 (of_zexp ze)
end.
Definition of_OpSeqZ (ze : ZExp.t) (surround : ZExp.opseq_surround) :=
let n := OperatorSeq.surround_prefix_length surround in
cons' n (of_zexp ze).
Definition of_OpSeqZ_pat (zp : ZPat.t) (surround : ZPat.opseq_surround) :=
let n := OperatorSeq.surround_prefix_length surround in
cons' n (of_zpat zp).
Fixpoint follow_ty (fuel : Fuel.t) (path : t) (uty : UHTyp.t) : option(ZTyp.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match path with
| (nil, cursor_side) => Some (ZTyp.CursorT cursor_side uty)
| (cons x xs, cursor_side) =>
match uty with
| UHTyp.Hole
| UHTyp.Unit
| UHTyp.Num
| UHTyp.Bool => None
| UHTyp.Parenthesized uty1 =>
match x with
| O =>
match follow_ty fuel (xs, cursor_side) uty1 with
| Some zty => Some (ZTyp.ParenthesizedZ zty)
| None => None
end
| _ => None
end
| UHTyp.List uty1 =>
match x with
| O =>
match follow_ty fuel (xs, cursor_side) uty1 with
| None => None
| Some zty => Some (ZTyp.ListZ zty)
end
| _ => None
end
| UHTyp.OpSeq skel seq =>
match OperatorSeq.split x seq with
| Some (uty_n, surround) =>
match follow_ty fuel (xs, cursor_side) uty_n with
| Some zty_n =>
Some (ZTyp.OpSeqZ skel zty_n surround)
| None => None
end
| None => None
end
end
end
end.
Fixpoint follow_pat (fuel : Fuel.t) (path : t) (p : UHPat.t) : option(ZPat.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
let follow_pat := follow_pat fuel in
match path with
| (nil, cursor_side) => Some (ZPat.CursorP cursor_side p)
| (cons x xs, cursor_side) =>
match p with
| UHPat.Parenthesized p1 =>
match x with
| 0 =>
match follow_pat (xs, cursor_side) p1 with
| None => None
| Some zp1 => Some (ZPat.ParenthesizedZ zp1)
end
| _ => None
end
| UHPat.Pat err_status p' =>
match (x, p') with
| (_, UHPat.EmptyHole _)
| (_, UHPat.Wild)
| (_, UHPat.Var _)
| (_, UHPat.NumLit _)
| (_, UHPat.BoolLit _)
| (_, UHPat.ListNil) => None
(* | (n, UHPat.ListLit ps) =>
match ZList.split_at n ps with
| None => None
| Some psz =>
match ZList.optmap_z (follow_pat (xs, cursor_side)) psz with
| None => None
| Some zps =>
Some (ZPat.Deeper err_status (ZPat.ListLitZ zps))
end
end *)
| (0, UHPat.Inj side p1) =>
match follow_pat (xs, cursor_side) p1 with
| None => None
| Some zp1 => Some (ZPat.Deeper err_status (ZPat.InjZ side zp1))
end
| (_, UHPat.Inj _ _) => None
| (n, UHPat.OpSeq skel seq) =>
match OperatorSeq.split n seq with
| None => None
| Some (p, surround) =>
match follow_pat (xs, cursor_side) p with
| Some zp =>
Some (ZPat.Deeper err_status (ZPat.OpSeqZ skel zp surround))
| None => None
end
end
end
end
end
end.
Fixpoint follow_e (fuel : Fuel.t) (path : t) (e : UHExp.t) : option(ZExp.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
let follow_e := follow_e fuel in
match path with
| (nil, cursor_side) => Some (ZExp.CursorE cursor_side e)
| (cons x xs, cursor_side) =>
match e with
| UHExp.Parenthesized e1 =>
match x with
| O =>
match follow_e (xs, cursor_side) e1 with
| Some ze1 => Some (ZExp.ParenthesizedZ ze1)
| None => None
end
| _ => None
end
| UHExp.Tm err_status e =>
match (x, e) with
| (_, UHExp.EmptyHole _) => None
| (O, UHExp.Asc e1 ty) =>
match follow_e (xs, cursor_side) e1 with
| Some ze => Some (ZExp.Deeper err_status (ZExp.AscZ1 ze ty))
| None => None
end
| (1, UHExp.Asc e1 ty) =>
match follow_ty fuel (xs, cursor_side) ty with
| Some ztau => Some (ZExp.Deeper err_status (ZExp.AscZ2 e1 ztau))
| None => None
end
| (_, UHExp.Asc _ _) => None
| (_, UHExp.Var _ _) => None
| (O, UHExp.Let p ann e1 e2) =>
match follow_pat fuel (xs, cursor_side) p with
| None => None
| Some zp =>
Some (ZExp.Deeper err_status (ZExp.LetZP zp ann e1 e2))
end
| (1, UHExp.Let p ann e1 e2) =>
match ann with
| None => None
| Some ann_ty =>
match follow_ty fuel (xs, cursor_side) ann_ty with
| None => None
| Some zann => Some (ZExp.Deeper err_status (ZExp.LetZA p zann e1 e2))
end
end
| (2, UHExp.Let p ann e1 e2) =>
match follow_e (xs, cursor_side) e1 with
| Some ze1 => Some (ZExp.Deeper err_status (ZExp.LetZE1 p ann ze1 e2))
| None => None
end
| (3, UHExp.Let p ann e1 e2) =>
match follow_e (xs, cursor_side) e2 with
| Some ze2 => Some (ZExp.Deeper err_status (ZExp.LetZE2 p ann e1 ze2))
| None => None
end
| (_, UHExp.Let _ _ _ _) => None
| (O, UHExp.Lam p ann e1) =>
match follow_pat fuel (xs, cursor_side) p with
| None => None
| Some zp =>
Some (ZExp.Deeper err_status (ZExp.LamZP zp ann e1))
end
| (1, UHExp.Lam p ann e1) =>
match ann with
| None => None
| Some ann_ty =>
match follow_ty fuel (xs, cursor_side) ann_ty with
| None => None
| Some zann =>
Some (ZExp.Deeper err_status (ZExp.LamZA p zann e1))
end
end
| (2, UHExp.Lam p ann e1) =>
match follow_e (xs, cursor_side) e1 with
| None => None
| Some ze => Some (ZExp.Deeper err_status (ZExp.LamZE p ann ze))
end
| (_, UHExp.Lam _ _ _) => None
| (_, UHExp.NumLit _) => None
| (_, UHExp.BoolLit _) => None
| (O, UHExp.Inj side e1) =>
match follow_e (xs, cursor_side) e1 with
| Some ze => Some (ZExp.Deeper err_status (ZExp.InjZ side ze))
| None => None
end
| (_, UHExp.Inj _ _) => None
| (_, UHExp.ListNil) => None
(* | (n, UHExp.ListLit es) =>
match ZList.split_at n es with
| None => None
| Some esz =>
match ZList.optmap_z (follow_e (xs, cursor_side)) esz with
| None => None
| Some zes =>
Some (ZExp.Deeper err_status (ZExp.ListLitZ zes))
end
end *)
| (O, UHExp.Case e1 rules) =>
match follow_e (xs, cursor_side) e1 with
| Some ze => Some (ZExp.Deeper err_status (ZExp.CaseZE ze rules))
| None => None
end
| (S x, UHExp.Case e1 rules) =>
match ZList.split_at x rules with
| None => None
| Some split_rules =>
match ZList.optmap_z (follow_rule fuel (xs, cursor_side)) split_rules with
| None => None
| Some zrules =>
Some (ZExp.Deeper err_status (ZExp.CaseZR e1 zrules))
end
end
| (n, UHExp.OpSeq skel seq) =>
match OperatorSeq.split n seq with
| Some (e, surround) =>
match follow_e (xs, cursor_side) e with
| Some ze =>
Some (ZExp.Deeper err_status (ZExp.OpSeqZ skel ze surround))
| None => None
end
| None => None
end
| (hole_ref, UHExp.ApPalette name serialized_model hole_data) =>
let (next_hole_ref, holemap) := hole_data in
match NatMap.drop holemap hole_ref with
| None => None
| Some (holemap', te) =>
let (ty, e') := te in
match follow_e (xs, cursor_side) e' with
| None => None
| Some ze =>
let zholemap := (holemap', (hole_ref, (ty, ze))) in
let zholedata := (next_hole_ref, zholemap) in
Some (ZExp.Deeper NotInHole (ZExp.ApPaletteZ name serialized_model zholedata))
end
end
end
end
end
end
with follow_rule (fuel : Fuel.t) (path : t) (rule : UHExp.rule) : option(ZExp.zrule) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match rule with
| UHExp.Rule p e =>
match path with
| (nil, _) => None
| (cons 0 xs, cursor_side) =>
match follow_pat fuel (xs, cursor_side) p with
| None => None
| Some zp => Some (ZExp.RuleZP zp e)
end
| (cons 1 xs, cursor_side) =>
match follow_e fuel (xs, cursor_side) e with
| None => None
| Some ze => Some (ZExp.RuleZE p ze)
end
| (cons _ _, _) => None
end
end
end.
Definition cons_opt (n : nat) (x : option(list(nat))) : option(list(nat)) :=
match x with
| None => None
| Some xs => Some (cons n xs)
end.
Definition cons_opt2
(n1 : nat) (x1 : option(list(nat)))
(n2 : nat) (x2 : unit -> option(list(nat)))
: option(list(nat)) :=
match x1 with
| Some xs => Some (cons n1 xs)
| None =>
match x2 tt with
| Some xs => Some (cons n2 xs)
| None => None
end
end.
Definition cons_opt3
(n1 : nat) (x1 : option(list(nat)))
(n2 : nat) (x2 : unit -> option(list(nat)))
(n3 : nat) (x3 : unit -> option(list(nat)))
: option(list(nat)) :=
match x1 with
| Some xs => Some (cons n1 xs)
| None =>
match x2 tt with
| Some xs => Some (cons n2 xs)
| None =>
match x3 tt with
| Some xs => Some (cons n3 xs)
| None => None
end
end
end.
Fixpoint steps_to_hole_pat (fuel : Fuel.t) (p : UHPat.t) (u : MetaVar.t) : option(list(nat)) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match p with
| UHPat.Pat _ (UHPat.EmptyHole u') =>
if MetaVar.eq u u' then
Some nil
else None
| UHPat.Parenthesized p1 =>
cons_opt 0 (steps_to_hole_pat fuel p1 u)
| UHPat.Pat _ UHPat.Wild
| UHPat.Pat _ (UHPat.Var _)
| UHPat.Pat _ (UHPat.NumLit _)
| UHPat.Pat _ (UHPat.BoolLit _)
| UHPat.Pat _ UHPat.ListNil => None
(* | UHPat.Pat _ (UHPat.ListLit ps) =>
Util.findmapi ps (fun i p =>
match steps_to_hole_pat fuel p u with
| None => None
| Some ns => Some (cons i ns)
end) *)
| UHPat.Pat _ (UHPat.Inj _ p1) =>
cons_opt 0 (steps_to_hole_pat fuel p1 u)
| UHPat.Pat _ (UHPat.OpSeq skel seq) =>
steps_to_hole_seq_pat fuel seq u
end
end
with steps_to_hole_seq_pat (fuel : Fuel.t) (seq : UHPat.opseq) (u : MetaVar.t) : option(list(nat)) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match seq with
| OperatorSeq.ExpOpExp p1 _ p2 =>
cons_opt2
0 (steps_to_hole_pat fuel p1 u)
1 (fun _ => steps_to_hole_pat fuel p2 u)
| OperatorSeq.SeqOpExp seq1 op p1 =>
match steps_to_hole_seq_pat fuel seq1 u with
| (Some steps) as path => path
| None => cons_opt (OperatorSeq.seq_length seq1) (steps_to_hole_pat fuel p1 u)
end
end
end.
Fixpoint steps_to_hole (fuel : Fuel.t) (e : UHExp.t) (u : MetaVar.t) : option(list(nat)) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match e with
| UHExp.Tm _ (UHExp.EmptyHole u') =>
if MetaVar.eq u u' then
Some nil
else None
| UHExp.Parenthesized e1 =>
cons_opt O (steps_to_hole fuel e1 u)
| UHExp.Tm _ (UHExp.Var _ _)
| UHExp.Tm _ (UHExp.NumLit _)
| UHExp.Tm _ (UHExp.BoolLit _) => None
| UHExp.Tm _ (UHExp.Asc e1 _)
| UHExp.Tm _ (UHExp.Inj _ e1) =>
cons_opt O (steps_to_hole fuel e1 u)
| UHExp.Tm _ UHExp.ListNil => None
(* | UHExp.Tm _ (UHExp.ListLit es) =>
Util.findmapi es (fun i e =>
match steps_to_hole fuel e u with
| None => None
| Some ns => Some (cons i ns)
end) *)
| UHExp.Tm _ (UHExp.Lam p _ e1) =>
cons_opt2
0 (steps_to_hole_pat fuel p u)
2 (fun _ => steps_to_hole fuel e1 u)
| UHExp.Tm _ (UHExp.Let p ann e1 e2) =>
cons_opt3
0 (steps_to_hole_pat fuel p u)
2 (fun _ => steps_to_hole fuel e1 u)
3 (fun _ => steps_to_hole fuel e2 u)
| UHExp.Tm _ (UHExp.Case e1 rules) =>
match steps_to_hole fuel e1 u with
| Some steps => Some (cons 0 steps)
| None =>
Util.findmapi rules (
fun i rule =>
match rule with
| UHExp.Rule p e =>
match steps_to_hole_pat fuel p u with
| Some steps => Some (cons (S i) (cons 0 steps))
| None =>
match steps_to_hole fuel e u with
| Some steps => Some (cons (S i) (cons 1 steps))
| None => None
end
end
end)
end
| UHExp.Tm _ (UHExp.OpSeq skel seq) =>
steps_to_hole_seq fuel seq u
| UHExp.Tm _ (UHExp.ApPalette _ _ holedata) =>
let (_, holemap) := holedata in
NatMap.fold holemap (fun c v =>
match c with
| Some _ => c
| None =>
let (_, te) := v in
let (_, e) := te in
steps_to_hole fuel e u
end
) None
end
end
with steps_to_hole_seq (fuel : Fuel.t) (seq : UHExp.opseq) (u : MetaVar.t) : option(list(nat)) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match seq with
| OperatorSeq.ExpOpExp e1 _ e2 =>
cons_opt2
0 (steps_to_hole fuel e1 u)
1 (fun _ => steps_to_hole fuel e2 u)
| OperatorSeq.SeqOpExp seq1 op e1 =>
match steps_to_hole_seq fuel seq1 u with
| (Some steps) as path => path
| None => cons_opt (OperatorSeq.seq_length seq1) (steps_to_hole fuel e1 u)
end
end
end.
Definition path_to_hole (fuel : Fuel.t) (e : UHExp.t) (u : MetaVar.t) : option(t) :=
match steps_to_hole fuel e u with
| Some steps => Some (steps, Before)
| None => None
end.
Fixpoint first_hole_steps_ty (fuel : Fuel.t) (uty : UHTyp.t) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match uty with
| UHTyp.Parenthesized uty' => cons_opt O (first_hole_steps_ty fuel uty')
| UHTyp.Unit
| UHTyp.Num
| UHTyp.Bool => None
| UHTyp.Hole => Some nil
| UHTyp.List uty1 => cons_opt 0 (first_hole_steps_ty fuel uty1)
| UHTyp.OpSeq _ opseq => first_hole_steps_ty_opseq fuel opseq 0
end
end
(* return an optional path of the first hole in opseq starting with the nth term *)
with first_hole_steps_ty_opseq (fuel : Fuel.t) (opseq : OperatorSeq.opseq UHTyp.t UHTyp.op) (n : nat) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
if Nat.leb (OperatorSeq.seq_length opseq) n
then None
else
match OperatorSeq.seq_nth n opseq with
| None => None (* degenerate case *)
| Some uty' =>
match first_hole_steps_ty fuel uty' with
| Some ns => Some (cons n ns)
| None => first_hole_steps_ty_opseq fuel opseq (n+1)
end
end
end.
Fixpoint first_hole_steps_pat (fuel : Fuel.t) (p : UHPat.t) : option(list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match p with
| UHPat.Parenthesized p1 => cons_opt 0 (first_hole_steps_pat fuel p1)
| UHPat.Pat _ (UHPat.EmptyHole _) => Some nil
| UHPat.Pat _ UHPat.Wild
| UHPat.Pat _ (UHPat.Var _)
| UHPat.Pat _ (UHPat.NumLit _)
| UHPat.Pat _ (UHPat.BoolLit _) => None
| UHPat.Pat _ (UHPat.Inj _ p1) => cons_opt 0 (first_hole_steps_pat fuel p1)
| UHPat.Pat _ UHPat.ListNil => None
(* | UHPat.Pat _ (UHPat.ListLit ps) =>
Util.findmapi ps (fun i p =>
match first_hole_steps_pat fuel p with
| None => None
| Some ns => Some (cons i ns)
end) *)
| UHPat.Pat _ (UHPat.OpSeq _ seq) => first_hole_steps_opseq_pat fuel seq 0
end
end
with first_hole_steps_opseq_pat (fuel : Fuel.t) (opseq : UHPat.opseq) (n : nat) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
if Nat.leb (OperatorSeq.seq_length opseq) n
then None
else
match OperatorSeq.seq_nth n opseq with
| None => None
| Some ue =>
match first_hole_steps_pat fuel ue with
| Some ns => Some (cons n ns)
| None => first_hole_steps_opseq_pat fuel opseq (n+1)
end
end
end.
Fixpoint first_hole_steps (fuel : Fuel.t) (ue : UHExp.t) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match ue with
| UHExp.Parenthesized ue1 => cons_opt 0 (first_hole_steps fuel ue1)
| UHExp.Tm _ ue' =>
match ue' with
| UHExp.EmptyHole _ => Some nil
| UHExp.Asc ue1 uty =>
cons_opt2
0 (first_hole_steps fuel ue1)
1 (fun _ => first_hole_steps_ty fuel uty)
| UHExp.Var _ _ => None
| UHExp.Let p ann ue1 ue2 =>
match first_hole_steps_pat fuel p with
| Some ns => Some (cons 0 ns)
| None =>
match ann with
| Some ann_ty =>
cons_opt3
1 (first_hole_steps_ty fuel ann_ty)
2 (fun _ => first_hole_steps fuel ue1)
3 (fun _ => first_hole_steps fuel ue2)
| None =>
cons_opt2
2 (first_hole_steps fuel ue1)
3 (fun _ => first_hole_steps fuel ue2)
end
end
| UHExp.Lam p ann e1 =>
match first_hole_steps_pat fuel p with
| Some ns => Some (cons 0 ns)
| None =>
match ann with
| Some uty =>
cons_opt2
1 (first_hole_steps_ty fuel uty)
2 (fun _ => first_hole_steps fuel e1)
| None => cons_opt 2 (first_hole_steps fuel e1)
end
end
| UHExp.NumLit _ => None
| UHExp.BoolLit _ => None
| UHExp.ListNil => None
(* | UHExp.ListLit es =>
Util.findmapi es (fun i e =>
match first_hole_steps fuel e with
| None => None
| Some ns => Some (cons i ns)
end) *)
| UHExp.Inj _ e1 => cons_opt 0 (first_hole_steps fuel e1)
| UHExp.Case e1 rules =>
match first_hole_steps fuel e1 with
| Some ns => Some (cons 0 ns)
| None => first_hole_steps_rules fuel rules
end
| UHExp.OpSeq _ opseq => first_hole_steps_opseq fuel opseq 0
| UHExp.ApPalette _ _ _ => None (* TODO figure out tab order protocol *)
end
end
end
with first_hole_steps_rules (fuel : Fuel.t) (rules : UHExp.rules) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
Util.findmapi rules (
fun i rule =>
match rule with
| UHExp.Rule p e =>
match first_hole_steps_pat fuel p with
| Some ns => Some (cons (S i) (cons 0 ns))
| None =>
match first_hole_steps fuel e with
| Some ns => Some (cons (S i) (cons 1 ns))
| None => None
end
end
end)
end
(* return an optional path of the first hole in opseq starting with the nth term )*)
with first_hole_steps_opseq (fuel : Fuel.t) (opseq : OperatorSeq.opseq UHExp.t UHExp.op) (n : nat) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
if Nat.leb (OperatorSeq.seq_length opseq) n
then None
else
match OperatorSeq.seq_nth n opseq with
| None => None
| Some ue =>
match first_hole_steps fuel ue with
| Some ns => Some (cons n ns)
| None => first_hole_steps_opseq fuel opseq (n+1)
end
end
end.
Fixpoint next_hole_steps_ty (fuel : Fuel.t) (zty : ZTyp.t) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match zty with
| ZTyp.CursorT cursor_side uty =>
match cursor_side, uty with
| _, UHTyp.Hole => None
| Before, _ => first_hole_steps_ty fuel uty
| After, _ => None
| In _, _ => None
end
| ZTyp.ParenthesizedZ zty' => cons_opt 0 (next_hole_steps_ty fuel zty')
| ZTyp.ListZ zty1 => cons_opt 0 (next_hole_steps_ty fuel zty1)
| ZTyp.OpSeqZ _ zty' surround =>
let n := OperatorSeq.surround_prefix_length surround in
match next_hole_steps_ty fuel zty' with
| Some ns => Some (cons n ns)
| None =>
let uty' := ZTyp.erase zty' in
let opseq := OperatorSeq.opseq_of_exp_and_surround uty' surround in
first_hole_steps_ty_opseq fuel opseq (n+1)
end
end
end.
Fixpoint next_hole_path_ty (fuel : Fuel.t) (zty : ZTyp.t) : option Path.t :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match next_hole_steps_ty fuel zty with
| None => None
| Some path => Some (path, Before)
end
end.
Fixpoint next_hole_steps_pat (fuel : Fuel.t) (zp : ZPat.t) : option(list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match zp with
| ZPat.ParenthesizedZ zp1 => cons_opt 0 (next_hole_steps_pat fuel zp1)
| ZPat.CursorP cursor_side p =>
match cursor_side, p with
| _, (UHPat.Pat _ (UHPat.EmptyHole _)) => None
| After, _ => None
| Before, _ => first_hole_steps_pat fuel p
| In k, _ =>
match p with
| UHPat.Parenthesized _ => None
| UHPat.Pat err p' =>
match p' with
| UHPat.Wild
| UHPat.Var _
| UHPat.NumLit _
| UHPat.BoolLit _
| UHPat.ListNil
(* | UHPat.ListLit _ *)
| UHPat.OpSeq _ _ => None
| UHPat.Inj _ p1 => first_hole_steps_pat fuel p1
| UHPat.EmptyHole _ => None
end
end
end
| ZPat.Deeper _ (ZPat.InjZ _ zp1) => cons_opt 0 (next_hole_steps_pat fuel zp1)
(* | ZPat.Deeper _ (ZPat.ListLitZ zps) =>
let prefix_length := ZList.prefix_length zps in
let zp0 := ZList.prj_z zps in
match next_hole_steps_pat fuel zp0 with
| Some ns =>
Some (cons prefix_length ns)
| None =>
let suffix := ZList.prj_suffix zps in
Util.findmapi suffix (fun i p =>
match first_hole_steps_pat fuel p with
| None => None
| Some ns => Some (cons (prefix_length + i + 1) ns)
end)
end *)
| ZPat.Deeper _ (ZPat.OpSeqZ _ zp1 surround) =>
let n := OperatorSeq.surround_prefix_length surround in
match next_hole_steps_pat fuel zp1 with
| Some ns => Some (cons n ns)
| None =>
let p := ZPat.erase zp1 in
let opseq := OperatorSeq.opseq_of_exp_and_surround p surround in
first_hole_steps_opseq_pat fuel opseq (n+1)
end
end
end.
Fixpoint next_hole_path_pat (fuel : Fuel.t) (zp : ZPat.t) : option Path.t :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match next_hole_steps_pat fuel zp with
| None => None
| Some path => Some (path, Before)
end
end.
Fixpoint next_hole_steps (fuel : Fuel.t) (ze : ZExp.t) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match ze with
| ZExp.CursorE cursor_side ue =>
match cursor_side, ue with
| _, (UHExp.Tm _ (UHExp.EmptyHole _)) => None
| After, _ => None
| Before, _ => first_hole_steps fuel ue
| In k, _ =>
match ue with
| UHExp.Parenthesized _ => None
| UHExp.Tm err ue' =>
match ue' with
| UHExp.Asc _ uty => cons_opt 1 (first_hole_steps_ty fuel uty)
| UHExp.Var _ _ => None
| UHExp.Let p ann ue1 ue2 =>
first_hole_steps fuel ue
| UHExp.Lam _ _ _ =>
first_hole_steps fuel ue
| UHExp.NumLit _
| UHExp.BoolLit _
| UHExp.ListNil
(* | UHExp.ListLit _ *) => None
| UHExp.Inj _ ue'' =>
first_hole_steps fuel ue
| UHExp.Case e1 rules =>
match k with
| 0 => first_hole_steps fuel ue
| 1 => None
| _ => None
end
| UHExp.EmptyHole _ => None
| UHExp.OpSeq _ _ => None
| UHExp.ApPalette _ _ _ => None (* TODO move into palette holes *)
end
end
end
| ZExp.Deeper _ ze' =>
match ze' with
| ZExp.AscZ1 ze'' uty =>
cons_opt2
0 (next_hole_steps fuel ze'')
1 (fun _ => first_hole_steps_ty fuel uty)
| ZExp.AscZ2 _ zty => cons_opt 1 (next_hole_steps_ty fuel zty)
| ZExp.LetZP zp ann ue1 ue2 =>
match next_hole_steps_pat fuel zp with
| Some ns => Some (cons 0 ns)
| None =>
match ann with
| Some ann_ty =>
cons_opt3
1 (first_hole_steps_ty fuel ann_ty)
2 (fun _ => first_hole_steps fuel ue1)
3 (fun _ => first_hole_steps fuel ue2)
| None =>
cons_opt2
2 (first_hole_steps fuel ue1)
3 (fun _ => first_hole_steps fuel ue2)
end
end
| ZExp.LetZA _ zann e1 e2 =>
cons_opt3
1 (next_hole_steps_ty fuel zann)
2 (fun _ => first_hole_steps fuel e1)
3 (fun _ => first_hole_steps fuel e2)
| ZExp.LetZE1 _ _ ze1 e2 =>
cons_opt2
2 (next_hole_steps fuel ze1)
3 (fun _ => first_hole_steps fuel e2)
| ZExp.LetZE2 _ _ _ ze2 =>
cons_opt
3 (next_hole_steps fuel ze2)
| ZExp.LamZP zp ann e1 =>
match next_hole_steps_pat fuel zp with
| Some ns => Some (cons 0 ns)
| None =>
match ann with
| Some uty =>
cons_opt2
1 (first_hole_steps_ty fuel uty)
2 (fun _ => first_hole_steps fuel e1)
| None =>
cons_opt
2 (first_hole_steps fuel e1)
end
end
| ZExp.LamZA _ zann e1 =>
cons_opt2
1 (next_hole_steps_ty fuel zann)
2 (fun _ => first_hole_steps fuel e1)
| ZExp.LamZE _ _ ze1 =>
cons_opt
2 (next_hole_steps fuel ze1)
| ZExp.InjZ _ ze'' =>
cons_opt
0 (next_hole_steps fuel ze'')
(* | ZExp.ListLitZ zes =>
let prefix_length := ZList.prefix_length zes in
let ze0 := ZList.prj_z zes in
match next_hole_steps fuel ze0 with
| Some ns =>
Some (cons prefix_length ns)
| None =>
let suffix := ZList.prj_suffix zes in
Util.findmapi suffix (fun i e =>
match first_hole_steps fuel e with
| None => None
| Some ns => Some (cons (prefix_length + i + 1) ns)
end)
end *)
| ZExp.CaseZE ze1 rules =>
match next_hole_steps fuel ze1 with
| Some ns => Some (cons 0 ns)
| None => first_hole_steps_rules fuel rules
end
| ZExp.CaseZR _ zrules =>
let zr := ZList.prj_z zrules in
let prefix_len := List.length (ZList.prj_prefix zrules) in
match zr with
| ZExp.RuleZP zp e =>
match next_hole_steps_pat fuel zp with
| Some ns => Some (cons (S prefix_len) (cons 0 ns))
| None =>
match first_hole_steps fuel e with
| Some ns => Some (cons (S prefix_len) (cons 1 ns))
| None =>
let suffix := ZList.prj_suffix zrules in
match first_hole_steps_rules fuel suffix with
| Some (cons offset ns) => Some (cons (prefix_len + offset + 1) ns)
| Some nil => None (* should never happen *)
| None => None
end
end
end
| ZExp.RuleZE _ ze =>
match next_hole_steps fuel ze with
| Some ns => Some (cons (S prefix_len) (cons 1 ns))
| None =>
let suffix := ZList.prj_suffix zrules in
match first_hole_steps_rules fuel suffix with
| Some (cons offset ns) => Some (cons (prefix_len + offset + 1) ns)
| Some nil => None (* should never happen *)
| None => None
end
end
end
| ZExp.OpSeqZ _ ze'' surround =>
let n := OperatorSeq.surround_prefix_length surround in
match next_hole_steps fuel ze'' with
| Some ns => Some (cons n ns)
| None =>
let ue'' := ZExp.erase ze'' in
let opseq := OperatorSeq.opseq_of_exp_and_surround ue'' surround in
first_hole_steps_opseq fuel opseq (n+1)
end
| ZExp.ApPaletteZ _ _ _ => None (* TODO figure out tab order protocol *)
end
| ZExp.ParenthesizedZ ze' => cons_opt 0 (next_hole_steps fuel ze')
end
end.
Fixpoint next_hole_path (fuel : Fuel.t) (ze : ZExp.t) : option Path.t :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match next_hole_steps fuel ze with
| None => None
| Some path => Some (path, Before)
end
end.
Fixpoint last_hole_steps_ty (fuel : Fuel.t) (uty : UHTyp.t) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match uty with
| UHTyp.Hole => Some nil
| UHTyp.Parenthesized uty' => cons_opt 0 (last_hole_steps_ty fuel uty')
| UHTyp.Unit
| UHTyp.Num
| UHTyp.Bool => None
| UHTyp.List uty1 => cons_opt 0 (last_hole_steps_ty fuel uty1)
| UHTyp.OpSeq _ opseq => last_hole_steps_ty_opseq fuel opseq 0
end
end
(* return an optional path of the last hole in opseq starting with the mth term from the end
(e.g., the 0th and 1st term from the end of `1 + 2 + 3` are 3 and 2 respectively) *)
with last_hole_steps_ty_opseq (fuel : Fuel.t) (opseq : OperatorSeq.opseq UHTyp.t UHTyp.op) (m : nat) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
let l := OperatorSeq.seq_length opseq in
if Nat.leb l m
then None
else
let n := l-m-1 in
match OperatorSeq.seq_nth n opseq with
| None => None (* degenerate case *)
| Some uty' =>
match last_hole_steps_ty fuel uty' with
| Some ns => Some (cons n ns)
| None => last_hole_steps_ty_opseq fuel opseq (m+1)
end
end
end.
Fixpoint last_hole_steps_pat (fuel : Fuel.t) (p : UHPat.t) : option(list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match p with
| UHPat.Parenthesized p1 => cons_opt 0 (last_hole_steps_pat fuel p1)
| UHPat.Pat _ (UHPat.EmptyHole _) => Some nil
| UHPat.Pat _ UHPat.Wild
| UHPat.Pat _ (UHPat.Var _)
| UHPat.Pat _ (UHPat.NumLit _)
| UHPat.Pat _ (UHPat.BoolLit _) => None
| UHPat.Pat _ (UHPat.Inj _ p1) => cons_opt 0 (last_hole_steps_pat fuel p1)
| UHPat.Pat _ UHPat.ListNil => None
(* | UHPat.Pat _ (UHPat.ListLit ps) =>
let num_elts := List.length ps in
Util.findmapi ps (fun i p =>
match last_hole_steps_pat fuel p with
| None => None
| Some ns => Some (cons (num_elts - i - 1) ns)
end) *)
| UHPat.Pat _ (UHPat.OpSeq _ opseq) => last_hole_steps_opseq_pat fuel opseq 0
end
end
with last_hole_steps_opseq_pat (fuel : Fuel.t) (opseq : UHPat.opseq) (m : nat) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
let l := OperatorSeq.seq_length opseq in
if Nat.leb l m
then None
else
let n := l-m-1 in
match OperatorSeq.seq_nth n opseq with
| None => None
| Some ue =>
match last_hole_steps_pat fuel ue with
| Some ns => Some (cons n ns)
| None => last_hole_steps_opseq_pat fuel opseq (m+1)
end
end
end.
Fixpoint last_hole_steps (fuel : Fuel.t) (ue : UHExp.t) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match ue with
| UHExp.Parenthesized ue' => cons_opt 0 (last_hole_steps fuel ue')
| UHExp.Tm _ ue' =>
match ue' with
| UHExp.EmptyHole _ => Some nil
| UHExp.Asc ue0 uty1 =>
cons_opt2
1 (last_hole_steps_ty fuel uty1)
0 (fun _ => last_hole_steps fuel ue0)
| UHExp.Var _ _ => None
| UHExp.Let p ann e1 e2 =>
match last_hole_steps fuel e2 with
| Some ns => Some (cons 3 ns)
| None =>
match last_hole_steps fuel e1 with
| Some ns => Some (cons 2 ns)
| None =>
match ann with
| Some ann_ty =>
cons_opt2
1 (last_hole_steps_ty fuel ann_ty)
0 (fun _ => last_hole_steps_pat fuel p)
| None =>
cons_opt 0 (last_hole_steps_pat fuel p)
end
end
end
| UHExp.Lam p ann e1 =>
match last_hole_steps fuel e1 with
| Some ns => Some (cons 2 ns)
| None =>
match ann with
| Some uty1 =>
cons_opt2
1 (last_hole_steps_ty fuel uty1)
0 (fun _ => last_hole_steps_pat fuel p)
| None =>
cons_opt 0 (last_hole_steps_pat fuel p)
end
end
| UHExp.NumLit _
| UHExp.BoolLit _ => None
| UHExp.Inj _ ue0 => cons_opt 0 (last_hole_steps fuel ue0)
| UHExp.ListNil => None
(* | UHExp.ListLit es =>
let num_elts := List.length es in
Util.findmapi es (fun i e =>
match last_hole_steps fuel e with
| None => None
| Some ns => Some (cons (num_elts - i - 1) ns)
end) *)
| UHExp.Case e1 rules =>
match last_hole_steps_rules fuel rules with
| (Some ns) as result => result
| None => cons_opt 0 (last_hole_steps fuel e1)
end
| UHExp.OpSeq _ opseq => last_hole_steps_opseq fuel opseq 0
| UHExp.ApPalette _ _ _ => None (* TODO figure out tab order protocol *)
end
end
end
with last_hole_steps_rules
(fuel : Fuel.t)
(rules : UHExp.rules)
: option(list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
let n_rules := List.length rules in
Util.findmapi (List.rev rules) (
fun i rule =>
match rule with
| UHExp.Rule p e =>
match last_hole_steps fuel e with
| Some ns => Some (cons (n_rules - i) (cons 1 ns))
| None =>
match last_hole_steps_pat fuel p with
| Some ns => Some (cons (n_rules - i) (cons 0 ns))
| None => None
end
end
end)
end
(* return an optional path of the last hole in opseq starting with the mth term from the end
(e.g., the 0th and 1st term from the end of `1 + 2 + 3` are 3 and 2 respectively) *)
with last_hole_steps_opseq (fuel : Fuel.t) (opseq : OperatorSeq.opseq UHExp.t UHExp.op) (m : nat) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
let l := OperatorSeq.seq_length opseq in
if Nat.leb l m
then None
else
let n := l-m-1 in
match OperatorSeq.seq_nth n opseq with
| None => None
| Some ue =>
match last_hole_steps fuel ue with
| Some ns => Some (cons n ns)
| None => last_hole_steps_opseq fuel opseq (m+1)
end
end
end.
Fixpoint prev_hole_steps_ty (fuel : Fuel.t) (zty : ZTyp.t) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match zty with
| ZTyp.CursorT cursor_side uty =>
match cursor_side, uty with
| _, UHTyp.Hole => None
| Before, _ => None
| After, _ => last_hole_steps_ty fuel uty
| In _, _ => None
end
| ZTyp.ParenthesizedZ zty' => cons_opt 0 (prev_hole_steps_ty fuel zty')
| ZTyp.ListZ zty1 => cons_opt 0 (prev_hole_steps_ty fuel zty1)
| ZTyp.OpSeqZ _ zty' surround =>
let n := OperatorSeq.surround_prefix_length surround in
match prev_hole_steps_ty fuel zty' with
| Some ns => Some (cons n ns)
| None =>
let uty' := ZTyp.erase zty' in
let opseq := OperatorSeq.opseq_of_exp_and_surround uty' surround in
let m := OperatorSeq.surround_suffix_length surround in
last_hole_steps_ty_opseq fuel opseq (m+1)
end
end
end.
Fixpoint prev_hole_path_ty (fuel : Fuel.t) (zty : ZTyp.t) : option Path.t :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match prev_hole_steps_ty fuel zty with
| None => None
| Some path => Some (path, Before)
end
end.
Fixpoint prev_hole_steps_pat (fuel : Fuel.t) (zp : ZPat.t) : option(list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match zp with
| ZPat.ParenthesizedZ zp1 => cons_opt 0 (prev_hole_steps_pat fuel zp1)
| ZPat.CursorP cursor_side p =>
match cursor_side, p with
| _, (UHPat.Pat _ (UHPat.EmptyHole _)) => None
| Before, _ => None
| After, _ => last_hole_steps_pat fuel p
| In k, _ =>
match p with
| UHPat.Parenthesized _ => None
| UHPat.Pat err p' =>
match p' with
| UHPat.EmptyHole _ => None
| UHPat.Wild
| UHPat.Var _
| UHPat.NumLit _
| UHPat.BoolLit _
| UHPat.ListNil
(* | UHPat.ListLit _ *) => None
| UHPat.Inj _ p1 => None
| UHPat.OpSeq _ _ => None
end
end
end
| ZPat.Deeper _ (ZPat.InjZ _ zp1) => cons_opt 0 (prev_hole_steps_pat fuel zp1)
(* | ZPat.Deeper _ (ZPat.ListLitZ ((prefix, zp0), _)) =>
let prefix_length := List.length prefix in
match prev_hole_steps_pat fuel zp0 with
| Some ns => Some (cons prefix_length ns)
| None => last_hole_steps_pat fuel (UHPat.Pat NotInHole (UHPat.ListLit prefix))
end *)
| ZPat.Deeper _ (ZPat.OpSeqZ _ zp1 surround) =>
let n := OperatorSeq.surround_prefix_length surround in
match prev_hole_steps_pat fuel zp1 with
| Some ns => Some (cons n ns)
| None =>
let ue_n := ZPat.erase zp1 in
let opseq := OperatorSeq.opseq_of_exp_and_surround ue_n surround in
let m := OperatorSeq.surround_suffix_length surround in
last_hole_steps_opseq_pat fuel opseq (m+1)
end
end
end.
Fixpoint prev_hole_path_pat (fuel : Fuel.t) (zp : ZPat.t) : option Path.t :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match prev_hole_steps_pat fuel zp with
| None => None
| Some path => Some (path, Before)
end
end.
Fixpoint prev_hole_steps (fuel : Fuel.t) (ze : ZExp.t) : option (list nat) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match ze with
| ZExp.CursorE cursor_side ue =>
match cursor_side, ue with
| _, (UHExp.Tm _ (UHExp.EmptyHole _)) => None
| After, _ => last_hole_steps fuel ue
| Before, _ => None
| In k, _ =>
match ue with
| UHExp.Parenthesized _ => None (* cannot be In Parenthesized term *)
| UHExp.Tm err ue' =>
match ue' with
| UHExp.Asc ue'' _ => cons_opt 0 (last_hole_steps fuel ue'')
| UHExp.Var _ _ => None
| UHExp.Let _ _ _ _ => None
| UHExp.Lam _ _ _ => None
| UHExp.NumLit _
| UHExp.BoolLit _
| UHExp.ListNil
(* | UHExp.ListLit _ *) => None
| UHExp.Inj _ _ => None
| UHExp.Case _ _ =>
match k with
| 0 => None
| 1 => last_hole_steps fuel ue
| _ => None
end
| UHExp.EmptyHole _ => None
| UHExp.OpSeq _ _ => None
| UHExp.ApPalette _ _ _ => None (* TODO *)
end
end
end
| ZExp.Deeper _ ze' =>
match ze' with
| ZExp.AscZ1 ze0 _ =>
cons_opt 0 (prev_hole_steps fuel ze0)
| ZExp.AscZ2 ue0 zty1 =>
cons_opt2
1 (prev_hole_steps_ty fuel zty1)
0 (fun _ => last_hole_steps fuel ue0)
| ZExp.LetZP zp _ _ _ =>
cons_opt 0 (prev_hole_steps_pat fuel zp)
| ZExp.LetZA p zann _ _ =>
cons_opt2
1 (prev_hole_steps_ty fuel zann)
0 (fun _ => last_hole_steps_pat fuel p)
| ZExp.LetZE1 p ann ze1 _ =>
match prev_hole_steps fuel ze1 with
| Some ns => Some (cons 2 ns)
| None =>
match ann with
| Some ann_ty =>
cons_opt2
1 (last_hole_steps_ty fuel ann_ty)
0 (fun _ => last_hole_steps_pat fuel p)
| None =>
cons_opt 0 (last_hole_steps_pat fuel p)
end
end
| ZExp.LetZE2 p ann e1 ze2 =>
match prev_hole_steps fuel ze2 with
| Some ns => Some (cons 3 ns)
| None =>
match last_hole_steps fuel e1 with
| Some ns => Some (cons 2 ns)
| None =>
match ann with
| Some ann_ty =>
cons_opt2
1 (last_hole_steps_ty fuel ann_ty)
0 (fun _ => last_hole_steps_pat fuel p)
| None => None
end
end
end
| ZExp.LamZP zp _ _ => prev_hole_steps_pat fuel zp
| ZExp.LamZA p zann _ =>
cons_opt2
1 (prev_hole_steps_ty fuel zann)
0 (fun _ => last_hole_steps_pat fuel p)
| ZExp.LamZE p ann ze1 =>
match prev_hole_steps fuel ze1 with
| Some ns => Some (cons 2 ns)
| None =>
match ann with
| Some uty1 =>
cons_opt2
1 (last_hole_steps_ty fuel uty1)
0 (fun _ => last_hole_steps_pat fuel p)
| None => cons_opt 0 (last_hole_steps_pat fuel p)
end
end
| ZExp.InjZ _ ze0 => cons_opt 0 (prev_hole_steps fuel ze0)
(* | ZExp.ListLitZ ((prefix, ze0), _) =>
let prefix_length := List.length prefix in
match prev_hole_steps fuel ze0 with
| Some ns => Some (cons prefix_length ns)
| None => last_hole_steps fuel (UHExp.Tm NotInHole (UHExp.ListLit prefix))
end *)
| ZExp.CaseZE ze rules =>
cons_opt 0 (prev_hole_steps fuel ze)
| ZExp.CaseZR e1 zrules =>
let zr := ZList.prj_z zrules in
let prefix := ZList.prj_prefix zrules in
let prefix_len := List.length prefix in
match zr with
| ZExp.RuleZP zp e =>
match prev_hole_steps_pat fuel zp with
| Some ns => Some (cons (S prefix_len) (cons 0 ns))
| None =>
match last_hole_steps_rules fuel prefix with
| Some ns => Some ns
| None => Path.cons_opt 0 (last_hole_steps fuel e1)
end
end
| ZExp.RuleZE p ze =>
match prev_hole_steps fuel ze with
| Some ns => Some (cons (S prefix_len) (cons 1 ns))
| None =>
match last_hole_steps_pat fuel p with
| Some ns => Some (cons (S prefix_len) (cons 0 ns))
| None =>
match last_hole_steps_rules fuel prefix with
| Some ns => Some ns
| None => Path.cons_opt 0 (last_hole_steps fuel e1)
end
end
end
end
| ZExp.OpSeqZ _ ze_n surround =>
let n := OperatorSeq.surround_prefix_length surround in
match prev_hole_steps fuel ze_n with
| Some ns => Some (cons n ns)
| None =>
let ue_n := ZExp.erase ze_n in
let opseq := OperatorSeq.opseq_of_exp_and_surround ue_n surround in
let m := OperatorSeq.surround_suffix_length surround in
last_hole_steps_opseq fuel opseq (m+1)
end
| ZExp.ApPaletteZ _ _ _ => None (* TODO figure out tab order protocol *)
end
| ZExp.ParenthesizedZ ze0 => cons_opt 0 (prev_hole_steps fuel ze0)
end
end.
Fixpoint prev_hole_path (fuel : Fuel.t) (ze : ZExp.t) : option Path.t :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match prev_hole_steps fuel ze with
| None => None
| Some path => Some (path, Before)
end
end.
End Path.
Module Type ASSOCIATOR.
(* calls the parser (from OCaml) to produce a skel from an opseq.
* initially, there are no errors marked in the skel. *)
Parameter associate_ty : UHTyp.opseq -> UHTyp.skel_t.
Parameter associate_pat : UHPat.opseq -> UHPat.skel_t.
Parameter associate_exp : UHExp.opseq -> UHExp.skel_t.
End ASSOCIATOR.
Module FAction (Associator : ASSOCIATOR).
Inductive op_shape : Type :=
| SPlus : op_shape
| STimes : op_shape
| SLessThan : op_shape
| SSpace : op_shape
| SComma : op_shape
| SArrow : op_shape
| SVBar : op_shape
| SCons : op_shape.
Definition ty_op_of (os : op_shape) : option(UHTyp.op) :=
match os with
| SArrow => Some UHTyp.Arrow
| SComma => Some UHTyp.Prod
| SVBar => Some UHTyp.Sum
| SPlus
| STimes
| SLessThan
| SSpace
| SCons => None
end.
Definition op_shape_of_ty_op (op : UHTyp.op) : op_shape :=
match op with
| UHTyp.Arrow => SArrow
| UHTyp.Prod => SComma
| UHTyp.Sum => SVBar
end.
Definition pat_op_of (os : op_shape) : option(UHPat.op) :=
match os with
| SComma => Some UHPat.Comma
| SSpace => Some UHPat.Space
| SCons => Some UHPat.Cons
| SPlus
| STimes
| SLessThan
| SArrow
| SVBar => None
end.
Definition op_shape_of_pat_op (op : UHPat.op) : op_shape :=
match op with
| UHPat.Comma => SComma
| UHPat.Space => SSpace
| UHPat.Cons => SCons
end.
Definition exp_op_of (os : op_shape) : option(UHExp.op) :=
match os with
| SPlus => Some UHExp.Plus
| STimes => Some UHExp.Times
| SLessThan => Some UHExp.LessThan
| SSpace => Some UHExp.Space
| SComma => Some UHExp.Comma
| SCons => Some UHExp.Cons
| SArrow
| SVBar => None
end.
Definition op_shape_of_exp_op (op : UHExp.op) : op_shape :=
match op with
| UHExp.Plus => SPlus
| UHExp.Times => STimes
| UHExp.LessThan => SLessThan
| UHExp.Space => SSpace
| UHExp.Comma => SComma
| UHExp.Cons => SCons
end.
Inductive shape : Type :=
| SParenthesized : shape
(* type shapes *)
| SNum : shape
| SBool : shape
| SList : shape
(* expression shapes *)
| SAsc : shape
| SLet : shape
| SVar : Var.t -> ZExp.cursor_side -> shape
| SLam : shape
| SNumLit : nat -> ZExp.cursor_side -> shape
| SBoolLit : bool -> ZExp.cursor_side -> shape
| SListNil : shape
| SInj : inj_side -> shape
| SCase : shape
| SRule : shape
| SOp : op_shape -> shape
| SApPalette : PaletteName.t -> shape
(* pattern-only shapes *)
| SWild : shape.
Inductive t : Type :=
| MoveTo : Path.t -> t
| MoveToNextHole : t
| MoveToPrevHole : t
| UpdateApPalette : UHExp.HoleRefs.m_hole_ref(PaletteSerializedModel.t) -> t
| Delete : t
| Backspace : t
| Construct : shape -> t.
Definition make_ty_OpSeqZ
(zty0 : ZTyp.t) (surround : ZTyp.opseq_surround)
: ZTyp.t :=
let uty0 := ZTyp.erase zty0 in
let seq := OperatorSeq.opseq_of_exp_and_surround uty0 surround in
let skel := Associator.associate_ty seq in
ZTyp.OpSeqZ skel zty0 surround.
Fixpoint perform_ty (fuel : Fuel.t) (a : t) (zty : ZTyp.t) : option ZTyp.t :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match (a, zty) with
(* Movement *)
| (MoveTo path, _) =>
let ty := ZTyp.erase zty in
Path.follow_ty fuel path ty
| (MoveToPrevHole, _) =>
match Path.prev_hole_path_ty fuel zty with
| None => None
| Some path => perform_ty fuel (MoveTo path) zty
end
| (MoveToNextHole, _) =>
match Path.next_hole_path_ty fuel zty with
| None => None
| Some path =>
(* [debug] let path := Helper.log_path path in *)
perform_ty fuel (MoveTo path) zty
end
(* Backspace and Delete *)
| (Backspace, ZTyp.CursorT After uty)
| (Backspace, ZTyp.CursorT (In _) uty) =>
Some (ZTyp.CursorT Before UHTyp.Hole)
| (Backspace, ZTyp.CursorT Before _) => None
| (Delete, ZTyp.CursorT Before uty)
| (Delete, ZTyp.CursorT (In _) uty) =>
match uty with
| UHTyp.Hole =>
Some (ZTyp.CursorT After uty)
| _ =>
Some (ZTyp.CursorT Before UHTyp.Hole)
end
| (Delete, ZTyp.CursorT After uty) => None
| (Backspace,
ZTyp.OpSeqZ _
((ZTyp.CursorT Before uty0) as zty0)
surround) =>
match surround with
| OperatorSeq.EmptyPrefix _ => None
| OperatorSeq.EmptySuffix prefix =>
match prefix with
| OperatorSeq.ExpPrefix uty1 op1 =>
match uty0 with
| UHTyp.Hole =>
(* uty1 op1 |_ -> uty1| *)
Some (ZTyp.CursorT After uty1)
| _ =>
(* uty1 op1 |uty0 -> |uty0 *)
Some zty0
end
| OperatorSeq.SeqPrefix seq1 op1 =>
let (uty1, prefix') := OperatorSeq.split_tail seq1 in
match uty0 with
| UHTyp.Hole =>
(* prefix' uty1 op1 |_ --> prefix' uty1| *)
let surround' := OperatorSeq.EmptySuffix prefix' in
let ze1 := ZTyp.CursorT After uty1 in
Some (make_ty_OpSeqZ ze1 surround')
| _ =>
(* prefix' uty1 op |uty0 --> prefix' |uty0 *)
let surround' := OperatorSeq.EmptySuffix prefix' in
Some (make_ty_OpSeqZ zty0 surround')
end
end
| OperatorSeq.BothNonEmpty prefix suffix =>
match prefix with
| OperatorSeq.ExpPrefix uty1 op1 =>
match uty0 with
| UHTyp.Hole =>
(* uty1 op1 |_ suffix -> uty1| suffix *)
let surround' := OperatorSeq.EmptyPrefix suffix in
let zty1 := ZTyp.CursorT After uty1 in
Some (make_ty_OpSeqZ zty1 surround')
| _ =>
(* uty1 op1 |uty0 suffix -> |uty0 suffix *)
let surround' := OperatorSeq.EmptyPrefix suffix in
Some (make_ty_OpSeqZ zty0 surround')
end
| OperatorSeq.SeqPrefix seq1 op1 =>
let (uty1, prefix') := OperatorSeq.split_tail seq1 in
match uty0 with
| UHTyp.Hole =>
(* prefix' uty1 op1 |_ suffix --> prefix' uty1| suffix *)
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
let ze1 := ZTyp.CursorT After uty1 in
Some (make_ty_OpSeqZ ze1 surround')
| _ =>
(* prefix' uty1 op |uty0 suffix --> prefix' |uty0 suffix *)
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
Some (make_ty_OpSeqZ zty0 surround')
end
end
end
| (Delete,
ZTyp.OpSeqZ _
((ZTyp.CursorT After uty0) as zty0)
surround) =>
match surround with
| OperatorSeq.EmptySuffix _ => None
| OperatorSeq.EmptyPrefix suffix =>
match suffix with
| OperatorSeq.ExpSuffix op1 uty1 =>
match uty0 with
| UHTyp.Hole =>
(* _| op1 uty1 -> |uty1 *)
Some (ZTyp.CursorT Before uty1)
| _ =>
(* uty0| op1 uty0 -> uty0| *)
Some zty0
end
| OperatorSeq.SeqSuffix op1 seq1 =>
let (uty1, suffix') := OperatorSeq.split0 seq1 in
match uty0 with
| UHTyp.Hole =>
(* _| op1 uty1 suffix' --> |uty1 suffix' *)
let surround' := OperatorSeq.EmptyPrefix suffix' in
let ze1 := ZTyp.CursorT Before uty1 in
Some (make_ty_OpSeqZ ze1 surround')
| _ =>
(* uty0| op1 uty1 suffix' --> uty0| suffix' *)
let surround' := OperatorSeq.EmptyPrefix suffix' in
Some (make_ty_OpSeqZ zty0 surround')
end
end
| OperatorSeq.BothNonEmpty prefix suffix =>
match suffix with
| OperatorSeq.ExpSuffix op1 uty1 =>
match uty0 with
| UHTyp.Hole =>
(* prefix _| op1 uty1 -> prefix |uty1 *)
let surround' := OperatorSeq.EmptySuffix prefix in
let zty1 := ZTyp.CursorT Before uty1 in
Some (make_ty_OpSeqZ zty1 surround')
| _ =>
(* prefix uty0| op1 uty0 -> prefix uty0| *)
let surround' := OperatorSeq.EmptySuffix prefix in
Some (make_ty_OpSeqZ zty0 surround')
end
| OperatorSeq.SeqSuffix op1 seq1 =>
let (uty1, suffix') := OperatorSeq.split0 seq1 in
match uty0 with
| UHTyp.Hole =>
(* prefix _| op1 uty1 suffix' --> prefix |uty1 suffix' *)
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
let ze1 := ZTyp.CursorT Before uty1 in
Some (make_ty_OpSeqZ ze1 surround')
| _ =>
(* prefix uty0| op1 uty1 suffix' --> prefix uty0| suffix' *)
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
Some (make_ty_OpSeqZ zty0 surround')
end
end
end
(* Construction *)
| (Construct SParenthesized, ZTyp.CursorT _ _) =>
Some (ZTyp.ParenthesizedZ zty)
| (Construct SNum, ZTyp.CursorT _ UHTyp.Hole) =>
Some (ZTyp.CursorT After UHTyp.Num)
| (Construct SNum, ZTyp.CursorT _ _) => None
| (Construct SBool, ZTyp.CursorT _ UHTyp.Hole) =>
Some (ZTyp.CursorT After UHTyp.Bool)
| (Construct SBool, ZTyp.CursorT _ _) => None
| (Construct SList, ZTyp.CursorT _ ty1) =>
Some (ZTyp.ListZ zty)
| (Construct (SOp os), ZTyp.CursorT After uty1)
| (Construct (SOp os), ZTyp.CursorT (In _) uty1) =>
match ty_op_of os with
| None => None
| Some op =>
let surround := OperatorSeq.EmptySuffix (OperatorSeq.ExpPrefix uty1 op) in
let zty0 := ZTyp.CursorT Before UHTyp.Hole in
Some (make_ty_OpSeqZ zty0 surround)
end
| (Construct (SOp os), ZTyp.CursorT Before uty1) =>
match ty_op_of os with
| None => None
| Some op =>
let surround := OperatorSeq.EmptyPrefix (OperatorSeq.ExpSuffix op uty1) in
let zty0 := ZTyp.CursorT Before UHTyp.Hole in
Some (make_ty_OpSeqZ zty0 surround)
end
| (Construct (SOp os),
ZTyp.OpSeqZ _
((ZTyp.CursorT After uty0) as zty0)
surround)
| (Construct (SOp os),
ZTyp.OpSeqZ _
((ZTyp.CursorT (In _) uty0) as zty0)
surround) =>
match ty_op_of os with
| None => None
| Some op =>
match surround with
| OperatorSeq.EmptyPrefix suffix =>
(* zty0| suffix -> uty0 op |_ suffix *)
let prefix' := OperatorSeq.ExpPrefix uty0 op in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
let zty0' := ZTyp.CursorT Before UHTyp.Hole in
Some (make_ty_OpSeqZ zty0' surround')
| OperatorSeq.EmptySuffix prefix =>
(* prefix zty0| -> prefix uty0 op |_ *)
let prefix' := OperatorSeq.prefix_append_exp prefix uty0 op in
let surround' := OperatorSeq.EmptySuffix prefix' in
let zty0' := ZTyp.CursorT Before UHTyp.Hole in
Some (make_ty_OpSeqZ zty0' surround')
| OperatorSeq.BothNonEmpty prefix suffix =>
(* prefix zty0| suffix -> prefix uty0 op |_ suffix *)
let prefix' := OperatorSeq.prefix_append_exp prefix uty0 op in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
let zty0' := ZTyp.CursorT Before UHTyp.Hole in
Some (make_ty_OpSeqZ zty0' surround')
end
end
| (Construct (SOp os),
ZTyp.OpSeqZ _
((ZTyp.CursorT Before uty0) as zty0)
surround) =>
match ty_op_of os with
| None => None
| Some op =>
match surround with
| OperatorSeq.EmptyPrefix suffix =>
(* |zty0 suffix -> |_ op uty0 suffix *)
let suffix' := OperatorSeq.suffix_prepend_exp suffix op uty0 in
let surround' := OperatorSeq.EmptyPrefix suffix' in
let zty0' := ZTyp.CursorT Before UHTyp.Hole in
Some (make_ty_OpSeqZ zty0' surround')
| OperatorSeq.EmptySuffix prefix =>
(* prefix |zty0 -> prefix |_ op uty0 *)
let suffix' := OperatorSeq.ExpSuffix op uty0 in
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
let zty0' := ZTyp.CursorT Before UHTyp.Hole in
Some (make_ty_OpSeqZ zty0' surround')
| OperatorSeq.BothNonEmpty prefix suffix =>
(* prefix |zty0 suffix -> prefix |_ op uty0 suffix *)
let suffix' := OperatorSeq.suffix_prepend_exp suffix op uty0 in
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
let zty0' := ZTyp.CursorT Before UHTyp.Hole in
Some (make_ty_OpSeqZ zty0' surround')
end
end
(* Zipper Cases *)
| (a, ZTyp.ParenthesizedZ zty1) =>
match perform_ty fuel a zty1 with
| Some zty1' =>
Some (ZTyp.ParenthesizedZ zty1')
| None => None
end
| (a, ZTyp.ListZ zty1) =>
match perform_ty fuel a zty1 with
| Some zty1 =>
Some (ZTyp.ListZ zty1)
| None => None
end
| (a, ZTyp.OpSeqZ skel zty0 surround) =>
match perform_ty fuel a zty0 with
| Some zty0' =>
Some (ZTyp.OpSeqZ skel zty0' surround)
| None => None
end
(* Invalid actions at the type level *)
| (UpdateApPalette _, _)
| (Construct SAsc, _)
| (Construct SLet, _)
| (Construct (SVar _ _), _)
| (Construct SLam, _)
| (Construct (SNumLit _ _), _)
| (Construct (SBoolLit _ _), _)
| (Construct SListNil, _)
| (Construct (SInj _), _)
| (Construct SCase, _)
| (Construct SRule, _)
| (Construct (SApPalette _), _)
| (Construct SWild, _) => None
end
end.
Definition abs_perform_Backspace_Before_op
{E Z op M : Type}
(combine_for_Backspace_Space : E -> Z -> Z)
(z_typecheck_fix_holes : Fuel.t -> Contexts.t -> MetaVarGen.t -> Z -> option(M))
(make_and_typecheck_OpSeqZ :
Fuel.t -> Contexts.t -> MetaVarGen.t ->
Z -> OperatorSeq.opseq_surround E op ->
option(M))
(is_EmptyHole : E -> bool)
(is_Space : op -> bool)
(Space : op)
(Cursor : cursor_side -> E -> Z)
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(e0 : E)
(ze0 : Z)
(surround : OperatorSeq.opseq_surround E op)
: option(M) :=
match surround with
| OperatorSeq.EmptyPrefix _ => None
| OperatorSeq.EmptySuffix prefix =>
match prefix with
| OperatorSeq.ExpPrefix e1 op1 =>
(* e1 op1 |ze0 *)
if is_Space op1 then
(* e1 |ze0 *)
let ze0' := combine_for_Backspace_Space e1 ze0 in
z_typecheck_fix_holes fuel ctx u_gen ze0'
else
match (is_EmptyHole e1, is_EmptyHole e0) with
| (true, true) =>
(* _1 op1 |_0 --> _1| *)
let ze0' := Cursor After e1 in
z_typecheck_fix_holes fuel ctx u_gen ze0'
| (true, _) =>
(* _1 op1 |e0 --> |e0 *)
z_typecheck_fix_holes fuel ctx u_gen ze0
| (false, true) =>
(* e1 op1 |_0 --> e1| *)
let ze0' := Cursor After e1 in
z_typecheck_fix_holes fuel ctx u_gen ze0'
| (false, false) =>
(* e1 op1 |ze0 --> e1 |ze0 *)
let surround' :=
OperatorSeq.EmptySuffix
(OperatorSeq.ExpPrefix e1 Space) in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
| OperatorSeq.SeqPrefix seq1 op1 =>
(* seq1 op1 |ze0 *)
match is_Space op1 with
| true =>
(* seq1 |ze0 *)
let (e1, prefix') := OperatorSeq.split_tail seq1 in
let surround' := OperatorSeq.EmptySuffix prefix' in
let ze0' := combine_for_Backspace_Space e1 ze0 in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0' surround'
| false =>
let (e1, prefix') := OperatorSeq.split_tail seq1 in
if is_EmptyHole e0 then
(* prefix' e1 op1 |_0 --> prefix' e1| *)
let surround' := OperatorSeq.EmptySuffix prefix' in
let ze0' := Cursor After e1 in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0' surround'
else if is_EmptyHole e1 then
(* prefix' _1 op1 |e0 --> prefix' |e0 *)
let surround' := OperatorSeq.EmptySuffix prefix' in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
else
(* seq1 op1 |ze0 --> seq1 |ze0 *)
let prefix' := OperatorSeq.SeqPrefix seq1 Space in
let surround' := OperatorSeq.EmptySuffix prefix' in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
end
| OperatorSeq.BothNonEmpty prefix suffix =>
match prefix with
| OperatorSeq.ExpPrefix e1 op1 =>
(* e1 op1 |ze0 ...suffix *)
match is_Space op1 with
| true =>
(* e1 |ze0 ...suffix *)
let ze0' := combine_for_Backspace_Space e1 ze0 in
let surround' := OperatorSeq.EmptyPrefix suffix in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0' surround'
| false =>
if is_EmptyHole e0 then
(* e1 op1 |_0 suffix --> e1| suffix *)
let surround' := OperatorSeq.EmptyPrefix suffix in
let ze0' := Cursor After e1 in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0' surround'
else if is_EmptyHole e1 then
(* _1 op1 |e0 suffix --> |e0 suffix *)
let surround' := OperatorSeq.EmptyPrefix suffix in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
else
(* e1 op1 |ze0 --> e1 |ze0 ...suffix *)
let surround' :=
OperatorSeq.BothNonEmpty
(OperatorSeq.ExpPrefix e1 Space)
suffix in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
| OperatorSeq.SeqPrefix seq1 op1 =>
(* seq1 op1 |ze0 ...suffix *)
match is_Space op1 with
| true =>
(* seq1 |ze0 ...suffix *)
let (e1, prefix') := OperatorSeq.split_tail seq1 in
let ze0' := combine_for_Backspace_Space e1 ze0 in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0' surround'
| false =>
let (e1, prefix') := OperatorSeq.split_tail seq1 in
if is_EmptyHole e0 then
(* prefix' e1 op1 |_0 suffix --> prefix' e1| suffix *)
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
let ze0' := Cursor After e1 in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0' surround'
else if is_EmptyHole e1 then
(* prefix' _1 op1 |e0 suffix --> prefix' |e0 suffix *)
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
else
(* seq1 op1 |ze0 suffix --> seq1 |ze0 suffix *)
let prefix' := OperatorSeq.SeqPrefix seq1 Space in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
end
end.
Definition abs_perform_Delete_After_op
{E Z op M : Type}
(combine_for_Delete_Space : Z -> E -> Z)
(z_typecheck_fix_holes : Fuel.t -> Contexts.t -> MetaVarGen.t -> Z -> option(M))
(make_and_typecheck_OpSeqZ :
Fuel.t -> Contexts.t -> MetaVarGen.t ->
Z -> OperatorSeq.opseq_surround E op ->
option(M))
(is_EmptyHole : E -> bool)
(is_Space : op -> bool)
(Space : op)
(Cursor : cursor_side -> E -> Z)
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(e0 : E)
(ze0 : Z)
(surround : OperatorSeq.opseq_surround E op)
: option(M) :=
match surround with
| OperatorSeq.EmptySuffix _ => None (* precluded by pattern match above *)
| OperatorSeq.EmptyPrefix suffix =>
match suffix with
| OperatorSeq.ExpSuffix op e1 =>
match is_Space op with
| true =>
let ze0' := combine_for_Delete_Space ze0 e1 in
z_typecheck_fix_holes fuel ctx u_gen ze0'
| false =>
match (is_EmptyHole e0, is_EmptyHole e1) with
| (true, true) =>
(* _0| op _1 --> _0| *)
z_typecheck_fix_holes fuel ctx u_gen ze0
| (true, false) =>
(* _0| op e1 --> |e1 *)
let ze1 := Cursor Before e1 in
z_typecheck_fix_holes fuel ctx u_gen ze1
| (false, true) =>
(* e0| op _ --> e0| *)
z_typecheck_fix_holes fuel ctx u_gen ze0
| (false, false) =>
(* e0| op e1 --> e0| e1 *)
let surround' :=
OperatorSeq.EmptyPrefix
(OperatorSeq.ExpSuffix Space e1) in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
end
| OperatorSeq.SeqSuffix op seq =>
match is_Space op with
| true =>
let (e, suffix') := OperatorSeq.split0 seq in
let surround' := OperatorSeq.EmptyPrefix suffix' in
let ze0' := combine_for_Delete_Space ze0 e in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0' surround'
| false =>
let (e1, suffix') := OperatorSeq.split0 seq in
if is_EmptyHole e1 then
(* e0| op _ suffix' --> e0| suffix' *)
let surround' := OperatorSeq.EmptyPrefix suffix' in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
else if is_EmptyHole e0 then
(* _0| op e1 suffix' --> |e1 suffix' *)
let surround' := OperatorSeq.EmptyPrefix suffix' in
let ze1 := Cursor Before e1 in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze1 surround'
else
(* e0| op seq --> e0| seq *)
let suffix' := OperatorSeq.SeqSuffix Space seq in
let surround' := OperatorSeq.EmptyPrefix suffix' in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
end
| OperatorSeq.BothNonEmpty prefix suffix =>
match suffix with
| OperatorSeq.ExpSuffix op e1 =>
match is_Space op with
| true =>
let ze0' := combine_for_Delete_Space ze0 e1 in
let surround' := OperatorSeq.EmptySuffix prefix in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0' surround'
| false =>
if is_EmptyHole e1 then
(* prefix e0| op _ --> prefix e0| *)
let surround' := OperatorSeq.EmptySuffix prefix in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
else if is_EmptyHole e0 then
(* prefix _0| op e1 --> prefix |e1 *)
let surround' := OperatorSeq.EmptySuffix prefix in
let ze1 := Cursor Before e1 in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze1 surround'
else
(* prefix e0| op e1 --> e0| e1 *)
let surround' :=
OperatorSeq.BothNonEmpty prefix
(OperatorSeq.ExpSuffix Space e1) in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
| OperatorSeq.SeqSuffix op seq =>
match is_Space op with
| true =>
let (e, suffix') := OperatorSeq.split0 seq in
let ze0' := combine_for_Delete_Space ze0 e in
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0' surround'
| false =>
let (e1, suffix') := OperatorSeq.split0 seq in
if is_EmptyHole e1 then
(* prefix e0| op _ suffix' --> prefix e0| suffix' *)
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
else if is_EmptyHole e0 then
(* prefix _0| op e1 suffix' --> prefix |e1 suffix' *)
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
let ze1 := Cursor Before e1 in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze1 surround'
else
(* prefix e| op seq --> e| seq *)
let suffix' := OperatorSeq.SeqSuffix Space seq in
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
end
end.
Definition abs_perform_Construct_SOp_After
{E Z Op M : Type}
(bidelimit : E -> E)
(new_EmptyHole : MetaVarGen.t -> (Z * MetaVarGen.t))
(make_and_typecheck_OpSeqZ :
Fuel.t -> Contexts.t -> MetaVarGen.t ->
Z -> OperatorSeq.opseq_surround E Op ->
option(M))
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(e : E) (op : Op)
: option(M) :=
let e' := bidelimit e in
let prefix := OperatorSeq.ExpPrefix e' op in
let surround := OperatorSeq.EmptySuffix prefix in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround.
Definition abs_perform_Construct_SOp_Before
{E Z Op M : Type}
(bidelimit : E -> E)
(new_EmptyHole : MetaVarGen.t -> (Z * MetaVarGen.t))
(make_and_typecheck_OpSeqZ :
Fuel.t -> Contexts.t -> MetaVarGen.t ->
Z -> OperatorSeq.opseq_surround E Op ->
option(M))
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(e : E) (op : Op)
: option(M) :=
let e' := bidelimit e in
let suffix := OperatorSeq.ExpSuffix op e' in
let surround := OperatorSeq.EmptyPrefix suffix in
let (ze0, u_gen') := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround.
Definition abs_perform_Construct_SOp_After_surround
{E Z Op M : Type}
(new_EmptyHole : MetaVarGen.t -> (Z * MetaVarGen.t))
(make_and_typecheck_OpSeqZ :
Fuel.t -> Contexts.t -> MetaVarGen.t ->
Z -> OperatorSeq.opseq_surround E Op -> option(M))
(is_Space : Op -> bool)
(Space : Op)
(Cursor : cursor_side -> E -> Z)
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(e : E)
(op : Op)
(surround : OperatorSeq.opseq_surround E Op)
: option(M) :=
match surround with
| OperatorSeq.EmptySuffix prefix =>
let prefix' := OperatorSeq.prefix_append_exp prefix e op in
let surround' := OperatorSeq.EmptySuffix prefix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| OperatorSeq.EmptyPrefix suffix =>
match suffix with
| OperatorSeq.ExpSuffix op' e' =>
match is_Space op with
| true =>
(* e| op' e' --> e |_ op' e' *)
let prefix' := OperatorSeq.ExpPrefix e op in
let suffix' := OperatorSeq.ExpSuffix op' e' in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| false =>
match is_Space op' with
| true =>
(* e| e' --> e op |e' *)
let prefix' := OperatorSeq.ExpPrefix e op in
let surround' := OperatorSeq.EmptySuffix prefix' in
let ze0 := Cursor Before e' in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| false =>
(* e| op' e' --> e op |_ op' e' *)
let prefix' := OperatorSeq.ExpPrefix e op in
let suffix' := OperatorSeq.ExpSuffix op' e' in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
end
| OperatorSeq.SeqSuffix op' seq' =>
match is_Space op with
| true =>
(* e| seq' --> e |_ op' seq' *)
let prefix' := OperatorSeq.ExpPrefix e op in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| false =>
match is_Space op' with
| true =>
(* e| seq' --> e op |seq' *)
let prefix' := OperatorSeq.ExpPrefix e op in
let (e0', suffix') := OperatorSeq.split0 seq' in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix' in
let ze0 := Cursor Before e0' in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| false =>
(* e| op' seq' --> e op |_ op' seq' *)
let prefix' := OperatorSeq.ExpPrefix e op in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
end
end
| OperatorSeq.BothNonEmpty prefix suffix =>
match suffix with
| OperatorSeq.ExpSuffix op' e' =>
match is_Space op with
| true =>
(* prefix e| op' e' --> prefix e |_ op' e' *)
let prefix' := OperatorSeq.prefix_append_exp prefix e op in
let suffix' := OperatorSeq.ExpSuffix op' e' in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| false =>
match is_Space op' with
| true =>
(* prefix e| e' --> prefix e op |e' *)
let prefix' := OperatorSeq.prefix_append_exp prefix e op in
let surround' := OperatorSeq.EmptySuffix prefix' in
let ze0 := Cursor Before e' in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| false =>
(* prefix e| op' e' --> prefix e op |_ op' e' *)
let prefix' := OperatorSeq.prefix_append_exp prefix e op in
let suffix' := OperatorSeq.ExpSuffix op' e' in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
end
| OperatorSeq.SeqSuffix op' seq' =>
match is_Space op with
| true =>
(* prefix e| op' seq' --> prefix e |_ op' seq' *)
let prefix' := OperatorSeq.prefix_append_exp prefix e op in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| false =>
match is_Space op' with
| true =>
(* prefix e| seq' --> prefix e op |seq' *)
let prefix' := OperatorSeq.prefix_append_exp prefix e op in
let (e0', suffix') := OperatorSeq.split0 seq' in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix' in
let ze0' := Cursor Before e0' in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0' surround'
| false =>
(* prefix e| op' seq' --> prefix e op |_ op' seq' *)
let prefix' := OperatorSeq.prefix_append_exp prefix e op in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
end
end
end.
Definition abs_perform_Construct_SOp_Before_surround
{E Z Op M : Type}
(erase : Z -> E)
(new_EmptyHole : MetaVarGen.t -> (Z * MetaVarGen.t))
(make_and_typecheck_OpSeqZ :
Fuel.t -> Contexts.t -> MetaVarGen.t ->
Z -> OperatorSeq.opseq_surround E Op -> option(M))
(is_Space : Op -> bool)
(Space : Op)
(Cursor : cursor_side -> E -> Z)
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(ze0 : Z)
(op : Op)
(surround : OperatorSeq.opseq_surround E Op)
: option(M) :=
match surround with
| OperatorSeq.EmptyPrefix suffix =>
(* |ze0 ... --> |_ op e0 ... *)
let e0 := erase ze0 in
let suffix' := OperatorSeq.suffix_prepend_exp suffix op e0 in
let surround' := OperatorSeq.EmptyPrefix suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| OperatorSeq.EmptySuffix ((OperatorSeq.ExpPrefix e1 op') as prefix) =>
match is_Space op' with
| true =>
match is_Space op with
| true =>
(* e1 |ze0 --> e1 |_ e0 *)
let e0 := erase ze0 in
let suffix' := OperatorSeq.ExpSuffix Space e0 in
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| false =>
(* e1 |ze0 --> e1 op |ze0 *)
let surround' := OperatorSeq.EmptySuffix (OperatorSeq.ExpPrefix e1 op) in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
| false =>
(* prefix [^ ] |ze0 --> prefix |_ op e0 *)
let e0 := erase ze0 in
let suffix' := OperatorSeq.ExpSuffix op e0 in
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
| OperatorSeq.EmptySuffix ((OperatorSeq.SeqPrefix seq1 op') as prefix) =>
match is_Space op' with
| true =>
match is_Space op with
| true =>
(* seq1 |ze0 --> seq1 |_ e0 *)
let e0 := erase ze0 in
let suffix' := OperatorSeq.ExpSuffix Space e0 in
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| false =>
(* seq1 |ze0 --> seq1 op |ze0 *)
let surround' := OperatorSeq.EmptySuffix (OperatorSeq.SeqPrefix seq1 op) in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
| false =>
(* prefix [^ ] |ze0 --> prefix |_ op e0 *)
let e0 := erase ze0 in
let suffix' := OperatorSeq.ExpSuffix op e0 in
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
| OperatorSeq.BothNonEmpty ((OperatorSeq.ExpPrefix e1 op') as prefix) suffix =>
match is_Space op' with
| true =>
match is_Space op with
| true =>
(* e1 |ze0 suffix --> e1 |_ e0 suffix *)
let e0 := erase ze0 in
let suffix' := OperatorSeq.suffix_prepend_exp suffix Space e0 in
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| false =>
(* e1 |ze0 suffix --> e1 op |ze0 suffix *)
let prefix' := OperatorSeq.ExpPrefix e1 op in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
| false =>
(* prefix [^ ] |ze0 suffix --> prefix |_ op e0 suffix *)
let e0 := erase ze0 in
let suffix' := OperatorSeq.suffix_prepend_exp suffix op e0 in
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
| OperatorSeq.BothNonEmpty ((OperatorSeq.SeqPrefix seq1 op') as prefix) suffix =>
match is_Space op' with
| true =>
match is_Space op with
| true =>
(* seq1 |ze0 suffix --> seq1 |_ e0 suffix *)
let e0 := erase ze0 in
let suffix' := OperatorSeq.suffix_prepend_exp suffix Space e0 in
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
| false =>
(* seq1 |ze0 suffix --> seq1 op |ze0 suffix *)
let prefix' := OperatorSeq.SeqPrefix seq1 op in
let surround' := OperatorSeq.BothNonEmpty prefix' suffix in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
| false =>
(* prefix [^ ] |ze0 suffix --> prefix |_ op e0 suffix *)
let e0 := erase ze0 in
let suffix' := OperatorSeq.suffix_prepend_exp suffix op e0 in
let surround' := OperatorSeq.BothNonEmpty prefix suffix' in
let (ze0, u_gen) := new_EmptyHole u_gen in
make_and_typecheck_OpSeqZ fuel ctx u_gen ze0 surround'
end
end.
Definition syn_zpat_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(zp : ZPat.t)
: option (ZPat.t * HTyp.t * Contexts.t * MetaVarGen.t) :=
let path := Path.of_zpat zp in
let p := ZPat.erase zp in
match UHExp.syn_pat_fix_holes fuel ctx u_gen false p with
| None => None
| Some (p, ty, ctx, u_gen) =>
match Path.follow_pat fuel path p with
| None => None
| Some zp => Some (zp, ty, ctx, u_gen)
end
end.
Definition ana_zpat_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(zp : ZPat.t)
(ty : HTyp.t)
: option (ZPat.t * Contexts.t * MetaVarGen.t) :=
let path := Path.of_zpat zp in
let p := ZPat.erase zp in
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p ty with
| None => None
| Some (p, ctx, u_gen) =>
match Path.follow_pat fuel path p with
| None => None
| Some zp => Some (zp, ctx, u_gen)
end
end.
Definition make_and_syn_OpSeqZ_pat
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(zp0 : ZPat.t)
(surround : ZPat.opseq_surround)
: option (ZPat.t * HTyp.t * Contexts.t * MetaVarGen.t) :=
(* figure out the current path so that we can follow it again
* to reconstitute the Z-exp after calling into the UHExp hole
* insertion logic (otherwise we'd have to do a version of that
* logic specific to Z-exps) *)
let path0 := Path.of_OpSeqZ_pat zp0 surround in
let p0 := ZPat.erase zp0 in
let seq := OperatorSeq.opseq_of_exp_and_surround p0 surround in
let skel := Associator.associate_pat seq in
match UHExp.syn_skel_pat_fix_holes fuel ctx u_gen false skel seq with
| Some (skel, seq, ty, ctx, u_gen) =>
let p := UHPat.Pat NotInHole (UHPat.OpSeq skel seq) in
match Path.follow_pat fuel path0 p with
| Some zp => Some (zp, ty, ctx, u_gen)
| None => None
end
| None => None
end.
Definition make_and_ana_OpSeqZ_pat
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(zp0 : ZPat.t)
(surround : ZPat.opseq_surround)
(ty : HTyp.t)
: option (ZPat.t * Contexts.t * MetaVarGen.t) :=
(* figure out the current path so that we can follow it again
* to reconstitute the Z-exp after calling into the UHExp hole
* insertion logic (otherwise we'd have to do a version of that
* logic specific to Z-exps) *)
let path0 := Path.of_OpSeqZ_pat zp0 surround in
let p0 := ZPat.erase zp0 in
let seq := OperatorSeq.opseq_of_exp_and_surround p0 surround in
let skel := Associator.associate_pat seq in
match UHExp.ana_skel_pat_fix_holes fuel ctx u_gen false skel seq ty with
| Some ((Skel.BinOp err _ _ _) as skel, seq, ctx, u_gen) =>
let p := UHPat.Pat err (UHPat.OpSeq skel seq) in
match Path.follow_pat fuel path0 p with
| Some zp => Some (zp, ctx, u_gen)
| None => None
end
| Some (Skel.Placeholder _ _, _, _, _)
| None => None
end.
Definition combine_for_Backspace_Space_pat p1 zp0 :=
match zp0 with
| ZPat.CursorP _ (UHPat.Pat _ (UHPat.EmptyHole _)) =>
(* p1 |_ --> p1| *)
ZPat.CursorP After p1
| _ =>
(* p1 |zp0 --> |zp0 *)
zp0
end.
Definition combine_for_Delete_Space_pat zp0 p :=
match (zp0, p) with
| ((ZPat.CursorP After (UHPat.Pat _ (UHPat.EmptyHole _))),
UHPat.Pat _ (UHPat.EmptyHole _)) =>
(* _| _ --> _| *)
zp0
| ((ZPat.CursorP After (UHPat.Pat _ (UHPat.EmptyHole _))),
_) =>
(* _| p --> |p *)
ZPat.CursorP Before p
| _ =>
zp0
end.
Fixpoint perform_syn_pat
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(a : t)
(zp : ZPat.t)
: option(ZPat.t * HTyp.t * Contexts.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match (a, zp) with
(* Movement *)
(* NOTE: we don't need to handle movement actions here for the purposes of the UI,
* since it's handled at the top (expression) level, but for the sake of API completeness
* we include it *)
| (MoveTo path, _) =>
let p := ZPat.erase zp in
match UHExp.syn_pat fuel ctx p with
| None => None
| Some (ty, _) =>
match Path.follow_pat fuel path p with
| Some zp => Some (zp, ty, ctx, u_gen)
| None => None
end
end
| (MoveToPrevHole, _) =>
match Path.prev_hole_path_pat fuel zp with
| None => None
| Some path => perform_syn_pat fuel ctx u_gen (MoveTo path) zp
end
| (MoveToNextHole, _) =>
match Path.next_hole_path_pat fuel zp with
| None => None
| Some path => perform_syn_pat fuel ctx u_gen (MoveTo path) zp
end
(* Backspace and Delete *)
| (Backspace, ZPat.CursorP After p) =>
match p with
| UHPat.Pat _ (UHPat.EmptyHole _) =>
Some (ZPat.CursorP Before p, HTyp.Hole, ctx, u_gen)
| _ =>
let (p, u_gen) := UHPat.new_EmptyHole u_gen in
Some (ZPat.CursorP Before p, HTyp.Hole, ctx, u_gen)
end
| (Backspace, ZPat.CursorP Before _) => None
| (Delete, ZPat.CursorP Before p) =>
match p with
| UHPat.Pat _ (UHPat.EmptyHole _) =>
Some (ZPat.CursorP After p, HTyp.Hole, ctx, u_gen)
| _ =>
let (e', u_gen') := UHExp.new_EmptyHole u_gen in
Some (ZPat.CursorP Before p, HTyp.Hole, ctx, u_gen)
end
| (Delete, ZPat.CursorP After _) => None
| (Backspace, ZPat.CursorP (In _) _)
| (Delete, ZPat.CursorP (In _) _) =>
let (p, u_gen) := UHPat.new_EmptyHole u_gen in
let zp := ZPat.CursorP Before p in
Some (zp, HTyp.Hole, ctx, u_gen)
| (Backspace, ZPat.Deeper _
(ZPat.OpSeqZ _
((ZPat.CursorP Before p0) as zp0)
((OperatorSeq.EmptySuffix _) as surround)))
| (Backspace, ZPat.Deeper _
(ZPat.OpSeqZ _
((ZPat.CursorP Before p0) as zp0)
((OperatorSeq.BothNonEmpty _ _) as surround))) =>
abs_perform_Backspace_Before_op
combine_for_Backspace_Space_pat
syn_zpat_fix_holes
make_and_syn_OpSeqZ_pat
UHPat.is_EmptyHole
UHPat.is_Space
UHPat.Space
ZPat.CursorP
fuel ctx u_gen p0 zp0 surround
| (Delete, ZPat.Deeper _
(ZPat.OpSeqZ _
((ZPat.CursorP After p0) as zp0)
((OperatorSeq.EmptyPrefix _) as surround)))
| (Delete, ZPat.Deeper _
(ZPat.OpSeqZ _
((ZPat.CursorP After p0) as zp0)
((OperatorSeq.BothNonEmpty _ _) as surround))) =>
abs_perform_Delete_After_op
combine_for_Delete_Space_pat
syn_zpat_fix_holes
make_and_syn_OpSeqZ_pat
UHPat.is_EmptyHole
UHPat.is_Space
UHPat.Space
ZPat.CursorP
fuel ctx u_gen p0 zp0 surround
(* Construct *)
| (Construct SParenthesized, ZPat.CursorP _ p) =>
match UHExp.syn_pat fuel ctx p with
| None => None
| Some (ty, ctx) =>
Some (
ZPat.ParenthesizedZ zp,
ty,
ctx,
u_gen)
end
| (Construct (SVar x side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.EmptyHole _)))
| (Construct (SVar x side), ZPat.CursorP _ (UHPat.Pat _ UHPat.Wild))
| (Construct (SVar x side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.Var _)))
| (Construct (SVar x side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.NumLit _)))
| (Construct (SVar x side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.BoolLit _))) =>
Var.check_valid x (
let ctx := Contexts.extend_gamma ctx (x, HTyp.Hole) in
Some
(ZPat.CursorP side (UHPat.Pat NotInHole (UHPat.Var x)),
HTyp.Hole,
ctx,
u_gen)
)
| (Construct (SVar _ _), ZPat.CursorP _ _) => None
| (Construct SWild, ZPat.CursorP _ (UHPat.Pat _ (UHPat.EmptyHole _)))
| (Construct SWild, ZPat.CursorP _ (UHPat.Pat _ UHPat.Wild))
| (Construct SWild, ZPat.CursorP _ (UHPat.Pat _ (UHPat.Var _)))
| (Construct SWild, ZPat.CursorP _ (UHPat.Pat _ (UHPat.NumLit _)))
| (Construct SWild, ZPat.CursorP _ (UHPat.Pat _ (UHPat.BoolLit _))) =>
Some
(ZPat.CursorP After (UHPat.Pat NotInHole UHPat.Wild),
HTyp.Hole,
ctx,
u_gen)
| (Construct SWild, ZPat.CursorP _ _) => None
| (Construct (SNumLit n side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.EmptyHole _)))
| (Construct (SNumLit n side), ZPat.CursorP _ (UHPat.Pat _ UHPat.Wild))
| (Construct (SNumLit n side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.Var _)))
| (Construct (SNumLit n side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.NumLit _)))
| (Construct (SNumLit n side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.BoolLit _))) =>
Some
(ZPat.CursorP side (UHPat.Pat NotInHole (UHPat.NumLit n)),
HTyp.Num,
ctx,
u_gen)
| (Construct (SNumLit _ _), ZPat.CursorP _ _) => None
| (Construct (SBoolLit b side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.EmptyHole _)))
| (Construct (SBoolLit b side), ZPat.CursorP _ (UHPat.Pat _ UHPat.Wild))
| (Construct (SBoolLit b side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.Var _)))
| (Construct (SBoolLit b side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.NumLit _)))
| (Construct (SBoolLit b side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.BoolLit _))) =>
Some
(ZPat.CursorP side (UHPat.Pat NotInHole (UHPat.BoolLit b)),
HTyp.Bool,
ctx,
u_gen)
| (Construct (SBoolLit _ _), ZPat.CursorP _ _) => None
| (Construct (SInj side), ZPat.CursorP _ p1) =>
match UHExp.syn_pat fuel ctx p1 with
| None => None
| Some (ty1, ctx) =>
let zp := ZPat.Deeper NotInHole
(ZPat.InjZ side zp) in
let ty :=
match side with
| L => HTyp.Sum ty1 HTyp.Hole
| R => HTyp.Sum HTyp.Hole ty1
end in
Some (zp, ty, ctx, u_gen)
end
| (Construct SListNil, (ZPat.CursorP _ (UHPat.Pat _ (UHPat.EmptyHole _)))) =>
let zp := ZPat.CursorP After (UHPat.Pat NotInHole UHPat.ListNil) in
let ty := HTyp.List HTyp.Hole in
Some (zp, ty, ctx, u_gen)
| (Construct SListNil, ZPat.CursorP _ _) => None
| (Construct (SOp os), ZPat.Deeper _ (
ZPat.OpSeqZ _ (ZPat.CursorP (In _) p) surround))
| (Construct (SOp os), ZPat.Deeper _ (
ZPat.OpSeqZ _ (ZPat.CursorP After p) surround)) =>
match pat_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_After_surround
ZPat.new_EmptyHole
make_and_syn_OpSeqZ_pat
UHPat.is_Space
UHPat.Space
ZPat.CursorP
fuel ctx u_gen p op surround
end
| (Construct (SOp os),
ZPat.Deeper _ (ZPat.OpSeqZ _
((ZPat.CursorP Before _) as zp0) surround)) =>
match pat_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_Before_surround
ZPat.erase
ZPat.new_EmptyHole
make_and_syn_OpSeqZ_pat
UHPat.is_Space
UHPat.Space
ZPat.CursorP
fuel ctx u_gen zp0 op surround
end
| (Construct (SOp os), ZPat.CursorP (In _) p)
| (Construct (SOp os), ZPat.CursorP After p) =>
match pat_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_After
UHPat.bidelimit
ZPat.new_EmptyHole
make_and_syn_OpSeqZ_pat
fuel ctx u_gen p op
end
| (Construct (SOp os), ZPat.CursorP Before p) =>
match pat_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_Before
UHPat.bidelimit
ZPat.new_EmptyHole
make_and_syn_OpSeqZ_pat
fuel ctx u_gen p op
end
(* Zipper *)
| (_, ZPat.ParenthesizedZ zp1) =>
match perform_syn_pat fuel ctx u_gen a zp1 with
| None => None
| Some (zp1, ty, ctx, u_gen) =>
Some (
ZPat.ParenthesizedZ zp1,
ty,
ctx,
u_gen)
end
| (_, ZPat.Deeper _ (ZPat.InjZ side zp1)) =>
match perform_syn_pat fuel ctx u_gen a zp1 with
| None => None
| Some (zp1, ty1, ctx, u_gen) =>
let zp := ZPat.Deeper NotInHole
(ZPat.InjZ side zp1) in
let ty :=
match side with
| L => HTyp.Sum ty1 HTyp.Hole
| R => HTyp.Sum HTyp.Hole ty1
end in
Some (zp, ty, ctx, u_gen)
end
| (_, ZPat.Deeper _ (ZPat.OpSeqZ _ zp0 surround)) =>
let i := OperatorSeq.surround_prefix_length surround in
match ZPat.erase zp with
| UHPat.Pat _ (UHPat.OpSeq skel seq) =>
match UHExp.syn_skel_pat fuel ctx skel seq (Some i) with
| Some (ty, ctx, Some mode) =>
match mode with
| UHExp.AnalyzedAgainst ty0 =>
match perform_ana_pat fuel ctx u_gen a zp0 ty0 with
| None => None
| Some (zp0, ctx, u_gen) =>
let zp0 := ZPat.bidelimit zp0 in
Some (
ZPat.Deeper NotInHole (ZPat.OpSeqZ skel zp0 surround),
ty, ctx, u_gen)
end
| UHExp.Synthesized ty0 =>
match perform_syn_pat fuel ctx u_gen a zp0 with
| Some (zp0, ty0, ctx, u_gen) =>
let zp0 := ZPat.bidelimit zp0 in
make_and_syn_OpSeqZ_pat fuel ctx u_gen zp0 surround
| None => None
end
end
| Some _ => None (* should never happen *)
| None => None (* should never happen *)
end
| _ => None (* should never happen *)
end
| (UpdateApPalette _, _)
| (Construct (SApPalette _), _)
| (Construct SNum, _)
| (Construct SBool, _)
| (Construct SList, _)
| (Construct SAsc, _)
| (Construct SLet, _)
| (Construct SLam, _)
| (Construct SCase, _)
| (Construct SRule, _) => None
end
end
with perform_ana_pat
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(a : t)
(zp : ZPat.t)
(ty : HTyp.t)
: option(ZPat.t * Contexts.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match (a, zp) with
(* Movement *)
(* NOTE: we don't need to handle movement actions here for the purposes of the UI,
* since it's handled at the top (expression) level, but for the sake of API completeness
* we include it *)
| (MoveTo path, _) =>
let p := ZPat.erase zp in
match Path.follow_pat fuel path p with
| Some zp => Some (zp, ctx, u_gen)
| None => None
end
| (MoveToPrevHole, _) =>
match Path.prev_hole_path_pat fuel zp with
| None => None
| Some path => perform_ana_pat fuel ctx u_gen (MoveTo path) zp ty
end
| (MoveToNextHole, _) =>
match Path.next_hole_path_pat fuel zp with
| None => None
| Some path => perform_ana_pat fuel ctx u_gen (MoveTo path) zp ty
end
(* switch to synthesis if in a hole *)
| (_, ZPat.Deeper (InHole TypeInconsistent u) zp1) =>
let zp1_not_in_hole := ZPat.Deeper NotInHole zp1 in
let p1 := ZPat.erase zp1_not_in_hole in
match UHExp.syn_pat fuel ctx p1 with
| None => None
| Some (ty1, _) =>
match perform_syn_pat fuel ctx u_gen a zp1_not_in_hole with
| None => None
| Some (zp1, ty', ctx, u_gen) =>
if HTyp.consistent ty ty' then
Some (zp1, ctx, u_gen)
else
Some (ZPat.set_inconsistent u zp1, ctx, u_gen)
end
end
(* Backspace and Delete *)
| (Backspace, ZPat.CursorP After p) =>
match p with
| UHPat.Pat _ (UHPat.EmptyHole _) =>
Some (ZPat.CursorP Before p, ctx, u_gen)
| _ =>
let (p, u_gen) := UHPat.new_EmptyHole u_gen in
Some (ZPat.CursorP Before p, ctx, u_gen)
end
| (Backspace, ZPat.CursorP Before p) => None
| (Delete, ZPat.CursorP Before p) =>
match p with
| UHPat.Pat _ (UHPat.EmptyHole _) =>
Some (ZPat.CursorP After p, ctx, u_gen)
| _ =>
let (e', u_gen') := UHExp.new_EmptyHole u_gen in
Some (ZPat.CursorP Before p, ctx, u_gen)
end
| (Backspace, ZPat.CursorP (In _) _)
| (Delete, ZPat.CursorP (In _) _) =>
let (p, u_gen) := UHPat.new_EmptyHole u_gen in
let zp := ZPat.CursorP Before p in
Some (zp, ctx, u_gen)
| (Delete, ZPat.CursorP After _) => None
(* Construct *)
| (Construct SParenthesized, ZPat.CursorP _ p) =>
match UHExp.ana_pat fuel ctx p ty with
| None => None
| Some ctx =>
Some (
ZPat.ParenthesizedZ zp,
ctx,
u_gen)
end
| (Construct (SVar x side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.EmptyHole _)))
| (Construct (SVar x side), ZPat.CursorP _ (UHPat.Pat _ UHPat.Wild))
| (Construct (SVar x side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.Var _)))
| (Construct (SVar x side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.NumLit _)))
| (Construct (SVar x side), ZPat.CursorP _ (UHPat.Pat _ (UHPat.BoolLit _))) =>
Var.check_valid x (
let ctx := Contexts.extend_gamma ctx (x, ty) in
Some
(ZPat.CursorP side (UHPat.Pat NotInHole (UHPat.Var x)),
ctx,
u_gen)
)
| (Construct (SVar _ _), ZPat.CursorP _ _) => None
| (Construct SWild, ZPat.CursorP _ (UHPat.Pat _ (UHPat.EmptyHole _)))
| (Construct SWild, ZPat.CursorP _ (UHPat.Pat _ UHPat.Wild))
| (Construct SWild, ZPat.CursorP _ (UHPat.Pat _ (UHPat.Var _)))
| (Construct SWild, ZPat.CursorP _ (UHPat.Pat _ (UHPat.NumLit _)))
| (Construct SWild, ZPat.CursorP _ (UHPat.Pat _ (UHPat.BoolLit _))) =>
Some
(ZPat.CursorP After (UHPat.Pat NotInHole UHPat.Wild),
ctx,
u_gen)
| (Construct SWild, ZPat.CursorP _ _) => None
| (Construct (SInj side), ZPat.CursorP cursor_side p1) =>
match HTyp.matched_sum ty with
| Some (tyL, tyR) =>
let ty1 := pick_side side tyL tyR in
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p1 ty1 with
| None => None
| Some (p1, ctx, u_gen) =>
let zp :=
ZPat.Deeper NotInHole
(ZPat.InjZ side
(ZPat.CursorP cursor_side p1)) in
Some (zp, ctx, u_gen)
end
| None =>
match UHExp.syn_pat_fix_holes fuel ctx u_gen false p1 with
| None => None
| Some (p1, _, ctx, u_gen) =>
let (u, u_gen) := MetaVarGen.next u_gen in
let zp :=
ZPat.Deeper (InHole TypeInconsistent u)
(ZPat.InjZ side
(ZPat.CursorP cursor_side p1)) in
Some (zp, ctx, u_gen)
end
end
| (Construct (SOp os), ZPat.Deeper _ (
ZPat.OpSeqZ _ (ZPat.CursorP (In _) p) surround))
| (Construct (SOp os), ZPat.Deeper _ (
ZPat.OpSeqZ _ (ZPat.CursorP After p) surround)) =>
match pat_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_After_surround
ZPat.new_EmptyHole
(fun fuel ctx u_gen zp surround =>
make_and_ana_OpSeqZ_pat fuel ctx u_gen zp surround ty)
UHPat.is_Space
UHPat.Space
ZPat.CursorP
fuel ctx u_gen p op surround
end
| (Construct (SOp os),
ZPat.Deeper _ (ZPat.OpSeqZ _
((ZPat.CursorP Before _) as zp0) surround)) =>
match pat_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_Before_surround
ZPat.erase
ZPat.new_EmptyHole
(fun fuel ctx u_gen zp surround =>
make_and_ana_OpSeqZ_pat fuel ctx u_gen zp surround ty)
UHPat.is_Space
UHPat.Space
ZPat.CursorP
fuel ctx u_gen zp0 op surround
end
| (Construct (SOp os), ZPat.CursorP (In _) p)
| (Construct (SOp os), ZPat.CursorP After p) =>
match pat_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_After
UHPat.bidelimit
ZPat.new_EmptyHole
(fun fuel ctx u_gen zp surround =>
make_and_ana_OpSeqZ_pat fuel ctx u_gen zp surround ty)
fuel ctx u_gen p op
end
| (Construct (SOp os), ZPat.CursorP Before p) =>
match pat_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_Before
UHPat.bidelimit
ZPat.new_EmptyHole
(fun fuel ctx u_gen zp surround =>
make_and_ana_OpSeqZ_pat fuel ctx u_gen zp surround ty)
fuel ctx u_gen p op
end
(* Zipper *)
| (_, ZPat.ParenthesizedZ zp1) =>
match perform_ana_pat fuel ctx u_gen a zp1 ty with
| None => None
| Some (zp1, ctx, u_gen) =>
Some (
ZPat.ParenthesizedZ zp1,
ctx,
u_gen)
end
| (_, ZPat.Deeper _ (ZPat.InjZ side zp1)) =>
match HTyp.matched_sum ty with
| None => None
| Some (tyL, tyR) =>
let ty1 := pick_side side tyL tyR in
match perform_ana_pat fuel ctx u_gen a zp1 ty1 with
| None => None
| Some (zp1, ctx, u_gen) =>
let zp := ZPat.Deeper NotInHole (ZPat.InjZ side zp1) in
Some (zp, ctx, u_gen)
end
end
| (_, ZPat.Deeper _ (ZPat.OpSeqZ _ zp0 surround)) =>
let i := OperatorSeq.surround_prefix_length surround in
match ZPat.erase zp with
| UHPat.Pat _ (UHPat.OpSeq skel seq) =>
match UHExp.ana_skel_pat fuel ctx skel seq ty (Some i) with
| Some (ctx, Some mode) =>
match mode with
| UHExp.AnalyzedAgainst ty0 =>
match perform_ana_pat fuel ctx u_gen a zp0 ty0 with
| None => None
| Some (zp0, ctx, u_gen) =>
let zp0 := ZPat.bidelimit zp0 in
Some (
ZPat.Deeper NotInHole (ZPat.OpSeqZ skel zp0 surround),
ctx, u_gen)
end
| UHExp.Synthesized ty0 =>
match perform_syn_pat fuel ctx u_gen a zp0 with
| Some (zp0, ty0, ctx, u_gen) =>
let zp0 := ZPat.bidelimit zp0 in
make_and_ana_OpSeqZ_pat fuel ctx u_gen zp0 surround ty
| None => None
end
end
| Some _ => None (* should never happen *)
| None => None (* should never happen *)
end
| _ => None (* should never happen *)
end
(* Subsumption *)
| (Construct (SNumLit _ _), _)
| (Construct (SBoolLit _ _), _)
| (Construct FAction.SListNil, _) =>
match perform_syn_pat fuel ctx u_gen a zp with
| None => None
| Some (zp, ty', ctx, u_gen) =>
if HTyp.consistent ty ty' then
Some (zp, ctx, u_gen)
else
let (zp, u_gen) := ZPat.make_inconsistent u_gen zp in
Some (zp, ctx, u_gen)
end
(* Invalid actions at the pattern level *)
| (UpdateApPalette _, _)
| (Construct (SApPalette _), _)
| (Construct SNum, _)
| (Construct SBool, _)
| (Construct SList, _)
| (Construct SAsc, _)
| (Construct SLet, _)
| (Construct SLam, _)
| (Construct SCase, _)
| (Construct SRule, _) => None
end
end.
Definition zexp_syn_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(ze : ZExp.t)
: option (ZExp.t * HTyp.t * MetaVarGen.t) :=
let path := Path.of_zexp ze in
let e := ZExp.erase ze in
match UHExp.syn_fix_holes fuel ctx u_gen e with
| Some (e', ty, u_gen') =>
match Path.follow_e fuel path e' with
| Some ze' => Some (ze', ty, u_gen')
| None => None
end
| None => None
end.
Definition zexp_ana_fix_holes
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(ze : ZExp.t)
(ty : HTyp.t)
: option (ZExp.t * MetaVarGen.t) :=
let path := Path.of_zexp ze in
let e := ZExp.erase ze in
match UHExp.ana_fix_holes fuel ctx u_gen e ty with
| Some (e', u_gen') =>
match Path.follow_e fuel path e' with
| Some ze' => Some (ze', u_gen')
| None => None
end
| None => None
end.
Definition make_and_syn_OpSeqZ
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(ze0 : ZExp.t)
(surround : ZExp.opseq_surround)
: option (ZExp.t * HTyp.t * MetaVarGen.t) :=
(* figure out the current path so that we can follow it again
* to reconstitute the Z-exp after calling into the UHExp hole
* insertion logic (otherwise we'd have to do a version of that
* logic specific to Z-exps) *)
let path0 := Path.of_OpSeqZ ze0 surround in
let e0 := ZExp.erase ze0 in
let seq := OperatorSeq.opseq_of_exp_and_surround e0 surround in
let skel := Associator.associate_exp seq in
match UHExp.syn_skel_fix_holes fuel ctx u_gen false skel seq with
| Some (skel', seq', ty, u_gen') =>
let e' := UHExp.Tm NotInHole (UHExp.OpSeq skel' seq') in
match Path.follow_e fuel path0 e' with
| Some ze' => Some (ze', ty, u_gen')
| None => None
end
| None => None
end.
Definition make_and_ana_OpSeqZ
(fuel : Fuel.t)
(ctx : Contexts.t)
(u_gen : MetaVarGen.t)
(ze0 : ZExp.t)
(surround : ZExp.opseq_surround)
(ty : HTyp.t)
: option (ZExp.t * MetaVarGen.t) :=
(* figure out the current path so that we can follow it again
* to reconstitute the Z-exp after calling into the UHExp hole
* insertion logic (otherwise we'd have to do a version of that
* logic specific to Z-exps) *)
let path0 := Path.of_OpSeqZ ze0 surround in
let e0 := ZExp.erase ze0 in
let seq := OperatorSeq.opseq_of_exp_and_surround e0 surround in
let skel := Associator.associate_exp seq in
match UHExp.ana_skel_fix_holes fuel ctx u_gen false skel seq ty with
| Some ((Skel.BinOp err _ _ _) as skel, seq, u_gen) =>
let e := UHExp.Tm err (UHExp.OpSeq skel seq) in
match Path.follow_e fuel path0 e with
| Some ze => Some (ze, u_gen)
| None => None
end
| Some (Skel.Placeholder _ _, _, _)
| None => None
end.
Definition combine_for_Backspace_Space e1 ze0 :=
match (e1, ze0) with
| (_, ZExp.CursorE _ (UHExp.Tm _ (UHExp.EmptyHole _))) =>
(* e1 |_ --> e1| *)
ZExp.CursorE After e1
| _ => ze0
end.
Definition combine_for_Delete_Space ze0 e :=
match (ze0, e) with
| ((ZExp.CursorE After (UHExp.Tm _ (UHExp.EmptyHole _))),
UHExp.Tm _ (UHExp.EmptyHole _)) =>
(* _| _ --> _| *)
ze0
| ((ZExp.CursorE After (UHExp.Tm _ (UHExp.EmptyHole _))),
_) =>
(* _| e --> |e *)
ZExp.CursorE Before e
| _ =>
ze0
end.
Fixpoint perform_syn
(fuel: Fuel.t)
(ctx: Contexts.t)
(a: t)
(ze_ty: (ZExp.t * HTyp.t) * MetaVarGen.t)
: option ((ZExp.t * HTyp.t) * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match ze_ty with
| (ze, ty, u_gen) =>
match (a, ze) with
(* Movement *)
| (MoveTo path, _) =>
let e := ZExp.erase ze in
match Path.follow_e fuel path e with
| Some ze' => Some (ze', ty, u_gen)
| None => None
end
| (MoveToPrevHole, _) =>
match Path.prev_hole_path fuel ze with
| None => None
| Some path => perform_syn fuel ctx (MoveTo path) ze_ty
end
| (MoveToNextHole, _) =>
match Path.next_hole_path fuel ze with
| None => None
| Some path =>
(* let path := Helper.log_path path in *)
perform_syn fuel ctx (MoveTo path) ze_ty
end
(* Backspace & Deletion *)
| (Backspace, ZExp.CursorE After e) =>
match e with
| UHExp.Tm _ (UHExp.EmptyHole _) =>
Some (ZExp.CursorE Before e, ty, u_gen)
| _ =>
let (e', u_gen') := UHExp.new_EmptyHole u_gen in
Some (ZExp.CursorE Before e', HTyp.Hole, u_gen')
end
| (Backspace, ZExp.CursorE Before e) => None
| (Delete, ZExp.CursorE Before e) =>
match e with
| UHExp.Tm _ (UHExp.EmptyHole _) =>
Some (ZExp.CursorE After e, ty, u_gen)
| _ =>
let (e', u_gen') := UHExp.new_EmptyHole u_gen in
Some (ZExp.CursorE Before e', HTyp.Hole, u_gen)
end
| (Delete, ZExp.CursorE After e) => None
| (Backspace,
ZExp.Deeper _ (ZExp.AscZ2 e1
(ZTyp.CursorT Before _)))
| (Backspace,
ZExp.Deeper _ (ZExp.AscZ2 e1
(ZTyp.OpSeqZ _
(ZTyp.CursorT Before _)
(OperatorSeq.EmptyPrefix _)))) =>
let ze' := ZExp.CursorE After e1 in
zexp_syn_fix_holes fuel ctx u_gen ze'
| (Delete,
ZExp.Deeper _ (ZExp.AscZ1
(ZExp.CursorE After e1)
_)) =>
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| Some (e1', ty', u_gen) =>
let ze' := ZExp.CursorE After e1' in
Some (ze', ty', u_gen)
| None => None
end
| (Backspace, ZExp.Deeper _
(ZExp.LetZA p (ZTyp.CursorT Before _) e1 e2))
| (Backspace, ZExp.Deeper _
(ZExp.LetZA p
(ZTyp.OpSeqZ _
(ZTyp.CursorT Before _)
(OperatorSeq.EmptyPrefix _)) e1 e2)) =>
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| None => None
| Some (e1, ty1, u_gen) =>
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p ty1 with
| None => None
| Some (p, ctx, u_gen) =>
match UHExp.syn_fix_holes fuel ctx u_gen e2 with
| None => None
| Some (e2, ty, u_gen) =>
let ze :=
ZExp.Deeper NotInHole
(ZExp.LetZP (ZPat.CursorP After p) None e1 e2) in
Some (ze, ty, u_gen)
end
end
end
| (Delete, ZExp.Deeper _
(ZExp.LetZP ((ZPat.CursorP After _) as zp) (Some _) e1 e2))
| (Delete, ZExp.Deeper _
(ZExp.LetZP
((ZPat.Deeper _
(ZPat.OpSeqZ _ (ZPat.CursorP After _)
(OperatorSeq.EmptySuffix _))) as zp)
(Some _)
e1 e2)) =>
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| None => None
| Some (e1, ty1, u_gen) =>
match ana_zpat_fix_holes fuel ctx u_gen zp ty1 with
| None => None
| Some (zp, ctx, u_gen) =>
match UHExp.syn_fix_holes fuel ctx u_gen e2 with
| None => None
| Some (e2, ty, u_gen) =>
let ze :=
ZExp.Deeper NotInHole
(ZExp.LetZP zp None e1 e2) in
Some (ze, ty, u_gen)
end
end
end
| (Backspace, ZExp.Deeper _
(ZExp.LamZA p (ZTyp.CursorT Before _) e1))
| (Backspace, ZExp.Deeper _
(ZExp.LamZA p
(ZTyp.OpSeqZ _
(ZTyp.CursorT Before _)
(OperatorSeq.EmptyPrefix _)) e1)) =>
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p HTyp.Hole with
| None => None
| Some (p, ctx, u_gen) =>
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| None => None
| Some (e1, ty2, u_gen) =>
let ze := ZExp.Deeper NotInHole
(ZExp.LamZP (ZPat.CursorP After p) None e1) in
Some (ze, HTyp.Arrow HTyp.Hole ty2, u_gen)
end
end
| (Delete, ZExp.Deeper _
(ZExp.LamZP ((ZPat.CursorP After _) as zp) (Some _) e1))
| (Delete, ZExp.Deeper _
(ZExp.LamZP
((ZPat.Deeper _
(ZPat.OpSeqZ _
(ZPat.CursorP After _)
(OperatorSeq.EmptySuffix _))) as zp)
(Some _)
e1)) =>
match ana_zpat_fix_holes fuel ctx u_gen zp HTyp.Hole with
| None => None
| Some (zp, ctx, u_gen) =>
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| None => None
| Some (e1, ty2, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LamZP zp None e1) in
Some (ze, HTyp.Arrow HTyp.Hole ty2, u_gen)
end
end
| (Backspace, ZExp.Deeper _
(ZExp.OpSeqZ _
((ZExp.CursorE Before e0) as ze0)
((OperatorSeq.EmptySuffix _) as surround)))
| (Backspace, ZExp.Deeper _
(ZExp.OpSeqZ _
((ZExp.CursorE Before e0) as ze0)
((OperatorSeq.BothNonEmpty _ _) as surround))) =>
abs_perform_Backspace_Before_op
combine_for_Backspace_Space
zexp_syn_fix_holes
make_and_syn_OpSeqZ
UHExp.is_EmptyHole
UHExp.is_Space
UHExp.Space
ZExp.CursorE
fuel ctx u_gen e0 ze0 surround
| (Delete, ZExp.Deeper _
(ZExp.OpSeqZ _
((ZExp.CursorE After e0) as ze0)
((OperatorSeq.EmptyPrefix _) as surround)))
| (Delete, ZExp.Deeper _
(ZExp.OpSeqZ _
((ZExp.CursorE After e0) as ze0)
((OperatorSeq.BothNonEmpty _ _) as surround))) =>
abs_perform_Delete_After_op
combine_for_Delete_Space
zexp_syn_fix_holes
make_and_syn_OpSeqZ
UHExp.is_EmptyHole
UHExp.is_Space
UHExp.Space
ZExp.CursorE
fuel ctx u_gen e0 ze0 surround
| (Backspace, ZExp.CursorE (In _) e)
| (Delete, ZExp.CursorE (In _) e) =>
let (e', u_gen') := UHExp.new_EmptyHole u_gen in
let ze' := ZExp.CursorE Before e' in
Some (ze', HTyp.Hole, u_gen')
(* Construction *)
| (Construct SParenthesized, ZExp.CursorE cursor_side e) =>
Some (
ZExp.ParenthesizedZ ze,
ty,
u_gen)
| (Construct SAsc, ZExp.CursorE _ e) =>
let e' := UHExp.bidelimit e in
Some (
ZExp.Deeper NotInHole
(ZExp.AscZ2 e' (ZTyp.CursorT Before UHTyp.Hole)),
ty,
u_gen)
| (Construct SAsc, ZExp.Deeper err_status (ZExp.LetZP zp None e1 e2)) =>
match UHExp.syn fuel ctx e1 with
| None => None
| Some ty1 =>
let uty1 := UHTyp.contract ty1 in
let ze := ZExp.Deeper err_status
(ZExp.LetZA (ZPat.erase zp) (ZTyp.place_Before uty1) e1 e2) in
Some (ze, ty, u_gen)
end
| (Construct SAsc, ZExp.Deeper err_status (ZExp.LamZP zp None e1)) =>
let ze := ZExp.Deeper err_status
(ZExp.LamZA (ZPat.erase zp) (ZTyp.place_Before UHTyp.Hole) e1) in
Some (ze, ty, u_gen)
| (Construct SAsc, ZExp.Deeper err_status (ZExp.LetZP zp (Some uty1) e1 e2)) =>
(* just move the cursor over if there is already an ascription *)
let ze := ZExp.Deeper err_status
(ZExp.LetZA (ZPat.erase zp) (ZTyp.place_Before uty1) e1 e2) in
Some (ze, ty, u_gen)
| (Construct SAsc, ZExp.Deeper err_status (ZExp.LamZP zp (Some uty1) e1)) =>
(* just move the cursor over if there is already an ascription *)
let ze := ZExp.Deeper err_status
(ZExp.LamZA (ZPat.erase zp) (ZTyp.place_Before uty1) e1) in
Some (ze, ty, u_gen)
| (Construct (SVar x side), ZExp.CursorE _ (UHExp.Tm _ (UHExp.EmptyHole _)))
| (Construct (SVar x side), ZExp.CursorE _ (UHExp.Tm _ (UHExp.Var _ _)))
| (Construct (SVar x side), ZExp.CursorE _ (UHExp.Tm _ (UHExp.NumLit _)))
| (Construct (SVar x side), ZExp.CursorE _ (UHExp.Tm _ (UHExp.BoolLit _))) =>
Var.check_valid x (
let (gamma, _) := ctx in
match VarMap.lookup gamma x with
| Some xty => Some (ZExp.CursorE side
(UHExp.Tm NotInHole (UHExp.Var NotInVHole x)),
xty, u_gen)
| None =>
let (u, u_gen) := MetaVarGen.next u_gen in
Some (ZExp.CursorE side
(UHExp.Tm NotInHole (UHExp.Var (InVHole u) x)),
HTyp.Hole, u_gen)
end)
| (Construct (SVar _ _), ZExp.CursorE _ _) => None
| (Construct SLet, ZExp.CursorE _ e1) =>
let (zp, u_gen) := ZPat.new_EmptyHole u_gen in
let (e2, u_gen) := UHExp.new_EmptyHole u_gen in
let ze := ZExp.Deeper NotInHole
(ZExp.LetZP zp None e1 e2) in
Some (ze, HTyp.Hole, u_gen)
| (Construct SLam, ZExp.CursorE _ e1) =>
let (zp, u_gen) := ZPat.new_EmptyHole u_gen in
let ze :=
ZExp.Deeper NotInHole
(ZExp.LamZP zp (Some UHTyp.Hole) e1) in
let ty' := HTyp.Arrow HTyp.Hole ty in
Some (ze, ty', u_gen)
| (Construct (SNumLit n side), ZExp.CursorE _ (UHExp.Tm _ (UHExp.EmptyHole _)))
| (Construct (SNumLit n side), ZExp.CursorE _ (UHExp.Tm _ (UHExp.NumLit _)))
| (Construct (SNumLit n side), ZExp.CursorE _ (UHExp.Tm _ (UHExp.BoolLit _)))
| (Construct (SNumLit n side), ZExp.CursorE _ (UHExp.Tm _ (UHExp.Var _ _))) =>
Some (ZExp.CursorE side (UHExp.Tm NotInHole (UHExp.NumLit n)), HTyp.Num, u_gen)
| (Construct (SNumLit _ _), ZExp.CursorE _ _) => None
| (Construct (SBoolLit b side), ZExp.CursorE _ (UHExp.Tm _ (UHExp.EmptyHole _)))
| (Construct (SBoolLit b side), ZExp.CursorE _ (UHExp.Tm _ (UHExp.NumLit _)))
| (Construct (SBoolLit b side), ZExp.CursorE _ (UHExp.Tm _ (UHExp.BoolLit _)))
| (Construct (SBoolLit b side), ZExp.CursorE _ (UHExp.Tm _ (UHExp.Var _ _))) =>
Some (ZExp.CursorE side (UHExp.Tm NotInHole (UHExp.BoolLit b)), HTyp.Bool, u_gen)
| (Construct (SBoolLit _ _), ZExp.CursorE _ _) => None
| (Construct (SInj side), (ZExp.CursorE _ e)) =>
let ze' :=
ZExp.Deeper NotInHole
(ZExp.InjZ side ze) in
let ty' :=
match side with
| L => HTyp.Sum ty HTyp.Hole
| R => HTyp.Sum HTyp.Hole ty
end in
Some (ze', ty', u_gen)
| (Construct SListNil, ZExp.CursorE _ (UHExp.Tm _ (UHExp.EmptyHole _))) =>
let ze := ZExp.CursorE After (UHExp.Tm NotInHole UHExp.ListNil) in
let ty := HTyp.List HTyp.Hole in
Some (ze, ty, u_gen)
| (Construct SListNil, ZExp.CursorE _ _) => None
| (Construct SCase, (ZExp.CursorE _ e1)) =>
match e1 with
| UHExp.Tm _ (UHExp.EmptyHole _) =>
let (rule_p, u_gen) := UHPat.new_EmptyHole u_gen in
let (rule_e, u_gen) := UHExp.new_EmptyHole u_gen in
let rule := UHExp.Rule rule_p rule_e in
let rules := cons rule nil in
let caseze := ZExp.Deeper NotInHole (ZExp.CaseZE ze rules) in
let ze := ZExp.Deeper NotInHole (ZExp.AscZ1 caseze (UHTyp.Hole)) in
Some (ze, HTyp.Hole, u_gen)
| _ =>
let (zp, u_gen) := ZPat.new_EmptyHole u_gen in
let (rule_e, u_gen) := UHExp.new_EmptyHole u_gen in
let zrule := ZExp.RuleZP zp rule_e in
let zrules := ZList.singleton zrule in
let caseze := ZExp.Deeper NotInHole (ZExp.CaseZR e1 zrules) in
let ze := ZExp.Deeper NotInHole (ZExp.AscZ1 caseze (UHTyp.Hole)) in
Some (ze, HTyp.Hole, u_gen)
end
| (Construct (SOp os), ZExp.Deeper _ (
ZExp.OpSeqZ _ (ZExp.CursorE (In _) e) surround))
| (Construct (SOp os), ZExp.Deeper _ (
ZExp.OpSeqZ _ (ZExp.CursorE After e) surround)) =>
match exp_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_After_surround
ZExp.new_EmptyHole
make_and_syn_OpSeqZ
UHExp.is_Space
UHExp.Space
ZExp.CursorE
fuel ctx u_gen e op surround
end
| (Construct (SOp os),
ZExp.Deeper _ (ZExp.OpSeqZ _
((ZExp.CursorE Before _) as ze0) surround)) =>
match exp_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_Before_surround
ZExp.erase
ZExp.new_EmptyHole
make_and_syn_OpSeqZ
UHExp.is_Space
UHExp.Space
ZExp.CursorE
fuel ctx u_gen ze0 op surround
end
| (Construct (SOp os), ZExp.CursorE (In _) e)
| (Construct (SOp os), ZExp.CursorE After e) =>
match exp_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_After
UHExp.bidelimit
ZExp.new_EmptyHole
make_and_syn_OpSeqZ
fuel ctx u_gen e op
end
| (Construct (SOp os), ZExp.CursorE Before e) =>
match exp_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_Before
UHExp.bidelimit
ZExp.new_EmptyHole
make_and_syn_OpSeqZ
fuel ctx u_gen e op
end
| (Construct SRule, ZExp.CursorE _ _) => None
| (Construct (SApPalette name), ZExp.CursorE _ (UHExp.Tm _ (UHExp.EmptyHole _))) =>
let (_, palette_ctx) := ctx in
match PaletteCtx.lookup palette_ctx name with
| Some palette_defn =>
let m_initial_model := UHExp.PaletteDefinition.initial_model palette_defn in
let (q, u_gen) := UHExp.HoleRefs.exec m_initial_model (UHExp.PaletteHoleData.empty) u_gen in
let (initial_model, initial_hole_data) := q in
let expansion_ty := UHExp.PaletteDefinition.expansion_ty palette_defn in
let expansion := (UHExp.PaletteDefinition.to_exp palette_defn) initial_model in
let (_, initial_hole_map) := initial_hole_data in
let expansion_ctx := UHExp.PaletteHoleData.extend_ctx_with_hole_map ctx initial_hole_map in
match (UHExp.ana fuel expansion_ctx expansion expansion_ty) with
| Some _ =>
Some (ZExp.CursorE After (UHExp.Tm NotInHole (UHExp.ApPalette name initial_model initial_hole_data)),
expansion_ty, u_gen)
| None => None
end
| None => None
end
| (Construct (SApPalette _), ZExp.CursorE _ _) => None
| (UpdateApPalette monad,
ZExp.CursorE _ (UHExp.Tm _ (UHExp.ApPalette name _ hole_data))) =>
let (_, palette_ctx) := ctx in
match PaletteCtx.lookup palette_ctx name with
| Some palette_defn =>
let (q, u_gen') := UHExp.HoleRefs.exec monad hole_data u_gen in
let (serialized_model, hole_data') := q in
let expansion_ty := UHExp.PaletteDefinition.expansion_ty palette_defn in
let expansion := (UHExp.PaletteDefinition.to_exp palette_defn) serialized_model in
let (_, hole_map') := hole_data' in
let expansion_ctx := UHExp.PaletteHoleData.extend_ctx_with_hole_map ctx hole_map' in
match (UHExp.ana fuel expansion_ctx expansion expansion_ty) with
| Some _ =>
Some (ZExp.CursorE After (UHExp.Tm NotInHole (UHExp.ApPalette name serialized_model hole_data')),
expansion_ty, u_gen)
| None => None
end
| None => None
end
| (UpdateApPalette _, ZExp.CursorE _ _) => None
(* Zipper Cases *)
| (_, ZExp.ParenthesizedZ ze1) =>
match perform_syn fuel ctx a (ze1, ty, u_gen) with
| Some (ze1', ty', u_gen') =>
Some (
ZExp.ParenthesizedZ ze1',
ty',
u_gen')
| None => None
end
| (_, ZExp.Deeper _ (ZExp.AscZ1 ze uty1)) =>
let ty1 := UHTyp.expand fuel uty1 in
match perform_ana fuel u_gen ctx a ze ty1 with
| Some (ze', u_gen') =>
let ze'' := ZExp.bidelimit ze' in
Some (
ZExp.Deeper NotInHole (ZExp.AscZ1 ze'' uty1),
ty,
u_gen')
| None => None
end
| (_, ZExp.Deeper _ (ZExp.AscZ2 e zty)) =>
match perform_ty fuel a zty with
| Some zty' =>
let uty' := ZTyp.erase zty' in
let ty' := UHTyp.expand fuel uty' in
match UHExp.ana_fix_holes fuel ctx u_gen e ty' with
| None => None
| Some (e', u_gen') =>
Some (
ZExp.Deeper NotInHole (ZExp.AscZ2 e' zty'),
ty',
u_gen')
end
| None =>
None
end
| (_, ZExp.Deeper _ (ZExp.LetZP zp ann e1 e2)) =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
match perform_ana_pat fuel ctx u_gen a zp ty1 with
| None => None
| Some (zp, ctx2, u_gen) =>
let p := ZPat.erase zp in
let ctx1 := UHExp.ctx_for_let ctx p ty1 e1 in
match UHExp.ana_fix_holes fuel ctx1 u_gen e1 ty1 with
| None => None
| Some (e1, u_gen) =>
match UHExp.syn_fix_holes fuel ctx2 u_gen e2 with
| None => None
| Some (e2, ty, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZP zp ann e1 e2) in
Some (ze, ty, u_gen)
end
end
end
| None =>
match UHExp.syn fuel ctx e1 with
| None => None
| Some ty1 =>
match perform_ana_pat fuel ctx u_gen a zp ty1 with
| None => None
| Some (zp, ctx2, u_gen) =>
match UHExp.syn_fix_holes fuel ctx2 u_gen e2 with
| None => None
| Some (e2, ty, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZP zp ann e1 e2) in
Some (ze, ty, u_gen)
end
end
end
end
| (_, ZExp.Deeper _ (ZExp.LetZA p zann e1 e2)) =>
(* (ctx) let p (ctx2) : ty = (ctx1) e1 in (ctx2) e2 *)
match perform_ty fuel a zann with
| None => None
| Some zann =>
let ty1 := UHTyp.expand fuel (ZTyp.erase zann) in
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p ty1 with
| None => None
| Some (p, ctx2, u_gen) =>
let ctx1 := UHExp.ctx_for_let ctx p ty1 e1 in
match UHExp.ana_fix_holes fuel ctx1 u_gen e1 ty1 with
| None => None
| Some (e1, u_gen) =>
match UHExp.syn_fix_holes fuel ctx2 u_gen e2 with
| None => None
| Some (e2, ty, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZA p zann e1 e2) in
Some (ze, ty, u_gen)
end
end
end
end
| (_, ZExp.Deeper _ (ZExp.LetZE1 p ann ze1 e2)) =>
match ann with
| Some ann_ty =>
let ty1 := UHTyp.expand fuel ann_ty in
let ctx1 := UHExp.ctx_for_let ctx p ty1 (ZExp.erase ze1) in
match perform_ana fuel u_gen ctx1 a ze1 ty1 with
| None => None
| Some (ze1, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZE1 p ann ze1 e2) in
Some (ze, ty, u_gen)
end
| None =>
let e1 := ZExp.erase ze1 in
match UHExp.syn fuel ctx e1 with
| None => None
| Some ty1 =>
match perform_syn fuel ctx a (ze1, ty1, u_gen) with
| None => None
| Some (ze1, ty1, u_gen) =>
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p ty1 with
| None => None
| Some (p, ctx2, u_gen) =>
match UHExp.syn_fix_holes fuel ctx2 u_gen e2 with
| None => None
| Some (e2, ty, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZE1 p ann ze1 e2) in
Some (ze, ty, u_gen)
end
end
end
end
end
| (_, ZExp.Deeper _ (ZExp.LetZE2 p ann e1 ze2)) =>
let ty1 :=
match ann with
| Some uty1 => Some (UHTyp.expand fuel uty1)
| None => UHExp.syn fuel ctx e1
end in
match ty1 with
| None => None
| Some ty1 =>
match UHExp.ana_pat fuel ctx p ty1 with
| None => None
| Some ctx2 =>
match perform_syn fuel ctx2 a (ze2, ty, u_gen) with
| None => None
| Some (ze2, ty, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZE2 p ann e1 ze2) in
Some (ze, ty, u_gen)
end
end
end
| (_, ZExp.Deeper _ (ZExp.LamZP zp ann e1)) =>
let ty1 :=
match ann with
| Some uty1 => UHTyp.expand fuel uty1
| None => HTyp.Hole
end in
match perform_ana_pat fuel ctx u_gen a zp ty1 with
| None => None
| Some (zp, ctx, u_gen) =>
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| None => None
| Some (e1, ty2, u_gen) =>
let ty := HTyp.Arrow ty1 ty2 in
let ze := ZExp.Deeper NotInHole (ZExp.LamZP zp ann e1) in
Some (ze, ty, u_gen)
end
end
| (_, ZExp.Deeper _ (ZExp.LamZA p zann e1)) =>
match perform_ty fuel a zann with
| None => None
| Some zann =>
let ty1 := UHTyp.expand fuel (ZTyp.erase zann) in
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p ty1 with
| None => None
| Some (p, ctx, u_gen) =>
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| None => None
| Some (e1, ty2, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LamZA p zann e1) in
Some (ze, HTyp.Arrow ty1 ty2, u_gen)
end
end
end
| (_, ZExp.Deeper _ (ZExp.LamZE p ann ze1)) =>
match HTyp.matched_arrow ty with
| None => None
| Some (_, ty2) =>
let ty1 :=
match ann with
| Some uty1 => UHTyp.expand fuel uty1
| None => HTyp.Hole
end in
match UHExp.ana_pat fuel ctx p ty1 with
| None => None
| Some ctx =>
match perform_syn fuel ctx a (ze1, ty2, u_gen) with
| None => None
| Some (ze1, ty2, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LamZE p ann ze1) in
Some (ze, HTyp.Arrow ty1 ty2, u_gen)
end
end
end
| (_, ZExp.Deeper _ (ZExp.InjZ side ze1)) =>
match ty with
| HTyp.Sum ty1 ty2 =>
let ty_side := pick_side side ty1 ty2 in
match perform_syn fuel ctx a (ze1, ty_side, u_gen) with
| None => None
| Some (ze1', ty_side', u_gen') =>
let ty' :=
match side with
| L => HTyp.Sum ty_side' ty2
| R => HTyp.Sum ty1 ty_side'
end in
Some (
ZExp.Deeper NotInHole (ZExp.InjZ side ze1'),
ty',
u_gen')
end
| _ => None (* should never happen *)
end
| (_, ZExp.Deeper _ (ZExp.OpSeqZ _ ze0 surround)) =>
let i := OperatorSeq.surround_prefix_length surround in
match ZExp.erase ze with
| UHExp.Tm _ (UHExp.OpSeq skel seq) =>
match UHExp.syn_skel fuel ctx skel seq (Some i) with
| Some (ty, Some mode) =>
match mode with
| UHExp.AnalyzedAgainst ty0 =>
match perform_ana fuel u_gen ctx a ze0 ty0 with
| None => None
| Some (ze0', u_gen) =>
let ze0'' := ZExp.bidelimit ze0' in
Some (
ZExp.Deeper NotInHole (ZExp.OpSeqZ skel ze0'' surround),
ty, u_gen)
end
| UHExp.Synthesized ty0 =>
match perform_syn fuel ctx a (ze0, ty0, u_gen) with
| None => None
| Some (ze0', ty0', u_gen) =>
let ze0'' := ZExp.bidelimit ze0' in
make_and_syn_OpSeqZ fuel ctx u_gen ze0'' surround
end
end
| Some _ => None (* should never happen *)
| None => None (* should never happen *)
end
| _ => None (* should never happen *)
end
| (_, ZExp.Deeper _ (ZExp.ApPaletteZ name serialized_model z_hole_data)) =>
let (next_lbl, z_nat_map) := z_hole_data in
let (rest_map, z_data) := z_nat_map in
let (cell_lbl, cell_data) := z_data in
let (cell_ty, cell_ze) := cell_data in
match perform_ana fuel u_gen ctx a cell_ze cell_ty with
| None => None
| Some(cell_ze', u_gen') =>
let z_hole_data' := (next_lbl, (rest_map, (cell_lbl, (cell_ty, cell_ze')))) in
Some(
ZExp.Deeper NotInHole (ZExp.ApPaletteZ name serialized_model z_hole_data'),
ty,
u_gen')
end
| (_, ZExp.Deeper _ (ZExp.CaseZE _ _)) => None
| (_, ZExp.Deeper _ (ZExp.CaseZR _ _)) => None
(* Invalid actions at expression level *)
| (Construct SNum, _)
| (Construct SBool, _)
| (Construct SList, _)
| (Construct SWild, _) => None
end
end
end
with perform_ana
(fuel: Fuel.t)
(u_gen : MetaVarGen.t)
(ctx: Contexts.t)
(a: t)
(ze: ZExp.t)
(ty: HTyp.t)
: option (ZExp.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match (a, ze) with
| (_, ZExp.Deeper (InHole TypeInconsistent u) ze1') =>
let ze' := ZExp.Deeper NotInHole ze1' in
let e' := ZExp.erase ze' in
match UHExp.syn fuel ctx e' with
| Some ty1 =>
match perform_syn fuel ctx a (ze', ty1, u_gen) with
| Some (ze', ty1', u_gen') =>
if HTyp.consistent ty1' ty then
Some (ze', u_gen')
else
Some (ZExp.set_inconsistent u ze', u_gen')
| None => None
end
| None => None
end
(* Movement *)
| (MoveTo path, _) =>
let e := ZExp.erase ze in
match Path.follow_e fuel path e with
| Some ze' => Some (ze', u_gen)
| None => None
end
| (MoveToPrevHole, _) =>
match Path.prev_hole_path fuel ze with
| None => None
| Some path => perform_ana fuel u_gen ctx (MoveTo path) ze ty
end
| (MoveToNextHole, _) =>
match Path.next_hole_path fuel ze with
| None => None
| Some path =>
(* [debug] let path := Helper.log_path path in *)
perform_ana fuel u_gen ctx (MoveTo path) ze ty
end
(* Backspace & Delete *)
| (Backspace, ZExp.CursorE After e) =>
match e with
| UHExp.Tm _ (UHExp.EmptyHole _) =>
Some (ZExp.CursorE Before e, u_gen)
| _ =>
let (e', u_gen) := UHExp.new_EmptyHole u_gen in
Some (ZExp.CursorE Before e', u_gen)
end
| (Backspace, ZExp.CursorE Before e) => None
| (Delete, ZExp.CursorE Before e) =>
match e with
| UHExp.Tm _ (UHExp.EmptyHole _) =>
Some (ZExp.CursorE After e, u_gen)
| _ =>
let (e', u_gen) := UHExp.new_EmptyHole u_gen in
Some (ZExp.CursorE Before e', u_gen)
end
| (Delete, ZExp.CursorE After e) => None
| (Backspace, ZExp.CursorE (In _) e)
| (Delete, ZExp.CursorE (In _) e) =>
let (e', u_gen) := UHExp.new_EmptyHole u_gen in
let ze' := ZExp.CursorE Before e' in
Some (ze', u_gen)
| (Backspace,
ZExp.Deeper _ (ZExp.AscZ2 e1
(ZTyp.CursorT Before uty1))) =>
let ze' := ZExp.CursorE After e1 in
zexp_ana_fix_holes fuel ctx u_gen ze' ty
| (Backspace,
ZExp.Deeper _ (ZExp.AscZ2 e1
(ZTyp.OpSeqZ _
(ZTyp.CursorT Before _)
(OperatorSeq.EmptyPrefix _)))) =>
let ze' := ZExp.CursorE After e1 in
zexp_ana_fix_holes fuel ctx u_gen ze' ty
| (Delete,
ZExp.Deeper _ (ZExp.AscZ1
(ZExp.CursorE After e1)
_)) =>
match UHExp.ana_fix_holes fuel ctx u_gen e1 ty with
| Some (e1', u_gen) =>
let ze' := ZExp.CursorE After e1' in
Some (ze', u_gen)
| None => None
end
| (Backspace, ZExp.Deeper _
(ZExp.LetZA p (ZTyp.CursorT Before _) e1 e2))
| (Backspace, ZExp.Deeper _
(ZExp.LetZA p
(ZTyp.OpSeqZ _
(ZTyp.CursorT Before _)
(OperatorSeq.EmptyPrefix _)) e1 e2)) =>
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| None => None
| Some (e1, ty1, u_gen) =>
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p ty1 with
| None => None
| Some (p, ctx, u_gen) =>
match UHExp.ana_fix_holes fuel ctx u_gen e2 ty with
| None => None
| Some (e2, u_gen) =>
let ze :=
ZExp.Deeper NotInHole
(ZExp.LetZP (ZPat.place_After p) None e1 e2) in
Some (ze, u_gen)
end
end
end
| (Delete, ZExp.Deeper _
(ZExp.LetZP ((ZPat.CursorP After _) as zp) (Some _) e1 e2))
| (Delete, ZExp.Deeper _
(ZExp.LetZP
((ZPat.Deeper _ (ZPat.OpSeqZ _
(ZPat.CursorP After _)
(OperatorSeq.EmptySuffix _))) as zp)
(Some _)
e1 e2)) =>
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| None => None
| Some (e1, ty1, u_gen) =>
match ana_zpat_fix_holes fuel ctx u_gen zp ty1 with
| None => None
| Some (zp, ctx, u_gen) =>
match UHExp.ana_fix_holes fuel ctx u_gen e2 ty with
| None => None
| Some (e2, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZP zp None e1 e2) in
Some (ze, u_gen)
end
end
end
| (Backspace, ZExp.Deeper _
(ZExp.LamZA p (ZTyp.CursorT Before _) e1))
| (Backspace, ZExp.Deeper _
(ZExp.LamZA p
(ZTyp.OpSeqZ _
(ZTyp.CursorT Before _)
(OperatorSeq.EmptyPrefix _)) e1)) =>
match HTyp.matched_arrow ty with
| None => None
| Some (ty1, ty2) =>
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p ty1 with
| None => None
| Some (p, ctx, u_gen) =>
match UHExp.ana_fix_holes fuel ctx u_gen e1 ty2 with
| None => None
| Some (e1, u_gen) =>
let zp := ZPat.place_After p in
let ze := ZExp.Deeper NotInHole (ZExp.LamZP zp None e1) in
Some (ze, u_gen)
end
end
end
| (Delete, ZExp.Deeper _
(ZExp.LamZP ((ZPat.CursorP After _) as zp) (Some _) e1))
| (Delete, ZExp.Deeper _
(ZExp.LamZP
((ZPat.Deeper _
(ZPat.OpSeqZ _
(ZPat.CursorP After _)
(OperatorSeq.EmptySuffix _))) as zp)
(Some _)
e1)) =>
match HTyp.matched_arrow ty with
| None => None
| Some (ty1, ty2) =>
match ana_zpat_fix_holes fuel ctx u_gen zp ty1 with
| None => None
| Some (zp, ctx, u_gen) =>
match UHExp.ana_fix_holes fuel ctx u_gen e1 ty2 with
| None => None
| Some (e1, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LamZP zp None e1) in
Some (ze, u_gen)
end
end
end
| (Backspace,
ZExp.Deeper _
(ZExp.CaseZR e1
(prefix, ZExp.RuleZP (ZPat.CursorP Before _) _, suffix)))
| (Backspace,
ZExp.Deeper _
(ZExp.CaseZR e1
(prefix, ZExp.RuleZP
(ZPat.Deeper _
(ZPat.OpSeqZ _
(ZPat.CursorP Before _)
(OperatorSeq.EmptyPrefix _)))
_, suffix))) =>
match suffix with
| nil =>
match prefix with
| nil =>
let (zrule, u_gen) := ZExp.empty_zrule u_gen in
let ze := ZExp.Deeper NotInHole
(ZExp.CaseZR e1
(prefix, zrule, suffix)) in
Some (ze, u_gen)
| cons _ _ =>
match List.rev prefix with
| nil => None
| cons (UHExp.Rule p2 e2) rev_prefix' =>
let prefix' := List.rev rev_prefix' in
let zrule := ZExp.RuleZP (ZPat.place_Before p2) e2 in
let ze := ZExp.Deeper NotInHole
(ZExp.CaseZR e1
(prefix', zrule, suffix)) in
Some (ze, u_gen)
end
end
| cons (UHExp.Rule p2 e2) suffix' =>
let zrule := ZExp.RuleZP (ZPat.place_Before p2) e2 in
let ze := ZExp.Deeper NotInHole
(ZExp.CaseZR e1
(prefix, zrule, suffix')) in
Some (ze, u_gen)
end
| (Backspace, ZExp.Deeper _
(ZExp.OpSeqZ _
((ZExp.CursorE Before e0) as ze0)
((OperatorSeq.EmptySuffix _) as surround)))
| (Backspace, ZExp.Deeper _
(ZExp.OpSeqZ _
((ZExp.CursorE Before e0) as ze0)
((OperatorSeq.BothNonEmpty _ _) as surround))) =>
abs_perform_Backspace_Before_op
combine_for_Backspace_Space
(fun fuel ctx u_gen ze =>
zexp_ana_fix_holes fuel ctx u_gen ze ty)
(fun fuel ctx u_gen ze surround =>
make_and_ana_OpSeqZ fuel ctx u_gen ze surround ty)
UHExp.is_EmptyHole
UHExp.is_Space
UHExp.Space
ZExp.CursorE
fuel ctx u_gen e0 ze0 surround
| (Delete, ZExp.Deeper _
(ZExp.OpSeqZ _
((ZExp.CursorE After e0) as ze0)
((OperatorSeq.EmptyPrefix _) as surround)))
| (Delete, ZExp.Deeper _
(ZExp.OpSeqZ _
((ZExp.CursorE After e0) as ze0)
((OperatorSeq.BothNonEmpty _ _) as surround))) =>
abs_perform_Delete_After_op
combine_for_Delete_Space
(fun fuel ctx u_gen ze =>
zexp_ana_fix_holes fuel ctx u_gen ze ty)
(fun fuel ctx u_gen ze surround =>
make_and_ana_OpSeqZ fuel ctx u_gen ze surround ty)
UHExp.is_EmptyHole
UHExp.is_Space
UHExp.Space
ZExp.CursorE
fuel ctx u_gen e0 ze0 surround
(* Construction *)
| (Construct SParenthesized, ZExp.CursorE _ e) =>
Some (
ZExp.ParenthesizedZ ze,
u_gen)
| (Construct SAsc, ZExp.CursorE _ e) =>
let e' := UHExp.bidelimit e in
let uty := UHTyp.contract ty in
Some (
ZExp.Deeper NotInHole
(ZExp.AscZ2 e' (ZTyp.place_Before uty)),
u_gen)
| (Construct SAsc, ZExp.Deeper err_status (ZExp.LetZP zp None e1 e2)) =>
match UHExp.syn fuel ctx e1 with
| None => None
| Some ty1 =>
let uty1 := UHTyp.contract ty1 in
let ze := ZExp.Deeper err_status
(ZExp.LetZA (ZPat.erase zp) (ZTyp.place_Before uty1) e1 e2) in
Some (ze, u_gen)
end
| (Construct SAsc, ZExp.Deeper err_status (ZExp.LamZP zp None e1)) =>
let ze := ZExp.Deeper err_status
(ZExp.LamZA (ZPat.erase zp) (ZTyp.CursorT Before UHTyp.Hole) e1) in
Some (ze, u_gen)
| (Construct SAsc, ZExp.Deeper err_status (ZExp.LetZP zp (Some uty1) e1 e2)) =>
(* just move the cursor over if there is already an ascription *)
let ze := ZExp.Deeper err_status
(ZExp.LetZA (ZPat.erase zp) (ZTyp.place_Before uty1) e1 e2) in
Some (ze, u_gen)
| (Construct SAsc, ZExp.Deeper err_status (ZExp.LamZP zp (Some uty1) e1)) =>
(* just move the cursor over if there is already an ascription *)
let ze := ZExp.Deeper err_status
(ZExp.LamZA (ZPat.erase zp) (ZTyp.place_Before uty1) e1) in
Some (ze, u_gen)
| (Construct SLet, ZExp.CursorE _ e1) =>
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| Some (e1, ty1, u_gen) =>
let (zp, u_gen) := ZPat.new_EmptyHole u_gen in
let (e2, u_gen) := UHExp.new_EmptyHole u_gen in
let ze := ZExp.Deeper NotInHole
(ZExp.LetZP zp None e1 e2) in
Some (ze, u_gen)
| None =>
let (zp, u_gen) := ZPat.new_EmptyHole u_gen in
let (e2, u_gen) := UHExp.new_EmptyHole u_gen in
let ann := Some (UHTyp.contract ty) in
let ze := ZExp.Deeper NotInHole
(ZExp.LetZP zp ann e1 e2) in
Some (ze, u_gen)
end
| (Construct SLam, ZExp.CursorE _ e) =>
match HTyp.matched_arrow ty with
| Some (_, ty2) =>
match UHExp.ana_fix_holes fuel ctx u_gen e ty2 with
| None => None
| Some (e, u_gen) =>
let (zp, u_gen) := ZPat.new_EmptyHole u_gen in
let ze := ZExp.Deeper NotInHole (ZExp.LamZP zp None e) in
Some (ze, u_gen)
end
| None =>
match UHExp.syn_fix_holes fuel ctx u_gen e with
| None => None
| Some (e, _, u_gen) =>
let (zp, u_gen) := ZPat.new_EmptyHole u_gen in
let (u, u_gen) := MetaVarGen.next u_gen in
let ze := ZExp.Deeper (InHole TypeInconsistent u) (ZExp.LamZP zp None e) in
Some (ze, u_gen)
end
end
| (Construct (SInj side), ZExp.CursorE cursor_side e1) =>
match HTyp.matched_sum ty with
| Some (tyL, tyR) =>
let ty1 := pick_side side tyL tyR in
match UHExp.ana_fix_holes fuel ctx u_gen e1 ty1 with
| None => None
| Some (e1, u_gen) =>
let ze := ZExp.Deeper NotInHole
(ZExp.InjZ side (ZExp.CursorE cursor_side e1)) in
Some (ze, u_gen)
end
| None =>
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| None => None
| Some (e1, _, u_gen) =>
let (u, u_gen) := MetaVarGen.next u_gen in
let ze := ZExp.Deeper (InHole TypeInconsistent u)
(ZExp.InjZ side
(ZExp.CursorE cursor_side e1)) in
Some (ze, u_gen)
end
end
| (Construct SCase, ZExp.CursorE _ e1) =>
match e1 with
| UHExp.Tm _ (UHExp.EmptyHole _) =>
let (rule, u_gen) := UHExp.empty_rule u_gen in
let rules := cons rule nil in
let ze := ZExp.Deeper NotInHole (ZExp.CaseZE ze rules) in
Some (ze, u_gen)
| _ =>
let (zrule, u_gen) := ZExp.empty_zrule u_gen in
let zrules := ZList.singleton zrule in
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| None => None
| Some (e1, _, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.CaseZR e1 zrules) in
Some (ze, u_gen)
end
end
| (Construct SRule,
ZExp.Deeper _
(ZExp.CaseZR e1
(prefix,
ZExp.RuleZP
(ZPat.CursorP Before p) re,
suffix))) =>
let (zrule, u_gen) := ZExp.empty_zrule u_gen in
let prev_rule := UHExp.Rule p re in
let suffix := cons prev_rule suffix in
let ze :=
ZExp.Deeper NotInHole
(ZExp.CaseZR e1
(prefix,
zrule,
suffix)) in
Some (ze, u_gen)
| (Construct SRule,
ZExp.Deeper _
(ZExp.CaseZR e1
(prefix,
(ZExp.RuleZE _
((ZExp.CursorE After _))) as zrule,
suffix)))
| (Construct SRule,
ZExp.Deeper _
(ZExp.CaseZR e1
(prefix,
(ZExp.RuleZE _
(ZExp.Deeper _ (ZExp.OpSeqZ _
(ZExp.CursorE After _)
(OperatorSeq.EmptySuffix _)))) as zrule,
suffix)))
| (Construct SRule,
ZExp.Deeper _
(ZExp.CaseZR e1
(prefix,
(ZExp.RuleZP
(ZPat.CursorP After _)
_) as zrule, suffix)))
| (Construct SRule,
ZExp.Deeper _
(ZExp.CaseZR e1
(prefix,
(ZExp.RuleZP
((ZPat.Deeper _
(ZPat.OpSeqZ _
(ZPat.CursorP After _)
(OperatorSeq.EmptySuffix _))))
_) as zrule, suffix)))
=>
let prev_rule := ZExp.erase_rule zrule in
let (zrule, u_gen) := ZExp.empty_zrule u_gen in
let prefix := prefix ++ (cons prev_rule nil) in
let ze :=
ZExp.Deeper NotInHole
(ZExp.CaseZR e1
(prefix,
zrule,
suffix)) in
Some (ze, u_gen)
| (Construct SRule, ZExp.CursorE _ _) => None
| (Construct (SOp os), ZExp.Deeper _ (
ZExp.OpSeqZ _ (ZExp.CursorE (In _) e) surround))
| (Construct (SOp os), ZExp.Deeper _ (
ZExp.OpSeqZ _ (ZExp.CursorE After e) surround)) =>
match exp_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_After_surround
ZExp.new_EmptyHole
(fun fuel ctx u_gen ze surround =>
make_and_ana_OpSeqZ fuel ctx u_gen ze surround ty)
UHExp.is_Space
UHExp.Space
ZExp.CursorE
fuel ctx u_gen e op surround
end
| (Construct (SOp os),
ZExp.Deeper _ (ZExp.OpSeqZ _
((ZExp.CursorE Before _) as ze0) surround)) =>
match exp_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_Before_surround
ZExp.erase
ZExp.new_EmptyHole
(fun fuel ctx u_gen ze surround =>
make_and_ana_OpSeqZ fuel ctx u_gen ze surround ty)
UHExp.is_Space
UHExp.Space
ZExp.CursorE
fuel ctx u_gen ze0 op surround
end
| (Construct (SOp os), ZExp.CursorE (In _) e)
| (Construct (SOp os), ZExp.CursorE After e) =>
match exp_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_After
UHExp.bidelimit
ZExp.new_EmptyHole
(fun fuel ctx u_gen ze surround =>
make_and_ana_OpSeqZ fuel ctx u_gen ze surround ty)
fuel ctx u_gen e op
end
| (Construct (SOp os), ZExp.CursorE Before e) =>
match exp_op_of os with
| None => None
| Some op =>
abs_perform_Construct_SOp_Before
UHExp.bidelimit
ZExp.new_EmptyHole
(fun fuel ctx u_gen ze surround =>
make_and_ana_OpSeqZ fuel ctx u_gen ze surround ty)
fuel ctx u_gen e op
end
(* Zipper Cases *)
| (_, ZExp.ParenthesizedZ ze1) =>
match perform_ana fuel u_gen ctx a ze1 ty with
| Some (ze1', u_gen') =>
Some (
ZExp.ParenthesizedZ ze1',
u_gen')
| None => None
end
| (_, ZExp.Deeper _ (ZExp.LetZP zp ann e1 e2)) =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
match perform_ana_pat fuel ctx u_gen a zp ty1 with
| None => None
| Some (zp, ctx2, u_gen) =>
let p := ZPat.erase zp in
let ctx1 := UHExp.ctx_for_let ctx p ty1 e1 in
match UHExp.ana_fix_holes fuel ctx1 u_gen e1 ty1 with
| None => None
| Some (e1, u_gen) =>
match UHExp.ana_fix_holes fuel ctx2 u_gen e2 ty with
| None => None
| Some (e2, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZP zp ann e1 e2) in
Some (ze, u_gen)
end
end
end
| None =>
match UHExp.syn fuel ctx e1 with
| None => None
| Some ty1 =>
match perform_ana_pat fuel ctx u_gen a zp ty1 with
| None => None
| Some (zp, ctx2, u_gen) =>
match UHExp.ana_fix_holes fuel ctx2 u_gen e2 ty with
| None => None
| Some (e2, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZP zp ann e1 e2) in
Some (ze, u_gen)
end
end
end
end
| (_, ZExp.Deeper _ (ZExp.LetZA p zann e1 e2)) =>
(* (ctx) let p (ctx2) : ty = (ctx1) e1 in (ctx2) e2 *)
match perform_ty fuel a zann with
| None => None
| Some zann =>
let ty1 := UHTyp.expand fuel (ZTyp.erase zann) in
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p ty1 with
| None => None
| Some (p, ctx2, u_gen) =>
let ctx1 := UHExp.ctx_for_let ctx p ty1 e1 in
match UHExp.ana_fix_holes fuel ctx1 u_gen e1 ty1 with
| None => None
| Some (e1, u_gen) =>
match UHExp.ana_fix_holes fuel ctx2 u_gen e2 ty with
| None => None
| Some (e2, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZA p zann e1 e2) in
Some (ze, u_gen)
end
end
end
end
| (_, ZExp.Deeper _ (ZExp.LetZE1 p ann ze1 e2)) =>
match ann with
| Some ann_ty =>
let ty1 := UHTyp.expand fuel ann_ty in
let ctx1 := UHExp.ctx_for_let ctx p ty1 (ZExp.erase ze1) in
match perform_ana fuel u_gen ctx1 a ze1 ty1 with
| None => None
| Some (ze1, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZE1 p ann ze1 e2) in
Some (ze, u_gen)
end
| None =>
let e1 := ZExp.erase ze1 in
match UHExp.syn fuel ctx e1 with
| None => None
| Some ty1 =>
match perform_syn fuel ctx a (ze1, ty1, u_gen) with
| None => None
| Some (ze1, ty1, u_gen) =>
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p ty1 with
| None => None
| Some (p, ctx2, u_gen) =>
match UHExp.ana_fix_holes fuel ctx2 u_gen e2 ty with
| None => None
| Some (e2, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZE1 p ann ze1 e2) in
Some (ze, u_gen)
end
end
end
end
end
| (_, ZExp.Deeper _ (ZExp.LetZE2 p ann e1 ze2)) =>
let ty1 :=
match ann with
| Some uty1 => Some (UHTyp.expand fuel uty1)
| None => UHExp.syn fuel ctx e1
end in
match ty1 with
| None => None
| Some ty1 =>
match UHExp.ana_pat fuel ctx p ty1 with
| None => None
| Some ctx2 =>
match perform_ana fuel u_gen ctx2 a ze2 ty with
| None => None
| Some (ze2, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LetZE2 p ann e1 ze2) in
Some (ze, u_gen)
end
end
end
| (_, ZExp.Deeper _ (ZExp.LamZP zp ann e1)) =>
match HTyp.matched_arrow ty with
| None => None
| Some (ty1_given, ty2) =>
let ty1 :=
match ann with
| Some uty1 => UHTyp.expand fuel uty1
| None => ty1_given
end in
match perform_ana_pat fuel ctx u_gen a zp ty1 with
| None => None
| Some (zp, ctx, u_gen) =>
match UHExp.ana_fix_holes fuel ctx u_gen e1 ty2 with
| None => None
| Some (e1, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LamZP zp ann e1) in
Some (ze, u_gen)
end
end
end
| (_, ZExp.Deeper _ (ZExp.LamZA p zann e1)) =>
match HTyp.matched_arrow ty with
| None => None
| Some (ty1_given, ty2) =>
match perform_ty fuel a zann with
| None => None
| Some zann =>
let ty1 := UHTyp.expand fuel (ZTyp.erase zann) in
match HTyp.consistent ty1 ty1_given with
| true =>
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p ty1 with
| None => None
| Some (p, ctx, u_gen) =>
match UHExp.ana_fix_holes fuel ctx u_gen e1 ty2 with
| None => None
| Some (e1, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LamZA p zann e1) in
Some (ze, u_gen)
end
end
| false =>
match UHExp.ana_pat_fix_holes fuel ctx u_gen false p ty1 with
| None => None
| Some (p, ctx, u_gen) =>
match UHExp.syn_fix_holes fuel ctx u_gen e1 with
| None => None
| Some (e1, _, u_gen) =>
let (u, u_gen) := MetaVarGen.next u_gen in
let ze := ZExp.Deeper (InHole TypeInconsistent u) (ZExp.LamZA p zann e1) in
Some (ze, u_gen)
end
end
end
end
end
| (_, ZExp.Deeper _ (ZExp.LamZE p ann ze1)) =>
match HTyp.matched_arrow ty with
| None => None
| Some (_, ty2) =>
let ty1 :=
match ann with
| Some uty1 => UHTyp.expand fuel uty1
| None => HTyp.Hole
end in
match UHExp.ana_pat fuel ctx p ty1 with
| None => None
| Some ctx =>
match perform_ana fuel u_gen ctx a ze1 ty2 with
| None => None
| Some (ze1, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.LamZE p ann ze1) in
Some (ze, u_gen)
end
end
end
| (_, ZExp.Deeper _ (ZExp.InjZ side ze)) =>
match HTyp.matched_sum ty with
| Some (ty1, ty2) =>
let picked := pick_side side ty1 ty2 in
match perform_ana fuel u_gen ctx a ze picked with
| Some (ze', u_gen') => Some (
ZExp.Deeper (NotInHole) (
ZExp.InjZ side ze'), u_gen')
| None => None
end
| None => None
end
| (_, ZExp.Deeper _ (ZExp.CaseZE ze1 rules)) =>
match UHExp.syn fuel ctx (ZExp.erase ze1) with
| None => None
| Some ty1 =>
match perform_syn fuel ctx a (ze1, ty1, u_gen) with
| None => None
| Some (ze1, ty1, u_gen) =>
match UHExp.ana_rules_fix_holes fuel ctx u_gen false rules ty1 ty with
| None => None
| Some (rules, u_gen) =>
let ze := ZExp.Deeper NotInHole (ZExp.CaseZE ze1 rules) in
Some (ze, u_gen)
end
end
end
| (_, ZExp.Deeper _ (ZExp.CaseZR e1 zrules)) =>
match UHExp.syn fuel ctx e1 with
| None => None
| Some ty1 =>
match ZList.prj_z zrules with
| ZExp.RuleZP zp e =>
match perform_ana_pat fuel ctx u_gen a zp ty1 with
| None => None
| Some(zp, ctx, u_gen) =>
match UHExp.ana_fix_holes fuel ctx u_gen e ty with
| None => None
| Some (e, u_gen) =>
let zrule := ZExp.RuleZP zp e in
let ze := ZExp.Deeper NotInHole
(ZExp.CaseZR e1 (ZList.replace_z zrules zrule)) in
Some (ze, u_gen)
end
end
| ZExp.RuleZE p ze =>
match UHExp.ana_pat fuel ctx p ty1 with
| None => None
| Some ctx =>
match perform_ana fuel u_gen ctx a ze ty with
| None => None
| Some (ze, u_gen) =>
let zrule := ZExp.RuleZE p ze in
let ze := ZExp.Deeper NotInHole
(ZExp.CaseZR e1 (ZList.replace_z zrules zrule)) in
Some (ze, u_gen)
end
end
end
end
| (_, ZExp.Deeper _ (ZExp.OpSeqZ _ ze0 surround)) =>
let i := OperatorSeq.surround_prefix_length surround in
match ZExp.erase ze with
| UHExp.Tm _ (UHExp.OpSeq skel seq) =>
match UHExp.ana_skel fuel ctx skel seq ty (Some i) with
| Some (Some mode) =>
match mode with
| UHExp.AnalyzedAgainst ty0 =>
match perform_ana fuel u_gen ctx a ze0 ty0 with
| None => None
| Some (ze0', u_gen) =>
let ze0'' := ZExp.bidelimit ze0' in
Some (
ZExp.Deeper NotInHole (ZExp.OpSeqZ skel ze0'' surround),
u_gen)
end
| UHExp.Synthesized ty0 =>
match perform_syn fuel ctx a (ze0, ty0, u_gen) with
| None => None
| Some (ze0', ty0', u_gen) =>
let ze0'' := ZExp.bidelimit ze0' in
make_and_ana_OpSeqZ fuel ctx u_gen ze0'' surround ty
end
end
| Some _ => None (* should never happen *)
| None => None (* should never happen *)
end
| _ => None (* should never happen *)
end
(* Subsumption *)
| (UpdateApPalette _, _)
| (Construct (SApPalette _), _)
| (Construct (SVar _ _), _)
| (Construct (SNumLit _ _), _)
| (Construct (SBoolLit _ _), _)
| (Construct SListNil, _)
| (_, ZExp.Deeper _ (ZExp.AscZ1 _ _))
| (_, ZExp.Deeper _ (ZExp.AscZ2 _ _))
| (_, ZExp.Deeper _ (ZExp.ApPaletteZ _ _ _)) =>
perform_ana_subsume fuel u_gen ctx a ze ty
(* Invalid actions at expression level *)
| (Construct SNum, _)
| (Construct SBool, _)
| (Construct SList, _)
| (Construct SWild, _) => None
end
end
with perform_ana_subsume
(fuel : Fuel.t)
(u_gen : MetaVarGen.t)
(ctx : Contexts.t)
(a : t)
(ze : ZExp.t)
(ty : HTyp.t)
: option (ZExp.t * MetaVarGen.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
match UHExp.syn fuel ctx (ZExp.erase ze) with
| Some ty1 =>
match perform_syn fuel ctx a (ze, ty1, u_gen) with
| Some (ze', ty1', u_gen') =>
if HTyp.consistent ty ty1' then
Some (ze', u_gen')
else
let (ze'', u_gen'') := ZExp.make_inconsistent u_gen' ze' in
Some (ze'', u_gen'')
| None => None
end
| None => None
end
end.
Definition can_perform
(fuel : Fuel.t)
(ctx : Contexts.t)
(edit_state : (ZExp.t * HTyp.t) * MetaVarGen.t)
(ci : ZExp.cursor_info)
(a : t)
: bool :=
match a with
| Construct SParenthesized => true
| Construct SAsc =>
let sort := ZExp.sort ci in
match sort with
| ZExp.IsExpr _ => true
| ZExp.IsPat _ => true
| ZExp.IsType => false
end
| Construct SLet
| Construct SLam
| Construct (SInj _)
| Construct SCase =>
match ZExp.mode ci with
| ZExp.AnaOnly _ => false
| ZExp.AnaAnnotatedLambda _ _
| ZExp.AnaTypeInconsistent _ _
| ZExp.AnaWrongLength _ _ _
| ZExp.AnaFree _
| ZExp.AnaSubsumed _ _
| ZExp.SynOnly _
| ZExp.SynFree
| ZExp.SynErrorArrow _ _
| ZExp.SynMatchingArrow _ _
| ZExp.SynFreeArrow _ => true
| ZExp.TypePosition => false
| ZExp.PatAnaOnly _
| ZExp.PatAnaTypeInconsistent _ _
| ZExp.PatAnaWrongLength _ _ _
| ZExp.PatAnaSubsumed _ _
| ZExp.PatSynOnly _ => false
end
| Construct SListNil
| Construct (SApPalette _)
=>
match ZExp.sort ci with
| ZExp.IsExpr (UHExp.Tm _ (UHExp.EmptyHole _)) => true
| ZExp.IsExpr _ => false
| ZExp.IsPat (UHPat.Pat _ (UHPat.EmptyHole _)) => true
| ZExp.IsPat _ => false
| ZExp.IsType => false
end
| (Construct (SOp SArrow))
| (Construct (SOp SVBar))
| Construct SList =>
match ZExp.sort ci with
| ZExp.IsType => true
| ZExp.IsExpr _
| ZExp.IsPat _ => false
end
| Construct (SVar _ _) (* see can_enter_varchar below *)
| Construct SWild
| Construct (SNumLit _ _) (* see can_enter_numeral below *)
| Construct (SBoolLit _ _)
| Construct SRule
| Construct (SOp _)
| Construct SNum (* TODO enrich cursor_info to allow simplifying these type cases *)
| Construct SBool (* TODO enrich cursor_info to allow simplifying these type cases *)
| MoveTo _
| MoveToNextHole
| MoveToPrevHole
| UpdateApPalette _
| Delete
| Backspace =>
match perform_syn fuel ctx a edit_state with
| Some _ => true
| None => false
end
end.
Definition can_enter_varchar
(ci : ZExp.cursor_info)
: bool :=
match ZExp.sort ci with
| ZExp.IsExpr (UHExp.Tm _ (UHExp.Var _ _))
| ZExp.IsExpr (UHExp.Tm _ (UHExp.EmptyHole _))
| ZExp.IsExpr (UHExp.Tm _ (UHExp.BoolLit _))
| ZExp.IsPat (UHPat.Pat _ (UHPat.Var _))
| ZExp.IsPat (UHPat.Pat _ (UHPat.EmptyHole _))
| ZExp.IsPat (UHPat.Pat _ (UHPat.BoolLit _))
=> true
| ZExp.IsExpr (UHExp.Tm _ (UHExp.NumLit _))
| ZExp.IsPat (UHPat.Pat _ (UHPat.NumLit _))
=>
match ZExp.side ci with
| Before => true
| In _ | After => false
end
| ZExp.IsExpr _
| ZExp.IsPat _
| ZExp.IsType
=> false
end.
Definition can_enter_numeral
(ci : ZExp.cursor_info)
: bool :=
match ZExp.sort ci with
| ZExp.IsExpr (UHExp.Tm _ (UHExp.NumLit _))
| ZExp.IsExpr (UHExp.Tm _ (UHExp.EmptyHole _))
| ZExp.IsPat (UHPat.Pat _ (UHPat.NumLit _))
| ZExp.IsPat (UHPat.Pat _ (UHPat.EmptyHole _)) => true
| ZExp.IsExpr _
| ZExp.IsPat _
| ZExp.IsType => false
end.
Definition can_construct_palette
(ci : ZExp.cursor_info)
: bool :=
match ZExp.sort ci with
| ZExp.IsExpr (UHExp.Tm _ (UHExp.EmptyHole _)) => true
| _ => false
end.
End FAction.
Module FDynamics (Associator : ASSOCIATOR).
Inductive hole_sort :=
| ExpressionHole : hole_sort
| PatternHole : hole_sort.
Module Delta.
Definition t : Type := MetaVarMap.t (hole_sort * HTyp.t * VarCtx.t).
Definition empty : t := MetaVarMap.empty.
End Delta.
(* hole instance numbers are all 0 after expansion and during evaluation --
* renumbering is done on the final result (see below) *)
Definition inst_num : Type := nat.
Module DHPat.
Inductive t : Type :=
| EmptyHole : MetaVar.t -> inst_num -> t
| NonEmptyHole : in_hole_reason -> MetaVar.t -> inst_num -> t -> t
| Wild : t
| Var : Var.t -> t
| NumLit : nat -> t
| BoolLit : bool -> t
| Inj : inj_side -> t -> t
| ListNil : t
| Cons : t -> t -> t
| Pair : t -> t -> t
| Triv : t (* unit intro *)
| Ap : t -> t -> t.
Fixpoint make_tuple
(ds : list(t))
: t :=
match ds with
| cons d1 (cons d2 nil) => Pair d1 d2
| cons d1 nil => d1
| cons d1 ds =>
let d2 := make_tuple ds in
Pair d1 d2
| nil => Triv
end.
(* whether dp contains the variable x outside of a hole *)
Fixpoint binds_var (x : Var.t) (dp : t) : bool :=
match dp with
| EmptyHole _ _
| NonEmptyHole _ _ _ _
| Wild
| NumLit _
| BoolLit _
| Triv
| ListNil => false
| Var y => Var.eq x y
| Inj _ dp1 => binds_var x dp1
| Pair dp1 dp2 => binds_var x dp1 || binds_var x dp2
| Cons dp1 dp2 => binds_var x dp1 || binds_var x dp2
| Ap dp1 dp2 => false
end.
Inductive expand_result : Type :=
| Expands : t -> HTyp.t -> Contexts.t -> Delta.t -> expand_result
| DoesNotExpand : expand_result.
Fixpoint syn_expand
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(p : UHPat.t)
: expand_result :=
match fuel with
| Fuel.Kicked => DoesNotExpand
| Fuel.More fuel => let syn_expand := syn_expand fuel in
match p with
| UHPat.Pat (InHole (TypeInconsistent as reason) u) p'
| UHPat.Pat (InHole (WrongLength as reason) u)
((UHPat.OpSeq (Skel.BinOp (InHole WrongLength _) UHPat.Comma _ _) _) as p') =>
match syn_expand' fuel ctx delta p' with
| DoesNotExpand => DoesNotExpand
| Expands dp _ ctx delta =>
let gamma := Contexts.gamma ctx in
let delta := MetaVarMap.extend delta (u, (PatternHole, HTyp.Hole, gamma)) in
Expands
(NonEmptyHole reason u 0 dp)
HTyp.Hole
ctx
delta
end
| UHPat.Pat (InHole WrongLength _) _ => DoesNotExpand
| UHPat.Pat NotInHole p' => syn_expand' fuel ctx delta p'
| UHPat.Parenthesized p1 => syn_expand ctx delta p1
end
end
with syn_expand'
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(p' : UHPat.t')
: expand_result :=
match fuel with
| Fuel.Kicked => DoesNotExpand
| Fuel.More fuel => let syn_expand' := syn_expand' fuel in
match p' with
| UHPat.EmptyHole u =>
let gamma := Contexts.gamma ctx in
let dp := EmptyHole u 0 in
let ty := HTyp.Hole in
let delta := MetaVarMap.extend delta (u, (PatternHole, ty, gamma)) in
Expands dp ty ctx delta
| UHPat.Wild => Expands Wild HTyp.Hole ctx delta
| UHPat.Var x =>
let ctx := Contexts.extend_gamma ctx (x, HTyp.Hole) in
Expands (Var x) HTyp.Hole ctx delta
| UHPat.NumLit n => Expands (NumLit n) HTyp.Num ctx delta
| UHPat.BoolLit b => Expands (BoolLit b) HTyp.Bool ctx delta
| UHPat.Inj side p =>
match syn_expand fuel ctx delta p with
| DoesNotExpand => DoesNotExpand
| Expands dp1 ty1 ctx delta =>
let dp := Inj side dp1 in
let ty :=
match side with
| L => HTyp.Sum ty1 HTyp.Hole
| R => HTyp.Sum HTyp.Hole ty1
end in
Expands dp ty ctx delta
end
| UHPat.ListNil => Expands ListNil (HTyp.List HTyp.Hole) ctx delta
| UHPat.OpSeq skel seq => syn_expand_skel fuel ctx delta skel seq
end
end
with syn_expand_skel
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(skel : UHPat.skel_t)
(seq : UHPat.opseq)
: expand_result :=
match fuel with
| Fuel.Kicked => DoesNotExpand
| Fuel.More fuel => let syn_expand_skel := syn_expand_skel fuel in
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| None => DoesNotExpand
| Some pn =>
syn_expand fuel ctx delta pn
end
| Skel.BinOp (InHole (TypeInconsistent as reason) u) op skel1 skel2
| Skel.BinOp (InHole (WrongLength as reason) u) (UHPat.Comma as op) skel1 skel2 =>
let skel_not_in_hole := Skel.BinOp NotInHole op skel1 skel2 in
match syn_expand_skel ctx delta skel_not_in_hole seq with
| DoesNotExpand => DoesNotExpand
| Expands dp _ ctx delta =>
let gamma := Contexts.gamma ctx in
let delta := MetaVarMap.extend delta (u, (PatternHole, HTyp.Hole, gamma)) in
Expands
(NonEmptyHole reason u 0 dp)
HTyp.Hole
ctx
delta
end
| Skel.BinOp (InHole WrongLength _) _ _ _ => DoesNotExpand
| Skel.BinOp NotInHole UHPat.Comma skel1 skel2 =>
match syn_expand_skel ctx delta skel1 seq with
| DoesNotExpand => DoesNotExpand
| Expands dp1 ty1 ctx delta =>
match syn_expand_skel ctx delta skel2 seq with
| DoesNotExpand => DoesNotExpand
| Expands dp2 ty2 ctx delta =>
let dp := Pair dp1 dp2 in
Expands dp (HTyp.Prod ty1 ty2) ctx delta
end
end
| Skel.BinOp NotInHole UHPat.Space skel1 skel2 =>
match syn_expand_skel ctx delta skel1 seq with
| DoesNotExpand => DoesNotExpand
| Expands dp1 ty1 ctx delta =>
match syn_expand_skel ctx delta skel2 seq with
| DoesNotExpand => DoesNotExpand
| Expands dp2 ty2 ctx delta =>
let dp := Ap dp1 dp2 in
Expands dp HTyp.Hole ctx delta
end
end
| Skel.BinOp NotInHole UHPat.Cons skel1 skel2 =>
match syn_expand_skel ctx delta skel1 seq with
| DoesNotExpand => DoesNotExpand
| Expands dp1 ty1 ctx delta =>
let ty := HTyp.List ty1 in
match ana_expand_skel fuel ctx delta skel2 seq ty with
| DoesNotExpand => DoesNotExpand
| Expands dp2 ty' ctx delta =>
match HTyp.join ty ty' with
| None => DoesNotExpand
| Some ty =>
let dp := Cons dp1 dp2 in
Expands dp ty ctx delta
end
end
end
end
end
with ana_expand
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(p : UHPat.t)
(ty : HTyp.t)
: expand_result :=
match fuel with
| Fuel.Kicked => DoesNotExpand
| Fuel.More fuel =>
match p with
| UHPat.Pat NotInHole p' =>
ana_expand' fuel ctx delta p' ty
| UHPat.Pat (InHole (TypeInconsistent as reason) u) p' =>
match syn_expand' fuel ctx delta p' with
| DoesNotExpand => DoesNotExpand
| Expands dp1 _ ctx delta =>
let dp := NonEmptyHole reason u 0 dp1 in
let gamma := Contexts.gamma ctx in
let delta := MetaVarMap.extend delta (u, (PatternHole, ty, gamma)) in
Expands dp ty ctx delta
end
| UHPat.Pat (InHole (WrongLength as reason) u)
((UHPat.OpSeq (Skel.BinOp (InHole WrongLength _) UHPat.Comma _ _) _) as p') =>
match ana_expand' fuel ctx delta p' ty with
| DoesNotExpand => DoesNotExpand
| Expands dp1 _ ctx delta =>
let dp := NonEmptyHole reason u 0 dp1 in
let gamma := Contexts.gamma ctx in
let delta := MetaVarMap.extend delta (u, (PatternHole, ty, gamma)) in
Expands dp ty ctx delta
end
| UHPat.Pat (InHole WrongLength _) _ => DoesNotExpand
| UHPat.Parenthesized p => ana_expand fuel ctx delta p ty
end
end
with ana_expand'
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(p' : UHPat.t')
(ty : HTyp.t)
: expand_result :=
match fuel with
| Fuel.Kicked => DoesNotExpand
| Fuel.More fuel => let ana_expand' := ana_expand' fuel in
match p' with
| UHPat.EmptyHole u =>
let gamma := Contexts.gamma ctx in
let dp := EmptyHole u 0 in
let delta := MetaVarMap.extend delta (u, (PatternHole, ty, gamma)) in
Expands dp ty ctx delta
| UHPat.Var x =>
let ctx := Contexts.extend_gamma ctx (x, ty) in
Expands (DHPat.Var x) ty ctx delta
| UHPat.Wild =>
Expands DHPat.Wild ty ctx delta
| UHPat.NumLit _
| UHPat.BoolLit _ => syn_expand' fuel ctx delta p'
| UHPat.Inj side p1 =>
match HTyp.matched_sum ty with
| None => DoesNotExpand
| Some (tyL, tyR) =>
let ty1 := pick_side side tyL tyR in
match ana_expand fuel ctx delta p1 ty1 with
| DoesNotExpand => DoesNotExpand
| Expands dp1 ty1 ctx delta =>
let ty :=
match side with
| L => HTyp.Sum ty1 tyR
| R => HTyp.Sum tyL ty1
end in
Expands (DHPat.Inj side dp1) ty ctx delta
end
end
| UHPat.ListNil =>
match HTyp.matched_list ty with
| None => DoesNotExpand
| Some ty_elt => Expands ListNil (HTyp.List ty_elt) ctx delta
end
| UHPat.OpSeq skel seq => ana_expand_skel fuel ctx delta skel seq ty
end
end
with ana_expand_skel
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(skel : UHPat.skel_t)
(seq : UHPat.opseq)
(ty : HTyp.t)
: expand_result :=
match fuel with
| Fuel.Kicked => DoesNotExpand
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| None => DoesNotExpand
| Some pn => ana_expand fuel ctx delta pn ty
end
| Skel.BinOp (InHole (TypeInconsistent as reason) u) op skel1 skel2 =>
let skel_not_in_hole := Skel.BinOp NotInHole op skel1 skel2 in
match syn_expand_skel fuel ctx delta skel_not_in_hole seq with
| DoesNotExpand => DoesNotExpand
| Expands dp1 _ ctx delta =>
let dp := DHPat.NonEmptyHole reason u 0 dp1 in
let gamma := Contexts.gamma ctx in
let delta := MetaVarMap.extend delta (u, (PatternHole, ty, gamma)) in
Expands dp ty ctx delta
end
| Skel.BinOp NotInHole UHPat.Comma skel1 skel2 =>
match HTyp.matched_prod ty with
| None => DoesNotExpand
| Some (ty1, ty2) =>
match ana_expand_skel fuel ctx delta skel1 seq ty1 with
| DoesNotExpand => DoesNotExpand
| Expands dp1 ty1 ctx delta =>
match ana_expand_skel fuel ctx delta skel2 seq ty2 with
| DoesNotExpand => DoesNotExpand
| Expands dp2 ty2 ctx delta =>
let dp := Pair dp1 dp2 in
Expands dp (HTyp.Prod ty1 ty2) ctx delta
end
end
end
| Skel.BinOp (InHole WrongLength u) (UHPat.Comma as op) skel1 skel2 =>
match ty with
| HTyp.Prod ty1 ty2 =>
let types := HTyp.get_tuple ty1 ty2 in
let skels := UHPat.get_tuple skel1 skel2 in
let (zipped, remainder) := HTyp.zip_with_skels skels types in
let processed1 :=
List.fold_right (fun (skel_ty : UHPat.skel_t * HTyp.t) opt_result =>
match opt_result with
| None => None
| Some (elts, ctx, delta) =>
let (skel, ty) := skel_ty in
match ana_expand_skel fuel ctx delta skel seq ty with
| DoesNotExpand => None
| Expands dp ty ctx delta =>
Some (cons (dp, ty) elts, ctx, delta)
end
end) (Some (nil, ctx, delta)) zipped in
match processed1 with
| None => DoesNotExpand
| Some (elts1, ctx, delta) =>
let processed2 :=
List.fold_right (fun (skel : UHPat.skel_t) opt_result =>
match opt_result with
| None => None
| Some (elts, ctx, delta) =>
match syn_expand_skel fuel ctx delta skel seq with
| DoesNotExpand => None
| Expands dp ty ctx delta =>
Some (cons (dp, ty) elts, ctx, delta)
end
end) (Some (nil, ctx, delta)) remainder in
match processed2 with
| None => DoesNotExpand
| Some (elts2, ctx, delta) =>
let (ds, tys) := Util.unzip (elts1 ++ elts2) in
let d := make_tuple ds in
let ty := HTyp.make_tuple tys in
Expands d ty ctx delta
end
end
| _ => DoesNotExpand
end
| Skel.BinOp (InHole WrongLength _) _ _ _ => DoesNotExpand
| Skel.BinOp NotInHole UHPat.Space skel1 skel2 => DoesNotExpand
| Skel.BinOp NotInHole UHPat.Cons skel1 skel2 =>
match HTyp.matched_list ty with
| None => DoesNotExpand
| Some ty_elt =>
match ana_expand_skel fuel ctx delta skel1 seq ty_elt with
| DoesNotExpand => DoesNotExpand
| Expands dp1 ty_elt' ctx delta =>
let ty_list := HTyp.List ty_elt in
match ana_expand_skel fuel ctx delta skel2 seq ty_list with
| DoesNotExpand => DoesNotExpand
| Expands dp2 (HTyp.List ty_elt'') ctx delta =>
match HTyp.join ty_elt' ty_elt'' with
| None => DoesNotExpand
| Some ty_elt =>
let ty := HTyp.List ty_elt in
let dp := Cons dp1 dp2 in
Expands dp ty ctx delta
end
| Expands _ _ _ _ => DoesNotExpand
end
end
end
end
end.
End DHPat.
Module DHExp.
Inductive bin_num_op : Type :=
| Plus : bin_num_op
| Times : bin_num_op
| LessThan : bin_num_op.
Definition of_op op :=
match op with
| UHExp.Plus => Some (Plus, HTyp.Num)
| UHExp.Times => Some (Times, HTyp.Num)
| UHExp.LessThan => Some (LessThan, HTyp.Bool)
| UHExp.Space
| UHExp.Cons
| UHExp.Comma => None
end.
Definition to_op bno :=
match bno with
| Plus => UHExp.Plus
| Times => UHExp.Times
| LessThan => UHExp.LessThan
end.
Inductive t : Type :=
| EmptyHole : MetaVar.t -> inst_num -> VarMap.t_(t) -> t
| NonEmptyHole : in_hole_reason -> MetaVar.t -> inst_num -> VarMap.t_(t) -> t -> t
| FreeVar : MetaVar.t -> inst_num -> VarMap.t_(t) -> Var.t -> t
| BoundVar : Var.t -> t
| Let : DHPat.t -> t -> t -> t
| FixF : Var.t -> HTyp.t -> t -> t
| Lam : DHPat.t -> HTyp.t -> t -> t
| Ap : t -> t -> t
| BoolLit : bool -> t
| NumLit : nat -> t
| BinNumOp : bin_num_op -> t -> t -> t
| ListNil : t
| Cons : t -> t -> t
| Inj : HTyp.t -> inj_side -> t -> t
| Pair : t -> t -> t
| Triv : t
| Case : t -> list(rule) -> nat -> t
| Cast : t -> HTyp.t -> HTyp.t -> t
| FailedCast : t -> HTyp.t -> HTyp.t -> t
with rule : Type :=
| Rule : DHPat.t -> t -> rule.
Fixpoint make_tuple
(ds : list(t))
: t :=
match ds with
| cons d1 (cons d2 nil) => Pair d1 d2
| cons d1 nil => d1
| cons d1 ds =>
let d2 := make_tuple ds in
Pair d1 d2
| nil => Triv
end.
Definition cast (d : t) (t1 : HTyp.t) (t2 : HTyp.t) : t :=
if HTyp.eq t1 t2 then d else Cast d t1 t2.
Definition apply_casts (d : t) (casts : list(HTyp.t * HTyp.t)) : t :=
List.fold_left (fun d (c : HTyp.t * HTyp.t) =>
let (ty1, ty2) := c in
cast d ty1 ty2) casts d.
Module Environment.
Definition t : Type := VarMap.t_(t).
Include VarMap.
End Environment.
(* closed substitution [d1/x]d2*)
Fixpoint subst_var (fuel : Fuel.t) (d1 : t) (x : Var.t) (d2 : t) : t :=
match fuel with
| Fuel.Kicked => d2
| Fuel.More fuel => let subst_var := subst_var fuel in
match d2 with
| BoundVar y => if Var.eq x y then d1 else d2
| FreeVar _ _ _ _ => d2
| Let dp d3 d4 =>
let d3 := subst_var d1 x d3 in
let d4 := if DHPat.binds_var x dp then d4 else subst_var d1 x d4 in
Let dp d3 d4
| FixF y ty d3 =>
let d3 := if Var.eq x y then d3 else subst_var d1 x d3 in
FixF y ty d3
| Lam dp ty d3 =>
if DHPat.binds_var x dp then d2 else
let d3 := subst_var d1 x d3 in
Lam dp ty d3
| Ap d3 d4 =>
let d3 := subst_var d1 x d3 in
let d4 := subst_var d1 x d4 in
Ap d3 d4
| BoolLit _
| NumLit _
| ListNil
| Triv => d2
| Cons d3 d4 =>
let d3 := subst_var d1 x d3 in
let d4 := subst_var d1 x d4 in
Cons d3 d4
| BinNumOp op d3 d4 =>
let d3 := subst_var d1 x d3 in
let d4 := subst_var d1 x d4 in
BinNumOp op d3 d4
| Inj ty side d3 =>
let d3 := subst_var d1 x d3 in
Inj ty side d3
| Pair d3 d4 =>
let d3 := subst_var d1 x d3 in
let d4 := subst_var d1 x d4 in
Pair d3 d4
| Case d3 rules n =>
let d3 := subst_var d1 x d3 in
let rules := subst_var_rules fuel d1 x rules in
Case d3 rules n
| EmptyHole u i sigma =>
let sigma' := subst_var_env fuel d1 x sigma in
EmptyHole u i sigma'
| NonEmptyHole reason u i sigma d3 =>
let d3' := subst_var d1 x d3 in
let sigma' := subst_var_env fuel d1 x sigma in
NonEmptyHole reason u i sigma' d3'
| Cast d ty1 ty2 =>
let d' := subst_var d1 x d in
Cast d' ty1 ty2
| FailedCast d ty1 ty2 =>
let d' := subst_var d1 x d in
FailedCast d' ty1 ty2
end
end
with subst_var_rules (fuel : Fuel.t) (d1 : t) (x : Var.t) (rules : list(rule)) :=
match fuel with
| Fuel.Kicked => rules
| Fuel.More fuel =>
List.map (fun (r : rule) =>
match r with
| Rule dp d2 => if DHPat.binds_var x dp then r else Rule dp (subst_var fuel d1 x d2)
end) rules
end
with subst_var_env (fuel : Fuel.t) (d1 : t) (x : Var.t) (sigma : Environment.t) :=
match fuel with
| Fuel.Kicked => sigma
| Fuel.More fuel =>
Coq.Lists.List.map
(fun xd : Var.t * t =>
let (y, d) := xd in
(y, subst_var fuel d1 x d))
sigma
end.
Fixpoint subst
(fuel : Fuel.t)
(env : Environment.t)
(d : t)
: t :=
match fuel with
| Fuel.Kicked => d
| Fuel.More fuel =>
List.fold_left (fun d2 (xd : Var.t * t) =>
let (x, d1) := xd in
subst_var fuel d1 x d2) env d
end.
Inductive match_result : Type :=
| Matches : Environment.t -> match_result
| DoesNotMatch : match_result
| Indet : match_result. (* when pattern shape matches but contains hole *)
Fixpoint matches
(fuel : Fuel.t)
(dp : DHPat.t)
(d : t)
: match_result :=
match fuel with
| Fuel.Kicked => DoesNotMatch
| Fuel.More fuel =>
match (dp, d) with
| (_, BoundVar _) => DoesNotMatch
| (DHPat.EmptyHole _ _, _)
| (DHPat.NonEmptyHole _ _ _ _, _) => Indet
| (DHPat.Wild, _) => Matches Environment.empty
| (DHPat.Var x, _) =>
let env := Environment.extend Environment.empty (x, d) in
Matches env
| (_, EmptyHole _ _ _) => Indet
| (_, NonEmptyHole _ _ _ _ _) => Indet
| (_, FailedCast _ _ _) => Indet
| (_, FreeVar _ _ _ _) => Indet
| (_, Let _ _ _) => Indet
| (_, FixF _ _ _) => DoesNotMatch
| (_, Lam _ _ _) => DoesNotMatch
| (_, Ap _ _) => Indet
| (_, BinNumOp _ _ _) => Indet
| (_, Case _ _ _) => Indet
| (DHPat.BoolLit b1, BoolLit b2) =>
if Bool.eqb b1 b2 then Matches Environment.empty else DoesNotMatch
| (DHPat.BoolLit _, Cast d HTyp.Bool HTyp.Hole) => matches fuel dp d
| (DHPat.BoolLit _, Cast d HTyp.Hole HTyp.Bool) => matches fuel dp d
| (DHPat.BoolLit _, _) => DoesNotMatch
| (DHPat.NumLit n1, NumLit n2) =>
if Nat.eqb n1 n2 then Matches Environment.empty else DoesNotMatch
| (DHPat.NumLit _, Cast d HTyp.Num HTyp.Hole) => matches fuel dp d
| (DHPat.NumLit _, Cast d HTyp.Hole HTyp.Num) => matches fuel dp d
| (DHPat.NumLit _, _) => DoesNotMatch
| (DHPat.Inj side1 dp, Inj _ side2 d) =>
match (side1, side2) with
| (L, L) | (R, R) => matches fuel dp d
| _ => DoesNotMatch
end
| (DHPat.Inj side dp, Cast d (HTyp.Sum tyL1 tyR1) (HTyp.Sum tyL2 tyR2)) =>
matches_cast_Inj fuel side dp d (cons (tyL1, tyR1, tyL2, tyR2) nil)
| (DHPat.Inj _ _, Cast d (HTyp.Sum _ _) HTyp.Hole) => matches fuel dp d
| (DHPat.Inj _ _, Cast d HTyp.Hole (HTyp.Sum _ _)) => matches fuel dp d
| (DHPat.Inj _ _, _) => DoesNotMatch
| (DHPat.Pair dp1 dp2, Pair d1 d2) =>
match matches fuel dp1 d1 with
| DoesNotMatch => DoesNotMatch
| Indet => Indet
| Matches env1 =>
match matches fuel dp2 d2 with
| DoesNotMatch => DoesNotMatch
| Indet => Indet
| Matches env2 =>
Matches (Environment.union env1 env2)
end
end
| (DHPat.Pair dp1 dp2, Cast d (HTyp.Prod tyL1 tyR1) (HTyp.Prod tyL2 tyR2)) =>
matches_cast_Pair fuel dp1 dp2 d (cons (tyL1, tyL2) nil) (cons (tyR1, tyR2) nil)
| (DHPat.Pair dp1 dp2, Cast d HTyp.Hole (HTyp.Prod _ _)) => matches fuel dp d
| (DHPat.Pair dp1 dp2, Cast d (HTyp.Prod _ _) HTyp.Hole) => matches fuel dp d
| (DHPat.Pair _ _, _) => DoesNotMatch
| (DHPat.Triv, Triv) => Matches Environment.empty
| (DHPat.Triv, Cast d HTyp.Hole HTyp.Unit) => matches fuel dp d
| (DHPat.Triv, Cast d HTyp.Unit HTyp.Hole) => matches fuel dp d
| (DHPat.Triv, _) => DoesNotMatch
| (DHPat.ListNil, ListNil) => Matches Environment.empty
| (DHPat.ListNil, Cast d HTyp.Hole (HTyp.List _)) => matches fuel dp d
| (DHPat.ListNil, Cast d (HTyp.List _) HTyp.Hole) => matches fuel dp d
| (DHPat.ListNil, _) => DoesNotMatch
| (DHPat.Cons dp1 dp2, Cons d1 d2) =>
match matches fuel dp1 d1 with
| DoesNotMatch => DoesNotMatch
| Indet => Indet
| Matches env1 =>
match matches fuel dp2 d2 with
| DoesNotMatch => DoesNotMatch
| Indet => Indet
| Matches env2 =>
Matches (Environment.union env1 env2)
end
end
| (DHPat.Cons dp1 dp2, Cast d (HTyp.List ty1) (HTyp.List ty2)) =>
matches_cast_Cons fuel dp1 dp2 d (cons (ty1, ty2) nil)
| (DHPat.Cons _ _, Cast d HTyp.Hole (HTyp.List _)) => matches fuel dp d
| (DHPat.Cons _ _, Cast d (HTyp.List _) HTyp.Hole) => matches fuel dp d
| (DHPat.Cons _ _, _) => DoesNotMatch
| (DHPat.Ap _ _, _) => DoesNotMatch
end
end
with matches_cast_Inj
(fuel : Fuel.t)
(side : inj_side)
(dp : DHPat.t)
(d : t)
(casts : list(HTyp.t * HTyp.t * HTyp.t * HTyp.t))
: match_result :=
match fuel with
| Fuel.Kicked => DoesNotMatch
| Fuel.More fuel =>
match d with
| Inj _ side' d' =>
match (side, side') with
| (L, L) | (R, R) =>
let side_casts :=
List.map (fun (c : HTyp.t * HTyp.t * HTyp.t * HTyp.t) =>
let '(tyL1, tyR1, tyL2, tyR2) := c in
match side with
| L => (tyL1, tyL2)
| R => (tyR1, tyR2)
end) casts in
matches fuel dp (apply_casts d' side_casts)
| _ => DoesNotMatch
end
| Cast d' (HTyp.Sum tyL1 tyR1) (HTyp.Sum tyL2 tyR2) =>
matches_cast_Inj fuel side dp d' (cons (tyL1, tyR1, tyL2, tyR2) casts)
| Cast d' (HTyp.Sum _ _) (HTyp.Hole)
| Cast d' HTyp.Hole (HTyp.Sum _ _) =>
matches_cast_Inj fuel side dp d' casts
| Cast _ _ _ => DoesNotMatch
| BoundVar _ => DoesNotMatch
| FreeVar _ _ _ _ => Indet
| Let _ _ _ => Indet
| FixF _ _ _ => DoesNotMatch
| Lam _ _ _ => DoesNotMatch
| Ap _ _ => Indet
| BinNumOp _ _ _ => Indet
| BoolLit _ => DoesNotMatch
| NumLit _ => DoesNotMatch
| ListNil => DoesNotMatch
| Cons _ _ => DoesNotMatch
| Pair _ _ => DoesNotMatch
| Triv => DoesNotMatch
| Case _ _ _ => Indet
| EmptyHole _ _ _ => Indet
| NonEmptyHole _ _ _ _ _ => Indet
| FailedCast _ _ _ => Indet
end
end
with matches_cast_Pair
(fuel : Fuel.t)
(dp1 dp2 : DHPat.t)
(d : t)
(left_casts : list(HTyp.t * HTyp.t))
(right_casts : list(HTyp.t * HTyp.t))
: match_result :=
match fuel with
| Fuel.Kicked => DoesNotMatch
| Fuel.More fuel =>
match d with
| Pair d1 d2 =>
match matches fuel dp1 (apply_casts d1 left_casts) with
| DoesNotMatch => DoesNotMatch
| Indet => Indet
| Matches env1 =>
match matches fuel dp2 (apply_casts d2 right_casts) with
| DoesNotMatch => DoesNotMatch
| Indet => Indet
| Matches env2 =>
Matches (Environment.union env1 env2)
end
end
| Cast d' (HTyp.Prod tyL1 tyR1) (HTyp.Prod tyL2 tyR2) =>
matches_cast_Pair fuel dp1 dp2 d'
(cons (tyL1, tyL2) left_casts)
(cons (tyR1, tyR2) right_casts)
| Cast d' (HTyp.Prod _ _) HTyp.Hole
| Cast d' HTyp.Hole (HTyp.Prod _ _) =>
matches_cast_Pair fuel dp1 dp2 d' left_casts right_casts
| Cast _ _ _ => DoesNotMatch
| BoundVar _ => DoesNotMatch
| FreeVar _ _ _ _ => Indet
| Let _ _ _ => Indet
| FixF _ _ _ => DoesNotMatch
| Lam _ _ _ => DoesNotMatch
| Ap _ _ => Indet
| BinNumOp _ _ _ => Indet
| BoolLit _ => DoesNotMatch
| NumLit _ => DoesNotMatch
| Inj _ _ _ => DoesNotMatch
| ListNil => DoesNotMatch
| Cons _ _ => DoesNotMatch
| Triv => DoesNotMatch
| Case _ _ _ => Indet
| EmptyHole _ _ _ => Indet
| NonEmptyHole _ _ _ _ _ => Indet
| FailedCast _ _ _ => Indet
end
end
with matches_cast_Cons
(fuel : Fuel.t)
(dp1 dp2 : DHPat.t)
(d : t)
(elt_casts : list(HTyp.t * HTyp.t))
: match_result :=
match fuel with
| Fuel.Kicked => DoesNotMatch
| Fuel.More fuel =>
match d with
| Cons d1 d2 =>
match matches fuel dp1 (apply_casts d1 elt_casts) with
| DoesNotMatch => DoesNotMatch
| Indet => Indet
| Matches env1 =>
let list_casts := List.map (fun (c : HTyp.t * HTyp.t) =>
let (ty1, ty2) := c in
(HTyp.List ty1, HTyp.List ty2)) elt_casts in
match matches fuel dp2 (apply_casts d2 list_casts) with
| DoesNotMatch => DoesNotMatch
| Indet => Indet
| Matches env2 =>
Matches (Environment.union env1 env2)
end
end
| Cast d' (HTyp.List ty1) (HTyp.List ty2) =>
matches_cast_Cons fuel dp1 dp2 d' (cons (ty1, ty2) elt_casts)
| Cast d' (HTyp.List _) HTyp.Hole =>
matches_cast_Cons fuel dp1 dp2 d' elt_casts
| Cast d' HTyp.Hole (HTyp.List _) =>
matches_cast_Cons fuel dp1 dp2 d' elt_casts
| Cast _ _ _ => DoesNotMatch
| BoundVar _ => DoesNotMatch
| FreeVar _ _ _ _ => Indet
| Let _ _ _ => Indet
| FixF _ _ _ => DoesNotMatch
| Lam _ _ _ => DoesNotMatch
| Ap _ _ => Indet
| BinNumOp _ _ _ => Indet
| BoolLit _ => DoesNotMatch
| NumLit _ => DoesNotMatch
| Inj _ _ _ => DoesNotMatch
| ListNil => DoesNotMatch
| Pair _ _ => DoesNotMatch
| Triv => DoesNotMatch
| Case _ _ _ => Indet
| EmptyHole _ _ _ => Indet
| NonEmptyHole _ _ _ _ _ => Indet
| FailedCast _ _ _ => Indet
end
end.
(* Implementation of type assignment judgment in POPL 2019 paper.
* Not actually called anywhere, now stale.
Inductive type_result : Type :=
| WellTyped : HTyp.t -> type_result
| IllTyped.
Fixpoint assign_type
(fuel : Fuel.t)
(gamma : VarCtx.t) (delta : Delta.t)
(d : t)
: type_result :=
match fuel with
| Fuel.Kicked => IllTyped
| Fuel.More fuel =>
let assign_type := assign_type fuel in
match d with
| BoundVar x =>
match (Var.is_valid x, VarMap.lookup gamma x) with
| (true, Some ty) => WellTyped ty
| _ => IllTyped
end
| FreeVar u _ sigma x =>
if (Var.is_valid x) then
match MetaVarMap.lookup delta u with
| Some (ty, gamma') =>
if check_type_env fuel gamma delta sigma gamma' then
WellTyped ty
else IllTyped
| None => IllTyped
end
else IllTyped
| Let x d1 d2 =>
match (Var.is_valid_binder x, assign_type gamma delta d1) with
| (true, WellTyped ty1) =>
let gamma' := VarMap.extend gamma (x, ty1) in
assign_type gamma' delta d2
| _ => IllTyped
end
| FixF x ((HTyp.Arrow _ _) as ty1) d1 =>
let gamma' := VarMap.extend gamma (x, ty1) in
match (Var.is_valid_binder x, assign_type gamma' delta d1) with
| (true, WellTyped ty2) =>
if HTyp.eq ty1 ty2 then WellTyped ty2 else IllTyped
| _ => IllTyped
end
| FixF x _ d1 => IllTyped
| Lam x ty1 d1 =>
let gamma' := VarMap.extend gamma (x, ty1) in
match (Var.is_valid_binder x, assign_type gamma' delta d1) with
| (true, WellTyped ty2) => WellTyped (HTyp.Arrow ty1 ty2)
| _ => IllTyped
end
| Ap d1 d2 =>
match assign_type gamma delta d1 with
| IllTyped => IllTyped
| WellTyped (HTyp.Arrow ty2 ty) =>
match assign_type gamma delta d2 with
| IllTyped => IllTyped
| WellTyped ty2' =>
if HTyp.eq ty2 ty2' then WellTyped ty
else IllTyped
end
| WellTyped _ => IllTyped
end
| NumLit _ => WellTyped HTyp.Num
| BinNumOp _ d1 d2 =>
match (assign_type gamma delta d1,
assign_type gamma delta d2) with
| (WellTyped HTyp.Num, WellTyped HTyp.Num) =>
WellTyped HTyp.Num
| _ => IllTyped
end
| Inj other_ty side d1 =>
match assign_type gamma delta d1 with
| IllTyped => IllTyped
| WellTyped ty1 =>
match side with
| L => WellTyped (HTyp.Sum ty1 other_ty)
| R => WellTyped (HTyp.Sum other_ty ty1)
end
end
| Case d1 (x, d2) (y, d3) =>
match ((Var.is_valid_binder x) && (Var.is_valid_binder y), assign_type gamma delta d1) with
| (true, WellTyped (HTyp.Sum tyL tyR)) =>
let gamma1 := VarMap.extend gamma (x, tyL) in
let gamma2 := VarMap.extend gamma (y, tyR) in
match (assign_type gamma1 delta d2,
assign_type gamma2 delta d3) with
| (WellTyped ty2, WellTyped ty3) =>
if HTyp.eq ty2 ty3 then WellTyped ty2
else IllTyped
| _ => IllTyped
end
| _ => IllTyped
end
| EmptyHole u _ sigma =>
match MetaVarMap.lookup delta u with
| Some (ty, gamma') =>
if check_type_env fuel gamma delta sigma gamma' then
WellTyped ty
else IllTyped
| None => IllTyped
end
| NonEmptyHole reason u _ sigma d1 =>
match assign_type gamma delta d1 with
| WellTyped _ =>
match MetaVarMap.lookup delta u with
| Some (ty, gamma') =>
if check_type_env fuel gamma delta sigma gamma' then
WellTyped ty
else IllTyped
| None => IllTyped
end
| IllTyped => IllTyped
end
| Cast d1 ty1 ty2
| FailedCast d1 ty1 ty2 =>
match assign_type gamma delta d1 with
| IllTyped => IllTyped
| WellTyped ty1' =>
if HTyp.eq ty1 ty1' &&
HTyp.consistent ty1 ty2
then WellTyped ty2
else IllTyped
end
end
end
with check_type_env (fuel : Fuel.t)
(gamma : VarCtx.t) (delta : Delta.t)
(sigma : Environment.t)
(gamma' : VarCtx.t) : bool :=
match fuel with
| Fuel.More fuel =>
Coq.Lists.List.forallb
(fun xd : Var.t * t =>
let (x, d) := xd in
match assign_type fuel gamma delta d with
| WellTyped ty =>
match VarMap.lookup gamma' x with
| Some ty' => HTyp.consistent ty ty'
| None => false
end
| IllTyped => false
end)
sigma
| Fuel.Kicked => false
end.
*)
Inductive expand_result : Type :=
| Expands : t -> HTyp.t -> Delta.t -> expand_result
| DoesNotExpand.
Definition id_env (ctx : VarCtx.t) : Environment.t :=
VarMap.map
(fun xt : Var.t * HTyp.t =>
let (x, _) := xt in DHExp.BoundVar x)
ctx.
Fixpoint syn_expand
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(e : UHExp.t)
: expand_result :=
match fuel with
| Fuel.Kicked => DoesNotExpand
| Fuel.More fuel =>
match e with
| UHExp.Parenthesized e1 => syn_expand fuel ctx delta e1
| UHExp.Tm (NotInHole) e' => syn_expand' fuel ctx delta e'
| UHExp.Tm (InHole (TypeInconsistent as reason) u) e'
| UHExp.Tm (InHole (WrongLength as reason) u)
((UHExp.OpSeq (Skel.BinOp (InHole WrongLength _) UHExp.Comma _ _) _) as e') =>
match syn_expand' fuel ctx delta e' with
| Expands d _ delta =>
let gamma := Contexts.gamma ctx in
let sigma := id_env gamma in
let delta := MetaVarMap.extend delta (u, (ExpressionHole, HTyp.Hole, gamma)) in
Expands
(NonEmptyHole reason u 0 sigma d)
(HTyp.Hole)
(delta)
| DoesNotExpand => DoesNotExpand
end
| UHExp.Tm (InHole WrongLength _) _ => DoesNotExpand
end
end
with syn_expand'
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(e : UHExp.t')
: expand_result :=
match fuel with
| Fuel.Kicked => DoesNotExpand
| Fuel.More fuel =>
match e with
| UHExp.EmptyHole u =>
let gamma := Contexts.gamma ctx in
let sigma := id_env gamma in
let d := DHExp.EmptyHole u 0 sigma in
let ty := HTyp.Hole in
let delta := MetaVarMap.extend delta (u, (ExpressionHole, ty, gamma)) in
Expands d ty delta
| UHExp.Asc e1 uty =>
let ty := UHTyp.expand fuel uty in
match ana_expand fuel ctx delta e1 ty with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty' delta =>
Expands
(cast d1 ty' ty)
ty
delta
end
| UHExp.Var (NotInVHole) x =>
let gamma := Contexts.gamma ctx in
match VarMap.lookup gamma x with
| Some ty => Expands (DHExp.BoundVar x) ty delta
| None => DoesNotExpand
end
| UHExp.Var (InVHole u) x =>
let gamma := Contexts.gamma ctx in
let sigma := id_env gamma in
let delta := MetaVarMap.extend delta (u, (ExpressionHole, HTyp.Hole, gamma)) in
Expands
(DHExp.FreeVar u 0 sigma x)
(HTyp.Hole)
delta
| UHExp.Lam p ann e1 =>
let ty1 :=
match ann with
| Some uty1 => UHTyp.expand fuel uty1
| None => HTyp.Hole
end in
match DHPat.ana_expand fuel ctx delta p ty1 with
| DHPat.DoesNotExpand => DoesNotExpand
| DHPat.Expands dp ty1 ctx delta =>
match syn_expand fuel ctx delta e1 with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty2 delta =>
let d := Lam dp ty1 d1 in
Expands d (HTyp.Arrow ty1 ty2) delta
end
end
| UHExp.Let p ann e1 e2 =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
let (ctx1, is_recursive_fn) := UHExp.ctx_for_let' ctx p ty1 e1 in
match ana_expand fuel ctx1 delta e1 ty1 with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty1 delta =>
let d1 :=
match is_recursive_fn with
| None => d1
| Some x => FixF x ty1 d1
end in
match DHPat.ana_expand fuel ctx delta p ty1 with
| DHPat.DoesNotExpand => DoesNotExpand
| DHPat.Expands dp typ ctx delta =>
match syn_expand fuel ctx delta e2 with
| DoesNotExpand => DoesNotExpand
| Expands d2 ty delta =>
let d := Let dp d1 d2 in
Expands d ty delta
end
end
end
| None =>
match syn_expand fuel ctx delta e1 with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty1 delta =>
match DHPat.ana_expand fuel ctx delta p ty1 with
| DHPat.DoesNotExpand => DoesNotExpand
| DHPat.Expands dp ty1 ctx delta =>
match syn_expand fuel ctx delta e2 with
| DoesNotExpand => DoesNotExpand
| Expands d2 ty delta2 =>
let d := Let dp d1 d2 in
Expands d ty delta
end
end
end
end
| UHExp.NumLit n =>
Expands (NumLit n) HTyp.Num delta
| UHExp.BoolLit b =>
Expands (BoolLit b) HTyp.Bool delta
| UHExp.Inj side e1 =>
match syn_expand fuel ctx delta e1 with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty1 delta =>
let d := DHExp.Inj HTyp.Hole side d1 in
let ty :=
match side with
| L => HTyp.Sum ty1 HTyp.Hole
| R => HTyp.Sum HTyp.Hole ty1
end in
Expands d ty delta
end
| UHExp.ListNil => Expands ListNil (HTyp.List HTyp.Hole) delta
| UHExp.Case _ _ => DoesNotExpand
| UHExp.OpSeq skel seq =>
syn_expand_skel fuel ctx delta skel seq
| UHExp.ApPalette name serialized_model hole_data => DoesNotExpand
(* TODO fix me *)
(* let (_, palette_ctx) := ctx in
match (VarMap.lookup palette_ctx name) with
| Some palette_defn =>
let expansion_ty := UHExp.PaletteDefinition.expansion_ty palette_defn in
let to_exp := UHExp.PaletteDefinition.to_exp palette_defn in
let expansion := to_exp serialized_model in
let (_, hole_map) := hole_data in
(* bind each free variable in expansion by wrapping expansion
* in lambda, then apply lambda to args in hole data
*)
let bound_expansion :=
NatMap.fold hole_map
(fun bound entry =>
let (n, typ_exp) := entry in
let (htyp, hexp) := typ_exp in
let lam := UHExp.Tm NotInHole (UHExp.Lam (UHExp.PaletteHoleData.mk_hole_ref_var_name n) bound) in
let hexp_ann := UHExp.Tm NotInHole (UHExp.Asc (UHExp.Parenthesized hexp) (UHTyp.contract htyp)) in
let opseq := OperatorSeq.ExpOpExp (UHExp.Parenthesized lam) UHExp.Space (UHExp.Parenthesized hexp_ann) in
let ap := UHExp.OpSeq (Associator.associate_exp opseq) opseq in
UHExp.Tm NotInHole ap
)
expansion in
ana_expand fuel ctx bound_expansion expansion_ty
| None => DoesNotExpand
end *)
end
end
with syn_expand_skel
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(skel : UHExp.skel_t)
(seq : UHExp.opseq)
: expand_result :=
match fuel with
| Fuel.Kicked => DoesNotExpand
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| None => DoesNotExpand
| Some en => syn_expand fuel ctx delta en
end
| Skel.BinOp (InHole (TypeInconsistent as reason) u) op skel1 skel2
| Skel.BinOp (InHole (WrongLength as reason) u) (UHExp.Comma as op) skel1 skel2 =>
let skel_not_in_hole := Skel.BinOp NotInHole op skel1 skel2 in
match syn_expand_skel fuel ctx delta skel_not_in_hole seq with
| DoesNotExpand => DoesNotExpand
| Expands d _ delta =>
let gamma := Contexts.gamma ctx in
let sigma := id_env gamma in
let delta := MetaVarMap.extend delta (u, (ExpressionHole, HTyp.Hole, gamma)) in
Expands
(NonEmptyHole reason u 0 sigma d)
HTyp.Hole delta
end
| Skel.BinOp (InHole WrongLength _) _ _ _ => DoesNotExpand
| Skel.BinOp NotInHole UHExp.Space skel1 skel2 =>
match UHExp.syn_skel fuel ctx skel1 seq None with
| None => DoesNotExpand
| Some (ty1, _) =>
match HTyp.matched_arrow ty1 with
| None => DoesNotExpand
| Some (ty2, ty) =>
let ty2_arrow_ty := HTyp.Arrow ty2 ty in
match ana_expand_skel fuel ctx delta skel1 seq ty2_arrow_ty with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty1' delta =>
match ana_expand_skel fuel ctx delta skel2 seq ty2 with
| DoesNotExpand => DoesNotExpand
| Expands d2 ty2' delta =>
let dc1 := cast d1 ty1' ty2_arrow_ty in
let dc2 := cast d2 ty2' ty2 in
let d := Ap dc1 dc2 in
Expands d ty delta
end
end
end
end
| Skel.BinOp NotInHole UHExp.Comma skel1 skel2 =>
match syn_expand_skel fuel ctx delta skel1 seq with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty1 delta =>
match syn_expand_skel fuel ctx delta skel2 seq with
| DoesNotExpand => DoesNotExpand
| Expands d2 ty2 delta =>
let d := Pair d1 d2 in
let ty := HTyp.Prod ty1 ty2 in
Expands d ty delta
end
end
| Skel.BinOp NotInHole UHExp.Cons skel1 skel2 =>
match syn_expand_skel fuel ctx delta skel1 seq with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty1 delta =>
let ty := HTyp.List ty1 in
match ana_expand_skel fuel ctx delta skel2 seq ty with
| DoesNotExpand => DoesNotExpand
| Expands d2 ty' delta =>
match HTyp.join ty ty' with
| None => DoesNotExpand
| Some ty =>
let d := Cons d1 d2 in
Expands d ty delta
end
end
end
| Skel.BinOp NotInHole (UHExp.Plus as op) skel1 skel2
| Skel.BinOp NotInHole (UHExp.Times as op) skel1 skel2
| Skel.BinOp NotInHole (UHExp.LessThan as op) skel1 skel2 =>
match ana_expand_skel fuel ctx delta skel1 seq HTyp.Num with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty1 delta =>
match ana_expand_skel fuel ctx delta skel2 seq HTyp.Num with
| DoesNotExpand => DoesNotExpand
| Expands d2 ty2 delta =>
let dc1 := cast d1 ty1 HTyp.Num in
let dc2 := cast d2 ty2 HTyp.Num in
match of_op op with
| None => DoesNotExpand
| Some (op, ty) =>
let d := BinNumOp op dc1 dc2 in
Expands d ty delta
end
end
end
end
end
with ana_expand
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(e : UHExp.t)
(ty : HTyp.t)
: expand_result :=
match fuel with
| Fuel.Kicked => DoesNotExpand
| Fuel.More fuel =>
match e with
| UHExp.Tm NotInHole e' => ana_expand' fuel ctx delta e' ty
| UHExp.Tm (InHole (TypeInconsistent as reason) u) e' =>
match syn_expand' fuel ctx delta e' with
| DoesNotExpand => DoesNotExpand
| Expands d _ delta =>
let gamma := Contexts.gamma ctx in
let sigma := id_env gamma in
let delta := MetaVarMap.extend delta (u, (ExpressionHole, ty, gamma)) in
Expands
(NonEmptyHole reason u 0 sigma d)
ty
delta
end
| UHExp.Tm (InHole (WrongLength as reason) u)
((UHExp.OpSeq (Skel.BinOp (InHole WrongLength _) UHExp.Comma _ _) _) as e') =>
match ana_expand' fuel ctx delta e' ty with
| DoesNotExpand => DoesNotExpand
| Expands d1 _ delta =>
let gamma := Contexts.gamma ctx in
let sigma := id_env gamma in
let delta := MetaVarMap.extend delta (u, (ExpressionHole, ty, gamma)) in
let d := NonEmptyHole reason u 0 sigma d1 in
Expands d ty delta
end
| UHExp.Tm (InHole WrongLength _) _ => DoesNotExpand
| UHExp.Parenthesized e1 => ana_expand fuel ctx delta e1 ty
end
end
with ana_expand'
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(e : UHExp.t')
(ty : HTyp.t)
: expand_result :=
match fuel with
| Fuel.Kicked => DoesNotExpand
| Fuel.More fuel =>
match e with
| UHExp.EmptyHole u =>
let gamma := Contexts.gamma ctx in
let sigma := id_env gamma in
let d := EmptyHole u 0 sigma in
let delta := MetaVarMap.extend delta (u, (ExpressionHole, ty, gamma)) in
Expands d ty delta
| UHExp.Var (InVHole u) x =>
let gamma := Contexts.gamma ctx in
let sigma := id_env gamma in
let delta := MetaVarMap.extend delta (u, (ExpressionHole, ty, gamma)) in
Expands
(FreeVar u 0 sigma x)
ty
delta
| UHExp.Let p ann e1 e2 =>
match ann with
| Some uty1 =>
let ty1 := UHTyp.expand fuel uty1 in
let (ctx1, is_recursive_fn) := UHExp.ctx_for_let' ctx p ty1 e1 in
match ana_expand fuel ctx1 delta e1 ty1 with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty1 delta =>
let d1 :=
match is_recursive_fn with
| None => d1
| Some x => FixF x ty1 d1
end in
match DHPat.ana_expand fuel ctx delta p ty1 with
| DHPat.DoesNotExpand => DoesNotExpand
| DHPat.Expands dp _ ctx delta =>
match ana_expand fuel ctx delta e2 ty with
| DoesNotExpand => DoesNotExpand
| Expands d2 ty delta =>
let d := Let dp d1 d2 in
Expands d ty delta
end
end
end
| None =>
match syn_expand fuel ctx delta e1 with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty1 delta =>
match DHPat.ana_expand fuel ctx delta p ty1 with
| DHPat.DoesNotExpand => DoesNotExpand
| DHPat.Expands dp ty1 ctx delta =>
match ana_expand fuel ctx delta e2 ty with
| DoesNotExpand => DoesNotExpand
| Expands d2 ty delta =>
let d := Let dp d1 d2 in
Expands d ty delta
end
end
end
end
| UHExp.Lam p ann e1 =>
match HTyp.matched_arrow ty with
| None => DoesNotExpand
| Some (ty1_given, ty2) =>
match ann with
| Some uty1 =>
let ty1_ann := UHTyp.expand fuel uty1 in
match HTyp.consistent ty1_ann ty1_given with
| false => DoesNotExpand
| true =>
match DHPat.ana_expand fuel ctx delta p ty1_ann with
| DHPat.DoesNotExpand => DoesNotExpand
| DHPat.Expands dp ty1p ctx delta =>
match ana_expand fuel ctx delta e1 ty2 with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty2 delta =>
let ty := HTyp.Arrow ty1p ty2 in
let d := Lam dp ty1p d1 in
Expands d ty delta
end
end
end
| None =>
match DHPat.ana_expand fuel ctx delta p ty1_given with
| DHPat.DoesNotExpand => DoesNotExpand
| DHPat.Expands dp ty1 ctx delta =>
match ana_expand fuel ctx delta e1 ty2 with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty2 delta =>
let ty := HTyp.Arrow ty1 ty2 in
let d := Lam dp ty1 d1 in
Expands d ty delta
end
end
end
end
| UHExp.Inj side e1 =>
match HTyp.matched_sum ty with
| None => DoesNotExpand
| Some (ty1, ty2) =>
let e1ty := pick_side side ty1 ty2 in
match ana_expand fuel ctx delta e1 e1ty with
| DoesNotExpand => DoesNotExpand
| Expands d1 e1ty' delta =>
let (ann_ty, ty) :=
match side with
| L => (ty2, HTyp.Sum e1ty' ty2)
| R => (ty1, HTyp.Sum ty1 e1ty')
end in
let d := Inj ann_ty side d1 in
Expands d ty delta
end
end
| UHExp.ListNil =>
match HTyp.matched_list ty with
| None => DoesNotExpand
| Some _ => Expands ListNil ty delta
end
| UHExp.Case e1 rules =>
match syn_expand fuel ctx delta e1 with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty1 delta =>
match ana_expand_rules fuel ctx delta rules ty1 ty with
| None => DoesNotExpand
| Some (drs, delta) =>
let d := Case d1 drs 0 in
Expands d ty delta
end
end
| UHExp.OpSeq skel seq => ana_expand_skel fuel ctx delta skel seq ty
| UHExp.Asc _ _
| UHExp.Var NotInVHole _
| UHExp.BoolLit _
| UHExp.NumLit _
| UHExp.ApPalette _ _ _ =>
(* subsumption *)
syn_expand' fuel ctx delta e
end
end
with ana_expand_rules
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(rules : list(UHExp.rule))
(pat_ty : HTyp.t)
(clause_ty : HTyp.t)
: option(list(rule) * Delta.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
List.fold_left (fun b r =>
match b with
| None => None
| Some (drs, delta) =>
match ana_expand_rule fuel ctx delta r pat_ty clause_ty with
| None => None
| Some (dr, delta) =>
let drs := drs ++ (cons dr nil) in
Some (drs, delta)
end
end) rules (Some (nil, delta))
end
with ana_expand_rule
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(r : UHExp.rule)
(pat_ty : HTyp.t)
(clause_ty : HTyp.t)
: option(rule * Delta.t) :=
match fuel with
| Fuel.Kicked => None
| Fuel.More fuel =>
let (p, e) := r in
match DHPat.ana_expand fuel ctx delta p pat_ty with
| DHPat.DoesNotExpand => None
| DHPat.Expands dp _ ctx delta =>
match ana_expand fuel ctx delta e clause_ty with
| DoesNotExpand => None
| Expands d1 ty1 delta =>
Some (Rule dp (cast d1 ty1 clause_ty), delta)
end
end
end
with ana_expand_skel
(fuel : Fuel.t)
(ctx : Contexts.t)
(delta : Delta.t)
(skel : UHExp.skel_t)
(seq : UHExp.opseq)
(ty : HTyp.t)
: expand_result :=
match fuel with
| Fuel.Kicked => DoesNotExpand
| Fuel.More fuel =>
match skel with
| Skel.Placeholder _ n =>
match OperatorSeq.seq_nth n seq with
| None => DoesNotExpand
| Some en => ana_expand fuel ctx delta en ty
end
| Skel.BinOp (InHole (TypeInconsistent as reason) u) op skel1 skel2 =>
let skel_not_in_hole := Skel.BinOp NotInHole op skel1 skel2 in
match syn_expand_skel fuel ctx delta skel_not_in_hole seq with
| DoesNotExpand => DoesNotExpand
| Expands d1 _ delta =>
let gamma := Contexts.gamma ctx in
let sigma := id_env gamma in
let delta := MetaVarMap.extend delta (u, (ExpressionHole, ty, gamma)) in
let d := DHExp.NonEmptyHole reason u 0 sigma d1 in
Expands d ty delta
end
| Skel.BinOp NotInHole UHExp.Comma skel1 skel2 =>
match HTyp.matched_prod ty with
| None => DoesNotExpand
| Some (ty1, ty2) =>
match ana_expand_skel fuel ctx delta skel1 seq ty1 with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty1 delta =>
match ana_expand_skel fuel ctx delta skel2 seq ty2 with
| DoesNotExpand => DoesNotExpand
| Expands d2 ty2 delta =>
let d := Pair d1 d2 in
Expands d (HTyp.Prod ty1 ty2) delta
end
end
end
| Skel.BinOp (InHole WrongLength u) (UHExp.Comma as op) skel1 skel2 =>
match ty with
| HTyp.Prod ty1 ty2 =>
let types := HTyp.get_tuple ty1 ty2 in
let skels := UHExp.get_tuple skel1 skel2 in
let (zipped, remainder) := HTyp.zip_with_skels skels types in
let processed1 :=
List.fold_right (fun (skel_ty : UHExp.skel_t * HTyp.t) opt_result =>
match opt_result with
| None => None
| Some (elts, delta) =>
let (skel, ty) := skel_ty in
match ana_expand_skel fuel ctx delta skel seq ty with
| DoesNotExpand => None
| Expands d ty delta =>
Some (cons (d, ty) elts, delta)
end
end) (Some (nil, delta)) zipped in
match processed1 with
| None => DoesNotExpand
| Some (elts1, delta) =>
let processed2 :=
List.fold_right (fun (skel : UHExp.skel_t) opt_result =>
match opt_result with
| None => None
| Some (elts, delta) =>
match syn_expand_skel fuel ctx delta skel seq with
| DoesNotExpand => None
| Expands d ty delta =>
Some (cons (d, ty) elts, delta)
end
end) (Some (nil, delta)) remainder in
match processed2 with
| None => DoesNotExpand
| Some (elts2, delta) =>
let (ds, tys) := Util.unzip (elts1 ++ elts2) in
let d := DHExp.make_tuple ds in
let ty := HTyp.make_tuple tys in
Expands d ty delta
end
end
| _ => DoesNotExpand
end
| Skel.BinOp (InHole WrongLength _) _ _ _ => DoesNotExpand
| Skel.BinOp NotInHole UHExp.Cons skel1 skel2 =>
match HTyp.matched_list ty with
| None => DoesNotExpand
| Some ty_elt =>
match ana_expand_skel fuel ctx delta skel1 seq ty_elt with
| DoesNotExpand => DoesNotExpand
| Expands d1 ty_elt' delta =>
let ty_list := HTyp.List ty_elt in
match ana_expand_skel fuel ctx delta skel2 seq ty_list with
| DoesNotExpand => DoesNotExpand
| Expands d2 (HTyp.List ty_elt'') delta =>
match HTyp.join ty_elt' ty_elt'' with
| None => DoesNotExpand
| Some ty_elt =>
let ty := HTyp.List ty_elt in
let d := Cons d1 d2 in
Expands d ty delta
end
| Expands _ _ _ => DoesNotExpand
end
end
end
| Skel.BinOp _ UHExp.Plus _ _
| Skel.BinOp _ UHExp.Times _ _
| Skel.BinOp _ UHExp.LessThan _ _
| Skel.BinOp _ UHExp.Space _ _ =>
match syn_expand_skel fuel ctx delta skel seq with
| DoesNotExpand => DoesNotExpand
| Expands d ty' delta =>
if HTyp.consistent ty ty' then
Expands d ty' delta
else DoesNotExpand
end
end
end.
Module HoleInstance.
Definition t : Type := MetaVar.t * inst_num.
End HoleInstance.
Module InstancePath.
Definition t : Type := list(HoleInstance.t * Var.t).
End InstancePath.
Module HoleInstanceInfo.
Definition t : Type := MetaVarMap.t (list (Environment.t * InstancePath.t)).
Definition empty : t := MetaVarMap.empty.
Definition next (hii : t) (u : MetaVar.t) (sigma : Environment.t) (path : InstancePath.t) : nat * t :=
let (envs, hii) :=
MetaVarMap.insert_or_map hii u (fun _ => (cons (sigma, path) nil)) (
fun envs =>
cons (sigma, path) envs
) in
((List.length envs) - 1, hii).
Definition update_environment (hii : t) (inst : HoleInstance.t) (sigma : Environment.t) : t :=
let (u, i) := inst in
let (_, hii) := MetaVarMap.update_with
(
fun instances =>
let length := List.length instances in
Util.update_nth (length - i - 1) instances
(fun (inst_info : Environment.t * InstancePath.t) =>
let (_, path) := inst_info in
(sigma, path)
)
)
u hii nil in
hii.
Definition num_instances (hii : t) (u : MetaVar.t) :=
match MetaVarMap.lookup hii u with
| Some envs => List.length envs
| None => 0
end.
Definition default_instance (hii : t) (u : MetaVar.t) :=
match MetaVarMap.lookup hii u with
| Some envs =>
match envs with
| nil => None
| cons _ _ => Some (u, 0)
end
| None => None
end.
Definition lookup (hii : t) (inst : HoleInstance.t) :=
let (u, i) := inst in
match MetaVarMap.lookup hii u with
| Some envs =>
let length := List.length envs in
List.nth_error envs (length - i - 1)
| None => None
end.
End HoleInstanceInfo.
Fixpoint renumber_result_only_pat
(path : InstancePath.t)
(hii : HoleInstanceInfo.t)
(dp : DHPat.t)
: (DHPat.t * HoleInstanceInfo.t) :=
match dp with
| DHPat.Wild
| DHPat.Var _
| DHPat.NumLit _
| DHPat.BoolLit _
| DHPat.ListNil
| DHPat.Triv => (dp, hii)
| DHPat.EmptyHole u _ =>
(* TODO: Pattern holes don't need environments. Maybe this calls
* for a refactoring of types to reflect this, e.g., a separate
* PatHoleInstance type. Passing in an empty environment for now. *)
let sigma := Environment.empty in
let (i, hii) := HoleInstanceInfo.next hii u sigma path in
(DHPat.EmptyHole u i, hii)
| DHPat.NonEmptyHole reason u _ dp1 =>
(* TODO: see above *)
let sigma := Environment.empty in
let (i, hii) := HoleInstanceInfo.next hii u sigma path in
let (dp1, hii) := renumber_result_only_pat path hii dp1 in
(DHPat.NonEmptyHole reason u i dp1, hii)
| DHPat.Inj side dp1 =>
let (dp1, hii) := renumber_result_only_pat path hii dp1 in
(DHPat.Inj side dp1, hii)
| DHPat.Pair dp1 dp2 =>
let (dp1, hii) := renumber_result_only_pat path hii dp1 in
let (dp2, hii) := renumber_result_only_pat path hii dp2 in
(DHPat.Pair dp1 dp2, hii)
| DHPat.Cons dp1 dp2 =>
let (dp1, hii) := renumber_result_only_pat path hii dp1 in
let (dp2, hii) := renumber_result_only_pat path hii dp2 in
(DHPat.Cons dp1 dp2, hii)
| DHPat.Ap dp1 dp2 =>
let (dp1, hii) := renumber_result_only_pat path hii dp1 in
let (dp2, hii) := renumber_result_only_pat path hii dp2 in
(DHPat.Pair dp1 dp2, hii)
end.
Fixpoint renumber_result_only
(fuel : Fuel.t)
(path : InstancePath.t) (hii : HoleInstanceInfo.t) (d : DHExp.t)
: (DHExp.t * HoleInstanceInfo.t) :=
match fuel with
| Fuel.Kicked => (d, hii)
| Fuel.More fuel => let renumber_result_only := renumber_result_only fuel in
match d with
| BoundVar _
| BoolLit _
| NumLit _
| ListNil
| Triv => (d, hii)
| Let x d1 d2 =>
let (d1, hii) := renumber_result_only path hii d1 in
let (d2, hii) := renumber_result_only path hii d2 in
(Let x d1 d2, hii)
| FixF x ty d1 =>
let (d1, hii) := renumber_result_only path hii d1 in
(FixF x ty d1, hii)
| Lam x ty d1 =>
let (d1, hii) := renumber_result_only path hii d1 in
(Lam x ty d1, hii)
| Ap d1 d2 =>
let (d1, hii) := renumber_result_only path hii d1 in
let (d2, hii) := renumber_result_only path hii d2 in
(Ap d1 d2, hii)
| BinNumOp op d1 d2 =>
let (d1, hii) := renumber_result_only path hii d1 in
let (d2, hii) := renumber_result_only path hii d2 in
(BinNumOp op d1 d2, hii)
| Inj ty side d1 =>
let (d1, hii) := renumber_result_only path hii d1 in
(Inj ty side d1, hii)
| Pair d1 d2 =>
let (d1, hii) := renumber_result_only path hii d1 in
let (d2, hii) := renumber_result_only path hii d2 in
(Pair d1 d2, hii)
| Cons d1 d2 =>
let (d1, hii) := renumber_result_only path hii d1 in
let (d2, hii) := renumber_result_only path hii d2 in
(Cons d1 d2, hii)
| Case d1 rules n =>
let (d1, hii) := renumber_result_only path hii d1 in
let (drules, hii) := renumber_result_only_rules fuel path hii rules in
(Case d1 drules n, hii)
| EmptyHole u _ sigma =>
let (i, hii) := HoleInstanceInfo.next hii u sigma path in
(EmptyHole u i sigma, hii)
| NonEmptyHole reason u _ sigma d1 =>
let (i, hii) := HoleInstanceInfo.next hii u sigma path in
let (d1, hii) := renumber_result_only path hii d1 in
(NonEmptyHole reason u i sigma d1, hii)
| FreeVar u _ sigma x =>
let (i, hii) := HoleInstanceInfo.next hii u sigma path in
(FreeVar u i sigma x, hii)
| Cast d1 ty1 ty2 =>
let (d1, hii) := renumber_result_only path hii d1 in
(Cast d1 ty1 ty2, hii)
| FailedCast d1 ty1 ty2 =>
let (d1, hii) := renumber_result_only path hii d1 in
(FailedCast d1 ty1 ty2, hii)
end
end
with renumber_result_only_rules
(fuel : Fuel.t)
(path : InstancePath.t)
(hii : HoleInstanceInfo.t)
(rules : list(rule))
: (list(rule) * HoleInstanceInfo.t) :=
match fuel with
| Fuel.Kicked => (rules, hii)
| Fuel.More fuel =>
List.fold_left (fun (b : list(rule) * HoleInstanceInfo.t) r =>
let (rs, hii) := b in
match r with
| Rule dp d =>
let (dp, hii) := renumber_result_only_pat path hii dp in
let (d, hii) := renumber_result_only fuel path hii d in
(rs ++ (cons (Rule dp d) nil), hii)
end) rules (nil, hii)
end.
Fixpoint renumber_sigmas_only (fuel : Fuel.t)
(path : InstancePath.t) (hii : HoleInstanceInfo.t) (d : DHExp.t)
: (DHExp.t * HoleInstanceInfo.t) :=
match fuel with
| Fuel.Kicked => (d, hii)
| Fuel.More fuel =>
match d with
| BoundVar _
| BoolLit _
| NumLit _
| ListNil
| Triv => (d, hii)
| Let x d1 d2 =>
let (d1, hii) := renumber_sigmas_only fuel path hii d1 in
let (d2, hii) := renumber_sigmas_only fuel path hii d2 in
(Let x d1 d2, hii)
| FixF x ty d1 =>
let (d1, hii) := renumber_sigmas_only fuel path hii d1 in
(FixF x ty d1, hii)
| Lam x ty d1 =>
let (d1, hii) := renumber_sigmas_only fuel path hii d1 in
(Lam x ty d1, hii)
| Ap d1 d2 =>
let (d1, hii) := renumber_sigmas_only fuel path hii d1 in
let (d2, hii) := renumber_sigmas_only fuel path hii d2 in
(Ap d1 d2, hii)
| BinNumOp op d1 d2 =>
let (d1, hii) := renumber_sigmas_only fuel path hii d1 in
let (d2, hii) := renumber_sigmas_only fuel path hii d2 in
(BinNumOp op d1 d2, hii)
| Inj ty side d1 =>
let (d1, hii) := renumber_sigmas_only fuel path hii d1 in
(Inj ty side d1, hii)
| Pair d1 d2 =>
let (d1, hii) := renumber_sigmas_only fuel path hii d1 in
let (d2, hii) := renumber_sigmas_only fuel path hii d2 in
(Pair d1 d2, hii)
| Cons d1 d2 =>
let (d1, hii) := renumber_sigmas_only fuel path hii d1 in
let (d2, hii) := renumber_sigmas_only fuel path hii d2 in
(Cons d1 d2, hii)
| Case d1 rules n =>
let (d1, hii) := renumber_sigmas_only fuel path hii d1 in
let (rules, hii) := renumber_sigmas_only_rules fuel path hii rules in
(Case d1 rules n, hii)
| EmptyHole u i sigma =>
let (sigma, hii) := renumber_sigma fuel path u i hii sigma in
let hii := HoleInstanceInfo.update_environment hii (u, i) sigma in
(EmptyHole u i sigma, hii)
| NonEmptyHole reason u i sigma d1 =>
let (sigma, hii) := renumber_sigma fuel path u i hii sigma in
let hii := HoleInstanceInfo.update_environment hii (u, i) sigma in
let (d1, hii) := renumber_sigmas_only fuel path hii d1 in
(NonEmptyHole reason u i sigma d1, hii)
| FreeVar u i sigma x =>
let (sigma, hii) := renumber_sigma fuel path u i hii sigma in
let hii := HoleInstanceInfo.update_environment hii (u, i) sigma in
(FreeVar u i sigma x, hii)
| Cast d1 ty1 ty2 =>
let (d1, hii) := renumber_sigmas_only fuel path hii d1 in
(Cast d1 ty1 ty2, hii)
| FailedCast d1 ty1 ty2 =>
let (d1, hii) := renumber_sigmas_only fuel path hii d1 in
(FailedCast d1 ty1 ty2, hii)
end
end
with renumber_sigmas_only_rules
(fuel : Fuel.t)
(path : InstancePath.t)
(hii : HoleInstanceInfo.t)
(rules : list(rule))
: (list(rule) * HoleInstanceInfo.t) :=
match fuel with
| Fuel.Kicked => (rules, hii)
| Fuel.More fuel =>
List.fold_left (fun (b : list(rule) * HoleInstanceInfo.t) r =>
let (rs, hii) := b in
match r with
| Rule dp d =>
(* pattern holes don't have environments *)
let (d, hii) := renumber_sigmas_only fuel path hii d in
(rs ++ (cons (Rule dp d) nil), hii)
end) rules (nil, hii)
end
with renumber_sigma (fuel : Fuel.t)
(path : InstancePath.t) (u : MetaVar.t) (i : inst_num)
(hii : HoleInstanceInfo.t) (sigma : DHExp.Environment.t)
: (DHExp.Environment.t * HoleInstanceInfo.t) :=
match fuel with
| Fuel.Kicked => (sigma, hii)
| Fuel.More fuel =>
let (sigma, hii) := List.fold_right
(fun (xd : Var.t * DHExp.t) (acc : DHExp.Environment.t * HoleInstanceInfo.t) =>
let (x, d) := xd in
let (sigma_in, hii) := acc in
let path := cons (u, i, x) path in
let (d, hii) := renumber_result_only fuel path hii d in
let sigma_out := cons (x, d) sigma_in in
(sigma_out, hii)
)
(nil, hii)
sigma
in
List.fold_right
(fun (xd : Var.t * DHExp.t) (acc : DHExp.Environment.t * HoleInstanceInfo.t) =>
let (x, d) := xd in
let (sigma_in, hii) := acc in
let path := cons (u, i, x) path in
let (d, hii) := renumber_sigmas_only fuel path hii d in
let sigma_out := cons (x, d) sigma_in in
(sigma_out, hii)
)
(nil, hii)
sigma
end.
Fixpoint renumber (fuel : Fuel.t)
(path : InstancePath.t) (hii : HoleInstanceInfo.t) (d : DHExp.t)
: (DHExp.t * HoleInstanceInfo.t) :=
match fuel with
| Fuel.Kicked => (d, hii)
| Fuel.More fuel =>
let (d, hii) := renumber_result_only fuel path hii d in
renumber_sigmas_only fuel path hii d
end.
End DHExp.
Module Evaluator.
Inductive result :=
| InvalidInput : nat -> result (* not well-typed or otherwise invalid *)
| BoxedValue : DHExp.t -> result
| Indet : DHExp.t -> result.
(*
0 = out of fuel
1 = free or invalid variable
2 = ap invalid boxed function val
3 = boxed value not a number literal 2
4 = boxed value not a number literal 1
5 = bad pattern match
6 = Cast BV Hole Ground
*)
Inductive ground_cases :=
| Hole : ground_cases
| Ground : ground_cases
| NotGroundOrHole : HTyp.t -> ground_cases. (* the argument is the corresponding ground type *)
Definition grounded_Arrow := NotGroundOrHole (HTyp.Arrow HTyp.Hole HTyp.Hole).
Definition grounded_Sum := NotGroundOrHole (HTyp.Sum HTyp.Hole HTyp.Hole).
Definition grounded_Prod := NotGroundOrHole (HTyp.Prod HTyp.Hole HTyp.Hole).
Definition grounded_List := NotGroundOrHole (HTyp.List HTyp.Hole).
Definition ground_cases_of ty :=
match ty with
| HTyp.Hole => Hole
| HTyp.Bool
| HTyp.Num
| HTyp.Unit
| HTyp.Arrow HTyp.Hole HTyp.Hole
| HTyp.Sum HTyp.Hole HTyp.Hole
| HTyp.Prod HTyp.Hole HTyp.Hole
| HTyp.List HTyp.Hole => Ground
| HTyp.Arrow _ _ => grounded_Arrow
| HTyp.Sum _ _ => grounded_Sum
| HTyp.Prod _ _ => grounded_Prod
| HTyp.List _ => grounded_List
end.
Definition eval_bin_num_op op n1 n2 :=
match op with
| DHExp.Plus => DHExp.NumLit (n1 + n2)
| DHExp.Times => DHExp.NumLit (n1 * n2)
| DHExp.LessThan => DHExp.BoolLit (Nat.ltb n1 n2)
end.
Fixpoint evaluate
(fuel : Fuel.t)
(d : DHExp.t)
: result :=
match fuel with
| Fuel.Kicked => InvalidInput 0
| Fuel.More(fuel) =>
match d with
| DHExp.BoundVar _ => InvalidInput 1
| DHExp.Let dp d1 d2 =>
match evaluate fuel d1 with
| InvalidInput msg => InvalidInput msg
| BoxedValue d1 | Indet d1 =>
match DHExp.matches fuel dp d1 with
| DHExp.Indet => Indet d
| DHExp.DoesNotMatch => Indet d
| DHExp.Matches env => evaluate fuel (DHExp.subst fuel env d2)
end
end
| DHExp.FixF x ty d1 =>
evaluate fuel (DHExp.subst_var fuel d x d1)
| DHExp.Lam _ _ _ =>
BoxedValue d
| DHExp.Ap d1 d2 =>
match evaluate fuel d1 with
| InvalidInput msg => InvalidInput msg
| BoxedValue ((DHExp.Lam dp tau d3) as d1) =>
match evaluate fuel d2 with
| InvalidInput msg => InvalidInput msg
| BoxedValue d2 | Indet d2 =>
match DHExp.matches fuel dp d2 with
| DHExp.DoesNotMatch => Indet d
| DHExp.Indet => Indet d
| DHExp.Matches env =>
(* beta rule *)
evaluate fuel (DHExp.subst fuel env d3)
end
end
| BoxedValue (DHExp.Cast d1' (HTyp.Arrow ty1 ty2) (HTyp.Arrow ty1' ty2'))
| Indet (DHExp.Cast d1' (HTyp.Arrow ty1 ty2) (HTyp.Arrow ty1' ty2')) =>
match evaluate fuel d2 with
| InvalidInput msg => InvalidInput msg
| BoxedValue d2' | Indet d2' =>
(* ap cast rule *)
evaluate fuel
(DHExp.Cast
(DHExp.Ap
d1'
(DHExp.Cast
d2' ty1' ty1))
ty2 ty2')
end
| BoxedValue _ => InvalidInput 2
| Indet d1' =>
match evaluate fuel d2 with
| InvalidInput msg => InvalidInput msg
| BoxedValue d2' | Indet d2' =>
Indet (DHExp.Ap d1' d2')
end
end
| DHExp.ListNil
| DHExp.BoolLit _
| DHExp.NumLit _
| DHExp.Triv => BoxedValue d
| DHExp.BinNumOp op d1 d2 =>
match evaluate fuel d1 with
| InvalidInput msg => InvalidInput msg
| BoxedValue (DHExp.NumLit n1 as d1') =>
match evaluate fuel d2 with
| InvalidInput msg => InvalidInput msg
| BoxedValue (DHExp.NumLit n2) =>
BoxedValue (eval_bin_num_op op n1 n2)
| BoxedValue _ => InvalidInput 3
| Indet d2' =>
Indet (DHExp.BinNumOp op d1' d2')
end
| BoxedValue _ => InvalidInput 4
| Indet d1' =>
match evaluate fuel d2 with
| InvalidInput msg => InvalidInput msg
| BoxedValue d2' | Indet d2' =>
Indet (DHExp.BinNumOp op d1' d2')
end
end
| DHExp.Inj ty side d1 =>
match evaluate fuel d1 with
| InvalidInput msg => InvalidInput msg
| BoxedValue d1' => BoxedValue (DHExp.Inj ty side d1')
| Indet d1' => Indet (DHExp.Inj ty side d1')
end
| DHExp.Pair d1 d2 =>
match (evaluate fuel d1,
evaluate fuel d2) with
| (InvalidInput msg, _)
| (_, InvalidInput msg) => InvalidInput msg
| (Indet d1, Indet d2)
| (Indet d1, BoxedValue d2)
| (BoxedValue d1, Indet d2) => Indet (DHExp.Pair d1 d2)
| (BoxedValue d1, BoxedValue d2) => BoxedValue (DHExp.Pair d1 d2)
end
| DHExp.Cons d1 d2 =>
match (evaluate fuel d1,
evaluate fuel d2) with
| (InvalidInput msg, _)
| (_, InvalidInput msg) => InvalidInput msg
| (Indet d1, Indet d2)
| (Indet d1, BoxedValue d2)
| (BoxedValue d1, Indet d2) => Indet (DHExp.Cons d1 d2)
| (BoxedValue d1, BoxedValue d2) => BoxedValue (DHExp.Cons d1 d2)
end
| DHExp.Case d1 rules n => evaluate_case fuel d1 rules n
| DHExp.EmptyHole u i sigma =>
Indet d
| DHExp.NonEmptyHole reason u i sigma d1 =>
match evaluate fuel d1 with
| InvalidInput msg => InvalidInput msg
| BoxedValue d1' | Indet d1' =>
Indet (DHExp.NonEmptyHole reason u i sigma d1')
end
| DHExp.FreeVar u i sigma x =>
Indet d
| DHExp.Cast d1 ty ty' =>
match evaluate fuel d1 with
| InvalidInput msg => InvalidInput msg
| (BoxedValue d1' as result) =>
match (ground_cases_of ty, ground_cases_of ty') with
| (Hole, Hole) => result
| (Ground, Ground) =>
(* if two types are ground and consistent, then they are eq *)
result
| (Ground, Hole) =>
(* can't remove the cast or do anything else here, so we're done *)
BoxedValue (DHExp.Cast d1' ty ty')
| (Hole, Ground) =>
(* by canonical forms, d1' must be of the form d<ty'' => ?> *)
match d1' with
| DHExp.Cast d1'' ty'' HTyp.Hole =>
if HTyp.eq ty'' ty' then BoxedValue d1''
else Indet (DHExp.FailedCast d1' ty ty')
| _ => InvalidInput 6
end
| (Hole, NotGroundOrHole ty'_grounded) =>
(* ITExpand rule *)
let d' :=
DHExp.Cast
(DHExp.Cast d1' ty ty'_grounded)
ty'_grounded ty' in
evaluate fuel d'
| (NotGroundOrHole ty_grounded, Hole) =>
(* ITGround rule *)
let d' :=
DHExp.Cast
(DHExp.Cast d1' ty ty_grounded)
ty_grounded ty' in
evaluate fuel d'
| (Ground, NotGroundOrHole _)
| (NotGroundOrHole _, Ground) =>
(* can't do anything when casting between diseq, non-hole types *)
BoxedValue (DHExp.Cast d1' ty ty')
| (NotGroundOrHole _, NotGroundOrHole _) =>
(* they might be eq in this case, so remove cast if so *)
if HTyp.eq ty ty' then result
else BoxedValue (DHExp.Cast d1' ty ty')
end
| (Indet d1' as result) =>
match (ground_cases_of ty, ground_cases_of ty') with
| (Hole, Hole) => result
| (Ground, Ground) =>
(* if two types are ground and consistent, then they are eq *)
result
| (Ground, Hole) =>
(* can't remove the cast or do anything else here, so we're done *)
Indet (DHExp.Cast d1' ty ty')
| (Hole, Ground) =>
match d1' with
| DHExp.Cast d1'' ty'' HTyp.Hole =>
if HTyp.eq ty'' ty' then Indet d1''
else Indet (DHExp.FailedCast d1' ty ty')
| _ =>
Indet (DHExp.Cast d1' ty ty')
end
| (Hole, NotGroundOrHole ty'_grounded) =>
(* ITExpand rule *)
let d' :=
DHExp.Cast
(DHExp.Cast d1' ty ty'_grounded)
ty'_grounded ty' in
evaluate fuel d'
| (NotGroundOrHole ty_grounded, Hole) =>
(* ITGround rule *)
let d' :=
DHExp.Cast
(DHExp.Cast d1' ty ty_grounded)
ty_grounded ty' in
evaluate fuel d'
| (Ground, NotGroundOrHole _)
| (NotGroundOrHole _, Ground) =>
(* can't do anything when casting between diseq, non-hole types *)
Indet (DHExp.Cast d1' ty ty')
| (NotGroundOrHole _, NotGroundOrHole _) =>
(* it might be eq in this case, so remove cast if so *)
if HTyp.eq ty ty' then result else Indet (DHExp.Cast d1' ty ty')
end
end
| DHExp.FailedCast d1 ty ty' =>
match evaluate fuel d1 with
| InvalidInput msg => InvalidInput msg
| BoxedValue d1' | Indet d1' =>
Indet (DHExp.FailedCast d1' ty ty')
end
end
end
with evaluate_case
(fuel : Fuel.t)
(scrut : DHExp.t)
(rules : list(DHExp.rule))
(current_rule_index : nat)
: result :=
match fuel with
| Fuel.Kicked => InvalidInput 0
| Fuel.More fuel =>
match evaluate fuel scrut with
| InvalidInput msg => InvalidInput msg
| BoxedValue scrut | Indet scrut =>
match List.nth_error rules current_rule_index with
| None => Indet (DHExp.Case scrut rules current_rule_index)
| Some (DHExp.Rule dp d) =>
match DHExp.matches fuel dp scrut with
| DHExp.Indet => Indet (DHExp.Case scrut rules current_rule_index)
| DHExp.Matches env => evaluate fuel (DHExp.subst fuel env d)
| DHExp.DoesNotMatch => evaluate_case fuel scrut rules (current_rule_index+1)
end
end
end
end.
End Evaluator.
End FDynamics.
End FCore.
Extract Constant Util.str_eqb => "String.equal".
Extract Constant Coq.Strings.String.append => "(^)".
Extract Inductive Coq.Strings.String.string => "string"
["""""" "(fun (c, s) -> (String.make 1 c) ^ s)"]
"(fun fES fS s -> if s="""" then fES () else fS s.[0] (String.sub s 1 (String.length s - 1)))".
(* TODO: stolen from Coq.extraction.ExtrOcamlString, but I don't know how to import only
some of the `Extract` clauses in that library without importing others, so for now I'm
copy-pasting
*)
Extract Inductive Coq.Strings.Ascii.ascii => "char"
[
"(fun (b0,b1,b2,b3,b4,b5,b6,b7) -> let f b i = if b then 1 lsl i else 0 in Char.chr (f b0 0 + f b1 1 + f b2 2 + f b3 3 + f b4 4 + f b5 5 + f b6 6 + f b7 7))"
]
"(fun f c -> let n = Char.code c in let h i = (n land (1 lsl i)) <> 0 in f (h 0) (h 1) (h 2) (h 3) (h 4) (h 5) (h 6) (h 7))".
Extract Inductive Fuel.t => "unit" [ "()" "()" ] "(fun fMore _ fKicked -> fMore ())".
Extract Inductive bool => "bool" ["true" "false"].
Extract Inductive unit => "unit" ["()"].
Extract Constant negb => "not".
Extract Constant Coq.Arith.PeanoNat.Nat.eqb => "(=)".
Extract Constant Coq.Lists.List.map => "List.map".
Extract Inductive option => "option" ["Some" "None"].
Extract Inductive prod => "( * )" ["(,)"].
Extract Inductive list => "list" [ "[]" "(::)" ].
Extract Inductive nat => int [ "0" "((+) 1)" ]
"(fun fO fS n -> if n=0 then fO () else fS (n-1))".
Extract Constant plus => "(+)".
Extract Constant mult => "( * )".
Extract Constant Nat.eqb => "(=)".
Extract Constant Nat.leb => "(<=)".
Extract Constant Nat.ltb => "(<)".
Extraction FCore.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment