1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
open Mo_def
open Syntax
open Source

type visitor =
  { visit_exp : exp -> exp;
    visit_typ : typ -> typ;
    visit_pat : pat -> pat;
    visit_dec : dec -> dec;
    visit_inst : inst -> inst;
  }

let rec over_exp (v : visitor) (exp : exp) : exp =
  v.visit_exp (match exp.it with
  | HoleE (s, e) -> { exp with it = HoleE (s, ref (over_exp v !e)) }
  | ImportE _ | PrimE _ | VarE _ | LitE _ | ActorUrlE _ -> exp
  | UnE (x, y, exp1) -> { exp with it = UnE (x, y, over_exp v exp1) }
  | ShowE (x, exp1) -> { exp with it = ShowE (x, over_exp v exp1) }
  | ToCandidE exps ->  { exp with it = ToCandidE (List.map (over_exp v) exps) }
  | FromCandidE (exp1) -> { exp with it = FromCandidE (over_exp v exp1) }
  | ProjE (exp1, x) -> { exp with it = ProjE (over_exp v exp1, x) }
  | OptE exp1 -> { exp with it = OptE (over_exp v exp1) }
  | DoOptE exp1 -> { exp with it = DoOptE (over_exp v exp1) }
  | BangE exp1 -> { exp with it = BangE (over_exp v exp1) }
  | TagE (x, exp1) -> { exp with it = TagE (x, over_exp v exp1) }
  | DotE (exp1, x, n) -> { exp with it = DotE (over_exp v exp1, x, ref (Option.map (over_exp v) !n)) }
  | NotE exp1 -> { exp with it = NotE (over_exp v exp1) }
  | AssertE (how, exp1) -> { exp with it = AssertE (how, over_exp v exp1) }
  | LabelE (x, y, exp1) -> { exp with it = LabelE (x, y, over_exp v exp1) }
  | BreakE (x, exp1) -> { exp with it = BreakE (x, over_exp v exp1) }
  | RetE exp1 -> { exp with it = RetE (over_exp v exp1) }
  | AnnotE (exp1, t) -> { exp with it = AnnotE (over_exp v exp1, over_typ v t) }
  | AsyncE (par, s, tb, exp1) -> { exp with it = AsyncE (Option.map (over_exp v) par, s, tb, over_exp v exp1) }
  | AwaitE (s, exp1) -> { exp with it = AwaitE (s, over_exp v exp1) }
  | ThrowE exp1 -> { exp with it = ThrowE (over_exp v exp1) }
  | BinE (x, exp1, y, exp2) -> { exp with it = BinE (x, over_exp v exp1, y, over_exp v exp2) }
  | IdxE (exp1, exp2) -> { exp with it = IdxE (over_exp v exp1, over_exp v exp2) }
  | RelE (x, exp1, y, exp2) -> { exp with it = RelE (x, over_exp v exp1, y, over_exp v exp2) }
  | AssignE (exp1, exp2) -> { exp with it = AssignE (over_exp v exp1, over_exp v exp2) }
  | CallE (exp_opt, exp1, inst, (s, exp2)) -> { exp with it = CallE (Option.map (over_exp v) exp_opt, over_exp v exp1, over_inst v inst, (s, ref (over_exp v (!exp2)))) }
  | AndE (exp1, exp2) -> { exp with it = AndE (over_exp v exp1, over_exp v exp2) }
  | OrE (exp1, exp2) -> { exp with it = OrE (over_exp v exp1, over_exp v exp2) }
  | ImpliesE (exp1, exp2) -> { exp with it = ImpliesE (over_exp v exp1, over_exp v exp2) }
  | OldE exp1 -> { exp with it = OldE (over_exp v exp1) }
  | WhileE (exp1, exp2) -> { exp with it = WhileE (over_exp v exp1, over_exp v exp2) }
  | LoopE (exp1, exp2_opt) -> { exp with it = LoopE (over_exp v exp1, Option.map (over_exp v) exp2_opt) }
  | ForE (x, exp1, exp2) -> { exp with it = ForE (x, over_exp v exp1, over_exp v exp2) }
  | DebugE exp1 -> { exp with it = DebugE (over_exp v exp1) }
  | TupE exps -> { exp with it = TupE (List.map (over_exp v) exps) }
  | ArrayE (x, exps) -> { exp with it = ArrayE (x, List.map (over_exp v) exps) }
  | BlockE ds -> { exp with it = BlockE (List.map (over_dec v) ds) }
  | ObjBlockE (eo, s, (n, t), dfs) -> { exp with it = ObjBlockE (Option.map (over_exp v) eo, s, (n, Option.map (over_typ v) t), List.map (over_dec_field v) dfs) }
  | ObjE (bases, efs) -> { exp with it = ObjE (List.map (over_exp v) bases, List.map (over_exp_field v) efs) }
  | IfE (exp1, exp2, exp3) -> { exp with it = IfE(over_exp v exp1, over_exp v exp2, over_exp v exp3) }
  | TryE (exp1, cases, exp2) -> { exp with it = TryE (over_exp v exp1, List.map (over_case v) cases, Option.map (over_exp v) exp2) }
  | SwitchE (exp1, cases) -> { exp with it = SwitchE (over_exp v exp1, List.map (over_case v) cases) }
  | FuncE (name, sort_pat, typ_binds, pat, typ_opt, sugar, exp1) -> { exp with it = FuncE (name, sort_pat, typ_binds, over_pat v pat, Option.map (over_typ v) typ_opt, sugar, over_exp v exp1) }
  | IgnoreE exp1 -> { exp with it = IgnoreE (over_exp v exp1)})

and over_typ (v : visitor) (t : typ) : typ = v.visit_typ t
and over_inst (v : visitor) (i : inst) : inst = v.visit_inst i

and over_pat (v : visitor) (p : pat) : pat =
  v.visit_pat (match p.it with
  | WildP | VarP _ | LitP _ | SignP _ -> p
  | TupP ps -> { p with it = TupP (List.map (over_pat v) ps) }
  | ObjP pfs -> { p with it = ObjP (List.map (over_pat_field v) pfs) }
  | OptP p1 -> { p with it = OptP (over_pat v p1) }
  | TagP (x, p1) -> { p with it = TagP (x, over_pat v p1) }
  | AltP (p1, p2) -> { p with it = AltP (over_pat v p1, over_pat v p2) }
  | AnnotP (p1, t) -> { p with it = AnnotP (over_pat v p1, over_typ v t) }
  | ParP p1 -> { p with it = ParP (over_pat v p1) })

and over_dec (v : visitor) (d : dec) : dec =
  v.visit_dec (match d.it with
  | TypD (tid, tbs, t) -> { d with it = TypD (tid, tbs, over_typ v t) }
  | ExpD e -> { d with it = ExpD (over_exp v e)}
  | VarD (x, e) -> { d with it = VarD (x, over_exp v e)}
  | LetD (p, e, fail) -> { d with it = LetD (over_pat v p, over_exp v e, Option.map (over_exp v) fail)}
  | ClassD (eo, sp, s, cid, tbs, p, t_o, id, dfs) -> { d with it = ClassD (Option.map (over_exp v) eo, sp, s, cid, tbs, over_pat v p, Option.map (over_typ v) t_o, id, List.map (over_dec_field v) dfs)}
  | MixinD (p, dfs) -> { d with it = MixinD (over_pat v p, List.map (over_dec_field v) dfs) }
  | IncludeD (i, e, n) -> { d with it = IncludeD (i, over_exp v e, n) })

and over_dec_field (v : visitor) (df : dec_field) : dec_field =
  { df with it = { df.it with dec = over_dec v df.it.dec } }

and over_exp_field (v : visitor) (ef : exp_field) : exp_field =
  { ef with it = { ef.it with exp = over_exp v ef.it.exp } }

and over_pat_field (v : visitor) (pf : pat_field) : pat_field =
  match pf.it with
  | ValPF (id, p) -> { pf with it = ValPF(id, over_pat v p) }
  | TypPF (_) -> pf

and over_case (v : visitor) (case : case) : case =
  { case with it = { pat = over_pat v case.it.pat;
                     exp = over_exp v case.it.exp } }

and over_prog (v : visitor) (prog : prog) : prog =
  { prog with it = List.map (over_dec v) prog.it }