1 /* Expressions!
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 /* Trace error_set()/_clear().
31 #define DEBUG_ERROR
32  */
33 
34 /* Trace expr_clone()
35 #define DEBUG_CLONE
36  */
37 
38 /*
39 #define DEBUG
40  */
41 
42 #include "ip.h"
43 
44 /* Our signals.
45  */
46 enum {
47 	SIG_NEW_VALUE,		/* new value for root */
48 	SIG_LAST
49 };
50 
51 static iContainerClass *parent_class = NULL;
52 
53 static guint expr_signals[SIG_LAST] = { 0 };
54 
55 /* Set of expressions containing errors.
56  */
57 GSList *expr_error_all = NULL;
58 
59 void *
expr_error_print(Expr * expr,VipsBuf * buf)60 expr_error_print( Expr *expr, VipsBuf *buf )
61 {
62 	g_assert( expr->err );
63 
64 	vips_buf_appendf( buf, _( "error in \"%s\"" ),
65 		IOBJECT( expr->sym )->name );
66 	if( expr->sym->tool )
67 		tool_error( expr->sym->tool, buf );
68 	else if( expr->row ) {
69 		Workspace *ws = expr->row->ws;
70 		Workspacegroup *wsg = workspace_get_workspacegroup( ws );
71 
72 		vips_buf_appendf( buf, " (" );
73 		row_qualified_name( expr->row, buf );
74 		if( FILEMODEL( wsg )->filename )
75 			vips_buf_appendf( buf, " - %s",
76 				FILEMODEL( wsg )->filename );
77 		vips_buf_appendf( buf, ")" );
78 	}
79 
80 	/* Don't show error_top, it's just a summary of error_sub.
81 	 */
82 	vips_buf_appendf( buf, ": %s\n", expr->error_sub );
83 
84 	return( NULL );
85 }
86 
87 static Expr *
expr_map_all_sub(Symbol * sym,map_expr_fn fn,void * a)88 expr_map_all_sub( Symbol *sym, map_expr_fn fn, void *a )
89 {
90 	if( !sym->expr )
91 		return( NULL );
92 	else
93 		return( expr_map_all( sym->expr, fn, a ) );
94 }
95 
96 /* Apply a function to a expr ... and any local exprs.
97  */
98 Expr *
expr_map_all(Expr * expr,map_expr_fn fn,void * a)99 expr_map_all( Expr *expr, map_expr_fn fn, void *a )
100 {
101 	Expr *res;
102 
103 	/* Apply to this expr.
104 	 */
105 	if( (res = fn( expr, a, NULL )) )
106 		return( res );
107 
108 	/* And over any locals.
109 	 */
110 	if( expr->compile && (res = (Expr *)
111 		icontainer_map( ICONTAINER( expr->compile ),
112 			(icontainer_map_fn) expr_map_all_sub,
113 			(void *) fn, a )) )
114 		return( res );
115 
116 	return( NULL );
117 }
118 
119 void *
expr_name_print(Expr * expr)120 expr_name_print( Expr *expr )
121 {
122 	printf( "expr(%p) ", expr );
123 	symbol_name_print( expr->sym );
124 
125 	if( expr->row ) {
126 		printf( "(row " );
127 		row_name_print( expr->row );
128 		printf( ") " );
129 	}
130 
131 	return( NULL );
132 }
133 
134 void
expr_name(Expr * expr,VipsBuf * buf)135 expr_name( Expr *expr, VipsBuf *buf )
136 {
137 	if( expr->row )
138 		row_qualified_name( expr->row, buf );
139 	else
140 		symbol_qualified_name( expr->sym, buf );
141 }
142 
143 Expr *
expr_get_parent(Expr * expr)144 expr_get_parent( Expr *expr )
145 {
146 	Symbol *sym_parent = symbol_get_parent( expr->sym );
147 
148 	if( !sym_parent )
149 		return( NULL );
150 
151 	return( sym_parent->expr );
152 }
153 
154 /* Find the enclosing expr in the dynamic scope hierarchy.
155  */
156 static Expr *
expr_get_parent_dynamic(Expr * expr)157 expr_get_parent_dynamic( Expr *expr )
158 {
159 	Row *row;
160 
161 	if( !expr->row )
162 		return( expr_get_parent( expr ) );
163 	else if( (row = HEAPMODEL( expr->row )->row) )
164 		/* Enclosing row expr.
165 		 */
166 		return( row->expr );
167 	else {
168 		/* Enclosing workspace expr.
169 		 */
170 		Workspace *ws = expr->row->top_col->ws;
171 
172 		return( ws->sym->expr );
173 	}
174 }
175 
176 /* Look back up to find the root expr.
177  */
178 Expr *
expr_get_root(Expr * expr)179 expr_get_root( Expr *expr )
180 {
181 	if( is_top( expr->sym ) )
182 		return( expr );
183 	else
184 		return( expr_get_root( expr_get_parent( expr ) ) );
185 }
186 
187 /* Look back up to find the root expr using the dynamic hierarchy (if it's
188  * there).
189  */
190 Expr *
expr_get_root_dynamic(Expr * expr)191 expr_get_root_dynamic( Expr *expr )
192 {
193 	Expr *parent;
194 
195 	if( is_top( expr->sym ) )
196 		return( expr );
197 	else if( expr->row && expr->row->top_row && expr->row->top_row->expr )
198 		return( expr->row->top_row->expr );
199 	else if( (parent = expr_get_parent_dynamic( expr )) )
200 		return( expr_get_root_dynamic( parent ) );
201 	else
202 		return( NULL );
203 }
204 
205 /* Is an expr part of a row, including enclosing exprs.
206  *
207  * For example, row A1 could be "[x::x<-A2]", that would be expanded to
208  * something like
209  * "$lcomp0 {$lcomp0 = foldr $f0 [] A2 {$f0 x $sofar = x : $sofar}}"
210  * Now, row A1 depends on A2, but expr A1 will not ... it's $lcomp0, the local
211  * expr of A1, that will get called for expr_dirty.
212  *
213  * Return NULL for expr is not a row and has no enclosing rows.
214  */
215 static Row *
expr_get_row(Expr * expr)216 expr_get_row( Expr *expr )
217 {
218 	if( expr->row )
219 		return( expr->row );
220 	else if( is_top( expr->sym ) )
221 		return( NULL );
222 	else
223 		return( expr_get_row( expr_get_parent( expr ) ) );
224 }
225 
226 void
expr_new_value(Expr * expr)227 expr_new_value( Expr *expr )
228 {
229 #ifdef DEBUG
230 {
231 	PElement *root = &expr->root;
232 
233 	printf( "expr_new_value: " );
234 	symbol_name_print( expr->sym );
235 	printf( ": " );
236 	graph_pointer( root );
237 }
238 #endif /*DEBUG*/
239 
240 	g_signal_emit( G_OBJECT( expr ), expr_signals[SIG_NEW_VALUE], 0 );
241 }
242 
243 /* An expr has lost a value.
244  */
245 void
expr_value_destroy(Expr * expr)246 expr_value_destroy( Expr *expr )
247 {
248 	/* Break ImageInfo link (if any).
249 	 */
250 	if( expr->imageinfo )
251 		imageinfo_expr_remove( expr, expr->imageinfo );
252 }
253 
254 /* Clean up an expr, ready to have a new def parsed into it.
255  */
256 void *
expr_strip(Expr * expr)257 expr_strip( Expr *expr )
258 {
259 	expr_error_clear( expr );
260 
261 	/* Break top links we're part of.
262 	 */
263 	if( slist_map( expr->static_links,
264 		(SListMapFn) link_expr_destroy, NULL ) )
265 		return( expr );
266 	if( slist_map( expr->dynamic_links,
267 		(SListMapFn) link_expr_destroy, NULL ) )
268 		return( expr );
269 	g_assert( !expr->static_links );
270 	g_assert( !expr->dynamic_links );
271 
272 	/* Junk error stuff.
273 	 */
274 	IM_FREE( expr->error_top );
275 	IM_FREE( expr->error_sub );
276 
277 	/* Unref the compile.
278 	 */
279 	if( expr->compile )
280 		(void) compile_expr_link_break( expr->compile, expr );
281 
282 	return( NULL );
283 }
284 
285 static void
expr_dispose(GObject * gobject)286 expr_dispose( GObject *gobject )
287 {
288 	Expr *expr = EXPR( gobject );
289 	Symbol *sym = expr->sym;
290 
291 #ifdef DEBUG
292 	printf( "expr_dispose: " );
293 	expr_name_print( expr );
294 	printf( "\n" );
295 #endif /*DEBUG*/
296 
297 	expr_strip( expr );
298 
299 	/* Break the value link.
300 	 */
301 	expr_value_destroy( expr );
302 
303 	/* Unlink from symbol.
304 	 */
305 	if( sym->expr == expr )
306 		sym->expr = NULL;
307 
308 	if( expr->row ) {
309 		Row *row = expr->row;
310 
311 		/* If this is the sym for a top row, kill the row too.
312 		 * Otherwise just break the link and wait for the next row
313 		 * refresh to do the kill for us.
314 		 */
315 		if( row == row->top_row ) {
316 			IDESTROY( row );
317 		}
318 		else {
319 			row->expr = NULL;
320 			row->sym = NULL;
321 
322 			expr->row = NULL;
323 
324 			/* Make sure we will re-parse and compile any text
325 			 * with this sym that might have been modified from
326 			 * the default.
327 			 */
328 			if( row->child_rhs && row->child_rhs->itext ) {
329 				iText *itext = ITEXT( row->child_rhs->itext );
330 
331 				if( itext->edited )
332 					heapmodel_set_modified(
333 						HEAPMODEL( itext ), TRUE );
334 			}
335 		}
336 	}
337 
338 	G_OBJECT_CLASS( parent_class )->dispose( gobject );
339 }
340 
341 static void
expr_info(iObject * iobject,VipsBuf * buf)342 expr_info( iObject *iobject, VipsBuf *buf )
343 {
344 	Expr *expr = EXPR( iobject );
345 
346 	if( expr->err ) {
347 		vips_buf_appends( buf, _( "Error" ) );
348 		vips_buf_appendf( buf, ": %s\n%s\n",
349 			expr->error_top, expr->error_sub );
350 	}
351 }
352 
353 static void
expr_real_new_value(Expr * expr)354 expr_real_new_value( Expr *expr )
355 {
356 	PElement *root = &expr->root;
357 
358 	expr_value_destroy( expr );
359 	if( PEISIMAGE( root ) && PEGETII( root ) )
360 		imageinfo_expr_add( PEGETII( root ), expr );
361 
362 	/* If this is the main expr for this symbol, signal new value there
363 	 * too.
364 	 */
365 	if( expr->sym->expr == expr )
366 		symbol_new_value( expr->sym );
367 }
368 
369 static void
expr_class_init(ExprClass * class)370 expr_class_init( ExprClass *class )
371 {
372 	GObjectClass *gobject_class = (GObjectClass *) class;
373 	iObjectClass *iobject_class = (iObjectClass *) class;
374 
375 	parent_class = g_type_class_peek_parent( class );
376 
377 	/* Create signals.
378 	 */
379 	expr_signals[SIG_NEW_VALUE] = g_signal_new( "new_value",
380 		G_OBJECT_CLASS_TYPE( gobject_class ),
381 		G_SIGNAL_RUN_FIRST,
382 		G_STRUCT_OFFSET( ExprClass, new_value ),
383 		NULL, NULL,
384 		g_cclosure_marshal_VOID__VOID,
385 		G_TYPE_NONE, 0 );
386 
387 	/* Init methods.
388 	 */
389 	gobject_class->dispose = expr_dispose;
390 
391 	iobject_class->info = expr_info;
392 
393 	class->new_value = expr_real_new_value;
394 
395 	/* Static init.
396 	 */
397 }
398 
399 static void
expr_init(Expr * expr)400 expr_init( Expr *expr )
401 {
402 	expr->sym = NULL;
403 	expr->row = NULL;
404 	expr->compile = NULL;
405 
406 	expr->static_links = NULL;
407 	expr->dynamic_links = NULL;
408 
409 	expr->imageinfo = NULL;
410 
411 	expr->err = FALSE;
412 	expr->error_top = NULL;
413 	expr->error_sub = NULL;
414 }
415 
416 GType
expr_get_type(void)417 expr_get_type( void )
418 {
419 	static GType type = 0;
420 
421 	if( !type ) {
422 		static const GTypeInfo info = {
423 			sizeof( ExprClass ),
424 			NULL,           /* base_init */
425 			NULL,           /* base_finalize */
426 			(GClassInitFunc) expr_class_init,
427 			NULL,           /* class_finalize */
428 			NULL,           /* class_data */
429 			sizeof( Expr ),
430 			32,             /* n_preallocs */
431 			(GInstanceInitFunc) expr_init,
432 		};
433 
434 		type = g_type_register_static( TYPE_ICONTAINER,
435 			"Expr", &info, 0 );
436 	}
437 
438 	return( type );
439 }
440 
441 Expr *
expr_new(Symbol * sym)442 expr_new( Symbol *sym )
443 {
444 	Expr *expr;
445 
446 	expr = EXPR( g_object_new( TYPE_EXPR, NULL ) );
447 
448 	expr->sym = sym;
449 	PEPOINTE( &expr->root, &sym->base );
450 	icontainer_child_add( ICONTAINER( sym ), ICONTAINER( expr ), -1 );
451 
452 #ifdef DEBUG
453 	printf( "expr_new: " );
454 	expr_name_print( expr );
455 	printf( "\n" );
456 #endif /*DEBUG*/
457 
458 	return( expr );
459 }
460 
461 
462 /* Clone an existing expr.
463  */
464 Expr *
expr_clone(Symbol * sym)465 expr_clone( Symbol *sym )
466 {
467 	Expr *expr;
468 
469 	if( sym->expr && sym->expr->compile ) {
470 		/* Make a new expr, share the compile.
471 		 */
472                 expr = expr_new( sym );
473 		compile_expr_link_make( sym->expr->compile, expr );
474 	}
475 	else {
476 		/* No existing expr to copy, make a bare one for the
477 		 * row, at the same scope level as sym.
478 		 */
479                 expr = expr_new( sym );
480 	}
481 
482 	return( expr );
483 }
484 
485 /* Mark an expression as containing an error, save the error buffers.
486  */
487 void *
expr_error_set(Expr * expr)488 expr_error_set( Expr *expr )
489 {
490 	/* Was not in error? Add to error set.
491 	 */
492 	if( !expr->err ) {
493 #ifdef DEBUG_ERROR
494 		printf( "expr_error_set: error in " );
495 		symbol_name_print( expr->sym );
496 		printf( ": %s %s\n", error_get_top(), error_get_sub() );
497 #endif /*DEBUG_ERROR*/
498 
499 		IM_SETSTR( expr->error_top, error_get_top() );
500 		IM_SETSTR( expr->error_sub, error_get_sub() );
501 
502 		/* Zap the value of the expr ... it may contain pointers to
503 		 * dead stuff.
504 		 */
505 		PEPUTP( &expr->root, ELEMENT_NOVAL, (void *) 99 );
506 
507 		expr_error_all = g_slist_prepend( expr_error_all, expr );
508 		expr->err = TRUE;
509 		if( expr->row )
510 			row_error_set( expr->row );
511 
512 		/* If this is the value of a top-level sym, note state
513 		 * change on symbol.
514 		 */
515 		if( is_top( expr->sym ) && expr->sym->expr == expr )
516 			symbol_state_change( expr->sym );
517 	}
518 
519 	return( NULL );
520 }
521 
522 /* Extract the error from an expression.
523  */
524 void
expr_error_get(Expr * expr)525 expr_error_get( Expr *expr )
526 {
527 	if( !expr->err )
528 		error_clear();
529 	else {
530 		g_assert( expr->error_top );
531 		g_assert( expr->error_sub );
532 
533 		error_top( "%s", expr->error_top );
534 		error_sub( "%s", expr->error_sub );
535 	}
536 }
537 
538 /* Clear error state.
539  */
540 void
expr_error_clear(Expr * expr)541 expr_error_clear( Expr *expr )
542 {
543 	if( expr->err ) {
544 #ifdef DEBUG_ERROR
545 		printf( "expr_error_clear: " );
546 		symbol_name_print( expr->sym );
547 		printf( "\n"  );
548 #endif /*DEBUG_ERROR*/
549 
550 		expr->err = FALSE;
551 		expr_error_all = g_slist_remove( expr_error_all, expr );
552 		if( expr->row )
553 			row_error_clear( expr->row );
554 
555 		if( is_top( expr->sym ) && expr->sym->expr == expr )
556 			symbol_state_change( expr->sym );
557 	}
558 }
559 
560 /* Mark an expr dirty.
561  *
562  * Two cases: if expr has a row, this is part of a display. Use the row
563  * stuff to mark this expr dirty. Then use symbol_dirty() to mark on from the
564  * root of this row.
565  *
566  * Case two: this must be an expr inside a top-level ... just
567  * symbol_dirty() on from that top level.
568  *
569  * FIXME ... we should be able to scrap this expr_get_root() ... we want the
570  * 'parent' field in the Link we are probably being called from.
571  */
572 void *
expr_dirty(Expr * expr,int serial)573 expr_dirty( Expr *expr, int serial )
574 {
575 	Row *row;
576 
577 #ifdef DEBUG
578 	printf( "expr_dirty: " );
579 	symbol_name_print( expr->sym );
580 	printf( "\n" );
581 #endif /*DEBUG*/
582 
583 	if( (row = expr_get_row( expr )) &&
584 		row->top_row->sym ) {
585 		Symbol *top_sym = row->top_row->sym;
586 
587 		row_dirty( row, TRUE );
588 		symbol_dirty( top_sym, serial );
589 	}
590 	else
591 		symbol_dirty( expr_get_root( expr )->sym, serial );
592 
593 	return( NULL );
594 }
595 
596 void *
expr_dirty_intrans(Expr * expr,int serial)597 expr_dirty_intrans( Expr *expr, int serial )
598 {
599 	if( expr->row &&
600 		expr->row->top_row->sym ) {
601 		row_dirty_intrans( expr->row, TRUE );
602 		symbol_dirty( expr->row->top_row->sym, serial );
603 	}
604 	else
605 		symbol_dirty_intrans( expr->sym, serial );
606 
607 	return( NULL );
608 }
609 
610 void
expr_tip_sub(Expr * expr,VipsBuf * buf)611 expr_tip_sub( Expr *expr, VipsBuf *buf )
612 {
613 	Compile *compile = expr->compile;
614 
615 	if( is_top( expr->sym ) ) {
616 		vips_buf_appends( buf, _( "top level" ) );
617 		vips_buf_appends( buf, " " );
618 	}
619 
620 	if( compile &&
621 		is_class( compile ) ) {
622 		vips_buf_appends( buf, _( "class" ) );
623 		vips_buf_appends( buf, " " );
624 		if( compile->nparam == 0 ) {
625 			vips_buf_appends( buf, _( "instance" ) );
626 			vips_buf_appends( buf, " " );
627 		}
628 		else {
629 			vips_buf_appends( buf, _( "definition" ) );
630 			vips_buf_appends( buf, " " );
631 		}
632 
633 		vips_buf_appendf( buf, "\"%s\"", IOBJECT( expr->sym )->name );
634 	}
635 	else if( expr->sym->type == SYM_PARAM )
636 		vips_buf_appendf( buf, _( "parameter \"%s\"" ),
637 			IOBJECT( expr->sym )->name );
638 	else if( compile ) {
639 		if( is_member( expr->sym ) ) {
640 			vips_buf_appends( buf, _( "member" ) );
641 			vips_buf_appends( buf, " " );
642 		}
643 
644 		if( compile->nparam == 0 ) {
645 			vips_buf_appends( buf, _( "value" ) );
646 			vips_buf_appends( buf, " " );
647 		}
648 		else {
649 			vips_buf_appends( buf, _( "function" ) );
650 			vips_buf_appends( buf, " " );
651 		}
652 
653 		vips_buf_appendf( buf, "\"%s\"", IOBJECT( expr->sym )->name );
654 	}
655 
656 	if( !is_top( expr->sym ) ) {
657 		vips_buf_appends( buf, " " );
658 		vips_buf_appends( buf, _( "of" ) );
659 		vips_buf_appends( buf, " " );
660 		expr_tip_sub( expr_get_parent( expr ), buf );
661 	}
662 }
663 
664 /* Look at an expr, make a tooltip.
665  */
666 void
expr_tip(Expr * expr,VipsBuf * buf)667 expr_tip( Expr *expr, VipsBuf *buf )
668 {
669 	expr_name( expr, buf );
670 	vips_buf_appends( buf, ": " );
671 	expr_tip_sub( expr, buf );
672 }
673 
674 /* Bind unresolved refs in an expr. Bind for every enclosing dynamic scope.
675  */
676 void
expr_resolve(Expr * expr)677 expr_resolve( Expr *expr )
678 {
679 	Expr *top = symbol_root->expr;
680 	Expr *i;
681 
682 #ifdef DEBUG
683 	printf( "expr_resolve: " );
684 	expr_name_print( expr );
685 	printf( "\n" );
686 #endif /*DEBUG*/
687 
688 	for( i = expr; i != top; i = expr_get_parent_dynamic( i ) )
689 		/* May try to resolve out through a parameter.
690 		 */
691 		if( i->compile )
692 			compile_resolve_dynamic( expr->compile, i->compile );
693 }
694