-
Notifications
You must be signed in to change notification settings - Fork 125
/
pass_LiftDeepRecords.ml
143 lines (129 loc) · 5.79 KB
/
pass_LiftDeepRecords.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
(*
Copyright © 2011 MLstate
This file is part of OPA.
OPA is free software: you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License, version 3, as published by
the Free Software Foundation.
OPA is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
more details.
You should have received a copy of the GNU Affero General Public License
along with OPA. If not, see <http://www.gnu.org/licenses/>.
*)
module List = Base.List
module Q = QmlAst
type env = {
bindings : Q.expr IdentMap.t;
warn_x_field : unit (* just in case, if we want to add a field to this env *)
}
let depth_max = 10
let empty_env () = {
bindings = IdentMap.empty ;
warn_x_field = ()
}
let update_gamma gamma id ty =
let tsc = QmlTypes.Scheme.generalize gamma ty in
QmlTypes.Env.Ident.add id tsc gamma
let add_to_bindings env (id,e) = { env with bindings = IdentMap.add id e env.bindings }
let insert_bindings ~typed (gamma,annotmap) bindings e =
List.fold_right
(fun (id,e) (gamma,annotmap,expr) ->
if typed then
let ty = QmlAnnotMap.find_ty (Q.QAnnot.expr e) annotmap in
let gamma = update_gamma gamma id ty in
let annotmap,expr = QmlAstCons.TypedExpr.letin annotmap [(id,e)] expr in
gamma, annotmap, expr
else
let expr = QmlAstCons.UntypedExpr.letin [(id,e)] expr in
gamma, annotmap, expr
)
bindings
(gamma, annotmap, e)
let traverse_expr ~typed (gamma,annotmap) e =
let rec aux tra depth (gamma, annotmap, env) e =
let depth = succ depth in
match e with
| Q.Record _ ->
let ((gamma, annotmap, env), e) as nothing_to_do = tra depth (gamma, annotmap, env) e in
let (gamma, annotmap, env),e =
(match e with
| Q.Record (label, l) ->
if depth < depth_max then
nothing_to_do
else (* store bindings and make the replacements *)
let fresh () = Ident.next "r" in
let l = List.map (fun (f,e) -> f,fresh (),e) l in
let env = List.fold_left (fun env (_, id, e) -> add_to_bindings env (id,e)) env l in
let (gamma, annotmap), l =
List.fold_left_map
(fun (gamma, annotmap) (f, v, e) ->
let gamma, annotmap, new_expr =
if typed then
let ty = QmlAnnotMap.find_ty (Q.QAnnot.expr e) annotmap in
let gamma = update_gamma gamma v ty in
let annotmap,expr = QmlAstCons.TypedExpr.ident annotmap v ty in
gamma, annotmap, expr
else
let expr = QmlAstCons.UntypedExpr.ident v in
gamma, annotmap, expr
in (gamma, annotmap),(f, new_expr)
)
(gamma, annotmap)
l
in
(gamma, annotmap,env), Q.Record (label, l)
| Q.ExtendRecord (label, f, expr, r) ->
let (_gamma, _annotmap, env_), r = aux tra depth (gamma, annotmap, env) r in
let (gamma, annotmap, env), expr = aux tra depth (gamma, annotmap, env) expr in
let b = env_.bindings in
let env = { env with bindings =
IdentMap.fold (fun id e m -> IdentMap.add id e m) b env.bindings } in
let e = Q.ExtendRecord (label, f, expr, r) in
(gamma, annotmap, env), e
| _ -> tra 0 (gamma, annotmap, env) e)
in
(gamma, annotmap, env), e
| Q.ExtendRecord _ ->
tra depth (gamma, annotmap, env) e
| _ -> tra 0 (gamma, annotmap, env) e
in
let env = empty_env () in
let rec aux2 (gamma, annotmap) e =
match e with
| Q.Record _
| Q.ExtendRecord _ ->
let (gamma, annotmap, env),new_e = QmlAstWalk.Expr.traverse_foldmap_context_down aux 0 (gamma, annotmap, env) e in
let bindings = IdentMap.rev_ordered_list env.bindings in
let (gamma, annotmap, expr) = insert_bindings ~typed (gamma, annotmap) bindings new_e in
(gamma, annotmap), expr
| Q.Lambda (label, l, e) ->
let (gamma, annotmap), new_e = aux2 (gamma, annotmap) e in
let expr = Q.Lambda (label, l,new_e) in
(gamma, annotmap), expr
| Q.LetIn (_, l, e) ->
let l,e = QmlAstUtils.LetIn.uncons l e in
let (gamma, annotmap), new_e = aux2 (gamma, annotmap) e in
let expr = QmlAstUtils.LetIn.cons l new_e in
(gamma, annotmap), expr
| Q.LetRecIn (_, l, e) ->
let l,e = QmlAstUtils.LetRecIn.uncons l e in
let (gamma, annotmap), new_e = aux2 (gamma, annotmap) e in
let expr = QmlAstUtils.LetRecIn.cons l new_e in
(gamma, annotmap), expr
| Q.Match (_, e, p) ->
let if_,pats,exprs = QmlAstUtils.Match.uncons e p in
let (gamma, annotmap), new_e = aux2 (gamma, annotmap) if_ in
let (gamma, annotmap), new_exprs = List.fold_left_map aux2 (gamma, annotmap) exprs in
let expr = QmlAstUtils.Match.cons new_e pats new_exprs in
(gamma, annotmap), expr
| _ ->
let (gamma, annotmap, env), new_e = QmlAstWalk.Expr.traverse_foldmap_context_down aux 0 (gamma, annotmap, env) e in
let bindings = IdentMap.rev_ordered_list env.bindings in
let (gamma, annotmap,expr) = insert_bindings ~typed (gamma, annotmap) bindings new_e in
(gamma, annotmap), expr
in
aux2 (gamma, annotmap) e
let process_code ~typed gamma annotmap code =
let (gamma, annotmap), code = QmlAstWalk.CodeExpr.fold_map (traverse_expr ~typed) (gamma, annotmap) code in
(gamma,annotmap), code