]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/tools/build/src/engine/function.c
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / tools / build / src / engine / function.c
CommitLineData
7c673cae
FG
1/*
2 * Copyright 2011 Steven Watanabe
3 * Copyright 2016 Rene Rivera
4 * Distributed under the Boost Software License, Version 1.0.
5 * (See accompanying file LICENSE_1_0.txt or copy at
6 * http://www.boost.org/LICENSE_1_0.txt)
7 */
8
9#include "jam.h"
10#include "function.h"
11
12#include "class.h"
13#include "compile.h"
14#include "constants.h"
b32b8144 15#include "debugger.h"
7c673cae
FG
16#include "filesys.h"
17#include "frames.h"
18#include "lists.h"
19#include "mem.h"
20#include "pathsys.h"
21#include "rules.h"
22#include "search.h"
23#include "variable.h"
24#include "output.h"
25
26#include <assert.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
b32b8144 31/*
7c673cae 32#define FUNCTION_DEBUG_PROFILE
b32b8144 33*/
7c673cae
FG
34
35#ifndef FUNCTION_DEBUG_PROFILE
b32b8144
FG
36#undef PROFILE_ENTER_LOCAL
37#define PROFILE_ENTER_LOCAL(x) static int unused_LOCAL_##x = 0
38#undef PROFILE_EXIT_LOCAL
7c673cae
FG
39#define PROFILE_EXIT_LOCAL(x)
40#endif
41
42int glob( char const * s, char const * c );
43void backtrace( FRAME * );
44void backtrace_line( FRAME * );
45
46#define INSTR_PUSH_EMPTY 0
47#define INSTR_PUSH_CONSTANT 1
48#define INSTR_PUSH_ARG 2
49#define INSTR_PUSH_VAR 3
50#define INSTR_PUSH_VAR_FIXED 57
51#define INSTR_PUSH_GROUP 4
52#define INSTR_PUSH_RESULT 5
53#define INSTR_PUSH_APPEND 6
54#define INSTR_SWAP 7
55
56#define INSTR_JUMP_EMPTY 8
57#define INSTR_JUMP_NOT_EMPTY 9
58
59#define INSTR_JUMP 10
60#define INSTR_JUMP_LT 11
61#define INSTR_JUMP_LE 12
62#define INSTR_JUMP_GT 13
63#define INSTR_JUMP_GE 14
64#define INSTR_JUMP_EQ 15
65#define INSTR_JUMP_NE 16
66#define INSTR_JUMP_IN 17
67#define INSTR_JUMP_NOT_IN 18
68
69#define INSTR_JUMP_NOT_GLOB 19
70
71#define INSTR_FOR_INIT 56
72#define INSTR_FOR_LOOP 20
73
74#define INSTR_SET_RESULT 21
75#define INSTR_RETURN 22
76#define INSTR_POP 23
77
78#define INSTR_PUSH_LOCAL 24
79#define INSTR_POP_LOCAL 25
80#define INSTR_SET 26
81#define INSTR_APPEND 27
82#define INSTR_DEFAULT 28
83
84#define INSTR_PUSH_LOCAL_FIXED 58
85#define INSTR_POP_LOCAL_FIXED 59
86#define INSTR_SET_FIXED 60
87#define INSTR_APPEND_FIXED 61
88#define INSTR_DEFAULT_FIXED 62
89
90#define INSTR_PUSH_LOCAL_GROUP 29
91#define INSTR_POP_LOCAL_GROUP 30
92#define INSTR_SET_GROUP 31
93#define INSTR_APPEND_GROUP 32
94#define INSTR_DEFAULT_GROUP 33
95
96#define INSTR_PUSH_ON 34
97#define INSTR_POP_ON 35
98#define INSTR_SET_ON 36
99#define INSTR_APPEND_ON 37
100#define INSTR_DEFAULT_ON 38
101#define INSTR_GET_ON 65
102
103#define INSTR_CALL_RULE 39
104#define INSTR_CALL_MEMBER_RULE 66
105
106#define INSTR_APPLY_MODIFIERS 40
107#define INSTR_APPLY_INDEX 41
108#define INSTR_APPLY_INDEX_MODIFIERS 42
109#define INSTR_APPLY_MODIFIERS_GROUP 43
110#define INSTR_APPLY_INDEX_GROUP 44
111#define INSTR_APPLY_INDEX_MODIFIERS_GROUP 45
112#define INSTR_COMBINE_STRINGS 46
113#define INSTR_GET_GRIST 64
114
115#define INSTR_INCLUDE 47
116#define INSTR_RULE 48
117#define INSTR_ACTIONS 49
118#define INSTR_PUSH_MODULE 50
119#define INSTR_POP_MODULE 51
120#define INSTR_CLASS 52
121#define INSTR_BIND_MODULE_VARIABLES 63
122
123#define INSTR_APPEND_STRINGS 53
124#define INSTR_WRITE_FILE 54
125#define INSTR_OUTPUT_STRINGS 55
126
b32b8144 127#define INSTR_DEBUG_LINE 67
7c673cae
FG
128#define INSTR_FOR_POP 70
129
130typedef struct instruction
131{
132 unsigned int op_code;
133 int arg;
134} instruction;
135
136typedef struct _subfunction
137{
138 OBJECT * name;
139 FUNCTION * code;
140 int local;
141} SUBFUNCTION;
142
143typedef struct _subaction
144{
145 OBJECT * name;
146 FUNCTION * command;
147 int flags;
148} SUBACTION;
149
150#define FUNCTION_BUILTIN 0
151#define FUNCTION_JAM 1
152
153struct argument
154{
155 int flags;
156#define ARG_ONE 0
157#define ARG_OPTIONAL 1
158#define ARG_PLUS 2
159#define ARG_STAR 3
160#define ARG_VARIADIC 4
161 OBJECT * type_name;
162 OBJECT * arg_name;
163 int index;
164};
165
166struct arg_list
167{
168 int size;
169 struct argument * args;
170};
171
172struct _function
173{
174 int type;
175 int reference_count;
176 OBJECT * rulename;
177 struct arg_list * formal_arguments;
178 int num_formal_arguments;
179};
180
181typedef struct _builtin_function
182{
183 FUNCTION base;
184 LIST * ( * func )( FRAME *, int flags );
185 int flags;
186} BUILTIN_FUNCTION;
187
188typedef struct _jam_function
189{
190 FUNCTION base;
191 int code_size;
192 instruction * code;
193 int num_constants;
194 OBJECT * * constants;
195 int num_subfunctions;
196 SUBFUNCTION * functions;
197 int num_subactions;
198 SUBACTION * actions;
199 FUNCTION * generic;
200 OBJECT * file;
201 int line;
202} JAM_FUNCTION;
203
204
205#ifdef HAVE_PYTHON
206
207#define FUNCTION_PYTHON 2
208
209typedef struct _python_function
210{
211 FUNCTION base;
212 PyObject * python_function;
213} PYTHON_FUNCTION;
214
215static LIST * call_python_function( PYTHON_FUNCTION *, FRAME * );
216
217#endif
218
219
220struct _stack
221{
222 void * data;
223};
224
225static void * stack;
226
227STACK * stack_global()
228{
229 static STACK result;
230 if ( !stack )
231 {
232 int const size = 1 << 21;
233 stack = BJAM_MALLOC( size );
234 result.data = (char *)stack + size;
235 }
236 return &result;
237}
238
239struct list_alignment_helper
240{
241 char ch;
242 LIST * l;
243};
244
245#define LISTPTR_ALIGN_BASE ( sizeof( struct list_alignment_helper ) - sizeof( LIST * ) )
246#define LISTPTR_ALIGN ( ( LISTPTR_ALIGN_BASE > sizeof( LIST * ) ) ? sizeof( LIST * ) : LISTPTR_ALIGN_BASE )
247
248static void check_alignment( STACK * s )
249{
250 assert( (size_t)s->data % LISTPTR_ALIGN == 0 );
251}
252
253void * stack_allocate( STACK * s, int size )
254{
255 check_alignment( s );
256 s->data = (char *)s->data - size;
257 check_alignment( s );
258 return s->data;
259}
260
261void stack_deallocate( STACK * s, int size )
262{
263 check_alignment( s );
264 s->data = (char *)s->data + size;
265 check_alignment( s );
266}
267
268void stack_push( STACK * s, LIST * l )
269{
270 *(LIST * *)stack_allocate( s, sizeof( LIST * ) ) = l;
271}
272
273LIST * stack_pop( STACK * s )
274{
275 LIST * const result = *(LIST * *)s->data;
276 stack_deallocate( s, sizeof( LIST * ) );
277 return result;
278}
279
280LIST * stack_top( STACK * s )
281{
282 check_alignment( s );
283 return *(LIST * *)s->data;
284}
285
286LIST * stack_at( STACK * s, int n )
287{
288 check_alignment( s );
289 return *( (LIST * *)s->data + n );
290}
291
292void stack_set( STACK * s, int n, LIST * value )
293{
294 check_alignment( s );
295 *((LIST * *)s->data + n) = value;
296}
297
298void * stack_get( STACK * s )
299{
300 check_alignment( s );
301 return s->data;
302}
303
304LIST * frame_get_local( FRAME * frame, int idx )
305{
306 /* The only local variables are the arguments. */
307 return list_copy( lol_get( frame->args, idx ) );
308}
309
310static OBJECT * function_get_constant( JAM_FUNCTION * function, int idx )
311{
312 return function->constants[ idx ];
313}
314
315static LIST * function_get_variable( JAM_FUNCTION * function, FRAME * frame,
316 int idx )
317{
318 return list_copy( var_get( frame->module, function->constants[ idx ] ) );
319}
320
321static void function_set_variable( JAM_FUNCTION * function, FRAME * frame,
322 int idx, LIST * value )
323{
324 var_set( frame->module, function->constants[ idx ], value, VAR_SET );
325}
326
327static LIST * function_swap_variable( JAM_FUNCTION * function, FRAME * frame,
328 int idx, LIST * value )
329{
330 return var_swap( frame->module, function->constants[ idx ], value );
331}
332
333static void function_append_variable( JAM_FUNCTION * function, FRAME * frame,
334 int idx, LIST * value )
335{
336 var_set( frame->module, function->constants[ idx ], value, VAR_APPEND );
337}
338
339static void function_default_variable( JAM_FUNCTION * function, FRAME * frame,
340 int idx, LIST * value )
341{
342 var_set( frame->module, function->constants[ idx ], value, VAR_DEFAULT );
343}
344
345static void function_set_rule( JAM_FUNCTION * function, FRAME * frame,
346 STACK * s, int idx )
347{
348 SUBFUNCTION * sub = function->functions + idx;
349 new_rule_body( frame->module, sub->name, sub->code, !sub->local );
350}
351
352static void function_set_actions( JAM_FUNCTION * function, FRAME * frame,
353 STACK * s, int idx )
354{
355 SUBACTION * sub = function->actions + idx;
356 LIST * bindlist = stack_pop( s );
357 new_rule_actions( frame->module, sub->name, sub->command, bindlist,
358 sub->flags );
359}
360
361
362/*
363 * Returns the index if name is "<", ">", "1", "2", ... or "19" otherwise
364 * returns -1.
365 */
366
367static int get_argument_index( char const * s )
368{
369 if ( s[ 0 ] != '\0')
370 {
371 if ( s[ 1 ] == '\0' )
372 {
373 switch ( s[ 0 ] )
374 {
375 case '<': return 0;
376 case '>': return 1;
377
378 case '1':
379 case '2':
380 case '3':
381 case '4':
382 case '5':
383 case '6':
384 case '7':
385 case '8':
386 case '9':
387 return s[ 0 ] - '1';
388 }
389 }
390 else if ( s[ 0 ] == '1' && s[ 2 ] == '\0' )
391 {
392 switch( s[ 1 ] )
393 {
394 case '0':
395 case '1':
396 case '2':
397 case '3':
398 case '4':
399 case '5':
400 case '6':
401 case '7':
402 case '8':
403 case '9':
404 return s[ 1 ] - '0' + 10 - 1;
405 }
406 }
407 }
408 return -1;
409}
410
411static LIST * function_get_named_variable( JAM_FUNCTION * function,
412 FRAME * frame, OBJECT * name )
413{
414 int const idx = get_argument_index( object_str( name ) );
415 return idx == -1
416 ? list_copy( var_get( frame->module, name ) )
417 : list_copy( lol_get( frame->args, idx ) );
418}
419
420static void function_set_named_variable( JAM_FUNCTION * function, FRAME * frame,
421 OBJECT * name, LIST * value)
422{
423 var_set( frame->module, name, value, VAR_SET );
424}
425
426static LIST * function_swap_named_variable( JAM_FUNCTION * function,
427 FRAME * frame, OBJECT * name, LIST * value )
428{
429 return var_swap( frame->module, name, value );
430}
431
432static void function_append_named_variable( JAM_FUNCTION * function,
433 FRAME * frame, OBJECT * name, LIST * value)
434{
435 var_set( frame->module, name, value, VAR_APPEND );
436}
437
438static void function_default_named_variable( JAM_FUNCTION * function,
439 FRAME * frame, OBJECT * name, LIST * value )
440{
441 var_set( frame->module, name, value, VAR_DEFAULT );
442}
443
444static LIST * function_call_rule( JAM_FUNCTION * function, FRAME * frame,
445 STACK * s, int n_args, char const * unexpanded, OBJECT * file, int line )
446{
447 FRAME inner[ 1 ];
448 int i;
449 LIST * first = stack_pop( s );
450 LIST * result = L0;
451 OBJECT * rulename;
452 LIST * trailing;
453
454 frame->file = file;
455 frame->line = line;
456
457 if ( list_empty( first ) )
458 {
459 backtrace_line( frame );
460 out_printf( "warning: rulename %s expands to empty string\n", unexpanded );
461 backtrace( frame );
462 list_free( first );
463 for ( i = 0; i < n_args; ++i )
464 list_free( stack_pop( s ) );
465 return result;
466 }
467
468 rulename = object_copy( list_front( first ) );
469
470 frame_init( inner );
471 inner->prev = frame;
472 inner->prev_user = frame->module->user_module ? frame : frame->prev_user;
473 inner->module = frame->module; /* This gets fixed up in evaluate_rule(). */
474
475 for ( i = 0; i < n_args; ++i )
476 lol_add( inner->args, stack_at( s, n_args - i - 1 ) );
477
478 for ( i = 0; i < n_args; ++i )
479 stack_pop( s );
480
481 trailing = list_pop_front( first );
482 if ( trailing )
483 {
484 if ( inner->args->count == 0 )
485 lol_add( inner->args, trailing );
486 else
487 {
488 LIST * * const l = &inner->args->list[ 0 ];
489 *l = list_append( trailing, *l );
490 }
491 }
492
493 result = evaluate_rule( bindrule( rulename, inner->module ), rulename, inner );
494 frame_free( inner );
495 object_free( rulename );
496 return result;
497}
498
499static LIST * function_call_member_rule( JAM_FUNCTION * function, FRAME * frame, STACK * s, int n_args, OBJECT * rulename, OBJECT * file, int line )
500{
501 FRAME inner[ 1 ];
502 int i;
503 LIST * first = stack_pop( s );
504 LIST * result = L0;
505 LIST * trailing;
506 RULE * rule;
507 module_t * module;
508 OBJECT * real_rulename = 0;
509
510 frame->file = file;
511 frame->line = line;
512
513 if ( list_empty( first ) )
514 {
515 backtrace_line( frame );
516 out_printf( "warning: object is empty\n" );
517 backtrace( frame );
518
519 list_free( first );
520
521 for( i = 0; i < n_args; ++i )
522 {
523 list_free( stack_pop( s ) );
524 }
525
526 return result;
527 }
528
529 /* FIXME: handle generic case */
530 assert( list_length( first ) == 1 );
531
532 module = bindmodule( list_front( first ) );
533 if ( module->class_module )
534 {
535 rule = bindrule( rulename, module );
11fdf7f2
TL
536 if ( rule->procedure )
537 {
538 real_rulename = object_copy( function_rulename( rule->procedure ) );
539 }
540 else
541 {
542 string buf[ 1 ];
543 string_new( buf );
544 string_append( buf, object_str( module->name ) );
545 string_push_back( buf, '.' );
546 string_append( buf, object_str( rulename ) );
547 real_rulename = object_new( buf->value );
548 string_free( buf );
549 }
7c673cae
FG
550 }
551 else
552 {
553 string buf[ 1 ];
554 string_new( buf );
555 string_append( buf, object_str( list_front( first ) ) );
556 string_push_back( buf, '.' );
557 string_append( buf, object_str( rulename ) );
558 real_rulename = object_new( buf->value );
559 string_free( buf );
560 rule = bindrule( real_rulename, frame->module );
561 }
562
563 frame_init( inner );
564
565 inner->prev = frame;
566 inner->prev_user = frame->module->user_module ? frame : frame->prev_user;
567 inner->module = frame->module; /* This gets fixed up in evaluate_rule(), below. */
568
569 for( i = 0; i < n_args; ++i )
570 {
571 lol_add( inner->args, stack_at( s, n_args - i - 1 ) );
572 }
573
574 for( i = 0; i < n_args; ++i )
575 {
576 stack_pop( s );
577 }
578
579 if ( list_length( first ) > 1 )
580 {
581 string buf[ 1 ];
582 LIST * trailing = L0;
583 LISTITER iter = list_begin( first ), end = list_end( first );
584 iter = list_next( iter );
585 string_new( buf );
586 for ( ; iter != end; iter = list_next( iter ) )
587 {
588 string_append( buf, object_str( list_item( iter ) ) );
589 string_push_back( buf, '.' );
590 string_append( buf, object_str( rulename ) );
591 trailing = list_push_back( trailing, object_new( buf->value ) );
592 string_truncate( buf, 0 );
593 }
594 string_free( buf );
595 if ( inner->args->count == 0 )
596 lol_add( inner->args, trailing );
597 else
598 {
599 LIST * * const l = &inner->args->list[ 0 ];
600 *l = list_append( trailing, *l );
601 }
602 }
603
604 list_free( first );
605 result = evaluate_rule( rule, real_rulename, inner );
606 frame_free( inner );
607 object_free( real_rulename );
608 return result;
609}
610
611
612/* Variable expansion */
613
614typedef struct
615{
616 int sub1;
617 int sub2;
618} subscript_t;
619
620typedef struct
621{
622 PATHNAME f; /* :GDBSMR -- pieces */
623 char parent; /* :P -- go to parent directory */
624 char filemods; /* one of the above applied */
625 char downshift; /* :L -- downshift result */
626 char upshift; /* :U -- upshift result */
627 char to_slashes; /* :T -- convert "\" to "/" */
628 char to_windows; /* :W -- convert cygwin to native paths */
629 PATHPART empty; /* :E -- default for empties */
630 PATHPART join; /* :J -- join list with char */
631} VAR_EDITS;
632
633static LIST * apply_modifiers_impl( LIST * result, string * buf,
634 VAR_EDITS * edits, int n, LISTITER iter, LISTITER end );
635static void get_iters( subscript_t const subscript, LISTITER * const first,
636 LISTITER * const last, int const length );
637
638
639/*
640 * var_edit_parse() - parse : modifiers into PATHNAME structure
641 *
642 * The : modifiers in a $(varname:modifier) currently support replacing or
643 * omitting elements of a filename, and so they are parsed into a PATHNAME
644 * structure (which contains pointers into the original string).
645 *
646 * Modifiers of the form "X=value" replace the component X with the given value.
647 * Modifiers without the "=value" cause everything but the component X to be
648 * omitted. X is one of:
649 *
650 * G <grist>
651 * D directory name
652 * B base name
653 * S .suffix
654 * M (member)
655 * R root directory - prepended to whole path
656 *
657 * This routine sets:
658 *
659 * f->f_xxx.ptr = 0
660 * f->f_xxx.len = 0
661 * -> leave the original component xxx
662 *
663 * f->f_xxx.ptr = string
664 * f->f_xxx.len = strlen( string )
665 * -> replace component xxx with string
666 *
667 * f->f_xxx.ptr = ""
668 * f->f_xxx.len = 0
669 * -> omit component xxx
670 *
671 * var_edit_file() below and path_build() obligingly follow this convention.
672 */
673
674static int var_edit_parse( char const * mods, VAR_EDITS * edits, int havezeroed
675 )
676{
677 while ( *mods )
678 {
679 PATHPART * fp;
680
681 switch ( *mods++ )
682 {
683 case 'L': edits->downshift = 1; continue;
684 case 'U': edits->upshift = 1; continue;
685 case 'P': edits->parent = edits->filemods = 1; continue;
686 case 'E': fp = &edits->empty; goto strval;
687 case 'J': fp = &edits->join; goto strval;
688 case 'G': fp = &edits->f.f_grist; goto fileval;
689 case 'R': fp = &edits->f.f_root; goto fileval;
690 case 'D': fp = &edits->f.f_dir; goto fileval;
691 case 'B': fp = &edits->f.f_base; goto fileval;
692 case 'S': fp = &edits->f.f_suffix; goto fileval;
693 case 'M': fp = &edits->f.f_member; goto fileval;
694 case 'T': edits->to_slashes = 1; continue;
695 case 'W': edits->to_windows = 1; continue;
696 default:
697 continue; /* Should complain, but so what... */
698 }
699
700 fileval:
701 /* Handle :CHARS, where each char (without a following =) selects a
702 * particular file path element. On the first such char, we deselect all
703 * others (by setting ptr = "", len = 0) and for each char we select
704 * that element (by setting ptr = 0).
705 */
706 edits->filemods = 1;
707
708 if ( *mods != '=' )
709 {
710 if ( !havezeroed++ )
711 {
712 int i;
713 for ( i = 0; i < 6; ++i )
714 {
715 edits->f.part[ i ].len = 0;
716 edits->f.part[ i ].ptr = "";
717 }
718 }
719
720 fp->ptr = 0;
721 continue;
722 }
723
724 strval:
725 /* Handle :X=value, or :X */
726 if ( *mods != '=' )
727 {
728 fp->ptr = "";
729 fp->len = 0;
730 }
731 else
732 {
733 fp->ptr = ++mods;
734 fp->len = strlen( mods );
735 mods += fp->len;
736 }
737 }
738
739 return havezeroed;
740}
741
742
743/*
744 * var_edit_file() - copy input target name to output, modifying filename.
745 */
746
747static void var_edit_file( char const * in, string * out, VAR_EDITS * edits )
748{
749 if ( edits->filemods )
750 {
751 PATHNAME pathname;
752
753 /* Parse apart original filename, putting parts into "pathname". */
754 path_parse( in, &pathname );
755
756 /* Replace any pathname with edits->f */
757 if ( edits->f.f_grist .ptr ) pathname.f_grist = edits->f.f_grist;
758 if ( edits->f.f_root .ptr ) pathname.f_root = edits->f.f_root;
759 if ( edits->f.f_dir .ptr ) pathname.f_dir = edits->f.f_dir;
760 if ( edits->f.f_base .ptr ) pathname.f_base = edits->f.f_base;
761 if ( edits->f.f_suffix.ptr ) pathname.f_suffix = edits->f.f_suffix;
762 if ( edits->f.f_member.ptr ) pathname.f_member = edits->f.f_member;
763
764 /* If requested, modify pathname to point to parent. */
765 if ( edits->parent )
766 path_parent( &pathname );
767
768 /* Put filename back together. */
769 path_build( &pathname, out );
770 }
771 else
772 string_append( out, in );
773}
774
775
776/*
777 * var_edit_translate_path() - translate path to os native format.
778 */
779
780static void var_edit_translate_path( string * out, size_t pos, VAR_EDITS * edits )
781{
782 if ( edits->to_windows )
783 {
784 string result[ 1 ];
785 int translated;
786
787 /* Translate path to os native format. */
788 translated = path_translate_to_os( out->value + pos, result );
789 if ( translated )
790 {
791 string_truncate( out, pos );
792 string_append( out, result->value );
793 edits->to_slashes = 0;
794 }
795
796 string_free( result );
797 }
798}
799
800
801/*
802 * var_edit_shift() - do upshift/downshift & other mods.
803 */
804
805static void var_edit_shift( string * out, size_t pos, VAR_EDITS * edits )
806{
807#if defined( OS_CYGWIN ) || defined( OS_VMS )
808 var_edit_translate_path( out, pos, edits );
809#endif
810
811 if ( edits->upshift || edits->downshift || edits->to_slashes )
812 {
813 /* Handle upshifting, downshifting and slash translation now. */
814 char * p;
815 for ( p = out->value + pos; *p; ++p )
816 {
817 if ( edits->upshift )
818 *p = toupper( *p );
819 else if ( edits->downshift )
820 *p = tolower( *p );
821 if ( edits->to_slashes && ( *p == '\\' ) )
822 *p = '/';
823 }
824 }
825}
826
827
828/*
829 * Reads n LISTs from the top of the STACK and combines them to form VAR_EDITS.
830 * Returns the number of VAR_EDITS pushed onto the STACK.
831 */
832
833static int expand_modifiers( STACK * s, int n )
834{
835 int i;
836 int total = 1;
837 LIST * * args = stack_get( s );
838 for ( i = 0; i < n; ++i )
839 total *= list_length( args[ i ] );
840
841 if ( total != 0 )
842 {
843 VAR_EDITS * out = stack_allocate( s, total * sizeof( VAR_EDITS ) );
844 LISTITER * iter = stack_allocate( s, n * sizeof( LIST * ) );
845 for ( i = 0; i < n; ++i )
846 iter[ i ] = list_begin( args[ i ] );
847 i = 0;
848 {
849 int havezeroed;
850 loop:
851 memset( out, 0, sizeof( *out ) );
852 havezeroed = 0;
853 for ( i = 0; i < n; ++i )
854 havezeroed = var_edit_parse( object_str( list_item( iter[ i ] )
855 ), out, havezeroed );
856 ++out;
857 while ( --i >= 0 )
858 {
859 if ( list_next( iter[ i ] ) != list_end( args[ i ] ) )
860 {
861 iter[ i ] = list_next( iter[ i ] );
862 goto loop;
863 }
864 iter[ i ] = list_begin( args[ i ] );
865 }
866 }
867 stack_deallocate( s, n * sizeof( LIST * ) );
868 }
869 return total;
870}
871
872static LIST * apply_modifiers( STACK * s, int n )
873{
874 LIST * value = stack_top( s );
875 LIST * result = L0;
876 VAR_EDITS * const edits = (VAR_EDITS *)( (LIST * *)stack_get( s ) + 1 );
877 string buf[ 1 ];
878 string_new( buf );
879 result = apply_modifiers_impl( result, buf, edits, n, list_begin( value ),
880 list_end( value ) );
881 string_free( buf );
882 return result;
883}
884
885
886/*
887 * Parse a string of the form "1-2", "-2--1", "2-" and return the two
888 * subscripts.
889 */
890
891subscript_t parse_subscript( char const * s )
892{
893 subscript_t result;
894 result.sub1 = 0;
895 result.sub2 = 0;
896 do /* so we can use "break" */
897 {
898 /* Allow negative subscripts. */
899 if ( !isdigit( *s ) && ( *s != '-' ) )
900 {
901 result.sub2 = 0;
902 break;
903 }
904 result.sub1 = atoi( s );
905
906 /* Skip over the first symbol, which is either a digit or dash. */
907 ++s;
908 while ( isdigit( *s ) ) ++s;
909
910 if ( *s == '\0' )
911 {
912 result.sub2 = result.sub1;
913 break;
914 }
915
916 if ( *s != '-' )
917 {
918 result.sub2 = 0;
919 break;
920 }
921
922 ++s;
923
924 if ( *s == '\0' )
925 {
926 result.sub2 = -1;
927 break;
928 }
929
930 if ( !isdigit( *s ) && ( *s != '-' ) )
931 {
932 result.sub2 = 0;
933 break;
934 }
935
936 /* First, compute the index of the last element. */
937 result.sub2 = atoi( s );
938 while ( isdigit( *++s ) );
939
940 if ( *s != '\0' )
941 result.sub2 = 0;
942
943 } while ( 0 );
944 return result;
945}
946
947static LIST * apply_subscript( STACK * s )
948{
949 LIST * value = stack_top( s );
950 LIST * indices = stack_at( s, 1 );
951 LIST * result = L0;
952 int length = list_length( value );
953 string buf[ 1 ];
954 LISTITER indices_iter = list_begin( indices );
955 LISTITER const indices_end = list_end( indices );
956 string_new( buf );
957 for ( ; indices_iter != indices_end; indices_iter = list_next( indices_iter
958 ) )
959 {
960 LISTITER iter = list_begin( value );
961 LISTITER end = list_end( value );
962 subscript_t const subscript = parse_subscript( object_str( list_item(
963 indices_iter ) ) );
964 get_iters( subscript, &iter, &end, length );
965 for ( ; iter != end; iter = list_next( iter ) )
966 result = list_push_back( result, object_copy( list_item( iter ) ) );
967 }
968 string_free( buf );
969 return result;
970}
971
972
973/*
974 * Reads the LIST from first and applies subscript to it. The results are
975 * written to *first and *last.
976 */
977
978static void get_iters( subscript_t const subscript, LISTITER * const first,
979 LISTITER * const last, int const length )
980{
981 int start;
982 int size;
983 LISTITER iter;
984 LISTITER end;
985 {
986
987 if ( subscript.sub1 < 0 )
988 start = length + subscript.sub1;
989 else if ( subscript.sub1 > length )
990 start = length;
991 else
992 start = subscript.sub1 - 1;
993
994 size = subscript.sub2 < 0
995 ? length + 1 + subscript.sub2 - start
996 : subscript.sub2 - start;
997
998 /*
999 * HACK: When the first subscript is before the start of the list, it
1000 * magically becomes the beginning of the list. This is inconsistent,
1001 * but needed for backwards compatibility.
1002 */
1003 if ( start < 0 )
1004 start = 0;
1005
1006 /* The "sub2 < 0" test handles the semantic error of sub2 < sub1. */
1007 if ( size < 0 )
1008 size = 0;
1009
1010 if ( start + size > length )
1011 size = length - start;
1012 }
1013
1014 iter = *first;
1015 while ( start-- > 0 )
1016 iter = list_next( iter );
1017
1018 end = iter;
1019 while ( size-- > 0 )
1020 end = list_next( end );
1021
1022 *first = iter;
1023 *last = end;
1024}
1025
1026static LIST * apply_modifiers_empty( LIST * result, string * buf,
1027 VAR_EDITS * edits, int n )
1028{
1029 int i;
1030 for ( i = 0; i < n; ++i )
1031 {
1032 if ( edits[ i ].empty.ptr )
1033 {
1034 /** FIXME: is empty.ptr always null-terminated? */
1035 var_edit_file( edits[ i ].empty.ptr, buf, edits + i );
1036 var_edit_shift( buf, 0, edits + i );
1037 result = list_push_back( result, object_new( buf->value ) );
1038 string_truncate( buf, 0 );
1039 }
1040 }
1041 return result;
1042}
1043
1044static LIST * apply_modifiers_non_empty( LIST * result, string * buf,
1045 VAR_EDITS * edits, int n, LISTITER begin, LISTITER end )
1046{
1047 int i;
1048 LISTITER iter;
1049 for ( i = 0; i < n; ++i )
1050 {
1051 if ( edits[ i ].join.ptr )
1052 {
1053 var_edit_file( object_str( list_item( begin ) ), buf, edits + i );
1054 var_edit_shift( buf, 0, edits + i );
1055 for ( iter = list_next( begin ); iter != end; iter = list_next( iter
1056 ) )
1057 {
1058 size_t size;
1059 string_append( buf, edits[ i ].join.ptr );
1060 size = buf->size;
1061 var_edit_file( object_str( list_item( iter ) ), buf, edits + i
1062 );
1063 var_edit_shift( buf, size, edits + i );
1064 }
1065 result = list_push_back( result, object_new( buf->value ) );
1066 string_truncate( buf, 0 );
1067 }
1068 else
1069 {
1070 for ( iter = begin; iter != end; iter = list_next( iter ) )
1071 {
1072 var_edit_file( object_str( list_item( iter ) ), buf, edits + i );
1073 var_edit_shift( buf, 0, edits + i );
1074 result = list_push_back( result, object_new( buf->value ) );
1075 string_truncate( buf, 0 );
1076 }
1077 }
1078 }
1079 return result;
1080}
1081
1082static LIST * apply_modifiers_impl( LIST * result, string * buf,
1083 VAR_EDITS * edits, int n, LISTITER iter, LISTITER end )
1084{
1085 return iter == end
1086 ? apply_modifiers_empty( result, buf, edits, n )
1087 : apply_modifiers_non_empty( result, buf, edits, n, iter, end );
1088}
1089
1090static LIST * apply_subscript_and_modifiers( STACK * s, int n )
1091{
1092 LIST * const value = stack_top( s );
1093 LIST * const indices = stack_at( s, 1 );
1094 LIST * result = L0;
1095 VAR_EDITS * const edits = (VAR_EDITS *)((LIST * *)stack_get( s ) + 2);
1096 int const length = list_length( value );
1097 string buf[ 1 ];
1098 LISTITER indices_iter = list_begin( indices );
1099 LISTITER const indices_end = list_end( indices );
1100 string_new( buf );
1101 for ( ; indices_iter != indices_end; indices_iter = list_next( indices_iter
1102 ) )
1103 {
1104 LISTITER iter = list_begin( value );
1105 LISTITER end = list_end( value );
1106 subscript_t const sub = parse_subscript( object_str( list_item(
1107 indices_iter ) ) );
1108 get_iters( sub, &iter, &end, length );
1109 result = apply_modifiers_impl( result, buf, edits, n, iter, end );
1110 }
1111 string_free( buf );
1112 return result;
1113}
1114
1115
1116/*
1117 * expand() - expands a list of concatenated strings and variable refereces
1118 *
1119 * Takes a list of expansion items - each representing one element to be
1120 * concatenated and each containing a list of its values. Returns a list of all
1121 * possible values constructed by selecting a single value from each of the
1122 * elements and concatenating them together.
1123 *
1124 * For example, in the following code:
1125 *
1126 * local a = one two three four ;
1127 * local b = foo bar ;
1128 * ECHO /$(a)/$(b)/$(a)/ ;
1129 *
1130 * When constructing the result of /$(a)/$(b)/ this function would get called
1131 * with the following 7 expansion items:
1132 * 1. /
1133 * 2. one two three four
1134 * 3. /
1135 * 4. foo bar
1136 * 5. /
1137 * 6. one two three four
1138 * 7. /
1139 *
1140 * And would result in a list containing 32 values:
1141 * 1. /one/foo/one/
1142 * 2. /one/foo/two/
1143 * 3. /one/foo/three/
1144 * 4. /one/foo/four/
1145 * 5. /one/bar/one/
1146 * ...
1147 *
1148 */
1149
1150typedef struct expansion_item
1151{
1152 /* Item's value list initialized prior to calling expand(). */
1153 LIST * values;
1154
1155 /* Internal data initialized and used inside expand(). */
1156 LISTITER current; /* Currently used value. */
1157 int size; /* Concatenated string length prior to concatenating the
1158 * item's current value.
1159 */
1160} expansion_item;
1161
1162static LIST * expand( expansion_item * items, int const length )
1163{
1164 LIST * result = L0;
1165 string buf[ 1 ];
1166 int size = 0;
1167 int i;
1168
1169 assert( length > 0 );
1170 for ( i = 0; i < length; ++i )
1171 {
1172 LISTITER iter = list_begin( items[ i ].values );
1173 LISTITER const end = list_end( items[ i ].values );
1174
1175 /* If any of the items has no values - the result is an empty list. */
1176 if ( iter == end ) return L0;
1177
1178 /* Set each item's 'current' to its first listed value. This indicates
1179 * each item's next value to be used when constructing the list of all
1180 * possible concatenated values.
1181 */
1182 items[ i ].current = iter;
1183
1184 /* Calculate the longest concatenated string length - to know how much
1185 * memory we need to allocate as a buffer for holding the concatenated
1186 * strings.
1187 */
1188 {
1189 int max = 0;
1190 for ( ; iter != end; iter = list_next( iter ) )
1191 {
1192 int const len = strlen( object_str( list_item( iter ) ) );
1193 if ( len > max ) max = len;
1194 }
1195 size += max;
1196 }
1197 }
1198
1199 string_new( buf );
1200 string_reserve( buf, size );
1201
1202 i = 0;
1203 while ( i >= 0 )
1204 {
1205 for ( ; i < length; ++i )
1206 {
1207 items[ i ].size = buf->size;
1208 string_append( buf, object_str( list_item( items[ i ].current ) ) );
1209 }
1210 result = list_push_back( result, object_new( buf->value ) );
1211 while ( --i >= 0 )
1212 {
1213 if ( list_next( items[ i ].current ) != list_end( items[ i ].values
1214 ) )
1215 {
1216 items[ i ].current = list_next( items[ i ].current );
1217 string_truncate( buf, items[ i ].size );
1218 break;
1219 }
1220 else
1221 items[ i ].current = list_begin( items[ i ].values );
1222 }
1223 }
1224
1225 string_free( buf );
1226 return result;
1227}
1228
1229static void combine_strings( STACK * s, int n, string * out )
1230{
1231 int i;
1232 for ( i = 0; i < n; ++i )
1233 {
1234 LIST * const values = stack_pop( s );
1235 LISTITER iter = list_begin( values );
1236 LISTITER const end = list_end( values );
1237 if ( iter != end )
1238 {
1239 string_append( out, object_str( list_item( iter ) ) );
1240 for ( iter = list_next( iter ); iter != end; iter = list_next( iter
1241 ) )
1242 {
1243 string_push_back( out, ' ' );
1244 string_append( out, object_str( list_item( iter ) ) );
1245 }
1246 list_free( values );
1247 }
1248 }
1249}
1250
1251struct dynamic_array
1252{
1253 int size;
1254 int capacity;
1255 void * data;
1256};
1257
1258static void dynamic_array_init( struct dynamic_array * array )
1259{
1260 array->size = 0;
1261 array->capacity = 0;
1262 array->data = 0;
1263}
1264
1265static void dynamic_array_free( struct dynamic_array * array )
1266{
1267 BJAM_FREE( array->data );
1268}
1269
1270static void dynamic_array_push_impl( struct dynamic_array * const array,
1271 void const * const value, int const unit_size )
1272{
1273 if ( array->capacity == 0 )
1274 {
1275 array->capacity = 2;
1276 array->data = BJAM_MALLOC( array->capacity * unit_size );
1277 }
1278 else if ( array->capacity == array->size )
1279 {
1280 void * new_data;
1281 array->capacity *= 2;
1282 new_data = BJAM_MALLOC( array->capacity * unit_size );
1283 memcpy( new_data, array->data, array->size * unit_size );
1284 BJAM_FREE( array->data );
1285 array->data = new_data;
1286 }
1287 memcpy( (char *)array->data + array->size * unit_size, value, unit_size );
1288 ++array->size;
1289}
1290
1291#define dynamic_array_push( array, value ) (dynamic_array_push_impl(array, &value, sizeof(value)))
1292#define dynamic_array_at( type, array, idx ) (((type *)(array)->data)[idx])
1293#define dynamic_array_pop( array ) (--(array)->size)
1294
1295/*
1296 * struct compiler
1297 */
1298
1299struct label_info
1300{
1301 int absolute_position;
1302 struct dynamic_array uses[ 1 ];
1303};
1304
1305#define LOOP_INFO_BREAK 0
1306#define LOOP_INFO_CONTINUE 1
1307
1308struct loop_info
1309{
1310 int type;
1311 int label;
1312 int cleanup_depth;
1313};
1314
1315struct stored_rule
1316{
1317 OBJECT * name;
1318 PARSE * parse;
1319 int num_arguments;
1320 struct arg_list * arguments;
1321 int local;
1322};
1323
1324typedef struct compiler
1325{
1326 struct dynamic_array code[ 1 ];
1327 struct dynamic_array constants[ 1 ];
1328 struct dynamic_array labels[ 1 ];
1329 struct dynamic_array rules[ 1 ];
1330 struct dynamic_array actions[ 1 ];
1331 struct dynamic_array cleanups[ 1 ];
1332 struct dynamic_array loop_scopes[ 1 ];
1333} compiler;
1334
1335static void compiler_init( compiler * c )
1336{
1337 dynamic_array_init( c->code );
1338 dynamic_array_init( c->constants );
1339 dynamic_array_init( c->labels );
1340 dynamic_array_init( c->rules );
1341 dynamic_array_init( c->actions );
1342 dynamic_array_init( c->cleanups );
1343 dynamic_array_init( c->loop_scopes );
1344}
1345
1346static void compiler_free( compiler * c )
1347{
1348 int i;
1349 dynamic_array_free( c->actions );
1350 dynamic_array_free( c->rules );
1351 for ( i = 0; i < c->labels->size; ++i )
1352 dynamic_array_free( dynamic_array_at( struct label_info, c->labels, i
1353 ).uses );
1354 dynamic_array_free( c->labels );
1355 dynamic_array_free( c->constants );
1356 dynamic_array_free( c->code );
1357 dynamic_array_free( c->cleanups );
1358 dynamic_array_free( c->loop_scopes );
1359}
1360
1361static void compile_emit_instruction( compiler * c, instruction instr )
1362{
1363 dynamic_array_push( c->code, instr );
1364}
1365
1366static int compile_new_label( compiler * c )
1367{
1368 int result = c->labels->size;
1369 struct label_info info;
1370 info.absolute_position = -1;
1371 dynamic_array_init( info.uses );
1372 dynamic_array_push( c->labels, info );
1373 return result;
1374}
1375
1376static void compile_set_label( compiler * c, int label )
1377{
1378 struct label_info * const l = &dynamic_array_at( struct label_info,
1379 c->labels, label );
1380 int const pos = c->code->size;
1381 int i;
1382 assert( l->absolute_position == -1 );
1383 l->absolute_position = pos;
1384 for ( i = 0; i < l->uses->size; ++i )
1385 {
1386 int id = dynamic_array_at( int, l->uses, i );
1387 int offset = (int)( pos - id - 1 );
1388 dynamic_array_at( instruction, c->code, id ).arg = offset;
1389 }
1390}
1391
1392static void compile_emit( compiler * c, unsigned int op_code, int arg )
1393{
1394 instruction instr;
1395 instr.op_code = op_code;
1396 instr.arg = arg;
1397 compile_emit_instruction( c, instr );
1398}
1399
1400static void compile_emit_branch( compiler * c, unsigned int op_code, int label )
1401{
1402 struct label_info * const l = &dynamic_array_at( struct label_info,
1403 c->labels, label );
1404 int const pos = c->code->size;
1405 instruction instr;
1406 instr.op_code = op_code;
1407 if ( l->absolute_position == -1 )
1408 {
1409 instr.arg = 0;
1410 dynamic_array_push( l->uses, pos );
1411 }
1412 else
1413 instr.arg = (int)( l->absolute_position - pos - 1 );
1414 compile_emit_instruction( c, instr );
1415}
1416
1417static int compile_emit_constant( compiler * c, OBJECT * value )
1418{
1419 OBJECT * copy = object_copy( value );
1420 dynamic_array_push( c->constants, copy );
1421 return c->constants->size - 1;
1422}
1423
1424static void compile_push_cleanup( compiler * c, unsigned int op_code, int arg )
1425{
1426 instruction instr;
1427 instr.op_code = op_code;
1428 instr.arg = arg;
1429 dynamic_array_push( c->cleanups, instr );
1430}
1431
1432static void compile_pop_cleanup( compiler * c )
1433{
1434 dynamic_array_pop( c->cleanups );
1435}
1436
1437static void compile_emit_cleanups( compiler * c, int end )
1438{
1439 int i;
1440 for ( i = c->cleanups->size; --i >= end; )
1441 {
1442 compile_emit_instruction( c, dynamic_array_at( instruction, c->cleanups, i ) );
1443 }
1444}
1445
1446static void compile_emit_loop_jump( compiler * c, int type )
1447{
1448 struct loop_info * info = NULL;
1449 int i;
1450 for ( i = c->loop_scopes->size; --i >= 0; )
1451 {
1452 struct loop_info * elem = &dynamic_array_at( struct loop_info, c->loop_scopes, i );
1453 if ( elem->type == type )
1454 {
1455 info = elem;
1456 break;
1457 }
1458 }
1459 if ( info == NULL )
1460 {
1461 printf( "warning: ignoring break statement used outside of loop\n" );
1462 return;
1463 }
1464 compile_emit_cleanups( c, info->cleanup_depth );
1465 compile_emit_branch( c, INSTR_JUMP, info->label );
1466}
1467
1468static void compile_push_break_scope( compiler * c, int label )
1469{
1470 struct loop_info info;
1471 info.type = LOOP_INFO_BREAK;
1472 info.label = label;
1473 info.cleanup_depth = c->cleanups->size;
1474 dynamic_array_push( c->loop_scopes, info );
1475}
1476
1477static void compile_push_continue_scope( compiler * c, int label )
1478{
1479 struct loop_info info;
1480 info.type = LOOP_INFO_CONTINUE;
1481 info.label = label;
1482 info.cleanup_depth = c->cleanups->size;
1483 dynamic_array_push( c->loop_scopes, info );
1484}
1485
1486static void compile_pop_break_scope( compiler * c )
1487{
1488 assert( c->loop_scopes->size > 0 );
1489 assert( dynamic_array_at( struct loop_info, c->loop_scopes, c->loop_scopes->size - 1 ).type == LOOP_INFO_BREAK );
1490 dynamic_array_pop( c->loop_scopes );
1491}
1492
1493static void compile_pop_continue_scope( compiler * c )
1494{
1495 assert( c->loop_scopes->size > 0 );
1496 assert( dynamic_array_at( struct loop_info, c->loop_scopes, c->loop_scopes->size - 1 ).type == LOOP_INFO_CONTINUE );
1497 dynamic_array_pop( c->loop_scopes );
1498}
1499
1500static int compile_emit_rule( compiler * c, OBJECT * name, PARSE * parse,
1501 int num_arguments, struct arg_list * arguments, int local )
1502{
1503 struct stored_rule rule;
1504 rule.name = object_copy( name );
1505 rule.parse = parse;
1506 rule.num_arguments = num_arguments;
1507 rule.arguments = arguments;
1508 rule.local = local;
1509 dynamic_array_push( c->rules, rule );
1510 return (int)( c->rules->size - 1 );
1511}
1512
1513static int compile_emit_actions( compiler * c, PARSE * parse )
1514{
1515 SUBACTION a;
1516 a.name = object_copy( parse->string );
1517 a.command = function_compile_actions( object_str( parse->string1 ),
1518 parse->file, parse->line );
1519 a.flags = parse->num;
1520 dynamic_array_push( c->actions, a );
1521 return (int)( c->actions->size - 1 );
1522}
1523
1524static JAM_FUNCTION * compile_to_function( compiler * c )
1525{
1526 JAM_FUNCTION * const result = BJAM_MALLOC( sizeof( JAM_FUNCTION ) );
1527 int i;
1528 result->base.type = FUNCTION_JAM;
1529 result->base.reference_count = 1;
1530 result->base.formal_arguments = 0;
1531 result->base.num_formal_arguments = 0;
1532
1533 result->base.rulename = 0;
1534
1535 result->code_size = c->code->size;
1536 result->code = BJAM_MALLOC( c->code->size * sizeof( instruction ) );
1537 memcpy( result->code, c->code->data, c->code->size * sizeof( instruction ) );
1538
1539 result->constants = BJAM_MALLOC( c->constants->size * sizeof( OBJECT * ) );
1540 memcpy( result->constants, c->constants->data, c->constants->size * sizeof(
1541 OBJECT * ) );
1542 result->num_constants = c->constants->size;
1543
1544 result->num_subfunctions = c->rules->size;
1545 result->functions = BJAM_MALLOC( c->rules->size * sizeof( SUBFUNCTION ) );
1546 for ( i = 0; i < c->rules->size; ++i )
1547 {
1548 struct stored_rule * const rule = &dynamic_array_at( struct stored_rule,
1549 c->rules, i );
1550 result->functions[ i ].name = rule->name;
1551 result->functions[ i ].code = function_compile( rule->parse );
1552 result->functions[ i ].code->num_formal_arguments = rule->num_arguments;
1553 result->functions[ i ].code->formal_arguments = rule->arguments;
1554 result->functions[ i ].local = rule->local;
1555 }
1556
1557 result->actions = BJAM_MALLOC( c->actions->size * sizeof( SUBACTION ) );
1558 memcpy( result->actions, c->actions->data, c->actions->size * sizeof(
1559 SUBACTION ) );
1560 result->num_subactions = c->actions->size;
1561
1562 result->generic = 0;
1563
1564 result->file = 0;
1565 result->line = -1;
1566
1567 return result;
1568}
1569
1570
1571/*
1572 * Parsing of variable expansions
1573 */
1574
1575typedef struct VAR_PARSE_GROUP
1576{
1577 struct dynamic_array elems[ 1 ];
1578} VAR_PARSE_GROUP;
1579
1580typedef struct VAR_PARSE_ACTIONS
1581{
1582 struct dynamic_array elems[ 1 ];
1583} VAR_PARSE_ACTIONS;
1584
1585#define VAR_PARSE_TYPE_VAR 0
1586#define VAR_PARSE_TYPE_STRING 1
1587#define VAR_PARSE_TYPE_FILE 2
1588
1589typedef struct _var_parse
1590{
1591 int type; /* string, variable or file */
1592} VAR_PARSE;
1593
1594typedef struct
1595{
1596 VAR_PARSE base;
1597 VAR_PARSE_GROUP * name;
1598 VAR_PARSE_GROUP * subscript;
1599 struct dynamic_array modifiers[ 1 ];
1600} VAR_PARSE_VAR;
1601
1602typedef struct
1603{
1604 VAR_PARSE base;
1605 OBJECT * s;
1606} VAR_PARSE_STRING;
1607
1608typedef struct
1609{
1610 VAR_PARSE base;
1611 struct dynamic_array filename[ 1 ];
1612 struct dynamic_array contents[ 1 ];
1613} VAR_PARSE_FILE;
1614
1615static void var_parse_free( VAR_PARSE * );
1616
1617
1618/*
1619 * VAR_PARSE_GROUP
1620 */
1621
1622static VAR_PARSE_GROUP * var_parse_group_new()
1623{
1624 VAR_PARSE_GROUP * const result = BJAM_MALLOC( sizeof( VAR_PARSE_GROUP ) );
1625 dynamic_array_init( result->elems );
1626 return result;
1627}
1628
1629static void var_parse_group_free( VAR_PARSE_GROUP * group )
1630{
1631 int i;
1632 for ( i = 0; i < group->elems->size; ++i )
1633 var_parse_free( dynamic_array_at( VAR_PARSE *, group->elems, i ) );
1634 dynamic_array_free( group->elems );
1635 BJAM_FREE( group );
1636}
1637
1638static void var_parse_group_add( VAR_PARSE_GROUP * group, VAR_PARSE * elem )
1639{
1640 dynamic_array_push( group->elems, elem );
1641}
1642
1643static void var_parse_group_maybe_add_constant( VAR_PARSE_GROUP * group,
1644 char const * start, char const * end )
1645{
1646 if ( start != end )
1647 {
1648 string buf[ 1 ];
1649 VAR_PARSE_STRING * const value = (VAR_PARSE_STRING *)BJAM_MALLOC(
1650 sizeof(VAR_PARSE_STRING) );
1651 value->base.type = VAR_PARSE_TYPE_STRING;
1652 string_new( buf );
1653 string_append_range( buf, start, end );
1654 value->s = object_new( buf->value );
1655 string_free( buf );
1656 var_parse_group_add( group, (VAR_PARSE *)value );
1657 }
1658}
1659
1660VAR_PARSE_STRING * var_parse_group_as_literal( VAR_PARSE_GROUP * group )
1661{
1662 if ( group->elems->size == 1 )
1663 {
1664 VAR_PARSE * result = dynamic_array_at( VAR_PARSE *, group->elems, 0 );
1665 if ( result->type == VAR_PARSE_TYPE_STRING )
1666 return (VAR_PARSE_STRING *)result;
1667 }
1668 return 0;
1669}
1670
1671
1672/*
1673 * VAR_PARSE_ACTIONS
1674 */
1675
1676static VAR_PARSE_ACTIONS * var_parse_actions_new()
1677{
1678 VAR_PARSE_ACTIONS * const result = (VAR_PARSE_ACTIONS *)BJAM_MALLOC(
1679 sizeof(VAR_PARSE_ACTIONS) );
1680 dynamic_array_init( result->elems );
1681 return result;
1682}
1683
1684static void var_parse_actions_free( VAR_PARSE_ACTIONS * actions )
1685{
1686 int i;
1687 for ( i = 0; i < actions->elems->size; ++i )
1688 var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *,
1689 actions->elems, i ) );
1690 dynamic_array_free( actions->elems );
1691 BJAM_FREE( actions );
1692}
1693
1694
1695/*
1696 * VAR_PARSE_VAR
1697 */
1698
1699static VAR_PARSE_VAR * var_parse_var_new()
1700{
1701 VAR_PARSE_VAR * result = BJAM_MALLOC( sizeof( VAR_PARSE_VAR ) );
1702 result->base.type = VAR_PARSE_TYPE_VAR;
1703 result->name = var_parse_group_new();
1704 result->subscript = 0;
1705 dynamic_array_init( result->modifiers );
1706 return result;
1707}
1708
1709static void var_parse_var_free( VAR_PARSE_VAR * var )
1710{
1711 int i;
1712 var_parse_group_free( var->name );
1713 if ( var->subscript )
1714 var_parse_group_free( var->subscript );
1715 for ( i = 0; i < var->modifiers->size; ++i )
1716 var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *,
1717 var->modifiers, i ) );
1718 dynamic_array_free( var->modifiers );
1719 BJAM_FREE( var );
1720}
1721
1722static VAR_PARSE_GROUP * var_parse_var_new_modifier( VAR_PARSE_VAR * var )
1723{
1724 VAR_PARSE_GROUP * result = var_parse_group_new();
1725 dynamic_array_push( var->modifiers, result );
1726 return result;
1727}
1728
1729
1730/*
1731 * VAR_PARSE_STRING
1732 */
1733
1734static void var_parse_string_free( VAR_PARSE_STRING * string )
1735{
1736 object_free( string->s );
1737 BJAM_FREE( string );
1738}
1739
1740
1741/*
1742 * VAR_PARSE_FILE
1743 */
1744
1745static VAR_PARSE_FILE * var_parse_file_new( void )
1746{
1747 VAR_PARSE_FILE * const result = (VAR_PARSE_FILE *)BJAM_MALLOC( sizeof(
1748 VAR_PARSE_FILE ) );
1749 result->base.type = VAR_PARSE_TYPE_FILE;
1750 dynamic_array_init( result->filename );
1751 dynamic_array_init( result->contents );
1752 return result;
1753}
1754
1755static void var_parse_file_free( VAR_PARSE_FILE * file )
1756{
1757 int i;
1758 for ( i = 0; i < file->filename->size; ++i )
1759 var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *,
1760 file->filename, i ) );
1761 dynamic_array_free( file->filename );
1762 for ( i = 0; i < file->contents->size; ++i )
1763 var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *,
1764 file->contents, i ) );
1765 dynamic_array_free( file->contents );
1766 BJAM_FREE( file );
1767}
1768
1769
1770/*
1771 * VAR_PARSE
1772 */
1773
1774static void var_parse_free( VAR_PARSE * parse )
1775{
1776 switch ( parse->type )
1777 {
1778 case VAR_PARSE_TYPE_VAR:
1779 var_parse_var_free( (VAR_PARSE_VAR *)parse );
1780 break;
1781
1782 case VAR_PARSE_TYPE_STRING:
1783 var_parse_string_free( (VAR_PARSE_STRING *)parse );
1784 break;
1785
1786 case VAR_PARSE_TYPE_FILE:
1787 var_parse_file_free( (VAR_PARSE_FILE *)parse );
1788 break;
1789
1790 default:
1791 assert( !"Invalid type" );
1792 }
1793}
1794
1795
1796/*
1797 * Compile VAR_PARSE
1798 */
1799
1800static void var_parse_group_compile( VAR_PARSE_GROUP const * parse,
1801 compiler * c );
1802
1803static void var_parse_var_compile( VAR_PARSE_VAR const * parse, compiler * c )
1804{
1805 int expand_name = 0;
1806 int is_get_grist = 0;
1807 int has_modifiers = 0;
1808 /* Special case common modifiers */
1809 if ( parse->modifiers->size == 1 )
1810 {
1811 VAR_PARSE_GROUP * mod = dynamic_array_at( VAR_PARSE_GROUP *, parse->modifiers, 0 );
1812 if ( mod->elems->size == 1 )
1813 {
1814 VAR_PARSE * mod1 = dynamic_array_at( VAR_PARSE *, mod->elems, 0 );
1815 if ( mod1->type == VAR_PARSE_TYPE_STRING )
1816 {
1817 OBJECT * s = ( (VAR_PARSE_STRING *)mod1 )->s;
1818 if ( ! strcmp ( object_str( s ), "G" ) )
1819 {
1820 is_get_grist = 1;
1821 }
1822 }
1823 }
1824 }
1825 /* If there are modifiers, emit them in reverse order. */
1826 if ( parse->modifiers->size > 0 && !is_get_grist )
1827 {
1828 int i;
1829 has_modifiers = 1;
1830 for ( i = 0; i < parse->modifiers->size; ++i )
1831 var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *,
1832 parse->modifiers, parse->modifiers->size - i - 1 ), c );
1833 }
1834
1835 /* If there is a subscript, emit it. */
1836 if ( parse->subscript )
1837 var_parse_group_compile( parse->subscript, c );
1838
1839 /* If the variable name is empty, look it up. */
1840 if ( parse->name->elems->size == 0 )
1841 compile_emit( c, INSTR_PUSH_VAR, compile_emit_constant( c,
1842 constant_empty ) );
1843 /* If the variable name does not need to be expanded, look it up. */
1844 else if ( parse->name->elems->size == 1 && dynamic_array_at( VAR_PARSE *,
1845 parse->name->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
1846 {
1847 OBJECT * const name = ( (VAR_PARSE_STRING *)dynamic_array_at(
1848 VAR_PARSE *, parse->name->elems, 0 ) )->s;
1849 int const idx = get_argument_index( object_str( name ) );
1850 if ( idx != -1 )
1851 compile_emit( c, INSTR_PUSH_ARG, idx );
1852 else
1853 compile_emit( c, INSTR_PUSH_VAR, compile_emit_constant( c, name ) );
1854 }
1855 /* Otherwise, push the var names and use the group instruction. */
1856 else
1857 {
1858 var_parse_group_compile( parse->name, c );
1859 expand_name = 1;
1860 }
1861
1862 /** Select the instruction for expanding the variable. */
1863 if ( !has_modifiers && !parse->subscript && !expand_name )
1864 ;
1865 else if ( !has_modifiers && !parse->subscript && expand_name )
1866 compile_emit( c, INSTR_PUSH_GROUP, 0 );
1867 else if ( !has_modifiers && parse->subscript && !expand_name )
1868 compile_emit( c, INSTR_APPLY_INDEX, 0 );
1869 else if ( !has_modifiers && parse->subscript && expand_name )
1870 compile_emit( c, INSTR_APPLY_INDEX_GROUP, 0 );
1871 else if ( has_modifiers && !parse->subscript && !expand_name )
1872 compile_emit( c, INSTR_APPLY_MODIFIERS, parse->modifiers->size );
1873 else if ( has_modifiers && !parse->subscript && expand_name )
1874 compile_emit( c, INSTR_APPLY_MODIFIERS_GROUP, parse->modifiers->size );
1875 else if ( has_modifiers && parse->subscript && !expand_name )
1876 compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS, parse->modifiers->size );
1877 else if ( has_modifiers && parse->subscript && expand_name )
1878 compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS_GROUP,
1879 parse->modifiers->size );
1880
1881 /* Now apply any special modifiers */
1882 if ( is_get_grist )
1883 {
1884 compile_emit( c, INSTR_GET_GRIST, 0 );
1885 }
1886}
1887
1888static void var_parse_string_compile( VAR_PARSE_STRING const * parse,
1889 compiler * c )
1890{
1891 compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, parse->s )
1892 );
1893}
1894
1895static void var_parse_file_compile( VAR_PARSE_FILE const * parse, compiler * c )
1896{
1897 int i;
1898 for ( i = 0; i < parse->filename->size; ++i )
1899 var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *,
1900 parse->filename, parse->filename->size - i - 1 ), c );
1901 compile_emit( c, INSTR_APPEND_STRINGS, parse->filename->size );
1902 for ( i = 0; i < parse->contents->size; ++i )
1903 var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *,
1904 parse->contents, parse->contents->size - i - 1 ), c );
1905 compile_emit( c, INSTR_WRITE_FILE, parse->contents->size );
1906}
1907
1908static void var_parse_compile( VAR_PARSE const * parse, compiler * c )
1909{
1910 switch ( parse->type )
1911 {
1912 case VAR_PARSE_TYPE_VAR:
1913 var_parse_var_compile( (VAR_PARSE_VAR const *)parse, c );
1914 break;
1915
1916 case VAR_PARSE_TYPE_STRING:
1917 var_parse_string_compile( (VAR_PARSE_STRING const *)parse, c );
1918 break;
1919
1920 case VAR_PARSE_TYPE_FILE:
1921 var_parse_file_compile( (VAR_PARSE_FILE const *)parse, c );
1922 break;
1923
1924 default:
1925 assert( !"Unknown var parse type." );
1926 }
1927}
1928
1929static void var_parse_group_compile( VAR_PARSE_GROUP const * parse, compiler * c
1930 )
1931{
1932 /* Emit the elements in reverse order. */
1933 int i;
1934 for ( i = 0; i < parse->elems->size; ++i )
1935 var_parse_compile( dynamic_array_at( VAR_PARSE *, parse->elems,
1936 parse->elems->size - i - 1 ), c );
1937 /* If there are no elements, emit an empty string. */
1938 if ( parse->elems->size == 0 )
1939 compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c,
1940 constant_empty ) );
1941 /* If there is more than one element, combine them. */
1942 if ( parse->elems->size > 1 )
1943 compile_emit( c, INSTR_COMBINE_STRINGS, parse->elems->size );
1944}
1945
1946static void var_parse_actions_compile( VAR_PARSE_ACTIONS const * actions,
1947 compiler * c )
1948{
1949 int i;
1950 for ( i = 0; i < actions->elems->size; ++i )
1951 var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *,
1952 actions->elems, actions->elems->size - i - 1 ), c );
1953 compile_emit( c, INSTR_OUTPUT_STRINGS, actions->elems->size );
1954}
1955
1956
1957/*
1958 * Parse VAR_PARSE_VAR
1959 */
1960
1961static VAR_PARSE * parse_at_file( char const * start, char const * mid,
1962 char const * end );
1963static VAR_PARSE * parse_variable( char const * * string );
1964static int try_parse_variable( char const * * s_, char const * * string,
1965 VAR_PARSE_GROUP * out );
1966static void balance_parentheses( char const * * s_, char const * * string,
1967 VAR_PARSE_GROUP * out );
1968static void parse_var_string( char const * first, char const * last,
1969 struct dynamic_array * out );
1970
1971
1972/*
1973 * Parses a string that can contain variables to expand.
1974 */
1975
1976static VAR_PARSE_GROUP * parse_expansion( char const * * string )
1977{
1978 VAR_PARSE_GROUP * result = var_parse_group_new();
1979 char const * s = *string;
1980 for ( ; ; )
1981 {
1982 if ( try_parse_variable( &s, string, result ) ) {}
1983 else if ( s[ 0 ] == '\0' )
1984 {
1985 var_parse_group_maybe_add_constant( result, *string, s );
1986 return result;
1987 }
1988 else
1989 ++s;
1990 }
1991}
1992
1993static VAR_PARSE_ACTIONS * parse_actions( char const * string )
1994{
1995 VAR_PARSE_ACTIONS * const result = var_parse_actions_new();
1996 parse_var_string( string, string + strlen( string ), result->elems );
1997 return result;
1998}
1999
2000/*
2001 * Checks whether the string a *s_ starts with a variable expansion "$(".
2002 * *string should point to the first unemitted character before *s. If *s_
2003 * starts with variable expansion, appends elements to out up to the closing
2004 * ")", and adjusts *s_ and *string to point to next character. Returns 1 if s_
2005 * starts with a variable, 0 otherwise.
2006 */
2007
2008static int try_parse_variable( char const * * s_, char const * * string,
2009 VAR_PARSE_GROUP * out )
2010{
2011 char const * s = *s_;
2012 if ( s[ 0 ] == '$' && s[ 1 ] == '(' )
2013 {
2014 var_parse_group_maybe_add_constant( out, *string, s );
2015 s += 2;
2016 var_parse_group_add( out, parse_variable( &s ) );
2017 *string = s;
2018 *s_ = s;
2019 return 1;
2020 }
2021 if ( s[ 0 ] == '@' && s[ 1 ] == '(' )
2022 {
2023 int depth = 1;
2024 char const * ine;
2025 char const * split = 0;
2026 var_parse_group_maybe_add_constant( out, *string, s );
2027 s += 2;
2028 ine = s;
2029
2030 /* Scan the content of the response file @() section. */
2031 while ( *ine && ( depth > 0 ) )
2032 {
2033 switch ( *ine )
2034 {
2035 case '(': ++depth; break;
2036 case ')': --depth; break;
2037 case ':':
2038 if ( ( depth == 1 ) && ( ine[ 1 ] == 'E' ) && ( ine[ 2 ] == '='
2039 ) )
2040 split = ine;
2041 break;
2042 }
2043 ++ine;
2044 }
2045
2046 if ( !split || depth )
2047 return 0;
2048
2049 var_parse_group_add( out, parse_at_file( s, split, ine - 1 ) );
2050 *string = ine;
2051 *s_ = ine;
2052 return 1;
2053 }
2054 return 0;
2055}
2056
2057
2058static char const * current_file = "";
2059static int current_line;
2060
2061static void parse_error( char const * message )
2062{
2063 out_printf( "%s:%d: %s\n", current_file, current_line, message );
2064}
2065
2066
2067/*
2068 * Parses a single variable up to the closing ")" and adjusts *string to point
2069 * to the next character. *string should point to the character immediately
2070 * after the initial "$(".
2071 */
2072
2073static VAR_PARSE * parse_variable( char const * * string )
2074{
2075 VAR_PARSE_VAR * const result = var_parse_var_new();
2076 VAR_PARSE_GROUP * const name = result->name;
2077 char const * s = *string;
2078 for ( ; ; )
2079 {
2080 if ( try_parse_variable( &s, string, name ) ) {}
2081 else if ( s[ 0 ] == ':' )
2082 {
2083 VAR_PARSE_GROUP * mod;
2084 var_parse_group_maybe_add_constant( name, *string, s );
2085 ++s;
2086 *string = s;
2087 mod = var_parse_var_new_modifier( result );
2088 for ( ; ; )
2089 {
2090 if ( try_parse_variable( &s, string, mod ) ) {}
2091 else if ( s[ 0 ] == ')' )
2092 {
2093 var_parse_group_maybe_add_constant( mod, *string, s );
2094 *string = ++s;
2095 return (VAR_PARSE *)result;
2096 }
2097 else if ( s[ 0 ] == '(' )
2098 {
2099 ++s;
2100 balance_parentheses( &s, string, mod );
2101 }
2102 else if ( s[ 0 ] == ':' )
2103 {
2104 var_parse_group_maybe_add_constant( mod, *string, s );
2105 *string = ++s;
2106 mod = var_parse_var_new_modifier( result );
2107 }
2108 else if ( s[ 0 ] == '[' )
2109 {
2110 parse_error("unexpected subscript");
2111 ++s;
2112 }
2113 else if ( s[ 0 ] == '\0' )
2114 {
2115 parse_error( "unbalanced parentheses" );
2116 var_parse_group_maybe_add_constant( mod, *string, s );
2117 *string = s;
2118 return (VAR_PARSE *)result;
2119 }
2120 else
2121 ++s;
2122 }
2123 }
2124 else if ( s[ 0 ] == '[' )
2125 {
2126 VAR_PARSE_GROUP * subscript = var_parse_group_new();
2127 result->subscript = subscript;
2128 var_parse_group_maybe_add_constant( name, *string, s );
2129 *string = ++s;
2130 for ( ; ; )
2131 {
2132 if ( try_parse_variable( &s, string, subscript ) ) {}
2133 else if ( s[ 0 ] == ']' )
2134 {
2135 var_parse_group_maybe_add_constant( subscript, *string, s );
2136 *string = ++s;
2137 if ( s[ 0 ] != ')' && s[ 0 ] != ':' && s[ 0 ] != '\0' )
2138 parse_error( "unexpected text following []" );
2139 break;
2140 }
2141 else if ( isdigit( s[ 0 ] ) || s[ 0 ] == '-' )
2142 {
2143 ++s;
2144 }
2145 else if ( s[ 0 ] == '\0' )
2146 {
2147 parse_error( "malformed subscript" );
2148 break;
2149 }
2150 else
2151 {
2152 parse_error( "malformed subscript" );
2153 ++s;
2154 }
2155 }
2156 }
2157 else if ( s[ 0 ] == ')' )
2158 {
2159 var_parse_group_maybe_add_constant( name, *string, s );
2160 *string = ++s;
2161 return (VAR_PARSE *)result;
2162 }
2163 else if ( s[ 0 ] == '(' )
2164 {
2165 ++s;
2166 balance_parentheses( &s, string, name );
2167 }
2168 else if ( s[ 0 ] == '\0' )
2169 {
2170 parse_error( "unbalanced parentheses" );
2171 var_parse_group_maybe_add_constant( name, *string, s );
2172 *string = s;
2173 return (VAR_PARSE *)result;
2174 }
2175 else
2176 ++s;
2177 }
2178}
2179
2180static void parse_var_string( char const * first, char const * last,
2181 struct dynamic_array * out )
2182{
2183 char const * saved = first;
2184 while ( first != last )
2185 {
2186 /* Handle whitespace. */
2187 while ( first != last && isspace( *first ) ) ++first;
2188 if ( saved != first )
2189 {
2190 VAR_PARSE_GROUP * const group = var_parse_group_new();
2191 var_parse_group_maybe_add_constant( group, saved, first );
2192 saved = first;
2193 dynamic_array_push( out, group );
2194 }
2195 if ( first == last ) break;
2196
2197 /* Handle non-whitespace */
2198 {
2199 VAR_PARSE_GROUP * group = var_parse_group_new();
2200 for ( ; ; )
2201 {
2202 if ( first == last || isspace( *first ) )
2203 {
2204 var_parse_group_maybe_add_constant( group, saved, first );
2205 saved = first;
2206 break;
2207 }
2208 if ( try_parse_variable( &first, &saved, group ) )
2209 assert( first <= last );
2210 else
2211 ++first;
2212 }
2213 dynamic_array_push( out, group );
2214 }
2215 }
2216}
2217
2218/*
2219 * start should point to the character immediately following the opening "@(",
2220 * mid should point to the ":E=", and end should point to the closing ")".
2221 */
2222
2223static VAR_PARSE * parse_at_file( char const * start, char const * mid,
2224 char const * end )
2225{
2226 VAR_PARSE_FILE * result = var_parse_file_new();
2227 parse_var_string( start, mid, result->filename );
2228 parse_var_string( mid + 3, end, result->contents );
2229 return (VAR_PARSE *)result;
2230}
2231
2232/*
2233 * Given that *s_ points to the character after a "(", parses up to the matching
2234 * ")". *string should point to the first unemitted character before *s_.
2235 *
2236 * When the function returns, *s_ will point to the character after the ")", and
2237 * *string will point to the first unemitted character before *s_. The range
2238 * from *string to *s_ does not contain any variables that need to be expanded.
2239 */
2240
2241void balance_parentheses( char const * * s_, char const * * string,
2242 VAR_PARSE_GROUP * out)
2243{
2244 int depth = 1;
2245 char const * s = *s_;
2246 for ( ; ; )
2247 {
2248 if ( try_parse_variable( &s, string, out ) ) { }
2249 else if ( s[ 0 ] == ':' || s[ 0 ] == '[' )
2250 {
2251 parse_error( "unbalanced parentheses" );
2252 ++s;
2253 }
2254 else if ( s[ 0 ] == '\0' )
2255 {
2256 parse_error( "unbalanced parentheses" );
2257 break;
2258 }
2259 else if ( s[ 0 ] == ')' )
2260 {
2261 ++s;
2262 if ( --depth == 0 ) break;
2263 }
2264 else if ( s[ 0 ] == '(' )
2265 {
2266 ++depth;
2267 ++s;
2268 }
2269 else
2270 ++s;
2271 }
2272 *s_ = s;
2273}
2274
2275
2276/*
2277 * Main compile.
2278 */
2279
2280#define RESULT_STACK 0
2281#define RESULT_RETURN 1
2282#define RESULT_NONE 2
2283
2284static void compile_parse( PARSE * parse, compiler * c, int result_location );
2285static struct arg_list * arg_list_compile( PARSE * parse, int * num_arguments );
2286
2287static void compile_condition( PARSE * parse, compiler * c, int branch_true, int label )
2288{
2289 assert( parse->type == PARSE_EVAL );
2290 switch ( parse->num )
2291 {
2292 case EXPR_EXISTS:
2293 compile_parse( parse->left, c, RESULT_STACK );
2294 if ( branch_true )
2295 compile_emit_branch( c, INSTR_JUMP_NOT_EMPTY, label );
2296 else
2297 compile_emit_branch( c, INSTR_JUMP_EMPTY, label );
2298 break;
2299
2300 case EXPR_EQUALS:
2301 compile_parse( parse->left, c, RESULT_STACK );
2302 compile_parse( parse->right, c, RESULT_STACK );
2303 if ( branch_true )
2304 compile_emit_branch( c, INSTR_JUMP_EQ, label );
2305 else
2306 compile_emit_branch( c, INSTR_JUMP_NE, label );
2307 break;
2308
2309 case EXPR_NOTEQ:
2310 compile_parse( parse->left, c, RESULT_STACK );
2311 compile_parse( parse->right, c, RESULT_STACK );
2312 if ( branch_true )
2313 compile_emit_branch( c, INSTR_JUMP_NE, label );
2314 else
2315 compile_emit_branch( c, INSTR_JUMP_EQ, label );
2316 break;
2317
2318 case EXPR_LESS:
2319 compile_parse( parse->left, c, RESULT_STACK );
2320 compile_parse( parse->right, c, RESULT_STACK );
2321 if ( branch_true )
2322 compile_emit_branch( c, INSTR_JUMP_LT, label );
2323 else
2324 compile_emit_branch( c, INSTR_JUMP_GE, label );
2325 break;
2326
2327 case EXPR_LESSEQ:
2328 compile_parse( parse->left, c, RESULT_STACK );
2329 compile_parse( parse->right, c, RESULT_STACK );
2330 if ( branch_true )
2331 compile_emit_branch( c, INSTR_JUMP_LE, label );
2332 else
2333 compile_emit_branch( c, INSTR_JUMP_GT, label );
2334 break;
2335
2336 case EXPR_MORE:
2337 compile_parse( parse->left, c, RESULT_STACK );
2338 compile_parse( parse->right, c, RESULT_STACK );
2339 if ( branch_true )
2340 compile_emit_branch( c, INSTR_JUMP_GT, label );
2341 else
2342 compile_emit_branch( c, INSTR_JUMP_LE, label );
2343 break;
2344
2345 case EXPR_MOREEQ:
2346 compile_parse( parse->left, c, RESULT_STACK );
2347 compile_parse( parse->right, c, RESULT_STACK );
2348 if ( branch_true )
2349 compile_emit_branch( c, INSTR_JUMP_GE, label );
2350 else
2351 compile_emit_branch( c, INSTR_JUMP_LT, label );
2352 break;
2353
2354 case EXPR_IN:
2355 compile_parse( parse->left, c, RESULT_STACK );
2356 compile_parse( parse->right, c, RESULT_STACK );
2357 if ( branch_true )
2358 compile_emit_branch( c, INSTR_JUMP_IN, label );
2359 else
2360 compile_emit_branch( c, INSTR_JUMP_NOT_IN, label );
2361 break;
2362
2363 case EXPR_AND:
2364 if ( branch_true )
2365 {
2366 int f = compile_new_label( c );
2367 compile_condition( parse->left, c, 0, f );
2368 compile_condition( parse->right, c, 1, label );
2369 compile_set_label( c, f );
2370 }
2371 else
2372 {
2373 compile_condition( parse->left, c, 0, label );
2374 compile_condition( parse->right, c, 0, label );
2375 }
2376 break;
2377
2378 case EXPR_OR:
2379 if ( branch_true )
2380 {
2381 compile_condition( parse->left, c, 1, label );
2382 compile_condition( parse->right, c, 1, label );
2383 }
2384 else
2385 {
2386 int t = compile_new_label( c );
2387 compile_condition( parse->left, c, 1, t );
2388 compile_condition( parse->right, c, 0, label );
2389 compile_set_label( c, t );
2390 }
2391 break;
2392
2393 case EXPR_NOT:
2394 compile_condition( parse->left, c, !branch_true, label );
2395 break;
2396 }
2397}
2398
2399static void adjust_result( compiler * c, int actual_location,
2400 int desired_location )
2401{
2402 if ( actual_location == desired_location )
2403 ;
2404 else if ( actual_location == RESULT_STACK && desired_location == RESULT_RETURN )
2405 compile_emit( c, INSTR_SET_RESULT, 0 );
2406 else if ( actual_location == RESULT_STACK && desired_location == RESULT_NONE )
2407 compile_emit( c, INSTR_POP, 0 );
2408 else if ( actual_location == RESULT_RETURN && desired_location == RESULT_STACK )
2409 compile_emit( c, INSTR_PUSH_RESULT, 0 );
2410 else if ( actual_location == RESULT_RETURN && desired_location == RESULT_NONE )
2411 ;
2412 else if ( actual_location == RESULT_NONE && desired_location == RESULT_STACK )
2413 compile_emit( c, INSTR_PUSH_EMPTY, 0 );
2414 else if ( actual_location == RESULT_NONE && desired_location == RESULT_RETURN )
2415 {
2416 compile_emit( c, INSTR_PUSH_EMPTY, 0 );
2417 compile_emit( c, INSTR_SET_RESULT, 0 );
2418 }
2419 else
2420 assert( !"invalid result location" );
2421}
2422
2423static char const * parse_type( PARSE * parse )
2424{
2425 switch ( parse->type )
2426 {
2427 case PARSE_APPEND: return "append";
2428 case PARSE_EVAL: return "eval";
2429 case PARSE_RULES: return "rules";
2430 default: return "unknown";
2431 }
2432}
2433
2434static void compile_append_chain( PARSE * parse, compiler * c )
2435{
2436 assert( parse->type == PARSE_APPEND );
2437 if ( parse->left->type == PARSE_NULL )
2438 compile_parse( parse->right, c, RESULT_STACK );
2439 else
2440 {
2441 if ( parse->left->type == PARSE_APPEND )
2442 compile_append_chain( parse->left, c );
2443 else
2444 compile_parse( parse->left, c, RESULT_STACK );
2445 compile_parse( parse->right, c, RESULT_STACK );
2446 compile_emit( c, INSTR_PUSH_APPEND, 0 );
2447 }
2448}
2449
11fdf7f2 2450static void compile_emit_debug(compiler * c, int line)
7c673cae 2451{
b32b8144
FG
2452#ifdef JAM_DEBUGGER
2453 if ( debug_is_debugging() )
11fdf7f2 2454 compile_emit( c, INSTR_DEBUG_LINE, line );
b32b8144 2455#endif
11fdf7f2
TL
2456}
2457
2458static void compile_parse( PARSE * parse, compiler * c, int result_location )
2459{
2460 compile_emit_debug(c, parse->line);
7c673cae
FG
2461 if ( parse->type == PARSE_APPEND )
2462 {
2463 compile_append_chain( parse, c );
2464 adjust_result( c, RESULT_STACK, result_location );
2465 }
2466 else if ( parse->type == PARSE_EVAL )
2467 {
2468 /* FIXME: This is only needed because of the bizarre parsing of
2469 * conditions.
2470 */
2471 if ( parse->num == EXPR_EXISTS )
2472 compile_parse( parse->left, c, result_location );
2473 else
2474 {
2475 int f = compile_new_label( c );
2476 int end = compile_new_label( c );
2477
2478 out_printf( "%s:%d: Conditional used as list (check operator "
2479 "precedence).\n", object_str( parse->file ), parse->line );
2480
2481 /* Emit the condition */
2482 compile_condition( parse, c, 0, f );
2483 compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c,
2484 constant_true ) );
2485 compile_emit_branch( c, INSTR_JUMP, end );
2486 compile_set_label( c, f );
2487 compile_emit( c, INSTR_PUSH_EMPTY, 0 );
2488 compile_set_label( c, end );
2489 adjust_result( c, RESULT_STACK, result_location );
2490 }
2491 }
2492 else if ( parse->type == PARSE_FOREACH )
2493 {
2494 int var = compile_emit_constant( c, parse->string );
2495 int top = compile_new_label( c );
2496 int end = compile_new_label( c );
2497 int continue_ = compile_new_label( c );
2498
2499 /*
2500 * Evaluate the list.
2501 */
2502 compile_parse( parse->left, c, RESULT_STACK );
2503
2504 /* Localize the loop variable */
2505 if ( parse->num )
2506 {
2507 compile_emit( c, INSTR_PUSH_EMPTY, 0 );
2508 compile_emit( c, INSTR_PUSH_LOCAL, var );
2509 compile_emit( c, INSTR_SWAP, 1 );
2510 compile_push_cleanup( c, INSTR_POP_LOCAL, var );
2511 }
2512
2513 compile_emit( c, INSTR_FOR_INIT, 0 );
2514 compile_set_label( c, top );
2515 compile_emit_branch( c, INSTR_FOR_LOOP, end );
11fdf7f2 2516 compile_emit_debug( c, parse->line );
7c673cae
FG
2517 compile_emit( c, INSTR_SET, var );
2518
2519 compile_push_break_scope( c, end );
2520 compile_push_cleanup( c, INSTR_FOR_POP, 0 );
2521 compile_push_continue_scope( c, continue_ );
2522
2523 /* Run the loop body */
2524 compile_parse( parse->right, c, RESULT_NONE );
2525
2526 compile_pop_continue_scope( c );
2527 compile_pop_cleanup( c );
2528 compile_pop_break_scope( c );
2529
2530 compile_set_label( c, continue_ );
2531 compile_emit_branch( c, INSTR_JUMP, top );
2532 compile_set_label( c, end );
2533
2534 if ( parse->num )
2535 {
2536 compile_pop_cleanup( c );
2537 compile_emit( c, INSTR_POP_LOCAL, var );
2538 }
2539
2540 adjust_result( c, RESULT_NONE, result_location);
2541 }
2542 else if ( parse->type == PARSE_IF )
2543 {
2544 int f = compile_new_label( c );
2545 /* Emit the condition */
2546 compile_condition( parse->left, c, 0, f );
2547 /* Emit the if block */
2548 compile_parse( parse->right, c, result_location );
2549 if ( parse->third->type != PARSE_NULL || result_location != RESULT_NONE )
2550 {
2551 /* Emit the else block */
2552 int end = compile_new_label( c );
2553 compile_emit_branch( c, INSTR_JUMP, end );
2554 compile_set_label( c, f );
2555 compile_parse( parse->third, c, result_location );
2556 compile_set_label( c, end );
2557 }
2558 else
2559 compile_set_label( c, f );
2560
2561 }
2562 else if ( parse->type == PARSE_WHILE )
2563 {
2564 int nested_result = result_location == RESULT_NONE
2565 ? RESULT_NONE
2566 : RESULT_RETURN;
2567 int test = compile_new_label( c );
2568 int top = compile_new_label( c );
2569 int end = compile_new_label( c );
2570 /* Make sure that we return an empty list if the loop runs zero times.
2571 */
2572 adjust_result( c, RESULT_NONE, nested_result );
2573 /* Jump to the loop test. */
2574 compile_emit_branch( c, INSTR_JUMP, test );
2575 compile_set_label( c, top );
2576 /* Emit the loop body. */
2577 compile_push_break_scope( c, end );
2578 compile_push_continue_scope( c, test );
2579 compile_parse( parse->right, c, nested_result );
2580 compile_pop_continue_scope( c );
2581 compile_pop_break_scope( c );
2582 /* Emit the condition. */
2583 compile_set_label( c, test );
2584 compile_condition( parse->left, c, 1, top );
2585 compile_set_label( c, end );
2586
2587 adjust_result( c, nested_result, result_location );
2588 }
2589 else if ( parse->type == PARSE_INCLUDE )
2590 {
2591 compile_parse( parse->left, c, RESULT_STACK );
2592 compile_emit( c, INSTR_INCLUDE, 0 );
2593 compile_emit( c, INSTR_BIND_MODULE_VARIABLES, 0 );
2594 adjust_result( c, RESULT_NONE, result_location );
2595 }
2596 else if ( parse->type == PARSE_MODULE )
2597 {
2598 int const nested_result = result_location == RESULT_NONE
2599 ? RESULT_NONE
2600 : RESULT_RETURN;
2601 compile_parse( parse->left, c, RESULT_STACK );
2602 compile_emit( c, INSTR_PUSH_MODULE, 0 );
2603 compile_push_cleanup( c, INSTR_POP_MODULE, 0 );
2604 compile_parse( parse->right, c, nested_result );
2605 compile_pop_cleanup( c );
2606 compile_emit( c, INSTR_POP_MODULE, 0 );
2607 adjust_result( c, nested_result, result_location );
2608 }
2609 else if ( parse->type == PARSE_CLASS )
2610 {
2611 /* Evaluate the class name. */
2612 compile_parse( parse->left->right, c, RESULT_STACK );
2613 /* Evaluate the base classes. */
2614 if ( parse->left->left )
2615 compile_parse( parse->left->left->right, c, RESULT_STACK );
2616 else
2617 compile_emit( c, INSTR_PUSH_EMPTY, 0 );
2618 compile_emit( c, INSTR_CLASS, 0 );
2619 compile_push_cleanup( c, INSTR_POP_MODULE, 0 );
2620 compile_parse( parse->right, c, RESULT_NONE );
2621 compile_emit( c, INSTR_BIND_MODULE_VARIABLES, 0 );
2622 compile_pop_cleanup( c );
2623 compile_emit( c, INSTR_POP_MODULE, 0 );
2624
2625 adjust_result( c, RESULT_NONE, result_location );
2626 }
2627 else if ( parse->type == PARSE_LIST )
2628 {
2629 OBJECT * const o = parse->string;
2630 char const * s = object_str( o );
2631 VAR_PARSE_GROUP * group;
2632 current_file = object_str( parse->file );
2633 current_line = parse->line;
2634 group = parse_expansion( &s );
2635 var_parse_group_compile( group, c );
2636 var_parse_group_free( group );
2637 adjust_result( c, RESULT_STACK, result_location );
2638 }
2639 else if ( parse->type == PARSE_LOCAL )
2640 {
2641 int nested_result = result_location == RESULT_NONE
2642 ? RESULT_NONE
2643 : RESULT_RETURN;
2644 /* This should be left recursive group of compile_appends. */
2645 PARSE * vars = parse->left;
2646
2647 /* Special case an empty list of vars */
2648 if ( vars->type == PARSE_NULL )
2649 {
2650 compile_parse( parse->right, c, RESULT_NONE );
2651 compile_parse( parse->third, c, result_location );
2652 nested_result = result_location;
2653 }
2654 /* Check whether there is exactly one variable with a constant name. */
2655 else if ( vars->left->type == PARSE_NULL &&
2656 vars->right->type == PARSE_LIST )
2657 {
2658 char const * s = object_str( vars->right->string );
2659 VAR_PARSE_GROUP * group;
2660 current_file = object_str( parse->file );
2661 current_line = parse->line;
2662 group = parse_expansion( &s );
2663 if ( group->elems->size == 1 && dynamic_array_at( VAR_PARSE *,
2664 group->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
2665 {
2666 int const name = compile_emit_constant( c, (
2667 (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *,
2668 group->elems, 0 ) )->s );
2669 var_parse_group_free( group );
2670 compile_parse( parse->right, c, RESULT_STACK );
11fdf7f2 2671 compile_emit_debug(c, parse->line);
7c673cae
FG
2672 compile_emit( c, INSTR_PUSH_LOCAL, name );
2673 compile_push_cleanup( c, INSTR_POP_LOCAL, name );
2674 compile_parse( parse->third, c, nested_result );
2675 compile_pop_cleanup( c );
2676 compile_emit( c, INSTR_POP_LOCAL, name );
2677 }
2678 else
2679 {
2680 var_parse_group_compile( group, c );
2681 var_parse_group_free( group );
2682 compile_parse( parse->right, c, RESULT_STACK );
11fdf7f2 2683 compile_emit_debug(c, parse->line);
7c673cae
FG
2684 compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 );
2685 compile_push_cleanup( c, INSTR_POP_LOCAL_GROUP, 0 );
2686 compile_parse( parse->third, c, nested_result );
2687 compile_pop_cleanup( c );
2688 compile_emit( c, INSTR_POP_LOCAL_GROUP, 0 );
2689 }
2690 }
2691 else
2692 {
2693 compile_parse( parse->left, c, RESULT_STACK );
2694 compile_parse( parse->right, c, RESULT_STACK );
11fdf7f2 2695 compile_emit_debug(c, parse->line);
7c673cae
FG
2696 compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 );
2697 compile_push_cleanup( c, INSTR_POP_LOCAL_GROUP, 0 );
2698 compile_parse( parse->third, c, nested_result );
2699 compile_pop_cleanup( c );
2700 compile_emit( c, INSTR_POP_LOCAL_GROUP, 0 );
2701 }
2702 adjust_result( c, nested_result, result_location );
2703 }
2704 else if ( parse->type == PARSE_ON )
2705 {
2706 if ( parse->right->type == PARSE_APPEND &&
2707 parse->right->left->type == PARSE_NULL &&
2708 parse->right->right->type == PARSE_LIST )
2709 {
2710 /* [ on $(target) return $(variable) ] */
2711 PARSE * value = parse->right->right;
2712 OBJECT * const o = value->string;
2713 char const * s = object_str( o );
2714 VAR_PARSE_GROUP * group;
2715 OBJECT * varname = 0;
2716 current_file = object_str( value->file );
2717 current_line = value->line;
2718 group = parse_expansion( &s );
2719 if ( group->elems->size == 1 )
2720 {
2721 VAR_PARSE * one = dynamic_array_at( VAR_PARSE *, group->elems, 0 );
2722 if ( one->type == VAR_PARSE_TYPE_VAR )
2723 {
2724 VAR_PARSE_VAR * var = ( VAR_PARSE_VAR * )one;
2725 if ( var->modifiers->size == 0 && !var->subscript && var->name->elems->size == 1 )
2726 {
2727 VAR_PARSE * name = dynamic_array_at( VAR_PARSE *, var->name->elems, 0 );
2728 if ( name->type == VAR_PARSE_TYPE_STRING )
2729 {
2730 varname = ( ( VAR_PARSE_STRING * )name )->s;
2731 }
2732 }
2733 }
2734 }
2735 if ( varname )
2736 {
2737 /* We have one variable with a fixed name and no modifiers. */
2738 compile_parse( parse->left, c, RESULT_STACK );
2739 compile_emit( c, INSTR_GET_ON, compile_emit_constant( c, varname ) );
2740 }
2741 else
2742 {
2743 /* Too complex. Fall back on push/pop. */
2744 int end = compile_new_label( c );
2745 compile_parse( parse->left, c, RESULT_STACK );
2746 compile_emit_branch( c, INSTR_PUSH_ON, end );
2747 compile_push_cleanup( c, INSTR_POP_ON, 0 );
2748 var_parse_group_compile( group, c );
2749 compile_pop_cleanup( c );
2750 compile_emit( c, INSTR_POP_ON, 0 );
2751 compile_set_label( c, end );
2752 }
2753 var_parse_group_free( group );
2754 }
2755 else
2756 {
2757 int end = compile_new_label( c );
2758 compile_parse( parse->left, c, RESULT_STACK );
2759 compile_emit_branch( c, INSTR_PUSH_ON, end );
2760 compile_push_cleanup( c, INSTR_POP_ON, 0 );
2761 compile_parse( parse->right, c, RESULT_STACK );
2762 compile_pop_cleanup( c );
2763 compile_emit( c, INSTR_POP_ON, 0 );
2764 compile_set_label( c, end );
2765 }
2766 adjust_result( c, RESULT_STACK, result_location );
2767 }
2768 else if ( parse->type == PARSE_RULE )
2769 {
2770 PARSE * p;
2771 int n = 0;
2772 VAR_PARSE_GROUP * group;
2773 char const * s = object_str( parse->string );
2774
2775 if ( parse->left->left || parse->left->right->type != PARSE_NULL )
2776 for ( p = parse->left; p; p = p->left )
2777 {
2778 compile_parse( p->right, c, RESULT_STACK );
2779 ++n;
2780 }
2781
2782 current_file = object_str( parse->file );
2783 current_line = parse->line;
2784 group = parse_expansion( &s );
2785
2786 if ( group->elems->size == 2 &&
2787 dynamic_array_at( VAR_PARSE *, group->elems, 0 )->type == VAR_PARSE_TYPE_VAR &&
2788 dynamic_array_at( VAR_PARSE *, group->elems, 1 )->type == VAR_PARSE_TYPE_STRING &&
2789 ( object_str( ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 1 ) )->s )[ 0 ] == '.' ) )
2790 {
2791 VAR_PARSE_STRING * access = (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 1 );
2792 OBJECT * member = object_new( object_str( access->s ) + 1 );
2793 /* Emit the object */
2794 var_parse_var_compile( (VAR_PARSE_VAR *)dynamic_array_at( VAR_PARSE *, group->elems, 0 ), c );
2795 var_parse_group_free( group );
2796 compile_emit( c, INSTR_CALL_MEMBER_RULE, n );
2797 compile_emit( c, compile_emit_constant( c, member ), parse->line );
2798 object_free( member );
2799 }
2800 else
2801 {
2802 var_parse_group_compile( group, c );
2803 var_parse_group_free( group );
2804 compile_emit( c, INSTR_CALL_RULE, n );
2805 compile_emit( c, compile_emit_constant( c, parse->string ), parse->line );
2806 }
2807
2808 adjust_result( c, RESULT_STACK, result_location );
2809 }
2810 else if ( parse->type == PARSE_RULES )
2811 {
2812 do compile_parse( parse->left, c, RESULT_NONE );
2813 while ( ( parse = parse->right )->type == PARSE_RULES );
2814 compile_parse( parse, c, result_location );
2815 }
2816 else if ( parse->type == PARSE_SET )
2817 {
2818 PARSE * vars = parse->left;
2819 unsigned int op_code;
2820 unsigned int op_code_group;
2821
2822 switch ( parse->num )
2823 {
2824 case ASSIGN_APPEND: op_code = INSTR_APPEND; op_code_group = INSTR_APPEND_GROUP; break;
2825 case ASSIGN_DEFAULT: op_code = INSTR_DEFAULT; op_code_group = INSTR_DEFAULT_GROUP; break;
2826 default: op_code = INSTR_SET; op_code_group = INSTR_SET_GROUP; break;
2827 }
2828
2829 /* Check whether there is exactly one variable with a constant name. */
2830 if ( vars->type == PARSE_LIST )
2831 {
2832 char const * s = object_str( vars->string );
2833 VAR_PARSE_GROUP * group;
2834 current_file = object_str( parse->file );
2835 current_line = parse->line;
2836 group = parse_expansion( &s );
2837 if ( group->elems->size == 1 && dynamic_array_at( VAR_PARSE *,
2838 group->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
2839 {
2840 int const name = compile_emit_constant( c, (
2841 (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *,
2842 group->elems, 0 ) )->s );
2843 var_parse_group_free( group );
2844 compile_parse( parse->right, c, RESULT_STACK );
11fdf7f2 2845 compile_emit_debug(c, parse->line);
7c673cae
FG
2846 if ( result_location != RESULT_NONE )
2847 {
2848 compile_emit( c, INSTR_SET_RESULT, 1 );
2849 }
2850 compile_emit( c, op_code, name );
2851 }
2852 else
2853 {
2854 var_parse_group_compile( group, c );
2855 var_parse_group_free( group );
2856 compile_parse( parse->right, c, RESULT_STACK );
11fdf7f2 2857 compile_emit_debug(c, parse->line);
7c673cae
FG
2858 if ( result_location != RESULT_NONE )
2859 {
2860 compile_emit( c, INSTR_SET_RESULT, 1 );
2861 }
2862 compile_emit( c, op_code_group, 0 );
2863 }
2864 }
2865 else
2866 {
2867 compile_parse( parse->left, c, RESULT_STACK );
2868 compile_parse( parse->right, c, RESULT_STACK );
11fdf7f2 2869 compile_emit_debug(c, parse->line);
7c673cae
FG
2870 if ( result_location != RESULT_NONE )
2871 {
2872 compile_emit( c, INSTR_SET_RESULT, 1 );
2873 }
2874 compile_emit( c, op_code_group, 0 );
2875 }
2876 if ( result_location != RESULT_NONE )
2877 {
2878 adjust_result( c, RESULT_RETURN, result_location );
2879 }
2880 }
2881 else if ( parse->type == PARSE_SETCOMP )
2882 {
2883 int n_args;
2884 struct arg_list * args = arg_list_compile( parse->right, &n_args );
2885 int const rule_id = compile_emit_rule( c, parse->string, parse->left,
2886 n_args, args, parse->num );
2887 compile_emit( c, INSTR_RULE, rule_id );
2888 adjust_result( c, RESULT_NONE, result_location );
2889 }
2890 else if ( parse->type == PARSE_SETEXEC )
2891 {
2892 int const actions_id = compile_emit_actions( c, parse );
2893 compile_parse( parse->left, c, RESULT_STACK );
2894 compile_emit( c, INSTR_ACTIONS, actions_id );
2895 adjust_result( c, RESULT_NONE, result_location );
2896 }
2897 else if ( parse->type == PARSE_SETTINGS )
2898 {
2899 compile_parse( parse->left, c, RESULT_STACK );
2900 compile_parse( parse->third, c, RESULT_STACK );
2901 compile_parse( parse->right, c, RESULT_STACK );
2902
11fdf7f2 2903 compile_emit_debug(c, parse->line);
7c673cae
FG
2904 switch ( parse->num )
2905 {
2906 case ASSIGN_APPEND: compile_emit( c, INSTR_APPEND_ON, 0 ); break;
2907 case ASSIGN_DEFAULT: compile_emit( c, INSTR_DEFAULT_ON, 0 ); break;
2908 default: compile_emit( c, INSTR_SET_ON, 0 ); break;
2909 }
2910
2911 adjust_result( c, RESULT_STACK, result_location );
2912 }
2913 else if ( parse->type == PARSE_SWITCH )
2914 {
2915 int const switch_end = compile_new_label( c );
2916 compile_parse( parse->left, c, RESULT_STACK );
2917
2918 for ( parse = parse->right; parse; parse = parse->right )
2919 {
2920 int const id = compile_emit_constant( c, parse->left->string );
2921 int const next_case = compile_new_label( c );
2922 compile_emit( c, INSTR_PUSH_CONSTANT, id );
2923 compile_emit_branch( c, INSTR_JUMP_NOT_GLOB, next_case );
2924 compile_parse( parse->left->left, c, result_location );
2925 compile_emit_branch( c, INSTR_JUMP, switch_end );
2926 compile_set_label( c, next_case );
2927 }
2928 compile_emit( c, INSTR_POP, 0 );
2929 adjust_result( c, RESULT_NONE, result_location );
2930 compile_set_label( c, switch_end );
2931 }
2932 else if ( parse->type == PARSE_RETURN )
2933 {
2934 compile_parse( parse->left, c, RESULT_RETURN );
2935 compile_emit_cleanups( c, 0 );
2936 compile_emit( c, INSTR_RETURN, 0 ); /* 0 for return in the middle of a function. */
2937 }
2938 else if ( parse->type == PARSE_BREAK )
2939 {
2940 compile_emit_loop_jump( c, LOOP_INFO_BREAK );
2941 }
2942 else if ( parse->type == PARSE_CONTINUE )
2943 {
2944 compile_emit_loop_jump( c, LOOP_INFO_CONTINUE );
2945 }
2946 else if ( parse->type == PARSE_NULL )
2947 adjust_result( c, RESULT_NONE, result_location );
2948 else
2949 assert( !"unknown PARSE type." );
2950}
2951
2952OBJECT * function_rulename( FUNCTION * function )
2953{
2954 return function->rulename;
2955}
2956
2957void function_set_rulename( FUNCTION * function, OBJECT * rulename )
2958{
2959 function->rulename = rulename;
2960}
2961
2962void function_location( FUNCTION * function_, OBJECT * * file, int * line )
2963{
2964 if ( function_->type == FUNCTION_BUILTIN )
2965 {
2966 *file = constant_builtin;
2967 *line = -1;
2968 }
2969#ifdef HAVE_PYTHON
2970 if ( function_->type == FUNCTION_PYTHON )
2971 {
2972 *file = constant_builtin;
2973 *line = -1;
2974 }
2975#endif
2976 else
2977 {
2978 JAM_FUNCTION * function = (JAM_FUNCTION *)function_;
2979 assert( function_->type == FUNCTION_JAM );
2980 *file = function->file;
2981 *line = function->line;
2982 }
2983}
2984
2985static struct arg_list * arg_list_compile_builtin( char const * * args,
2986 int * num_arguments );
2987
2988FUNCTION * function_builtin( LIST * ( * func )( FRAME * frame, int flags ),
2989 int flags, char const * * args )
2990{
2991 BUILTIN_FUNCTION * result = BJAM_MALLOC( sizeof( BUILTIN_FUNCTION ) );
2992 result->base.type = FUNCTION_BUILTIN;
2993 result->base.reference_count = 1;
2994 result->base.rulename = 0;
2995 result->base.formal_arguments = arg_list_compile_builtin( args,
2996 &result->base.num_formal_arguments );
2997 result->func = func;
2998 result->flags = flags;
2999 return (FUNCTION *)result;
3000}
3001
3002FUNCTION * function_compile( PARSE * parse )
3003{
3004 compiler c[ 1 ];
3005 JAM_FUNCTION * result;
3006 compiler_init( c );
3007 compile_parse( parse, c, RESULT_RETURN );
3008 compile_emit( c, INSTR_RETURN, 1 );
3009 result = compile_to_function( c );
3010 compiler_free( c );
3011 result->file = object_copy( parse->file );
3012 result->line = parse->line;
3013 return (FUNCTION *)result;
3014}
3015
3016FUNCTION * function_compile_actions( char const * actions, OBJECT * file,
3017 int line )
3018{
3019 compiler c[ 1 ];
3020 JAM_FUNCTION * result;
3021 VAR_PARSE_ACTIONS * parse;
3022 current_file = object_str( file );
3023 current_line = line;
3024 parse = parse_actions( actions );
3025 compiler_init( c );
3026 var_parse_actions_compile( parse, c );
3027 var_parse_actions_free( parse );
3028 compile_emit( c, INSTR_RETURN, 1 );
3029 result = compile_to_function( c );
3030 compiler_free( c );
3031 result->file = object_copy( file );
3032 result->line = line;
3033 return (FUNCTION *)result;
3034}
3035
3036static void argument_list_print( struct arg_list * args, int num_args );
3037
3038
3039/* Define delimiters for type check elements in argument lists (and return type
3040 * specifications, eventually).
3041 */
3042# define TYPE_OPEN_DELIM '['
3043# define TYPE_CLOSE_DELIM ']'
3044
3045/*
3046 * is_type_name() - true iff the given string represents a type check
3047 * specification.
3048 */
3049
3050int is_type_name( char const * s )
3051{
3052 return s[ 0 ] == TYPE_OPEN_DELIM && s[ strlen( s ) - 1 ] ==
3053 TYPE_CLOSE_DELIM;
3054}
3055
3056static void argument_error( char const * message, FUNCTION * procedure,
3057 FRAME * frame, OBJECT * arg )
3058{
3059 extern void print_source_line( FRAME * );
3060 LOL * actual = frame->args;
3061 backtrace_line( frame->prev );
3062 out_printf( "*** argument error\n* rule %s ( ", frame->rulename );
3063 argument_list_print( procedure->formal_arguments,
3064 procedure->num_formal_arguments );
3065 out_printf( " )\n* called with: ( " );
3066 lol_print( actual );
3067 out_printf( " )\n* %s %s\n", message, arg ? object_str ( arg ) : "" );
3068 function_location( procedure, &frame->file, &frame->line );
3069 print_source_line( frame );
3070 out_printf( "see definition of rule '%s' being called\n", frame->rulename );
3071 backtrace( frame->prev );
3072 exit( EXITBAD );
3073}
3074
3075static void type_check_range( OBJECT * type_name, LISTITER iter, LISTITER end,
3076 FRAME * caller, FUNCTION * called, OBJECT * arg_name )
3077{
3078 static module_t * typecheck = 0;
3079
3080 /* If nothing to check, bail now. */
3081 if ( iter == end || !type_name )
3082 return;
3083
3084 if ( !typecheck )
3085 typecheck = bindmodule( constant_typecheck );
3086
3087 /* If the checking rule can not be found, also bail. */
3088 if ( !typecheck->rules || !hash_find( typecheck->rules, type_name ) )
3089 return;
3090
3091 for ( ; iter != end; iter = list_next( iter ) )
3092 {
3093 LIST * error;
3094 FRAME frame[ 1 ];
3095 frame_init( frame );
3096 frame->module = typecheck;
3097 frame->prev = caller;
3098 frame->prev_user = caller->module->user_module
3099 ? caller
3100 : caller->prev_user;
3101
3102 /* Prepare the argument list */
3103 lol_add( frame->args, list_new( object_copy( list_item( iter ) ) ) );
3104 error = evaluate_rule( bindrule( type_name, frame->module ), type_name, frame );
3105
3106 if ( !list_empty( error ) )
3107 argument_error( object_str( list_front( error ) ), called, caller,
3108 arg_name );
3109
3110 frame_free( frame );
3111 }
3112}
3113
3114static void type_check( OBJECT * type_name, LIST * values, FRAME * caller,
3115 FUNCTION * called, OBJECT * arg_name )
3116{
3117 type_check_range( type_name, list_begin( values ), list_end( values ),
3118 caller, called, arg_name );
3119}
3120
3121void argument_list_check( struct arg_list * formal, int formal_count,
3122 FUNCTION * function, FRAME * frame )
3123{
3124 LOL * all_actual = frame->args;
3125 int i;
3126
3127 for ( i = 0; i < formal_count; ++i )
3128 {
3129 LIST * actual = lol_get( all_actual, i );
3130 LISTITER actual_iter = list_begin( actual );
3131 LISTITER const actual_end = list_end( actual );
3132 int j;
3133 for ( j = 0; j < formal[ i ].size; ++j )
3134 {
3135 struct argument * formal_arg = &formal[ i ].args[ j ];
3136 LIST * value;
3137
3138 switch ( formal_arg->flags )
3139 {
3140 case ARG_ONE:
3141 if ( actual_iter == actual_end )
3142 argument_error( "missing argument", function, frame,
3143 formal_arg->arg_name );
3144 type_check_range( formal_arg->type_name, actual_iter,
3145 list_next( actual_iter ), frame, function,
3146 formal_arg->arg_name );
3147 actual_iter = list_next( actual_iter );
3148 break;
3149 case ARG_OPTIONAL:
3150 if ( actual_iter == actual_end )
3151 value = L0;
3152 else
3153 {
3154 type_check_range( formal_arg->type_name, actual_iter,
3155 list_next( actual_iter ), frame, function,
3156 formal_arg->arg_name );
3157 actual_iter = list_next( actual_iter );
3158 }
3159 break;
3160 case ARG_PLUS:
3161 if ( actual_iter == actual_end )
3162 argument_error( "missing argument", function, frame,
3163 formal_arg->arg_name );
3164 /* fallthrough */
3165 case ARG_STAR:
3166 type_check_range( formal_arg->type_name, actual_iter,
3167 actual_end, frame, function, formal_arg->arg_name );
3168 actual_iter = actual_end;
3169 break;
3170 case ARG_VARIADIC:
3171 return;
3172 }
3173 }
3174
3175 if ( actual_iter != actual_end )
3176 argument_error( "extra argument", function, frame, list_item(
3177 actual_iter ) );
3178 }
3179
3180 for ( ; i < all_actual->count; ++i )
3181 {
3182 LIST * actual = lol_get( all_actual, i );
3183 if ( !list_empty( actual ) )
3184 argument_error( "extra argument", function, frame, list_front(
3185 actual ) );
3186 }
3187}
3188
3189void argument_list_push( struct arg_list * formal, int formal_count,
3190 FUNCTION * function, FRAME * frame, STACK * s )
3191{
3192 LOL * all_actual = frame->args;
3193 int i;
3194
3195 for ( i = 0; i < formal_count; ++i )
3196 {
3197 LIST * actual = lol_get( all_actual, i );
3198 LISTITER actual_iter = list_begin( actual );
3199 LISTITER const actual_end = list_end( actual );
3200 int j;
3201 for ( j = 0; j < formal[ i ].size; ++j )
3202 {
3203 struct argument * formal_arg = &formal[ i ].args[ j ];
3204 LIST * value;
3205
3206 switch ( formal_arg->flags )
3207 {
3208 case ARG_ONE:
3209 if ( actual_iter == actual_end )
3210 argument_error( "missing argument", function, frame,
3211 formal_arg->arg_name );
3212 value = list_new( object_copy( list_item( actual_iter ) ) );
3213 actual_iter = list_next( actual_iter );
3214 break;
3215 case ARG_OPTIONAL:
3216 if ( actual_iter == actual_end )
3217 value = L0;
3218 else
3219 {
3220 value = list_new( object_copy( list_item( actual_iter ) ) );
3221 actual_iter = list_next( actual_iter );
3222 }
3223 break;
3224 case ARG_PLUS:
3225 if ( actual_iter == actual_end )
3226 argument_error( "missing argument", function, frame,
3227 formal_arg->arg_name );
3228 /* fallthrough */
3229 case ARG_STAR:
3230 value = list_copy_range( actual, actual_iter, actual_end );
3231 actual_iter = actual_end;
3232 break;
3233 case ARG_VARIADIC:
3234 return;
3235 }
3236
3237 type_check( formal_arg->type_name, value, frame, function,
3238 formal_arg->arg_name );
3239
3240 if ( formal_arg->index != -1 )
3241 {
3242 LIST * * const old = &frame->module->fixed_variables[
3243 formal_arg->index ];
3244 stack_push( s, *old );
3245 *old = value;
3246 }
3247 else
3248 stack_push( s, var_swap( frame->module, formal_arg->arg_name,
3249 value ) );
3250 }
3251
3252 if ( actual_iter != actual_end )
3253 argument_error( "extra argument", function, frame, list_item(
3254 actual_iter ) );
3255 }
3256
3257 for ( ; i < all_actual->count; ++i )
3258 {
3259 LIST * const actual = lol_get( all_actual, i );
3260 if ( !list_empty( actual ) )
3261 argument_error( "extra argument", function, frame, list_front(
3262 actual ) );
3263 }
3264}
3265
3266void argument_list_pop( struct arg_list * formal, int formal_count,
3267 FRAME * frame, STACK * s )
3268{
3269 int i;
3270 for ( i = formal_count - 1; i >= 0; --i )
3271 {
3272 int j;
3273 for ( j = formal[ i ].size - 1; j >= 0 ; --j )
3274 {
3275 struct argument * formal_arg = &formal[ i ].args[ j ];
3276
3277 if ( formal_arg->flags == ARG_VARIADIC )
3278 continue;
3279 if ( formal_arg->index != -1 )
3280 {
3281 LIST * const old = stack_pop( s );
3282 LIST * * const pos = &frame->module->fixed_variables[
3283 formal_arg->index ];
3284 list_free( *pos );
3285 *pos = old;
3286 }
3287 else
3288 var_set( frame->module, formal_arg->arg_name, stack_pop( s ),
3289 VAR_SET );
3290 }
3291 }
3292}
3293
3294
3295struct argument_compiler
3296{
3297 struct dynamic_array args[ 1 ];
3298 struct argument arg;
3299 int state;
3300#define ARGUMENT_COMPILER_START 0
3301#define ARGUMENT_COMPILER_FOUND_TYPE 1
3302#define ARGUMENT_COMPILER_FOUND_OBJECT 2
3303#define ARGUMENT_COMPILER_DONE 3
3304};
3305
3306
3307static void argument_compiler_init( struct argument_compiler * c )
3308{
3309 dynamic_array_init( c->args );
3310 c->state = ARGUMENT_COMPILER_START;
3311}
3312
3313static void argument_compiler_free( struct argument_compiler * c )
3314{
3315 dynamic_array_free( c->args );
3316}
3317
3318static void argument_compiler_add( struct argument_compiler * c, OBJECT * arg,
3319 OBJECT * file, int line )
3320{
3321 switch ( c->state )
3322 {
3323 case ARGUMENT_COMPILER_FOUND_OBJECT:
3324
3325 if ( object_equal( arg, constant_question_mark ) )
3326 {
3327 c->arg.flags = ARG_OPTIONAL;
3328 }
3329 else if ( object_equal( arg, constant_plus ) )
3330 {
3331 c->arg.flags = ARG_PLUS;
3332 }
3333 else if ( object_equal( arg, constant_star ) )
3334 {
3335 c->arg.flags = ARG_STAR;
3336 }
3337
3338 dynamic_array_push( c->args, c->arg );
3339 c->state = ARGUMENT_COMPILER_START;
3340
3341 if ( c->arg.flags != ARG_ONE )
3342 break;
3343 /* fall-through */
3344
3345 case ARGUMENT_COMPILER_START:
3346
3347 c->arg.type_name = 0;
3348 c->arg.index = -1;
3349 c->arg.flags = ARG_ONE;
3350
3351 if ( is_type_name( object_str( arg ) ) )
3352 {
3353 c->arg.type_name = object_copy( arg );
3354 c->state = ARGUMENT_COMPILER_FOUND_TYPE;
3355 break;
3356 }
3357 /* fall-through */
3358
3359 case ARGUMENT_COMPILER_FOUND_TYPE:
3360
3361 if ( is_type_name( object_str( arg ) ) )
3362 {
3363 err_printf( "%s:%d: missing argument name before type name: %s\n",
3364 object_str( file ), line, object_str( arg ) );
3365 exit( EXITBAD );
3366 }
3367
3368 c->arg.arg_name = object_copy( arg );
3369 if ( object_equal( arg, constant_star ) )
3370 {
3371 c->arg.flags = ARG_VARIADIC;
3372 dynamic_array_push( c->args, c->arg );
3373 c->state = ARGUMENT_COMPILER_DONE;
3374 }
3375 else
3376 {
3377 c->state = ARGUMENT_COMPILER_FOUND_OBJECT;
3378 }
3379 break;
3380
3381 case ARGUMENT_COMPILER_DONE:
3382 break;
3383 }
3384}
3385
3386static void argument_compiler_recurse( struct argument_compiler * c,
3387 PARSE * parse )
3388{
3389 if ( parse->type == PARSE_APPEND )
3390 {
3391 argument_compiler_recurse( c, parse->left );
3392 argument_compiler_recurse( c, parse->right );
3393 }
3394 else if ( parse->type != PARSE_NULL )
3395 {
3396 assert( parse->type == PARSE_LIST );
3397 argument_compiler_add( c, parse->string, parse->file, parse->line );
3398 }
3399}
3400
3401static struct arg_list arg_compile_impl( struct argument_compiler * c,
3402 OBJECT * file, int line )
3403{
3404 struct arg_list result;
3405 switch ( c->state )
3406 {
3407 case ARGUMENT_COMPILER_START:
3408 case ARGUMENT_COMPILER_DONE:
3409 break;
3410 case ARGUMENT_COMPILER_FOUND_TYPE:
3411 err_printf( "%s:%d: missing argument name after type name: %s\n",
3412 object_str( file ), line, object_str( c->arg.type_name ) );
3413 exit( EXITBAD );
3414 case ARGUMENT_COMPILER_FOUND_OBJECT:
3415 dynamic_array_push( c->args, c->arg );
3416 break;
3417 }
3418 result.size = c->args->size;
3419 result.args = BJAM_MALLOC( c->args->size * sizeof( struct argument ) );
3420 memcpy( result.args, c->args->data, c->args->size * sizeof( struct argument
3421 ) );
3422 return result;
3423}
3424
3425static struct arg_list arg_compile( PARSE * parse )
3426{
3427 struct argument_compiler c[ 1 ];
3428 struct arg_list result;
3429 argument_compiler_init( c );
3430 argument_compiler_recurse( c, parse );
3431 result = arg_compile_impl( c, parse->file, parse->line );
3432 argument_compiler_free( c );
3433 return result;
3434}
3435
3436struct argument_list_compiler
3437{
3438 struct dynamic_array args[ 1 ];
3439};
3440
3441static void argument_list_compiler_init( struct argument_list_compiler * c )
3442{
3443 dynamic_array_init( c->args );
3444}
3445
3446static void argument_list_compiler_free( struct argument_list_compiler * c )
3447{
3448 dynamic_array_free( c->args );
3449}
3450
3451static void argument_list_compiler_add( struct argument_list_compiler * c,
3452 PARSE * parse )
3453{
3454 struct arg_list args = arg_compile( parse );
3455 dynamic_array_push( c->args, args );
3456}
3457
3458static void argument_list_compiler_recurse( struct argument_list_compiler * c,
3459 PARSE * parse )
3460{
3461 if ( parse )
3462 {
3463 argument_list_compiler_add( c, parse->right );
3464 argument_list_compiler_recurse( c, parse->left );
3465 }
3466}
3467
3468static struct arg_list * arg_list_compile( PARSE * parse, int * num_arguments )
3469{
3470 if ( parse )
3471 {
3472 struct argument_list_compiler c[ 1 ];
3473 struct arg_list * result;
3474 argument_list_compiler_init( c );
3475 argument_list_compiler_recurse( c, parse );
3476 *num_arguments = c->args->size;
3477 result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
3478 memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list )
3479 );
3480 argument_list_compiler_free( c );
3481 return result;
3482 }
3483 *num_arguments = 0;
3484 return 0;
3485}
3486
3487static struct arg_list * arg_list_compile_builtin( char const * * args,
3488 int * num_arguments )
3489{
3490 if ( args )
3491 {
3492 struct argument_list_compiler c[ 1 ];
3493 struct arg_list * result;
3494 argument_list_compiler_init( c );
3495 while ( *args )
3496 {
3497 struct argument_compiler arg_comp[ 1 ];
3498 struct arg_list arg;
3499 argument_compiler_init( arg_comp );
3500 for ( ; *args; ++args )
3501 {
3502 OBJECT * token;
3503 if ( strcmp( *args, ":" ) == 0 )
3504 {
3505 ++args;
3506 break;
3507 }
3508 token = object_new( *args );
3509 argument_compiler_add( arg_comp, token, constant_builtin, -1 );
3510 object_free( token );
3511 }
3512 arg = arg_compile_impl( arg_comp, constant_builtin, -1 );
3513 dynamic_array_push( c->args, arg );
3514 argument_compiler_free( arg_comp );
3515 }
3516 *num_arguments = c->args->size;
3517 result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
3518 memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list )
3519 );
3520 argument_list_compiler_free( c );
3521 return result;
3522 }
3523 *num_arguments = 0;
3524 return 0;
3525}
3526
3527static void argument_list_print( struct arg_list * args, int num_args )
3528{
3529 if ( args )
3530 {
3531 int i;
3532 for ( i = 0; i < num_args; ++i )
3533 {
3534 int j;
3535 if ( i ) out_printf( " : " );
3536 for ( j = 0; j < args[ i ].size; ++j )
3537 {
3538 struct argument * formal_arg = &args[ i ].args[ j ];
3539 if ( j ) out_printf( " " );
3540 if ( formal_arg->type_name )
3541 out_printf( "%s ", object_str( formal_arg->type_name ) );
3542 out_printf( "%s", object_str( formal_arg->arg_name ) );
3543 switch ( formal_arg->flags )
3544 {
3545 case ARG_OPTIONAL: out_printf( " ?" ); break;
3546 case ARG_PLUS: out_printf( " +" ); break;
3547 case ARG_STAR: out_printf( " *" ); break;
3548 }
3549 }
3550 }
3551 }
3552}
3553
3554
3555struct arg_list * argument_list_bind_variables( struct arg_list * formal,
3556 int formal_count, module_t * module, int * counter )
3557{
3558 if ( formal )
3559 {
3560 struct arg_list * result = (struct arg_list *)BJAM_MALLOC( sizeof(
3561 struct arg_list ) * formal_count );
3562 int i;
3563
3564 for ( i = 0; i < formal_count; ++i )
3565 {
3566 int j;
3567 struct argument * args = (struct argument *)BJAM_MALLOC( sizeof(
3568 struct argument ) * formal[ i ].size );
3569 for ( j = 0; j < formal[ i ].size; ++j )
3570 {
3571 args[ j ] = formal[ i ].args[ j ];
3572 if ( args[ j ].type_name )
3573 args[ j ].type_name = object_copy( args[ j ].type_name );
3574 args[ j ].arg_name = object_copy( args[ j ].arg_name );
3575 if ( args[ j ].flags != ARG_VARIADIC )
3576 args[ j ].index = module_add_fixed_var( module,
3577 args[ j ].arg_name, counter );
3578 }
3579 result[ i ].args = args;
3580 result[ i ].size = formal[ i ].size;
3581 }
3582
3583 return result;
3584 }
3585 return 0;
3586}
3587
3588
3589void argument_list_free( struct arg_list * args, int args_count )
3590{
3591 int i;
3592 for ( i = 0; i < args_count; ++i )
3593 {
3594 int j;
3595 for ( j = 0; j < args[ i ].size; ++j )
3596 {
3597 if ( args[ i ].args[ j ].type_name )
3598 object_free( args[ i ].args[ j ].type_name );
3599 object_free( args[ i ].args[ j ].arg_name );
3600 }
3601 BJAM_FREE( args[ i ].args );
3602 }
3603 BJAM_FREE( args );
3604}
3605
3606
3607FUNCTION * function_unbind_variables( FUNCTION * f )
3608{
3609 if ( f->type == FUNCTION_JAM )
3610 {
3611 JAM_FUNCTION * const func = (JAM_FUNCTION *)f;
3612 return func->generic ? func->generic : f;
3613 }
3614#ifdef HAVE_PYTHON
3615 if ( f->type == FUNCTION_PYTHON )
3616 return f;
3617#endif
3618 assert( f->type == FUNCTION_BUILTIN );
3619 return f;
3620}
3621
3622FUNCTION * function_bind_variables( FUNCTION * f, module_t * module,
3623 int * counter )
3624{
3625 if ( f->type == FUNCTION_BUILTIN )
3626 return f;
3627#ifdef HAVE_PYTHON
3628 if ( f->type == FUNCTION_PYTHON )
3629 return f;
3630#endif
3631 {
3632 JAM_FUNCTION * func = (JAM_FUNCTION *)f;
3633 JAM_FUNCTION * new_func = BJAM_MALLOC( sizeof( JAM_FUNCTION ) );
3634 instruction * code;
3635 int i;
3636 assert( f->type == FUNCTION_JAM );
3637 memcpy( new_func, func, sizeof( JAM_FUNCTION ) );
3638 new_func->base.reference_count = 1;
3639 new_func->base.formal_arguments = argument_list_bind_variables(
3640 f->formal_arguments, f->num_formal_arguments, module, counter );
3641 new_func->code = BJAM_MALLOC( func->code_size * sizeof( instruction ) );
3642 memcpy( new_func->code, func->code, func->code_size * sizeof(
3643 instruction ) );
3644 new_func->generic = (FUNCTION *)func;
3645 func = new_func;
3646 for ( i = 0; ; ++i )
3647 {
3648 OBJECT * key;
3649 int op_code;
3650 code = func->code + i;
3651 switch ( code->op_code )
3652 {
3653 case INSTR_PUSH_VAR: op_code = INSTR_PUSH_VAR_FIXED; break;
3654 case INSTR_PUSH_LOCAL: op_code = INSTR_PUSH_LOCAL_FIXED; break;
3655 case INSTR_POP_LOCAL: op_code = INSTR_POP_LOCAL_FIXED; break;
3656 case INSTR_SET: op_code = INSTR_SET_FIXED; break;
3657 case INSTR_APPEND: op_code = INSTR_APPEND_FIXED; break;
3658 case INSTR_DEFAULT: op_code = INSTR_DEFAULT_FIXED; break;
3659 case INSTR_RETURN:
3660 if( code->arg == 1 ) return (FUNCTION *)new_func;
3661 else continue;
3662 case INSTR_CALL_MEMBER_RULE:
3663 case INSTR_CALL_RULE: ++i; continue;
3664 case INSTR_PUSH_MODULE:
3665 {
3666 int depth = 1;
3667 ++i;
3668 while ( depth > 0 )
3669 {
3670 code = func->code + i;
3671 switch ( code->op_code )
3672 {
3673 case INSTR_PUSH_MODULE:
3674 case INSTR_CLASS:
3675 ++depth;
3676 break;
3677 case INSTR_POP_MODULE:
3678 --depth;
3679 break;
3680 case INSTR_CALL_RULE:
3681 ++i;
3682 break;
3683 }
3684 ++i;
3685 }
3686 --i;
3687 }
3688 default: continue;
3689 }
3690 key = func->constants[ code->arg ];
3691 if ( !( object_equal( key, constant_TMPDIR ) ||
3692 object_equal( key, constant_TMPNAME ) ||
3693 object_equal( key, constant_TMPFILE ) ||
3694 object_equal( key, constant_STDOUT ) ||
3695 object_equal( key, constant_STDERR ) ) )
3696 {
3697 code->op_code = op_code;
3698 code->arg = module_add_fixed_var( module, key, counter );
3699 }
3700 }
3701 }
3702}
3703
b32b8144
FG
3704LIST * function_get_variables( FUNCTION * f )
3705{
3706 if ( f->type == FUNCTION_BUILTIN )
3707 return L0;
3708#ifdef HAVE_PYTHON
3709 if ( f->type == FUNCTION_PYTHON )
3710 return L0;
3711#endif
3712 {
3713 JAM_FUNCTION * func = (JAM_FUNCTION *)f;
3714 LIST * result = L0;
3715 instruction * code;
3716 int i;
3717 assert( f->type == FUNCTION_JAM );
3718 if ( func->generic ) func = ( JAM_FUNCTION * )func->generic;
3719
3720 for ( i = 0; ; ++i )
3721 {
3722 OBJECT * var;
3723 code = func->code + i;
3724 switch ( code->op_code )
3725 {
3726 case INSTR_PUSH_LOCAL: break;
3727 case INSTR_RETURN: return result;
3728 case INSTR_CALL_MEMBER_RULE:
3729 case INSTR_CALL_RULE: ++i; continue;
3730 case INSTR_PUSH_MODULE:
3731 {
3732 int depth = 1;
3733 ++i;
3734 while ( depth > 0 )
3735 {
3736 code = func->code + i;
3737 switch ( code->op_code )
3738 {
3739 case INSTR_PUSH_MODULE:
3740 case INSTR_CLASS:
3741 ++depth;
3742 break;
3743 case INSTR_POP_MODULE:
3744 --depth;
3745 break;
3746 case INSTR_CALL_RULE:
3747 ++i;
3748 break;
3749 }
3750 ++i;
3751 }
3752 --i;
3753 }
3754 default: continue;
3755 }
3756 var = func->constants[ code->arg ];
3757 if ( !( object_equal( var, constant_TMPDIR ) ||
3758 object_equal( var, constant_TMPNAME ) ||
3759 object_equal( var, constant_TMPFILE ) ||
3760 object_equal( var, constant_STDOUT ) ||
3761 object_equal( var, constant_STDERR ) ) )
3762 {
3763 result = list_push_back( result, var );
3764 }
3765 }
3766 }
3767}
3768
7c673cae
FG
3769void function_refer( FUNCTION * func )
3770{
3771 ++func->reference_count;
3772}
3773
3774void function_free( FUNCTION * function_ )
3775{
3776 int i;
3777
3778 if ( --function_->reference_count != 0 )
3779 return;
3780
3781 if ( function_->formal_arguments )
3782 argument_list_free( function_->formal_arguments,
3783 function_->num_formal_arguments );
3784
3785 if ( function_->type == FUNCTION_JAM )
3786 {
3787 JAM_FUNCTION * func = (JAM_FUNCTION *)function_;
3788
3789 BJAM_FREE( func->code );
3790
3791 if ( func->generic )
3792 function_free( func->generic );
3793 else
3794 {
3795 if ( function_->rulename ) object_free( function_->rulename );
3796
3797 for ( i = 0; i < func->num_constants; ++i )
3798 object_free( func->constants[ i ] );
3799 BJAM_FREE( func->constants );
3800
3801 for ( i = 0; i < func->num_subfunctions; ++i )
3802 {
3803 object_free( func->functions[ i ].name );
3804 function_free( func->functions[ i ].code );
3805 }
3806 BJAM_FREE( func->functions );
3807
3808 for ( i = 0; i < func->num_subactions; ++i )
3809 {
3810 object_free( func->actions[ i ].name );
3811 function_free( func->actions[ i ].command );
3812 }
3813 BJAM_FREE( func->actions );
3814
3815 object_free( func->file );
3816 }
3817 }
3818#ifdef HAVE_PYTHON
3819 else if ( function_->type == FUNCTION_PYTHON )
3820 {
3821 PYTHON_FUNCTION * func = (PYTHON_FUNCTION *)function_;
3822 Py_DECREF( func->python_function );
3823 if ( function_->rulename ) object_free( function_->rulename );
3824 }
3825#endif
3826 else
3827 {
3828 assert( function_->type == FUNCTION_BUILTIN );
3829 if ( function_->rulename ) object_free( function_->rulename );
3830 }
3831
3832 BJAM_FREE( function_ );
3833}
3834
3835
3836/* Alignment check for stack */
3837
3838struct align_var_edits
3839{
3840 char ch;
3841 VAR_EDITS e;
3842};
3843
3844struct align_expansion_item
3845{
3846 char ch;
3847 expansion_item e;
3848};
3849
3850static char check_align_var_edits[ sizeof(struct align_var_edits) <= sizeof(VAR_EDITS) + sizeof(void *) ? 1 : -1 ];
3851static char check_align_expansion_item[ sizeof(struct align_expansion_item) <= sizeof(expansion_item) + sizeof(void *) ? 1 : -1 ];
3852
3853static char check_ptr_size1[ sizeof(LIST *) <= sizeof(void *) ? 1 : -1 ];
3854static char check_ptr_size2[ sizeof(char *) <= sizeof(void *) ? 1 : -1 ];
3855
3856void function_run_actions( FUNCTION * function, FRAME * frame, STACK * s,
3857 string * out )
3858{
3859 *(string * *)stack_allocate( s, sizeof( string * ) ) = out;
3860 list_free( function_run( function, frame, s ) );
3861 stack_deallocate( s, sizeof( string * ) );
3862}
3863
3864/*
3865 * WARNING: The instruction set is tuned for Jam and is not really generic. Be
3866 * especially careful about stack push/pop.
3867 */
3868
3869LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s )
3870{
3871 JAM_FUNCTION * function;
3872 instruction * code;
3873 LIST * l;
3874 LIST * r;
3875 LIST * result = L0;
3876 void * saved_stack = s->data;
3877
3878 PROFILE_ENTER_LOCAL(function_run);
3879
b32b8144
FG
3880#ifdef JAM_DEBUGGER
3881 frame->function = function_;
3882#endif
3883
7c673cae
FG
3884 if ( function_->type == FUNCTION_BUILTIN )
3885 {
3886 PROFILE_ENTER_LOCAL(function_run_FUNCTION_BUILTIN);
3887 BUILTIN_FUNCTION const * const f = (BUILTIN_FUNCTION *)function_;
3888 if ( function_->formal_arguments )
3889 argument_list_check( function_->formal_arguments,
3890 function_->num_formal_arguments, function_, frame );
b32b8144
FG
3891
3892 debug_on_enter_function( frame, f->base.rulename, NULL, -1 );
3893 result = f->func( frame, f->flags );
3894 debug_on_exit_function( f->base.rulename );
7c673cae
FG
3895 PROFILE_EXIT_LOCAL(function_run_FUNCTION_BUILTIN);
3896 PROFILE_EXIT_LOCAL(function_run);
b32b8144 3897 return result;
7c673cae
FG
3898 }
3899
3900#ifdef HAVE_PYTHON
3901 else if ( function_->type == FUNCTION_PYTHON )
3902 {
3903 PROFILE_ENTER_LOCAL(function_run_FUNCTION_PYTHON);
3904 PYTHON_FUNCTION * f = (PYTHON_FUNCTION *)function_;
b32b8144
FG
3905 debug_on_enter_function( frame, f->base.rulename, NULL, -1 );
3906 result = call_python_function( f, frame );
3907 debug_on_exit_function( f->base.rulename );
7c673cae
FG
3908 PROFILE_EXIT_LOCAL(function_run_FUNCTION_PYTHON);
3909 PROFILE_EXIT_LOCAL(function_run);
b32b8144 3910 return result;
7c673cae
FG
3911 }
3912#endif
3913
3914 assert( function_->type == FUNCTION_JAM );
3915
3916 if ( function_->formal_arguments )
3917 argument_list_push( function_->formal_arguments,
3918 function_->num_formal_arguments, function_, frame, s );
3919
3920 function = (JAM_FUNCTION *)function_;
b32b8144 3921 debug_on_enter_function( frame, function->base.rulename, function->file, function->line );
7c673cae
FG
3922 code = function->code;
3923 for ( ; ; )
3924 {
3925 switch ( code->op_code )
3926 {
3927
3928 /*
3929 * Basic stack manipulation
3930 */
3931
3932 case INSTR_PUSH_EMPTY:
3933 {
3934 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_EMPTY);
3935 stack_push( s, L0 );
3936 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_EMPTY);
3937 break;
3938 }
3939
3940 case INSTR_PUSH_CONSTANT:
3941 {
3942 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_CONSTANT);
3943 OBJECT * value = function_get_constant( function, code->arg );
3944 stack_push( s, list_new( object_copy( value ) ) );
3945 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_CONSTANT);
3946 break;
3947 }
3948
3949 case INSTR_PUSH_ARG:
3950 {
3951 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_ARG);
3952 stack_push( s, frame_get_local( frame, code->arg ) );
3953 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_ARG);
3954 break;
3955 }
3956
3957 case INSTR_PUSH_VAR:
3958 {
3959 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_VAR);
3960 stack_push( s, function_get_variable( function, frame, code->arg ) );
3961 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_VAR);
3962 break;
3963 }
3964
3965 case INSTR_PUSH_VAR_FIXED:
3966 {
3967 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_VAR_FIXED);
3968 stack_push( s, list_copy( frame->module->fixed_variables[ code->arg
3969 ] ) );
3970 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_VAR_FIXED);
3971 break;
3972 }
3973
3974 case INSTR_PUSH_GROUP:
3975 {
3976 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_GROUP);
3977 LIST * value = L0;
3978 LISTITER iter;
3979 LISTITER end;
3980 l = stack_pop( s );
3981 for ( iter = list_begin( l ), end = list_end( l ); iter != end;
3982 iter = list_next( iter ) )
3983 value = list_append( value, function_get_named_variable(
3984 function, frame, list_item( iter ) ) );
3985 list_free( l );
3986 stack_push( s, value );
3987 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_GROUP);
3988 break;
3989 }
3990
3991 case INSTR_PUSH_APPEND:
3992 {
3993 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_APPEND);
3994 r = stack_pop( s );
3995 l = stack_pop( s );
3996 stack_push( s, list_append( l, r ) );
3997 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_APPEND);
3998 break;
3999 }
4000
4001 case INSTR_SWAP:
4002 {
4003 PROFILE_ENTER_LOCAL(function_run_INSTR_SWAP);
4004 l = stack_top( s );
4005 stack_set( s, 0, stack_at( s, code->arg ) );
4006 stack_set( s, code->arg, l );
4007 PROFILE_EXIT_LOCAL(function_run_INSTR_SWAP);
4008 break;
4009 }
4010
4011 case INSTR_POP:
4012 {
4013 PROFILE_ENTER_LOCAL(function_run_INSTR_POP);
4014 list_free( stack_pop( s ) );
4015 PROFILE_EXIT_LOCAL(function_run_INSTR_POP);
4016 break;
4017 }
4018
4019 /*
4020 * Branch instructions
4021 */
4022
4023 case INSTR_JUMP:
4024 {
4025 PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP);
4026 code += code->arg;
4027 PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP);
4028 break;
4029 }
4030
4031 case INSTR_JUMP_EMPTY:
4032 {
4033 PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_EMPTY);
4034 l = stack_pop( s );
4035 if ( !list_cmp( l, L0 ) ) code += code->arg;
4036 list_free( l );
4037 PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_EMPTY);
4038 break;
4039 }
4040
4041 case INSTR_JUMP_NOT_EMPTY:
4042 {
4043 PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_NOT_EMPTY);
4044 l = stack_pop( s );
4045 if ( list_cmp( l, L0 ) ) code += code->arg;
4046 list_free( l );
4047 PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_NOT_EMPTY);
4048 break;
4049 }
4050
4051 case INSTR_JUMP_LT:
4052 {
4053 PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_LT);
4054 r = stack_pop( s );
4055 l = stack_pop( s );
4056 if ( list_cmp( l, r ) < 0 ) code += code->arg;
4057 list_free( l );
4058 list_free( r );
4059 PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_LT);
4060 break;
4061 }
4062
4063 case INSTR_JUMP_LE:
4064 {
4065 PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_LE);
4066 r = stack_pop( s );
4067 l = stack_pop( s );
4068 if ( list_cmp( l, r ) <= 0 ) code += code->arg;
4069 list_free( l );
4070 list_free( r );
4071 PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_LE);
4072 break;
4073 }
4074
4075 case INSTR_JUMP_GT:
4076 {
4077 PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_GT);
4078 r = stack_pop( s );
4079 l = stack_pop( s );
4080 if ( list_cmp( l, r ) > 0 ) code += code->arg;
4081 list_free( l );
4082 list_free( r );
4083 PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_GT);
4084 break;
4085 }
4086
4087 case INSTR_JUMP_GE:
4088 {
4089 PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_GE);
4090 r = stack_pop( s );
4091 l = stack_pop( s );
4092 if ( list_cmp( l, r ) >= 0 ) code += code->arg;
4093 list_free( l );
4094 list_free( r );
4095 PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_GE);
4096 break;
4097 }
4098
4099 case INSTR_JUMP_EQ:
4100 {
4101 PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_EQ);
4102 r = stack_pop( s );
4103 l = stack_pop( s );
4104 if ( list_cmp( l, r ) == 0 ) code += code->arg;
4105 list_free( l );
4106 list_free( r );
4107 PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_EQ);
4108 break;
4109 }
4110
4111 case INSTR_JUMP_NE:
4112 {
4113 PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_NE);
4114 r = stack_pop(s);
4115 l = stack_pop(s);
4116 if ( list_cmp(l, r) != 0 ) code += code->arg;
4117 list_free(l);
4118 list_free(r);
4119 PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_NE);
4120 break;
4121 }
4122
4123 case INSTR_JUMP_IN:
4124 {
4125 PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_IN);
4126 r = stack_pop(s);
4127 l = stack_pop(s);
4128 if ( list_is_sublist( l, r ) ) code += code->arg;
4129 list_free(l);
4130 list_free(r);
4131 PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_IN);
4132 break;
4133 }
4134
4135 case INSTR_JUMP_NOT_IN:
4136 {
4137 PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_NOT_IN);
4138 r = stack_pop( s );
4139 l = stack_pop( s );
4140 if ( !list_is_sublist( l, r ) ) code += code->arg;
4141 list_free( l );
4142 list_free( r );
4143 PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_NOT_IN);
4144 break;
4145 }
4146
4147 /*
4148 * For
4149 */
4150
4151 case INSTR_FOR_INIT:
4152 {
4153 PROFILE_ENTER_LOCAL(function_run_INSTR_FOR_INIT);
4154 l = stack_top( s );
4155 *(LISTITER *)stack_allocate( s, sizeof( LISTITER ) ) =
4156 list_begin( l );
4157 PROFILE_EXIT_LOCAL(function_run_INSTR_FOR_INIT);
4158 break;
4159 }
4160
4161 case INSTR_FOR_LOOP:
4162 {
4163 PROFILE_ENTER_LOCAL(function_run_INSTR_FOR_LOOP);
4164 LISTITER iter = *(LISTITER *)stack_get( s );
4165 stack_deallocate( s, sizeof( LISTITER ) );
4166 l = stack_top( s );
4167 if ( iter == list_end( l ) )
4168 {
4169 list_free( stack_pop( s ) );
4170 code += code->arg;
4171 }
4172 else
4173 {
4174 r = list_new( object_copy( list_item( iter ) ) );
4175 iter = list_next( iter );
4176 *(LISTITER *)stack_allocate( s, sizeof( LISTITER ) ) = iter;
4177 stack_push( s, r );
4178 }
4179 PROFILE_EXIT_LOCAL(function_run_INSTR_FOR_LOOP);
4180 break;
4181 }
4182
4183 case INSTR_FOR_POP:
4184 {
4185 PROFILE_ENTER_LOCAL(function_run_INSTR_FOR_POP);
4186 stack_deallocate( s, sizeof( LISTITER ) );
4187 list_free( stack_pop( s ) );
4188 PROFILE_EXIT_LOCAL(function_run_INSTR_FOR_POP);
4189 break;
4190 }
4191
4192 /*
4193 * Switch
4194 */
4195
4196 case INSTR_JUMP_NOT_GLOB:
4197 {
4198 PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_NOT_GLOB);
4199 char const * pattern;
4200 char const * match;
4201 l = stack_pop( s );
4202 r = stack_top( s );
4203 pattern = list_empty( l ) ? "" : object_str( list_front( l ) );
4204 match = list_empty( r ) ? "" : object_str( list_front( r ) );
4205 if ( glob( pattern, match ) )
4206 code += code->arg;
4207 else
4208 list_free( stack_pop( s ) );
4209 list_free( l );
4210 PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_NOT_GLOB);
4211 break;
4212 }
4213
4214 /*
4215 * Return
4216 */
4217
4218 case INSTR_SET_RESULT:
4219 {
4220 PROFILE_ENTER_LOCAL(function_run_INSTR_SET_RESULT);
4221 list_free( result );
4222 if ( !code->arg )
4223 result = stack_pop( s );
4224 else
4225 result = list_copy( stack_top( s ) );
4226 PROFILE_EXIT_LOCAL(function_run_INSTR_SET_RESULT);
4227 break;
4228 }
4229
4230 case INSTR_PUSH_RESULT:
4231 {
4232 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_RESULT);
4233 stack_push( s, result );
4234 result = L0;
4235 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_RESULT);
4236 break;
4237 }
4238
4239 case INSTR_RETURN:
4240 {
4241 PROFILE_ENTER_LOCAL(function_run_INSTR_RETURN);
4242 if ( function_->formal_arguments )
4243 argument_list_pop( function_->formal_arguments,
4244 function_->num_formal_arguments, frame, s );
4245#ifndef NDEBUG
4246 if ( !( saved_stack == s->data ) )
4247 {
4248 frame->file = function->file;
4249 frame->line = function->line;
4250 backtrace_line( frame );
4251 out_printf( "error: stack check failed.\n" );
4252 backtrace( frame );
4253 assert( saved_stack == s->data );
4254 }
4255#endif
4256 assert( saved_stack == s->data );
b32b8144 4257 debug_on_exit_function( function->base.rulename );
7c673cae
FG
4258 PROFILE_EXIT_LOCAL(function_run_INSTR_RETURN);
4259 PROFILE_EXIT_LOCAL(function_run);
4260 return result;
4261 }
4262
4263 /*
4264 * Local variables
4265 */
4266
4267 case INSTR_PUSH_LOCAL:
4268 {
4269 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_LOCAL);
4270 LIST * value = stack_pop( s );
4271 stack_push( s, function_swap_variable( function, frame, code->arg,
4272 value ) );
4273 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_LOCAL);
4274 break;
4275 }
4276
4277 case INSTR_POP_LOCAL:
4278 {
4279 PROFILE_ENTER_LOCAL(function_run_INSTR_POP_LOCAL);
4280 function_set_variable( function, frame, code->arg, stack_pop( s ) );
4281 PROFILE_EXIT_LOCAL(function_run_INSTR_POP_LOCAL);
4282 break;
4283 }
4284
4285 case INSTR_PUSH_LOCAL_FIXED:
4286 {
4287 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_LOCAL_FIXED);
4288 LIST * value = stack_pop( s );
4289 LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
4290 assert( code->arg < frame->module->num_fixed_variables );
4291 stack_push( s, *ptr );
4292 *ptr = value;
4293 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_LOCAL_FIXED);
4294 break;
4295 }
4296
4297 case INSTR_POP_LOCAL_FIXED:
4298 {
4299 PROFILE_ENTER_LOCAL(function_run_INSTR_POP_LOCAL_FIXED);
4300 LIST * value = stack_pop( s );
4301 LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
4302 assert( code->arg < frame->module->num_fixed_variables );
4303 list_free( *ptr );
4304 *ptr = value;
4305 PROFILE_EXIT_LOCAL(function_run_INSTR_POP_LOCAL_FIXED);
4306 break;
4307 }
4308
4309 case INSTR_PUSH_LOCAL_GROUP:
4310 {
4311 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_LOCAL_GROUP);
4312 LIST * const value = stack_pop( s );
4313 LISTITER iter;
4314 LISTITER end;
4315 l = stack_pop( s );
4316 for ( iter = list_begin( l ), end = list_end( l ); iter != end;
4317 iter = list_next( iter ) )
4318 stack_push( s, function_swap_named_variable( function, frame,
4319 list_item( iter ), list_copy( value ) ) );
4320 list_free( value );
4321 stack_push( s, l );
4322 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_LOCAL_GROUP);
4323 break;
4324 }
4325
4326 case INSTR_POP_LOCAL_GROUP:
4327 {
4328 PROFILE_ENTER_LOCAL(function_run_INSTR_POP_LOCAL_GROUP);
4329 LISTITER iter;
4330 LISTITER end;
4331 r = stack_pop( s );
4332 l = list_reverse( r );
4333 list_free( r );
4334 for ( iter = list_begin( l ), end = list_end( l ); iter != end;
4335 iter = list_next( iter ) )
4336 function_set_named_variable( function, frame, list_item( iter ),
4337 stack_pop( s ) );
4338 list_free( l );
4339 PROFILE_EXIT_LOCAL(function_run_INSTR_POP_LOCAL_GROUP);
4340 break;
4341 }
4342
4343 /*
4344 * on $(TARGET) variables
4345 */
4346
4347 case INSTR_PUSH_ON:
4348 {
4349 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_ON);
4350 LIST * targets = stack_top( s );
4351 if ( !list_empty( targets ) )
4352 {
4353 /* FIXME: push the state onto the stack instead of using
4354 * pushsettings.
4355 */
4356 TARGET * t = bindtarget( list_front( targets ) );
4357 pushsettings( frame->module, t->settings );
4358 }
4359 else
4360 {
4361 /* [ on $(TARGET) ... ] is ignored if $(TARGET) is empty. */
4362 list_free( stack_pop( s ) );
4363 stack_push( s, L0 );
4364 code += code->arg;
4365 }
4366 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_ON);
4367 break;
4368 }
4369
4370 case INSTR_POP_ON:
4371 {
4372 PROFILE_ENTER_LOCAL(function_run_INSTR_POP_ON);
4373 LIST * result = stack_pop( s );
4374 LIST * targets = stack_pop( s );
4375 if ( !list_empty( targets ) )
4376 {
4377 TARGET * t = bindtarget( list_front( targets ) );
4378 popsettings( frame->module, t->settings );
4379 }
4380 list_free( targets );
4381 stack_push( s, result );
4382 PROFILE_EXIT_LOCAL(function_run_INSTR_POP_ON);
4383 break;
4384 }
4385
4386 case INSTR_SET_ON:
4387 {
4388 PROFILE_ENTER_LOCAL(function_run_INSTR_SET_ON);
4389 LIST * targets = stack_pop( s );
4390 LIST * value = stack_pop( s );
4391 LIST * vars = stack_pop( s );
4392 LISTITER iter = list_begin( targets );
4393 LISTITER const end = list_end( targets );
4394 for ( ; iter != end; iter = list_next( iter ) )
4395 {
4396 TARGET * t = bindtarget( list_item( iter ) );
4397 LISTITER vars_iter = list_begin( vars );
4398 LISTITER const vars_end = list_end( vars );
4399 for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter
4400 ) )
4401 t->settings = addsettings( t->settings, VAR_SET, list_item(
4402 vars_iter ), list_copy( value ) );
4403 }
4404 list_free( vars );
4405 list_free( targets );
4406 stack_push( s, value );
4407 PROFILE_EXIT_LOCAL(function_run_INSTR_SET_ON);
4408 break;
4409 }
4410
4411 case INSTR_APPEND_ON:
4412 {
4413 PROFILE_ENTER_LOCAL(function_run_INSTR_APPEND_ON);
4414 LIST * targets = stack_pop( s );
4415 LIST * value = stack_pop( s );
4416 LIST * vars = stack_pop( s );
4417 LISTITER iter = list_begin( targets );
4418 LISTITER const end = list_end( targets );
4419 for ( ; iter != end; iter = list_next( iter ) )
4420 {
4421 TARGET * const t = bindtarget( list_item( iter ) );
4422 LISTITER vars_iter = list_begin( vars );
4423 LISTITER const vars_end = list_end( vars );
4424 for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter
4425 ) )
4426 t->settings = addsettings( t->settings, VAR_APPEND,
4427 list_item( vars_iter ), list_copy( value ) );
4428 }
4429 list_free( vars );
4430 list_free( targets );
4431 stack_push( s, value );
4432 PROFILE_EXIT_LOCAL(function_run_INSTR_APPEND_ON);
4433 break;
4434 }
4435
4436 case INSTR_DEFAULT_ON:
4437 {
4438 PROFILE_ENTER_LOCAL(function_run_INSTR_DEFAULT_ON);
4439 LIST * targets = stack_pop( s );
4440 LIST * value = stack_pop( s );
4441 LIST * vars = stack_pop( s );
4442 LISTITER iter = list_begin( targets );
4443 LISTITER const end = list_end( targets );
4444 for ( ; iter != end; iter = list_next( iter ) )
4445 {
4446 TARGET * t = bindtarget( list_item( iter ) );
4447 LISTITER vars_iter = list_begin( vars );
4448 LISTITER const vars_end = list_end( vars );
4449 for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter
4450 ) )
4451 t->settings = addsettings( t->settings, VAR_DEFAULT,
4452 list_item( vars_iter ), list_copy( value ) );
4453 }
4454 list_free( vars );
4455 list_free( targets );
4456 stack_push( s, value );
4457 PROFILE_EXIT_LOCAL(function_run_INSTR_DEFAULT_ON);
4458 break;
4459 }
4460
4461 /* [ on $(target) return $(variable) ] */
4462 case INSTR_GET_ON:
4463 {
4464 PROFILE_ENTER_LOCAL(function_run_INSTR_GET_ON);
4465 LIST * targets = stack_pop( s );
4466 LIST * result = L0;
4467 if ( !list_empty( targets ) )
4468 {
4469 OBJECT * varname = function->constants[ code->arg ];
4470 TARGET * t = bindtarget( list_front( targets ) );
4471 SETTINGS * s = t->settings;
4472 int found = 0;
4473 for ( ; s != 0; s = s->next )
4474 {
4475 if ( object_equal( s->symbol, varname ) )
4476 {
4477 result = s->value;
4478 found = 1;
4479 break;
4480 }
4481 }
4482 if ( !found )
4483 {
4484 result = var_get( frame->module, varname ) ;
4485 }
4486 }
4487 list_free( targets );
4488 stack_push( s, list_copy( result ) );
4489 PROFILE_EXIT_LOCAL(function_run_INSTR_GET_ON);
4490 break;
4491 }
4492
4493 /*
4494 * Variable setting
4495 */
4496
4497 case INSTR_SET:
4498 {
4499 PROFILE_ENTER_LOCAL(function_run_INSTR_SET);
4500 function_set_variable( function, frame, code->arg,
4501 stack_pop( s ) );
4502 PROFILE_EXIT_LOCAL(function_run_INSTR_SET);
4503 break;
4504 }
4505
4506 case INSTR_APPEND:
4507 {
4508 PROFILE_ENTER_LOCAL(function_run_INSTR_APPEND);
4509 function_append_variable( function, frame, code->arg,
4510 stack_pop( s ) );
4511 PROFILE_EXIT_LOCAL(function_run_INSTR_APPEND);
4512 break;
4513 }
4514
4515 case INSTR_DEFAULT:
4516 {
4517 PROFILE_ENTER_LOCAL(function_run_INSTR_DEFAULT);
4518 function_default_variable( function, frame, code->arg,
4519 stack_pop( s ) );
4520 PROFILE_EXIT_LOCAL(function_run_INSTR_DEFAULT);
4521 break;
4522 }
4523
4524 case INSTR_SET_FIXED:
4525 {
4526 PROFILE_ENTER_LOCAL(function_run_INSTR_SET_FIXED);
4527 LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
4528 assert( code->arg < frame->module->num_fixed_variables );
4529 list_free( *ptr );
4530 *ptr = stack_pop( s );
4531 PROFILE_EXIT_LOCAL(function_run_INSTR_SET_FIXED);
4532 break;
4533 }
4534
4535 case INSTR_APPEND_FIXED:
4536 {
4537 PROFILE_ENTER_LOCAL(function_run_INSTR_APPEND_FIXED);
4538 LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
4539 assert( code->arg < frame->module->num_fixed_variables );
4540 *ptr = list_append( *ptr, stack_pop( s ) );
4541 PROFILE_EXIT_LOCAL(function_run_INSTR_APPEND_FIXED);
4542 break;
4543 }
4544
4545 case INSTR_DEFAULT_FIXED:
4546 {
4547 PROFILE_ENTER_LOCAL(function_run_INSTR_DEFAULT_FIXED);
4548 LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
4549 LIST * value = stack_pop( s );
4550 assert( code->arg < frame->module->num_fixed_variables );
4551 if ( list_empty( *ptr ) )
4552 *ptr = value;
4553 else
4554 list_free( value );
4555 PROFILE_EXIT_LOCAL(function_run_INSTR_DEFAULT_FIXED);
4556 break;
4557 }
4558
4559 case INSTR_SET_GROUP:
4560 {
4561 PROFILE_ENTER_LOCAL(function_run_INSTR_SET_GROUP);
4562 LIST * value = stack_pop( s );
4563 LIST * vars = stack_pop( s );
4564 LISTITER iter = list_begin( vars );
4565 LISTITER const end = list_end( vars );
4566 for ( ; iter != end; iter = list_next( iter ) )
4567 function_set_named_variable( function, frame, list_item( iter ),
4568 list_copy( value ) );
4569 list_free( vars );
4570 list_free( value );
4571 PROFILE_EXIT_LOCAL(function_run_INSTR_SET_GROUP);
4572 break;
4573 }
4574
4575 case INSTR_APPEND_GROUP:
4576 {
4577 PROFILE_ENTER_LOCAL(function_run_INSTR_APPEND_GROUP);
4578 LIST * value = stack_pop( s );
4579 LIST * vars = stack_pop( s );
4580 LISTITER iter = list_begin( vars );
4581 LISTITER const end = list_end( vars );
4582 for ( ; iter != end; iter = list_next( iter ) )
4583 function_append_named_variable( function, frame, list_item( iter
4584 ), list_copy( value ) );
4585 list_free( vars );
4586 list_free( value );
4587 PROFILE_EXIT_LOCAL(function_run_INSTR_APPEND_GROUP);
4588 break;
4589 }
4590
4591 case INSTR_DEFAULT_GROUP:
4592 {
4593 PROFILE_ENTER_LOCAL(function_run_INSTR_DEFAULT_GROUP);
4594 LIST * value = stack_pop( s );
4595 LIST * vars = stack_pop( s );
4596 LISTITER iter = list_begin( vars );
4597 LISTITER const end = list_end( vars );
4598 for ( ; iter != end; iter = list_next( iter ) )
4599 function_default_named_variable( function, frame, list_item(
4600 iter ), list_copy( value ) );
4601 list_free( vars );
4602 list_free( value );
4603 PROFILE_EXIT_LOCAL(function_run_INSTR_DEFAULT_GROUP);
4604 break;
4605 }
4606
4607 /*
4608 * Rules
4609 */
4610
4611 case INSTR_CALL_RULE:
4612 {
4613 PROFILE_ENTER_LOCAL(function_run_INSTR_CALL_RULE);
4614 char const * unexpanded = object_str( function_get_constant(
4615 function, code[ 1 ].op_code ) );
4616 LIST * result = function_call_rule( function, frame, s, code->arg,
4617 unexpanded, function->file, code[ 1 ].arg );
4618 stack_push( s, result );
4619 ++code;
4620 PROFILE_EXIT_LOCAL(function_run_INSTR_CALL_RULE);
4621 break;
4622 }
4623
4624 case INSTR_CALL_MEMBER_RULE:
4625 {
4626 PROFILE_ENTER_LOCAL(function_run_INSTR_CALL_MEMBER_RULE);
4627 OBJECT * rule_name = function_get_constant( function, code[1].op_code );
4628 LIST * result = function_call_member_rule( function, frame, s, code->arg, rule_name, function->file, code[1].arg );
4629 stack_push( s, result );
4630 ++code;
4631 PROFILE_EXIT_LOCAL(function_run_INSTR_CALL_MEMBER_RULE);
4632 break;
4633 }
4634
4635 case INSTR_RULE:
4636 {
4637 PROFILE_ENTER_LOCAL(function_run_INSTR_RULE);
4638 function_set_rule( function, frame, s, code->arg );
4639 PROFILE_EXIT_LOCAL(function_run_INSTR_RULE);
4640 break;
4641 }
4642
4643 case INSTR_ACTIONS:
4644 {
4645 PROFILE_ENTER_LOCAL(function_run_INSTR_ACTIONS);
4646 function_set_actions( function, frame, s, code->arg );
4647 PROFILE_EXIT_LOCAL(function_run_INSTR_ACTIONS);
4648 break;
4649 }
4650
4651 /*
4652 * Variable expansion
4653 */
4654
4655 case INSTR_APPLY_MODIFIERS:
4656 {
4657 PROFILE_ENTER_LOCAL(function_run_INSTR_APPLY_MODIFIERS);
4658 int n;
4659 int i;
4660 l = stack_pop( s );
4661 n = expand_modifiers( s, code->arg );
4662 stack_push( s, l );
4663 l = apply_modifiers( s, n );
4664 list_free( stack_pop( s ) );
4665 stack_deallocate( s, n * sizeof( VAR_EDITS ) );
4666 for ( i = 0; i < code->arg; ++i )
4667 list_free( stack_pop( s ) ); /* pop modifiers */
4668 stack_push( s, l );
4669 PROFILE_EXIT_LOCAL(function_run_INSTR_APPLY_MODIFIERS);
4670 break;
4671 }
4672
4673 case INSTR_APPLY_INDEX:
4674 {
4675 PROFILE_ENTER_LOCAL(function_run_INSTR_APPLY_INDEX);
4676 l = apply_subscript( s );
4677 list_free( stack_pop( s ) );
4678 list_free( stack_pop( s ) );
4679 stack_push( s, l );
4680 PROFILE_EXIT_LOCAL(function_run_INSTR_APPLY_INDEX);
4681 break;
4682 }
4683
4684 case INSTR_APPLY_INDEX_MODIFIERS:
4685 {
4686 PROFILE_ENTER_LOCAL(function_run_INSTR_APPLY_INDEX_MODIFIERS);
4687 int i;
4688 int n;
4689 l = stack_pop( s );
4690 r = stack_pop( s );
4691 n = expand_modifiers( s, code->arg );
4692 stack_push( s, r );
4693 stack_push( s, l );
4694 l = apply_subscript_and_modifiers( s, n );
4695 list_free( stack_pop( s ) );
4696 list_free( stack_pop( s ) );
4697 stack_deallocate( s, n * sizeof( VAR_EDITS ) );
4698 for ( i = 0; i < code->arg; ++i )
4699 list_free( stack_pop( s ) ); /* pop modifiers */
4700 stack_push( s, l );
4701 PROFILE_EXIT_LOCAL(function_run_INSTR_APPLY_INDEX_MODIFIERS);
4702 break;
4703 }
4704
4705 case INSTR_APPLY_MODIFIERS_GROUP:
4706 {
4707 PROFILE_ENTER_LOCAL(function_run_INSTR_APPLY_MODIFIERS_GROUP);
4708 int i;
4709 LIST * const vars = stack_pop( s );
4710 int const n = expand_modifiers( s, code->arg );
4711 LIST * result = L0;
4712 LISTITER iter = list_begin( vars );
4713 LISTITER const end = list_end( vars );
4714 for ( ; iter != end; iter = list_next( iter ) )
4715 {
4716 stack_push( s, function_get_named_variable( function, frame,
4717 list_item( iter ) ) );
4718 result = list_append( result, apply_modifiers( s, n ) );
4719 list_free( stack_pop( s ) );
4720 }
4721 list_free( vars );
4722 stack_deallocate( s, n * sizeof( VAR_EDITS ) );
4723 for ( i = 0; i < code->arg; ++i )
4724 list_free( stack_pop( s ) ); /* pop modifiers */
4725 stack_push( s, result );
4726 PROFILE_EXIT_LOCAL(function_run_INSTR_APPLY_MODIFIERS_GROUP);
4727 break;
4728 }
4729
4730 case INSTR_APPLY_INDEX_GROUP:
4731 {
4732 PROFILE_ENTER_LOCAL(function_run_INSTR_APPLY_INDEX_GROUP);
4733 LIST * vars = stack_pop( s );
4734 LIST * result = L0;
4735 LISTITER iter = list_begin( vars );
4736 LISTITER const end = list_end( vars );
4737 for ( ; iter != end; iter = list_next( iter ) )
4738 {
4739 stack_push( s, function_get_named_variable( function, frame,
4740 list_item( iter ) ) );
4741 result = list_append( result, apply_subscript( s ) );
4742 list_free( stack_pop( s ) );
4743 }
4744 list_free( vars );
4745 list_free( stack_pop( s ) );
4746 stack_push( s, result );
4747 PROFILE_EXIT_LOCAL(function_run_INSTR_APPLY_INDEX_GROUP);
4748 break;
4749 }
4750
4751 case INSTR_APPLY_INDEX_MODIFIERS_GROUP:
4752 {
4753 PROFILE_ENTER_LOCAL(function_run_INSTR_APPLY_INDEX_MODIFIERS_GROUP);
4754 int i;
4755 LIST * const vars = stack_pop( s );
4756 LIST * const r = stack_pop( s );
4757 int const n = expand_modifiers( s, code->arg );
4758 LIST * result = L0;
4759 LISTITER iter = list_begin( vars );
4760 LISTITER const end = list_end( vars );
4761 stack_push( s, r );
4762 for ( ; iter != end; iter = list_next( iter ) )
4763 {
4764 stack_push( s, function_get_named_variable( function, frame,
4765 list_item( iter ) ) );
4766 result = list_append( result, apply_subscript_and_modifiers( s,
4767 n ) );
4768 list_free( stack_pop( s ) );
4769 }
4770 list_free( stack_pop( s ) );
4771 list_free( vars );
4772 stack_deallocate( s, n * sizeof( VAR_EDITS ) );
4773 for ( i = 0; i < code->arg; ++i )
4774 list_free( stack_pop( s ) ); /* pop modifiers */
4775 stack_push( s, result );
4776 PROFILE_EXIT_LOCAL(function_run_INSTR_APPLY_INDEX_MODIFIERS_GROUP);
4777 break;
4778 }
4779
4780 case INSTR_COMBINE_STRINGS:
4781 {
4782 PROFILE_ENTER_LOCAL(function_run_INSTR_COMBINE_STRINGS);
4783 size_t const buffer_size = code->arg * sizeof( expansion_item );
4784 LIST * * const stack_pos = stack_get( s );
4785 expansion_item * items = stack_allocate( s, buffer_size );
4786 LIST * result;
4787 int i;
4788 for ( i = 0; i < code->arg; ++i )
4789 items[ i ].values = stack_pos[ i ];
4790 result = expand( items, code->arg );
4791 stack_deallocate( s, buffer_size );
4792 for ( i = 0; i < code->arg; ++i )
4793 list_free( stack_pop( s ) );
4794 stack_push( s, result );
4795 PROFILE_EXIT_LOCAL(function_run_INSTR_COMBINE_STRINGS);
4796 break;
4797 }
4798
4799 case INSTR_GET_GRIST:
4800 {
4801 PROFILE_ENTER_LOCAL(function_run_INSTR_GET_GRIST);
4802 LIST * vals = stack_pop( s );
4803 LIST * result = L0;
4804 LISTITER iter, end;
4805
4806 for ( iter = list_begin( vals ), end = list_end( vals ); iter != end; ++iter )
4807 {
4808 OBJECT * new_object;
4809 const char * value = object_str( list_item( iter ) );
4810 const char * p;
4811 if ( value[ 0 ] == '<' && ( p = strchr( value, '>' ) ) )
4812 {
4813 if( p[ 1 ] )
4814 new_object = object_new_range( value, p - value + 1 );
4815 else
4816 new_object = object_copy( list_item( iter ) );
4817 }
4818 else
4819 {
4820 new_object = object_copy( constant_empty );
4821 }
4822 result = list_push_back( result, new_object );
4823 }
4824
4825 list_free( vals );
4826 stack_push( s, result );
4827 PROFILE_EXIT_LOCAL(function_run_INSTR_GET_GRIST);
4828 break;
4829 }
4830
4831 case INSTR_INCLUDE:
4832 {
4833 PROFILE_ENTER_LOCAL(function_run_INSTR_INCLUDE);
4834 LIST * nt = stack_pop( s );
4835 if ( !list_empty( nt ) )
4836 {
4837 TARGET * const t = bindtarget( list_front( nt ) );
4838 list_free( nt );
4839
4840 /* DWA 2001/10/22 - Perforce Jam cleared the arguments here,
4841 * which prevented an included file from being treated as part
4842 * of the body of a rule. I did not see any reason to do that,
4843 * so I lifted the restriction.
4844 */
4845
4846 /* Bind the include file under the influence of "on-target"
4847 * variables. Though they are targets, include files are not
4848 * built with make().
4849 */
4850
4851 pushsettings( root_module(), t->settings );
4852 /* We do not expect that a file to be included is generated by
4853 * some action. Therefore, pass 0 as third argument. If the name
4854 * resolves to a directory, let it error out.
4855 */
4856 object_free( t->boundname );
4857 t->boundname = search( t->name, &t->time, 0, 0 );
4858 popsettings( root_module(), t->settings );
4859
4860 parse_file( t->boundname, frame );
b32b8144
FG
4861#ifdef JAM_DEBUGGER
4862 frame->function = function_;
4863#endif
7c673cae
FG
4864 }
4865 PROFILE_EXIT_LOCAL(function_run_INSTR_INCLUDE);
4866 break;
4867 }
4868
4869 /*
4870 * Classes and modules
4871 */
4872
4873 case INSTR_PUSH_MODULE:
4874 {
4875 PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_MODULE);
4876 LIST * const module_name = stack_pop( s );
4877 module_t * const outer_module = frame->module;
4878 frame->module = !list_empty( module_name )
4879 ? bindmodule( list_front( module_name ) )
4880 : root_module();
4881 list_free( module_name );
4882 *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) =
4883 outer_module;
4884 PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_MODULE);
4885 break;
4886 }
4887
4888 case INSTR_POP_MODULE:
4889 {
4890 PROFILE_ENTER_LOCAL(function_run_INSTR_POP_MODULE);
4891 module_t * const outer_module = *(module_t * *)stack_get( s );
4892 stack_deallocate( s, sizeof( module_t * ) );
4893 frame->module = outer_module;
4894 PROFILE_EXIT_LOCAL(function_run_INSTR_POP_MODULE);
4895 break;
4896 }
4897
4898 case INSTR_CLASS:
4899 {
4900 PROFILE_ENTER_LOCAL(function_run_INSTR_CLASS);
4901 LIST * bases = stack_pop( s );
4902 LIST * name = stack_pop( s );
4903 OBJECT * class_module = make_class_module( name, bases, frame );
4904
4905 module_t * const outer_module = frame->module;
4906 frame->module = bindmodule( class_module );
4907 object_free( class_module );
4908
4909 *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) =
4910 outer_module;
4911 PROFILE_EXIT_LOCAL(function_run_INSTR_CLASS);
4912 break;
4913 }
4914
4915 case INSTR_BIND_MODULE_VARIABLES:
4916 {
4917 PROFILE_ENTER_LOCAL(function_run_INSTR_BIND_MODULE_VARIABLES);
4918 module_bind_variables( frame->module );
4919 PROFILE_EXIT_LOCAL(function_run_INSTR_BIND_MODULE_VARIABLES);
4920 break;
4921 }
4922
4923 case INSTR_APPEND_STRINGS:
4924 {
4925 PROFILE_ENTER_LOCAL(function_run_INSTR_APPEND_STRINGS);
4926 string buf[ 1 ];
4927 string_new( buf );
4928 combine_strings( s, code->arg, buf );
4929 stack_push( s, list_new( object_new( buf->value ) ) );
4930 string_free( buf );
4931 PROFILE_EXIT_LOCAL(function_run_INSTR_APPEND_STRINGS);
4932 break;
4933 }
4934
4935 case INSTR_WRITE_FILE:
4936 {
4937 PROFILE_ENTER_LOCAL(function_run_INSTR_WRITE_FILE);
4938 string buf[ 1 ];
4939 char const * out;
4940 OBJECT * tmp_filename = 0;
4941 int out_debug = DEBUG_EXEC ? 1 : 0;
4942 FILE * out_file = 0;
4943 string_new( buf );
4944 combine_strings( s, code->arg, buf );
4945 out = object_str( list_front( stack_top( s ) ) );
4946
4947 /* For stdout/stderr we will create a temp file and generate a
4948 * command that outputs the content as needed.
4949 */
4950 if ( ( strcmp( "STDOUT", out ) == 0 ) ||
4951 ( strcmp( "STDERR", out ) == 0 ) )
4952 {
4953 int err_redir = strcmp( "STDERR", out ) == 0;
4954 string result[ 1 ];
4955
4956 tmp_filename = path_tmpfile();
4957
4958 /* Construct os-specific cat command. */
4959 {
4960 char * command = "cat";
4961 char * quote = "\"";
4962 char * redirect = "1>&2";
4963
4964 #ifdef OS_NT
4965 command = "type";
4966 quote = "\"";
4967 #elif defined( OS_VMS )
4968 command = "pipe type";
4969 quote = "";
4970
4971 /* Get tmp file name is os-format. */
4972 {
4973 string os_filename[ 1 ];
4974
4975 string_new( os_filename );
4976 path_translate_to_os( object_str( tmp_filename ), os_filename );
4977 object_free( tmp_filename );
4978 tmp_filename = object_new( os_filename->value );
4979 string_free( os_filename );
4980 }
4981 #endif
4982
4983 string_new( result );
4984 string_append( result, command );
4985 string_append( result, " " );
4986 string_append( result, quote );
4987 string_append( result, object_str( tmp_filename ) );
4988 string_append( result, quote );
4989 if ( err_redir )
4990 {
4991 string_append( result, " " );
4992 string_append( result, redirect );
4993 }
4994 }
4995
4996 /* Replace STDXXX with the temporary file. */
4997 list_free( stack_pop( s ) );
4998 stack_push( s, list_new( object_new( result->value ) ) );
4999 out = object_str( tmp_filename );
5000
5001 string_free( result );
5002
5003 /* Make sure temp files created by this get nuked eventually. */
5004 file_remove_atexit( tmp_filename );
5005 }
5006
5007 if ( !globs.noexec )
5008 {
5009 string out_name[ 1 ];
5010 /* Handle "path to file" filenames. */
5011 if ( ( out[ 0 ] == '"' ) && ( out[ strlen( out ) - 1 ] == '"' )
5012 )
5013 {
5014 string_copy( out_name, out + 1 );
5015 string_truncate( out_name, out_name->size - 1 );
5016 }
5017 else
5018 string_copy( out_name, out );
5019 out_file = fopen( out_name->value, "w" );
5020
5021 if ( !out_file )
5022 {
5023 err_printf( "failed to write output file '%s'!\n",
5024 out_name->value );
5025 exit( EXITBAD );
5026 }
5027 string_free( out_name );
5028 }
5029
5030 if ( out_debug ) out_printf( "\nfile %s\n", out );
5031 if ( out_file ) fputs( buf->value, out_file );
5032 if ( out_debug ) out_puts( buf->value );
5033 if ( out_file )
5034 {
5035 fflush( out_file );
5036 fclose( out_file );
5037 }
5038 string_free( buf );
5039 if ( tmp_filename )
5040 object_free( tmp_filename );
5041
5042 if ( out_debug ) out_putc( '\n' );
5043 PROFILE_EXIT_LOCAL(function_run_INSTR_WRITE_FILE);
5044 break;
5045 }
5046
5047 case INSTR_OUTPUT_STRINGS:
5048 {
5049 PROFILE_ENTER_LOCAL(function_run_INSTR_OUTPUT_STRINGS);
5050 string * const buf = *(string * *)( (char *)stack_get( s ) + (
5051 code->arg * sizeof( LIST * ) ) );
5052 combine_strings( s, code->arg, buf );
5053 PROFILE_EXIT_LOCAL(function_run_INSTR_OUTPUT_STRINGS);
5054 break;
5055 }
5056
b32b8144
FG
5057 case INSTR_DEBUG_LINE:
5058 {
5059 debug_on_instruction( frame, function->file, code->arg );
5060 break;
5061 }
5062
7c673cae
FG
5063 }
5064 ++code;
5065 }
5066
5067 PROFILE_EXIT_LOCAL(function_run);
5068}
5069
5070
5071#ifdef HAVE_PYTHON
5072
5073static struct arg_list * arg_list_compile_python( PyObject * bjam_signature,
5074 int * num_arguments )
5075{
5076 if ( bjam_signature )
5077 {
5078 struct argument_list_compiler c[ 1 ];
5079 struct arg_list * result;
5080 Py_ssize_t s;
5081 Py_ssize_t i;
5082 argument_list_compiler_init( c );
5083
5084 s = PySequence_Size( bjam_signature );
5085 for ( i = 0; i < s; ++i )
5086 {
5087 struct argument_compiler arg_comp[ 1 ];
5088 struct arg_list arg;
5089 PyObject * v = PySequence_GetItem( bjam_signature, i );
5090 Py_ssize_t j;
5091 Py_ssize_t inner;
5092 argument_compiler_init( arg_comp );
5093
5094 inner = PySequence_Size( v );
5095 for ( j = 0; j < inner; ++j )
5096 argument_compiler_add( arg_comp, object_new( PyString_AsString(
5097 PySequence_GetItem( v, j ) ) ), constant_builtin, -1 );
5098
5099 arg = arg_compile_impl( arg_comp, constant_builtin, -1 );
5100 dynamic_array_push( c->args, arg );
5101 argument_compiler_free( arg_comp );
5102 Py_DECREF( v );
5103 }
5104
5105 *num_arguments = c->args->size;
5106 result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
5107 memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list )
5108 );
5109 argument_list_compiler_free( c );
5110 return result;
5111 }
5112 *num_arguments = 0;
5113 return 0;
5114}
5115
5116FUNCTION * function_python( PyObject * function, PyObject * bjam_signature )
5117{
5118 PYTHON_FUNCTION * result = BJAM_MALLOC( sizeof( PYTHON_FUNCTION ) );
5119
5120 result->base.type = FUNCTION_PYTHON;
5121 result->base.reference_count = 1;
5122 result->base.rulename = 0;
5123 result->base.formal_arguments = arg_list_compile_python( bjam_signature,
5124 &result->base.num_formal_arguments );
5125 Py_INCREF( function );
5126 result->python_function = function;
5127
5128 return (FUNCTION *)result;
5129}
5130
5131
5132static void argument_list_to_python( struct arg_list * formal, int formal_count,
5133 FUNCTION * function, FRAME * frame, PyObject * kw )
5134{
5135 LOL * all_actual = frame->args;
5136 int i;
5137
5138 for ( i = 0; i < formal_count; ++i )
5139 {
5140 LIST * actual = lol_get( all_actual, i );
5141 LISTITER actual_iter = list_begin( actual );
5142 LISTITER const actual_end = list_end( actual );
5143 int j;
5144 for ( j = 0; j < formal[ i ].size; ++j )
5145 {
5146 struct argument * formal_arg = &formal[ i ].args[ j ];
5147 PyObject * value;
5148 LIST * l;
5149
5150 switch ( formal_arg->flags )
5151 {
5152 case ARG_ONE:
5153 if ( actual_iter == actual_end )
5154 argument_error( "missing argument", function, frame,
5155 formal_arg->arg_name );
5156 type_check_range( formal_arg->type_name, actual_iter, list_next(
5157 actual_iter ), frame, function, formal_arg->arg_name );
5158 value = PyString_FromString( object_str( list_item( actual_iter
5159 ) ) );
5160 actual_iter = list_next( actual_iter );
5161 break;
5162 case ARG_OPTIONAL:
5163 if ( actual_iter == actual_end )
5164 value = 0;
5165 else
5166 {
5167 type_check_range( formal_arg->type_name, actual_iter,
5168 list_next( actual_iter ), frame, function,
5169 formal_arg->arg_name );
5170 value = PyString_FromString( object_str( list_item(
5171 actual_iter ) ) );
5172 actual_iter = list_next( actual_iter );
5173 }
5174 break;
5175 case ARG_PLUS:
5176 if ( actual_iter == actual_end )
5177 argument_error( "missing argument", function, frame,
5178 formal_arg->arg_name );
5179 /* fallthrough */
5180 case ARG_STAR:
5181 type_check_range( formal_arg->type_name, actual_iter,
5182 actual_end, frame, function, formal_arg->arg_name );
5183 l = list_copy_range( actual, actual_iter, actual_end );
5184 value = list_to_python( l );
5185 list_free( l );
5186 actual_iter = actual_end;
5187 break;
5188 case ARG_VARIADIC:
5189 return;
5190 }
5191
5192 if ( value )
5193 {
5194 PyObject * key = PyString_FromString( object_str(
5195 formal_arg->arg_name ) );
5196 PyDict_SetItem( kw, key, value );
5197 Py_DECREF( key );
5198 Py_DECREF( value );
5199 }
5200 }
5201
5202 if ( actual_iter != actual_end )
5203 argument_error( "extra argument", function, frame, list_item(
5204 actual_iter ) );
5205 }
5206
5207 for ( ; i < all_actual->count; ++i )
5208 {
5209 LIST * const actual = lol_get( all_actual, i );
5210 if ( !list_empty( actual ) )
5211 argument_error( "extra argument", function, frame, list_front(
5212 actual ) );
5213 }
5214}
5215
5216
5217/* Given a Python object, return a string to use in Jam code instead of the said
5218 * object.
5219 *
5220 * If the object is a string, use the string value.
5221 * If the object implemenets __jam_repr__ method, use that.
5222 * Otherwise return 0.
5223 */
5224
5225OBJECT * python_to_string( PyObject * value )
5226{
5227 if ( PyString_Check( value ) )
5228 return object_new( PyString_AS_STRING( value ) );
5229
5230 /* See if this instance defines the special __jam_repr__ method. */
5231 if ( PyInstance_Check( value )
5232 && PyObject_HasAttrString( value, "__jam_repr__" ) )
5233 {
5234 PyObject * repr = PyObject_GetAttrString( value, "__jam_repr__" );
5235 if ( repr )
5236 {
5237 PyObject * arguments2 = PyTuple_New( 0 );
5238 PyObject * value2 = PyObject_Call( repr, arguments2, 0 );
5239 Py_DECREF( repr );
5240 Py_DECREF( arguments2 );
5241 if ( PyString_Check( value2 ) )
5242 return object_new( PyString_AS_STRING( value2 ) );
5243 Py_DECREF( value2 );
5244 }
5245 }
5246 return 0;
5247}
5248
5249
5250static module_t * python_module()
5251{
5252 static module_t * python = 0;
5253 if ( !python )
5254 python = bindmodule( constant_python );
5255 return python;
5256}
5257
5258
5259static LIST * call_python_function( PYTHON_FUNCTION * function, FRAME * frame )
5260{
5261 LIST * result = 0;
5262 PyObject * arguments = 0;
5263 PyObject * kw = NULL;
5264 int i;
5265 PyObject * py_result;
5266 FRAME * prev_frame_before_python_call;
5267
5268 if ( function->base.formal_arguments )
5269 {
5270 arguments = PyTuple_New( 0 );
5271 kw = PyDict_New();
5272 argument_list_to_python( function->base.formal_arguments,
5273 function->base.num_formal_arguments, &function->base, frame, kw );
5274 }
5275 else
5276 {
5277 arguments = PyTuple_New( frame->args->count );
5278 for ( i = 0; i < frame->args->count; ++i )
5279 PyTuple_SetItem( arguments, i, list_to_python( lol_get( frame->args,
5280 i ) ) );
5281 }
5282
5283 frame->module = python_module();
5284
5285 prev_frame_before_python_call = frame_before_python_call;
5286 frame_before_python_call = frame;
5287 py_result = PyObject_Call( function->python_function, arguments, kw );
5288 frame_before_python_call = prev_frame_before_python_call;
5289 Py_DECREF( arguments );
5290 Py_XDECREF( kw );
5291 if ( py_result != NULL )
5292 {
5293 if ( PyList_Check( py_result ) )
5294 {
5295 int size = PyList_Size( py_result );
5296 int i;
5297 for ( i = 0; i < size; ++i )
5298 {
5299 OBJECT * s = python_to_string( PyList_GetItem( py_result, i ) );
5300 if ( !s )
5301 err_printf(
5302 "Non-string object returned by Python call.\n" );
5303 else
5304 result = list_push_back( result, s );
5305 }
5306 }
5307 else if ( py_result == Py_None )
5308 {
5309 result = L0;
5310 }
5311 else
5312 {
5313 OBJECT * const s = python_to_string( py_result );
5314 if ( s )
5315 result = list_new( s );
5316 else
5317 /* We have tried all we could. Return empty list. There are
5318 * cases, e.g. feature.feature function that should return a
5319 * value for the benefit of Python code and which also can be
5320 * called by Jam code, where no sensible value can be returned.
5321 * We cannot even emit a warning, since there would be a pile of
5322 * them.
5323 */
5324 result = L0;
5325 }
5326
5327 Py_DECREF( py_result );
5328 }
5329 else
5330 {
5331 PyErr_Print();
5332 err_printf( "Call failed\n" );
5333 }
5334
5335 return result;
5336}
5337
5338#endif
5339
5340
5341void function_done( void )
5342{
5343 BJAM_FREE( stack );
5344}