diff --git a/proofmode/intro_patterns.v b/proofmode/intro_patterns.v index 2b6c74c65e92a2968f0e5ce842ac037b656b0f2d..6595977c93d8767e440f14281550a01f2e9f526e 100644 --- a/proofmode/intro_patterns.v +++ b/proofmode/intro_patterns.v @@ -11,6 +11,8 @@ Inductive intro_pat := | ISimpl : intro_pat | IAlways : intro_pat | INext : intro_pat + | IForall : intro_pat + | IAll : intro_pat | IClear : list string → intro_pat. Module intro_pat. @@ -31,7 +33,9 @@ Inductive token := | TAlways : token | TNext : token | TClearL : token - | TClearR : token. + | TClearR : token + | TForall : token + | TAll : token. Fixpoint cons_name (kn : string) (k : list token) : list token := match kn with "" => k | _ => TName (string_rev kn) :: k end. @@ -55,6 +59,8 @@ Fixpoint tokenize_go (s : string) (k : list token) (kn : string) : list token := | String "{" s => tokenize_go s (TClearL :: cons_name kn k) "" | String "}" s => tokenize_go s (TClearR :: cons_name kn k) "" | String "/" (String "=" s) => tokenize_go s (TSimpl :: cons_name kn k) "" + | String "*" (String "*" s) => tokenize_go s (TAll :: cons_name kn k) "" + | String "*" s => tokenize_go s (TForall :: cons_name kn k) "" | String a s => tokenize_go s k (String a kn) end. Definition tokenize (s : string) : list token := tokenize_go s [] "". @@ -127,6 +133,8 @@ Fixpoint parse_go (ts : list token) (k : stack) : option stack := | TSimpl :: ts => parse_go ts (SPat ISimpl :: k) | TAlways :: ts => parse_go ts (SPat IAlways :: k) | TNext :: ts => parse_go ts (SPat INext :: k) + | TAll :: ts => parse_go ts (SPat IAll :: k) + | TForall :: ts => parse_go ts (SPat IForall :: k) | TClearL :: ts => parse_go ts (SClear :: k) | TClearR :: ts => close_clear k [] ≫= parse_go ts end. diff --git a/proofmode/tactics.v b/proofmode/tactics.v index ab409612e4cf1a360688d26b86ebdb3ed2495c14..3760f11efb117cdcf8b2d68ac8632e8cde0e1513 100644 --- a/proofmode/tactics.v +++ b/proofmode/tactics.v @@ -558,10 +558,25 @@ Local Tactic Notation "iIntro" "#" constr(H) := first |env_cbv; reflexivity || fail 1 "iIntro:" H "not fresh"|] | fail 1 "iIntro: nothing to introduce" ]. +Local Tactic Notation "iIntroForall" := + lazymatch goal with + | |- ∀ _, ?P => fail + | |- ∀ _, _ => intro + | |- _ ⊢ (∀ _, _) => iIntro {?} + end. +Local Tactic Notation "iIntro" := + lazymatch goal with + | |- _ → ?P => intro + | |- _ ⊢ (_ -★ _) => iIntro {?} || let H := iFresh in iIntro #H || iIntro H + | |- _ ⊢ (_ → _) => iIntro {?} || let H := iFresh in iIntro #H || iIntro H + end. + Tactic Notation "iIntros" constr(pat) := let rec go pats := lazymatch pats with | [] => idtac + | IForall :: ?pats => repeat iIntroForall; go pats + | IAll :: ?pats => repeat (iIntroForall || iIntro); go pats | ISimpl :: ?pats => simpl; go pats | IAlways :: ?pats => iAlways; go pats | INext :: ?pats => iNext; go pats @@ -578,6 +593,7 @@ Tactic Notation "iIntros" constr(pat) := | _ => fail "iIntro: failed with" pats end in let pats := intro_pat.parse pat in try iProof; go pats. +Tactic Notation "iIntros" := iIntros "**". Tactic Notation "iIntros" "{" simple_intropattern(x1) "}" := try iProof; iIntro { x1 }. diff --git a/tests/proofmode.v b/tests/proofmode.v index 3e86f48768f8ebae945807cb8383b792e403de64..b5e863c38821c2af64307339865001332c549afe 100644 --- a/tests/proofmode.v +++ b/tests/proofmode.v @@ -60,7 +60,7 @@ Definition foo {M} (P : uPred M) := (P → P)%I. Definition bar {M} : uPred M := (∀ P, foo P)%I. Lemma demo_4 (M : cmraT) : True ⊢ @bar M. -Proof. iIntros {P} "HP". done. Qed. +Proof. iIntros. iIntros {P} "HP". done. Qed. Lemma demo_5 (M : cmraT) (x y : M) (P : uPred M) : (∀ z, P → z ≡ y) ⊢ (P -★ (x,x) ≡ (y,x)). @@ -71,3 +71,10 @@ Proof. iApply uPred.eq_refl. Qed. +Lemma demo_6 (M : cmraT) (P Q : uPred M) : + True ⊢ (∀ x y z, x = 0 → y = 0 → z = 0 → P → □ Q → foo False). +Proof. + iIntros {a} "*". + iIntros "#Hfoo **". + by iIntros "%". +Qed.