1 /*
2
3 Copyright (C) 1991-2003 The National Gallery
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19 */
20
21 /*
22
23 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
24
25 */
26
27 /*
28 #define DEBUG
29 */
30
31 /* Just show secrets we added
32 #define DEBUG_ADD
33 */
34
35 #include "ip.h"
36
37 /* build secret sets for exprs
38
39 cases:
40
41 fred a
42 = jim 12
43 {
44 jim b = a + b;
45 }
46
47 jim refers to a parameter in an enclosing scope ... we add extra secret
48 parameters to jim like this:
49
50 fred a
51 = jim [a] 12
52 {
53 jim [a] b = a + b;
54 }
55
56 across class boundaries:
57
58 fred a
59 = jim
60 {
61 jim = class {
62 b = a;
63 }
64 }
65
66 now fred.jim.b refers to fred.a ... a needs to be added to the secrets on
67 jim's constructor like this:
68
69 fred a
70 = jim [a]
71 {
72 jim [a] = class {
73 b = a;
74 }
75 }
76
77 if the secret is a class member, pass "this" instead and the inner thing then
78 gets from that
79
80 fred a = class
81 {
82 jim [fred.this] b = fred.this.a + b;
83 }
84
85 if the inner thing is also a class, need to get in two stages ... first get
86 the right this, then get from that
87
88 fred a = class
89 {
90 jim [fred.this] = class {
91 b = jim.this.fred.this.a;
92 }
93 }
94
95 need to work for any sort of nesting of functions and classes
96
97 fred = class {
98 b = c
99 {
100 c = this;
101 }
102 }
103
104 not just params ... can involve locals of parents
105
106 */
107
108 /* Add a secret. Set changed if we make a change.
109 */
110 static void *
secret_add(Symbol * secret,Compile * compile,gboolean * changed)111 secret_add( Symbol *secret, Compile *compile, gboolean *changed )
112 {
113 Compile *parent = compile_get_parent( compile );
114
115 #ifdef DEBUG
116 printf( "secret_add: considering secret " );
117 symbol_name_print( secret );
118 printf( "for " );
119 compile_name_print( compile );
120 printf( " ...\n" );
121 #endif /*DEBUG*/
122
123 /* If expr is a class, don't add our own this.
124 */
125 if( is_class( compile ) && secret == compile->this )
126 return( NULL );
127
128 /* If expr already has secret as a param or secret, don't add again.
129 */
130 if( g_slist_find( compile->secret, secret ) ||
131 g_slist_find( compile->param, secret ) )
132 return( NULL );
133
134 /* If secret is a member (param, func, whatever), add secret's
135 * enclosing "this" instead ... expr can then get secret from there.
136 * Unless the secret is already a "this", of course.
137 */
138 if( is_class( COMPILE( ICONTAINER( secret )->parent ) ) &&
139 !is_this( secret ) )
140 secret = COMPILE( ICONTAINER( secret )->parent )->this;
141
142 /* If compile is a member (and not a class itself), add the secret to
143 * compile's constructor instead ... compile can get from "this".
144 */
145 if( is_class( parent ) && secret != parent->this &&
146 !is_class( compile ) )
147 compile = parent;
148
149 /* We may have moved stuff about ... check for dupes again.
150 */
151 if( g_slist_find( compile->secret, secret ) ||
152 g_slist_find( compile->param, secret ) )
153 return( NULL );
154
155 #ifdef DEBUG_ADD
156 printf( "secret_add: adding secret " );
157 symbol_name_print( secret );
158 printf( "to " );
159 compile_name_print( compile );
160 printf( "\n" );
161 #endif /*DEBUG_ADD*/
162
163 compile->secret = g_slist_append( compile->secret, secret );
164 compile->nsecret += 1;
165 *changed = TRUE;
166
167 return( NULL );
168 }
169
170 /* If compile is a member, then secret lists are easy ... just use "this".
171 */
172 static void *
secret_set_class(Compile * compile)173 secret_set_class( Compile *compile )
174 {
175 if( is_class( compile_get_parent( compile ) ) ) {
176 Compile *parent = compile_get_parent( compile );
177 Symbol *ths = parent->this;
178 gboolean changed;
179
180 if( secret_add( ths, compile, &changed ) )
181 return( (void *) ths );
182 }
183
184 return( NULL );
185 }
186
187 /* child is one of compile's children ... is it reference to a parameter
188 * in an enclosing scope? If yes, we've found a secret!
189 */
190 static void *
secret_is_nonlocal(Symbol * child,Compile * compile)191 secret_is_nonlocal( Symbol *child, Compile *compile )
192 {
193 gboolean changed;
194
195 if( child->type == SYM_PARAM &&
196 COMPILE( ICONTAINER( child )->parent ) != compile ) {
197 if( secret_add( child, compile, &changed ) )
198 return( child );
199 }
200
201 return( NULL );
202 }
203
204 /* Make initial secret list ... if this is a member/function, search for
205 * references to symbols in an enclosing scope.
206 */
207 static void *
secret_find_nonlocal(Compile * compile)208 secret_find_nonlocal( Compile *compile )
209 {
210 /* Look for any secrets.
211 */
212 if( slist_map( compile->children,
213 (SListMapFn) secret_is_nonlocal, compile ) )
214 return( compile );
215
216 return( NULL );
217 }
218
219 /* Does child have any secrets that compile does not?
220 */
221 static void *
secret_test(Symbol * child,Compile * compile,gboolean * changed)222 secret_test( Symbol *child, Compile *compile, gboolean *changed )
223 {
224 /* If this is a parameter or a zombie, nothing to do.
225 */
226 if( !is_value( child ) )
227 return( NULL );
228
229 if( child->expr->compile )
230 if( slist_map2( child->expr->compile->secret,
231 (SListMap2Fn) secret_add, compile, changed ) )
232 return( child );
233
234 return( NULL );
235 }
236
237 /* Close secret list ... if sym has a child with a secret sym does not have,
238 * sym needs child's secret too.
239 */
240 static void *
secret_close(Compile * compile,gboolean * changed)241 secret_close( Compile *compile, gboolean *changed )
242 {
243 if( is_class( compile ) ) {
244 /* For classes, need to consider all of their locals. Any
245 * secrets our locals have, we need too.
246 */
247 if( icontainer_map( ICONTAINER( compile ),
248 (icontainer_map_fn) secret_test, compile, changed ) )
249 return( compile );
250 }
251 else {
252 /* Look at our immediate children, any of them have secrets
253 * we don't?
254 */
255 if( slist_map2( compile->children,
256 (SListMap2Fn) secret_test, compile, changed ) )
257 return( compile );
258 }
259
260 return( NULL );
261 }
262
263 #ifdef DEBUG
264 /* Sub-fn of below ... add param as a secret to sym.
265 */
266 static void *
secret_all_add(Compile * compile,Symbol * param)267 secret_all_add( Compile *compile, Symbol *param )
268 {
269 gboolean changed;
270
271 return( secret_add( param, compile, &changed ) );
272 }
273
274 /* Sub-fn of below ... add param as a secret for all of compile's locals.
275 */
276 static void *
secret_all_sym(Symbol * param,Compile * compile)277 secret_all_sym( Symbol *param, Compile *compile )
278 {
279 return( compile_map_all( compile,
280 (map_compile_fn) secret_all_add, param ) );
281 }
282
283 /* Make syms params and secrets secrets for all sub-syms. Only handy for
284 * debugging.
285 */
286 static void *
secret_all(Compile * compile)287 secret_all( Compile *compile )
288 {
289 if( slist_map( compile->param,
290 (SListMapFn) secret_all_sym, compile ) ||
291 slist_map( compile->secret,
292 (SListMapFn) secret_all_sym, compile ) )
293 return( compile );
294
295 return( NULL );
296 }
297 #endif /*DEBUG*/
298
299 /* Make secret param lists for compile and all of it's sub-defs.
300 */
301 void
secret_build(Compile * compile)302 secret_build( Compile *compile )
303 {
304 gboolean changed;
305
306 #ifdef DEBUG_ADD
307 printf( "secret_build: " );
308 symbol_name_print( compile->sym );
309 printf( "\n" );
310 #endif /*DEBUG_ADD*/
311
312 /* Look for class definitions ... all members of a
313 * class should take a single secret, their "this" parameter.
314 * When they in turn call their locals, they can get the
315 * secrets they need from "this".
316 */
317 (void) compile_map_all( compile,
318 (map_compile_fn) secret_set_class, NULL );
319
320 /* Now look for non-member functions ... if they reference
321 * parameters in an enclosing scope, add that parameter to
322 * the secret list.
323 */
324 (void) compile_map_all( compile,
325 (map_compile_fn) secret_find_nonlocal, NULL );
326
327 /* Now take the closure of the secret lists ... have to
328 * fix() this to get limit of secret_close().
329 */
330 do {
331 changed = FALSE;
332 (void) compile_map_all( compile,
333 (map_compile_fn) secret_close, &changed );
334 } while( changed );
335 }
336
337