From Coq Require Import Ascii. From mininix Require Export utils. From stdpp Require Import options. Module Import evallang. Inductive expr := | EString (s : string) | EId (ds : option expr) (x : string) | EEval (ds : gmap string expr) (ee : expr) | EAbs (ex e : expr) | EApp (e1 e2 : expr). Module parser. Inductive token := | TId (s : string) | TString (s : string) | TColon | TExclamation | TParenL | TParenR. Inductive token_state := TSString (s : string) | TSId (s : string) | TSOther. Definition token_state_push (st : token_state) (k : list token) : list token := match st with | TSId s => TId (String.rev s) :: k | _ => k end. Fixpoint tokenize_go (sin : string) (st : token_state) (k : list token) : option (list token) := match sin, st with | "", TSString _ => None (* no closing "" *) | "", _ => Some (reverse (token_state_push st k)) | String "\" (String """" sin), TSString s => tokenize_go sin (TSString (String """" s)) k | String """" sin, TSString s => tokenize_go sin TSOther (TString (String.rev s) :: k) | String a sin, TSString s => tokenize_go sin (TSString (String a s)) k | String ":" sin, _ => tokenize_go sin TSOther (TColon :: token_state_push st k) | String "!" sin, _ => tokenize_go sin TSOther (TExclamation :: token_state_push st k) | String "(" sin, _ => tokenize_go sin TSOther (TParenL :: token_state_push st k) | String ")" sin, _ => tokenize_go sin TSOther (TParenR :: token_state_push st k) | String """" sin, _ => tokenize_go sin (TSString "") k | String a sin, TSOther => if Ascii.is_space a then tokenize_go sin TSOther k else tokenize_go sin (TSId (String a EmptyString)) k | String a sin, TSId s => if Ascii.is_space a then tokenize_go sin TSOther (TId (String.rev s) :: k) else tokenize_go sin (TSId (String a s)) k end. Definition tokenize (sin : string) : option (list token) := tokenize_go sin TSOther []. Inductive stack_item := | SExpr (e : expr) | SAbsR (e : expr) | SEval | SParenL. Definition stack_push (e : expr) (k : list stack_item) : list stack_item := match k with | SExpr e1 :: k => SExpr (EApp e1 e) :: k | SEval :: k => SExpr (EEval ∅ e) :: k | _ => SExpr e :: k end. Fixpoint stack_pop_go (e : expr) (k : list stack_item) : option (expr * list stack_item) := match k with | SAbsR e1 :: k => stack_pop_go (EAbs e1 e) k | _ => Some (e, k) end. Definition stack_pop (k : list stack_item) : option (expr * list stack_item) := match k with | SExpr e :: k => stack_pop_go e k | _ => None end. Fixpoint parse_go (ts : list token) (k : list stack_item) : option expr := match ts with | [] => '(e, k) ← stack_pop k; guard (k = []);; Some e | TString x :: ts => parse_go ts (stack_push (EString x) k) | TId "eval" :: TExclamation :: ts => parse_go ts (SEval :: k) | TId x :: TColon :: ts => parse_go ts (SAbsR (EString x) :: k) | TId x :: ts => parse_go ts (stack_push (EId None x) k) | TColon :: ts => '(e, k) ← stack_pop k; parse_go ts (SAbsR e :: k) | TParenL :: ts => parse_go ts (SParenL :: k) | TParenR :: ts => '(e, k) ← stack_pop k; match k with | SParenL :: k => parse_go ts (stack_push e k) | _ => None end | _ => None end. Definition parse (sin : string) : option expr := ts ← tokenize sin; parse_go ts []. End parser. Definition parse := parser.parse. Fixpoint subst (ds : gmap string expr) (e : expr) : expr := match e with | EString s => EString s | EId ds' x => EId (ds !! x ∪ ds') x | EEval ds' ee => EEval (ds ∪ ds') (subst ds ee) | EAbs ex e => EAbs (subst ds ex) (subst ds e) | EApp e1 e2 => EApp (subst ds e1) (subst ds e2) end. Reserved Infix "-->" (right associativity, at level 55). Inductive step : expr → expr → Prop := | Sβ x e1 e2 : EApp (EAbs (EString x) e1) e2 --> subst {[x:=e2]} e1 | SId e x : EId (Some e) x --> e | SEvalString ds s e : parse s = Some e → EEval ds (EString s) --> subst ds e | SAbsL ex1 ex1' e : ex1 --> ex1' → EAbs ex1 e --> EAbs ex1' e | SAppL e1 e1' e2 : e1 --> e1' → EApp e1 e2 --> EApp e1' e2 | SEval ds e1 e1' : e1 --> e1' → EEval ds e1 --> EEval ds e1' where "e1 --> e2" := (step e1 e2). Infix "-->*" := (rtc step) (right associativity, at level 55). Definition final (e : expr) : Prop := match e with | EString _ => True | EAbs (EString _) _ => True | _ => False end. Definition stuck (e : expr) : Prop := nf step e ∧ ¬final e. End evallang.