-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathin-global.arc
163 lines (161 loc) · 6.1 KB
/
in-global.arc
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
; in-global.arc
; by AmkG
; Trivial global function inlining
(def in-global (ast)
(with (; internal functions
is-inlineable nil
get-inlineable nil
copy-ast nil
entable-params-args nil
perform-inline nil
; table of global symbols
; for inlining
inlineable (table)
; global symbols which
; we have determined to be unsafe
; for inlining
banned (table))
; determine if the given ast is indeed an inlineable function.
(= is-inlineable
(fn (ast)
(and
; has to be a function or *lam*bda
(alam ast)
(with (params (properify ast!params)
references (table)
check-refs nil)
; make sure that parameters
; are referenced at most once
(= check-refs
(fn (ast)
(if
(and (aref ast) (some ast!var params))
(if (references ast!var)
; if it's been referenced before,
; fail
nil
(= (references ast!var) t))
; assignments to a parameter would be
; too complicated for inlining, so fail...
(and (aset ast) (some ast!var params))
nil
; don't fail quotes
(aquote ast)
t
; else
(all check-refs ast!subx))))
(check-refs ast)))))
; get the set of inlineable functions
(= get-inlineable
(fn ()
(each ast ast!subx
; determine if this ast is an assignment
; to a global
(if (and (aset ast) (aglobal ast!var))
; determine if the global is not already
; in the inlineable set, and if the value
; being assigned to it is inlineable
(if (and (~inlineable ast!var) (is-inlineable (car ast!subx)))
(= (inlineable ast!var) (copy-ast (car ast!subx)))
; be paranoid if the global fails to
; pass
(= (banned ast!var) t))
(each b (gv-set ast)
(= banned.b t))))
(each b (keys banned)
(= inlineable.b nil))))
(= copy-ast
(fn (ast)
(with (subst-copy nil
replacetb (table))
(= subst-copy
(fn (ast)
(if
; for functions, replace
; the variables
(alam ast)
(do
(each v (properify ast!params)
(= replacetb.v (new-var v!id)))
(make-lam
(map subst-copy ast!subx)
(map-improper replacetb ast!params)))
(aref ast)
(make-ref '()
(or (replacetb ast!var) ast!var))
(aset ast)
(make-set (map subst-copy ast!subx)
(or (replacetb ast!var) ast!var))
; else
(let rv (table)
(ontable k v ast
(if (is k 'subx)
(= rv.k (map subst-copy v))
(= rv.k v)))
rv))))
(subst-copy ast))))
(= entable-params-args
(fn (params args)
(let rv (table)
((afn (params args)
(if
(no params)
(when args
(err:tostring
(pr "Inline attempt failed, too many arguments: ")
(write:source args)))
(acons params)
(if args
(with ((param . params) params
(arg . args ) args)
(= rv.param arg)
(self params args))
(err:tostring
(pr "Inline attempt failed, too few arguments: ")
(write:source params)))
; else, a variadic parameter
(= rv.params
((afn (asts)
(if asts
(make-prim
(list (car asts) (self (cdr asts)))
'%cons)
(make-lit '() nil)))
args))))
params args)
rv)))
(= perform-inline
(fn (ast done)
; ast is the AST to process
; done is a list of globals that we are currently
; performing inlining on. We avoid inlining a
; global if we're already inlining it
(let var nil
(aif
(and (anapp ast)
(aref (car ast!subx))
(= var ((car ast!subx) 'var))
(~some var done)
inlineable.var)
; 'it is now the function that we will inline
(with (body (perform-inline (copy-ast (car it!subx))
(cons var done))
args (map [perform-inline _ done] (cdr ast!subx)))
(let paramlookup (entable-params-args it!params args)
((afn (ast)
(aif
(and (aref ast) (paramlookup ast!var))
it
(aquote ast)
ast
(do (= ast!subx (map self ast!subx))
ast)))
body)))
(aquote ast)
ast
(do
(= ast!subx (map [perform-inline _ done] ast!subx))
ast)))))
; two passes: first search, then replace
(get-inlineable)
(perform-inline ast nil)))