1 /* Build parse trees.
2 */
3
4 /*
5
6 Copyright (C) 1991-2003 The National Gallery
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 */
23
24 /*
25
26 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
27
28 */
29
30 #include "ip.h"
31
32 /* Free any stuff attached to a ParseConst.
33 */
34 void
tree_const_destroy(ParseConst * pc)35 tree_const_destroy( ParseConst *pc )
36 {
37 if( pc->type == PARSE_CONST_STR )
38 IM_FREE( pc->val.str );
39 pc->type = PARSE_CONST_NONE;
40 }
41
42 void
tree_const_copy(ParseConst * from,ParseConst * to)43 tree_const_copy( ParseConst *from, ParseConst *to )
44 {
45 *to = *from;
46 if( to->type == PARSE_CONST_STR && to->val.str )
47 to->val.str = im_strdupn( to->val.str );
48 }
49
50 /* Free a parse node.
51 */
52 void *
tree_node_destroy(ParseNode * n)53 tree_node_destroy( ParseNode *n )
54 {
55 switch( n->type ) {
56 case NODE_PATTERN_CLASS:
57 case NODE_TAG:
58 IM_FREE( n->tag );
59 break;
60
61 case NODE_CONST:
62 tree_const_destroy( &n->con );
63 break;
64
65 case NODE_LISTCONST:
66 case NODE_SUPER:
67 IM_FREEF( g_slist_free, n->elist );
68 break;
69
70 case NODE_APPLY:
71 case NODE_CLASS:
72 case NODE_BINOP:
73 case NODE_UOP:
74 case NODE_LEAF:
75 case NODE_GENERATOR:
76 case NODE_NONE:
77 case NODE_COMPOSE:
78 break;
79
80 default:
81 g_assert( FALSE );
82 }
83
84 IM_FREE( n );
85
86 return( NULL );
87 }
88
89 /* Make an empty parse node.
90 */
91 static ParseNode *
tree_new(Compile * compile)92 tree_new( Compile *compile )
93 {
94 ParseNode *no = INEW( NULL, ParseNode );
95
96 no->compile = compile;
97 no->type = NODE_NONE;
98 no->biop = BI_NONE;
99 no->uop = UN_NONE;
100 no->arg1 = NULL;
101 no->arg2 = NULL;
102 no->arg3 = NULL;
103 no->leaf = NULL;
104 no->klass = NULL;
105 no->elist = NULL;
106 no->tag = NULL;
107 no->con.type = PARSE_CONST_NONE;
108 no->con.val.str = NULL;
109
110 compile->treefrag = g_slist_prepend( compile->treefrag, no );
111
112 return( no );
113 }
114
115 /* Make a binary operator node.
116 */
117 ParseNode *
tree_binop_new(Compile * compile,BinOp op,ParseNode * l,ParseNode * r)118 tree_binop_new( Compile *compile, BinOp op, ParseNode *l, ParseNode *r )
119 {
120 ParseNode *no = tree_new( compile );
121
122 no->type = NODE_BINOP;
123 no->biop = op;
124 no->arg1 = l;
125 no->arg2 = r;
126
127 return( no );
128 }
129
130 /* Make a function compose node.
131 */
132 ParseNode *
tree_compose_new(Compile * compile,ParseNode * f,ParseNode * g)133 tree_compose_new( Compile *compile, ParseNode *f, ParseNode *g )
134 {
135 ParseNode *no = tree_new( compile );
136
137 no->type = NODE_COMPOSE;
138 no->arg1 = f;
139 no->arg2 = g;
140
141 return( no );
142 }
143
144 /* Make a generator node.
145 */
146 ParseNode *
tree_generator_new(Compile * compile,ParseNode * s,ParseNode * n,ParseNode * f)147 tree_generator_new( Compile *compile, ParseNode *s, ParseNode *n, ParseNode *f )
148 {
149 ParseNode *no = tree_new( compile );
150
151 no->type = NODE_GENERATOR;
152 no->arg1 = s;
153 no->arg2 = n;
154 no->arg3 = f;
155
156 return( no );
157 }
158
159 /* Make an IF node.
160 */
161 ParseNode *
tree_ifelse_new(Compile * compile,ParseNode * c,ParseNode * t,ParseNode * e)162 tree_ifelse_new( Compile *compile, ParseNode *c, ParseNode *t, ParseNode *e )
163 {
164 ParseNode *else_node = tree_lconst_new( compile, e );
165 ParseNode *then_node = tree_lconst_extend( compile, else_node, t );
166 ParseNode *if_node = tree_binop_new( compile, BI_IF, c, then_node );
167
168 return( if_node );
169 }
170
171 /* Make a class node.
172 */
173 ParseNode *
tree_class_new(Compile * compile)174 tree_class_new( Compile *compile )
175 {
176 ParseNode *no = tree_new( compile );
177 Symbol *this, *super, *name, *cons;
178
179 g_assert( !compile->is_klass );
180 g_assert( !compile->this );
181 g_assert( !compile->super );
182
183 no->type = NODE_CLASS;
184 no->klass = compile;
185
186 /* Make enclosing into a class.
187 */
188 compile->is_klass = TRUE;
189
190 /* Add builtin syms.
191 */
192 this = symbol_new_defining( compile, MEMBER_THIS );
193 (void) symbol_parameter_builtin_init( this );
194 compile->this = this;
195
196 super = symbol_new_defining( compile, MEMBER_SUPER );
197 (void) symbol_user_init( super );
198 (void) compile_new_local( super->expr );
199 symbol_made( super );
200 compile->super = super;
201
202 name = symbol_new_defining( compile, MEMBER_NAME );
203 (void) symbol_parameter_builtin_init( name );
204
205 cons = symbol_new_defining( compile, IOBJECT( compile->sym )->name );
206 (void) symbol_user_init( cons );
207 (void) compile_new_local( cons->expr );
208 cons->expr->compile->tree = tree_leafsym_new( compile, compile->sym );
209 symbol_made( cons );
210
211 return( no );
212 }
213
214 /* Make a tag node.
215 */
216 ParseNode *
tree_tag_new(Compile * compile,const char * r)217 tree_tag_new( Compile *compile, const char *r )
218 {
219 ParseNode *no = tree_new( compile );
220
221 no->type = NODE_TAG;
222 no->tag = im_strdupn( r );
223
224 return( no );
225 }
226
227 /* Make a unary operator node.
228 */
229 ParseNode *
tree_unop_new(Compile * compile,UnOp op,ParseNode * a)230 tree_unop_new( Compile *compile, UnOp op, ParseNode *a )
231 {
232 ParseNode *no = tree_new( compile );
233
234 no->type = NODE_UOP;
235 no->uop = op;
236 no->arg1 = a;
237
238 return( no );
239 }
240
241 ParseNode *
tree_leaf_new(Compile * compile,const char * name)242 tree_leaf_new( Compile *compile, const char *name )
243 {
244 ParseNode *no = tree_new( compile );
245
246 no->type = NODE_LEAF;
247 no->leaf = symbol_new_reference( compile, name );
248
249 /* Have we a reference to a ZOMBIE? If yes, we may need to patch this
250 * leaf to point to a new symbol. Add the leaf's pointer to the
251 * refedat list on the ZOMBIE.
252 */
253 if( no->leaf->type == SYM_ZOMBIE )
254 (void) symbol_patch_add( (void **) &no->leaf, no->leaf );
255
256 return( no );
257 }
258
259 /* Make a new leaf node ... except we know the final symbol now.
260 */
261 ParseNode *
tree_leafsym_new(Compile * compile,Symbol * sym)262 tree_leafsym_new( Compile *compile, Symbol *sym )
263 {
264 ParseNode *no = tree_new( compile );
265
266 /* Fill fields.
267 */
268 no->type = NODE_LEAF;
269 no->leaf = sym;
270
271 /* Note that this compile refs this sym.
272 */
273 compile_link_make( compile, sym );
274
275 /* Have we a reference to a ZOMBIE? If yes, we may need to patch this
276 * leaf to point to a new symbol. Add the leaf's pointer to the
277 * refedat list on the ZOMBIE.
278 */
279 if( sym->type == SYM_ZOMBIE )
280 (void) symbol_patch_add( (void **) &no->leaf, sym );
281
282 return( no );
283 }
284
285 /* Init a clist.
286 */
287 ParseNode *
tree_lconst_new(Compile * compile,ParseNode * a)288 tree_lconst_new( Compile *compile, ParseNode *a )
289 {
290 ParseNode *no = tree_new( compile );
291
292 /* Fill fields.
293 */
294 no->type = NODE_LISTCONST;
295 no->elist = NULL;
296
297 no->elist = g_slist_prepend( no->elist, a );
298
299 return( no );
300 }
301
302 /* Extend a clist.
303 */
304 ParseNode *
tree_lconst_extend(Compile * compile,ParseNode * base,ParseNode * new)305 tree_lconst_extend( Compile *compile, ParseNode *base, ParseNode *new )
306 {
307 g_assert( base->type == NODE_LISTCONST );
308
309 base->elist = g_slist_prepend( base->elist, new );
310
311 return( base );
312 }
313
314 /* Init a super.
315 */
316 ParseNode *
tree_super_new(Compile * compile)317 tree_super_new( Compile *compile )
318 {
319 ParseNode *no = tree_new( compile );
320
321 no->type = NODE_SUPER;
322
323 return( no );
324 }
325
326 /* Extend a super.
327 */
328 ParseNode *
tree_super_extend(Compile * compile,ParseNode * base,ParseNode * new)329 tree_super_extend( Compile *compile, ParseNode *base, ParseNode *new )
330 {
331 g_assert( base->type == NODE_SUPER );
332
333 base->elist = g_slist_append( base->elist, new );
334
335 return( base );
336 }
337
338 /* Make a new constant node.
339 */
340 ParseNode *
tree_const_new(Compile * compile,ParseConst n)341 tree_const_new( Compile *compile, ParseConst n )
342 {
343 ParseNode *no = tree_new( compile );
344
345 no->type = NODE_CONST;
346 no->con = n;
347
348 return( no );
349 }
350
351 /* Make a new apply node.
352 */
353 ParseNode *
tree_appl_new(Compile * compile,ParseNode * l,ParseNode * r)354 tree_appl_new( Compile *compile, ParseNode *l, ParseNode *r )
355 {
356 ParseNode *no = tree_new( compile );
357
358 no->type = NODE_APPLY;
359 no->arg1 = l;
360 no->arg2 = r;
361
362 return( no );
363 }
364
365 ParseNode *
tree_pattern_class_new(Compile * compile,const char * class_name,ParseNode * l)366 tree_pattern_class_new( Compile *compile, const char *class_name, ParseNode *l )
367 {
368 ParseNode *no = tree_new( compile );
369
370 no->type = NODE_PATTERN_CLASS;
371 no->arg1 = l;
372 no->tag = im_strdupn( class_name );
373
374 return( no );
375 }
376
377 ParseNode *
tree_map(Compile * compile,tree_map_fn fn,ParseNode * node,void * a,void * b)378 tree_map( Compile *compile, tree_map_fn fn, ParseNode *node, void *a, void *b )
379 {
380 ParseNode *result;
381 GSList *l;
382
383 g_assert( node );
384
385 if( (result = fn( compile, node, a, b )) )
386 return( result );
387
388 switch( node->type ) {
389 case NODE_GENERATOR:
390 if( (result = tree_map( compile, fn, node->arg1, a, b )) )
391 return( result );
392 if( node->arg2 &&
393 (result = tree_map( compile, fn, node->arg2, a, b )) )
394 return( result );
395 if( node->arg3 &&
396 (result = tree_map( compile, fn, node->arg3, a, b )) )
397 return( result );
398 break;
399
400 case NODE_APPLY:
401 case NODE_BINOP:
402 case NODE_COMPOSE:
403 if( (result = tree_map( compile, fn, node->arg1, a, b )) ||
404 (result = tree_map( compile, fn, node->arg2, a, b )) )
405 return( result );
406 break;
407
408 case NODE_UOP:
409 if( (result = tree_map( compile, fn, node->arg1, a, b )) )
410 return( result );
411 break;
412
413 case NODE_SUPER:
414 case NODE_LISTCONST:
415 for( l = node->elist; l; l = l->next ) {
416 ParseNode *arg = (ParseNode *) l->data;
417
418 if( (result = tree_map( compile, fn, arg, a, b )) )
419 return( result );
420 }
421 break;
422
423 case NODE_LEAF:
424 case NODE_CLASS:
425 case NODE_TAG:
426 case NODE_CONST:
427 break;
428
429 case NODE_NONE:
430 default:
431 g_assert( FALSE );
432 }
433
434 return( NULL );
435 }
436
437 /* Copy a tree to a new context. Make all symbols afresh ... you need to link
438 * after calling this.
439 */
440 ParseNode *
tree_copy(Compile * compile,ParseNode * node)441 tree_copy( Compile *compile, ParseNode *node )
442 {
443 ParseNode *copy;
444 GSList *l;
445
446 g_assert( node );
447
448 switch( node->type ) {
449 case NODE_GENERATOR:
450 case NODE_APPLY:
451 case NODE_BINOP:
452 case NODE_COMPOSE:
453 case NODE_UOP:
454 case NODE_TAG:
455 case NODE_CONST:
456 case NODE_PATTERN_CLASS:
457 copy = tree_new( compile );
458 copy->type = node->type;
459 copy->uop = node->uop;
460 copy->biop = node->biop;
461 if( node->tag )
462 copy->tag = im_strdupn( node->tag );
463 tree_const_copy( &node->con, ©->con );
464 if( node->arg1 )
465 copy->arg1 = tree_copy( compile, node->arg1 );
466 if( node->arg2 )
467 copy->arg2 = tree_copy( compile, node->arg2 );
468 if( node->arg3 )
469 copy->arg3 = tree_copy( compile, node->arg3 );
470 break;
471
472 case NODE_SUPER:
473 case NODE_LISTCONST:
474 copy = tree_new( compile );
475 for( l = node->elist; l; l = l->next ) {
476 ParseNode *arg = (ParseNode *) l->data;
477
478 copy->elist = g_slist_append( copy->elist,
479 tree_copy( compile, arg ) );
480 }
481 copy->type = node->type;
482 break;
483
484 case NODE_CLASS:
485 copy = tree_class_new( compile );
486 break;
487
488 case NODE_LEAF:
489 copy = tree_leaf_new( compile, IOBJECT( node->leaf )->name );
490 break;
491
492 case NODE_NONE:
493 default:
494 copy = NULL;
495 g_assert( FALSE );
496 }
497
498 return( copy );
499 }
500
501