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, &copy->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