Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r75736 - in trunk/tools/build/v2/engine: . modules
From: steven_at_[hidden]
Date: 2011-11-29 19:00:38


Author: steven_watanabe
Date: 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
New Revision: 75736
URL: http://svn.boost.org/trac/boost/changeset/75736

Log:
Reimplement the interpreter.
Added:
   trunk/tools/build/v2/engine/function.c (contents, props changed)
   trunk/tools/build/v2/engine/function.h (contents, props changed)
Text files modified:
   trunk/tools/build/v2/engine/build.bat | 2
   trunk/tools/build/v2/engine/build.jam | 2
   trunk/tools/build/v2/engine/build.sh | 2
   trunk/tools/build/v2/engine/builtins.c | 123 +++---
   trunk/tools/build/v2/engine/builtins.h | 82 ++--
   trunk/tools/build/v2/engine/compile.c | 702 ---------------------------------------
   trunk/tools/build/v2/engine/compile.h | 20 -
   trunk/tools/build/v2/engine/constants.c | 3
   trunk/tools/build/v2/engine/constants.h | 1
   trunk/tools/build/v2/engine/frames.c | 3
   trunk/tools/build/v2/engine/frames.h | 3
   trunk/tools/build/v2/engine/jam.c | 2
   trunk/tools/build/v2/engine/jamgram.c | 40 +-
   trunk/tools/build/v2/engine/jamgram.y | 40 +-
   trunk/tools/build/v2/engine/jamgram.yy | 40 +-
   trunk/tools/build/v2/engine/lists.c | 37 ++
   trunk/tools/build/v2/engine/lists.h | 3
   trunk/tools/build/v2/engine/modules.c | 2
   trunk/tools/build/v2/engine/modules/order.c | 4
   trunk/tools/build/v2/engine/modules/path.c | 2
   trunk/tools/build/v2/engine/modules/property-set.c | 2
   trunk/tools/build/v2/engine/modules/regex.c | 2
   trunk/tools/build/v2/engine/modules/sequence.c | 2
   trunk/tools/build/v2/engine/modules/set.c | 2
   trunk/tools/build/v2/engine/native.c | 8
   trunk/tools/build/v2/engine/native.h | 4
   trunk/tools/build/v2/engine/parse.c | 17
   trunk/tools/build/v2/engine/parse.h | 25 +
   trunk/tools/build/v2/engine/rules.c | 18
   trunk/tools/build/v2/engine/rules.h | 6
   trunk/tools/build/v2/engine/subst.c | 7
   trunk/tools/build/v2/engine/w32_getreg.c | 10
   32 files changed, 288 insertions(+), 928 deletions(-)

Modified: trunk/tools/build/v2/engine/build.bat
==============================================================================
--- trunk/tools/build/v2/engine/build.bat (original)
+++ trunk/tools/build/v2/engine/build.bat 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -438,7 +438,7 @@
 set YYACC_SOURCES=yyacc.c
 set MKJAMBASE_SOURCES=mkjambase.c
 set BJAM_SOURCES=
-set BJAM_SOURCES=%BJAM_SOURCES% command.c compile.c constants.c debug.c execnt.c expand.c filent.c glob.c hash.c
+set BJAM_SOURCES=%BJAM_SOURCES% command.c compile.c constants.c debug.c execnt.c expand.c filent.c function.c glob.c hash.c
 set BJAM_SOURCES=%BJAM_SOURCES% hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c
 set BJAM_SOURCES=%BJAM_SOURCES% object.c option.c output.c parse.c pathunix.c regexp.c
 set BJAM_SOURCES=%BJAM_SOURCES% rules.c scan.c search.c subst.c timestamp.c variable.c modules.c

Modified: trunk/tools/build/v2/engine/build.jam
==============================================================================
--- trunk/tools/build/v2/engine/build.jam (original)
+++ trunk/tools/build/v2/engine/build.jam 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -471,7 +471,7 @@
 
 # We have some different files for UNIX, and NT.
 jam.source =
- command.c compile.c constants.c debug.c expand.c glob.c
+ command.c compile.c constants.c debug.c expand.c function.c glob.c
     hash.c hcache.c headers.c hdrmacro.c
     jam.c jambase.c jamgram.c
     lists.c make.c make1.c mem.c object.c

Modified: trunk/tools/build/v2/engine/build.sh
==============================================================================
--- trunk/tools/build/v2/engine/build.sh (original)
+++ trunk/tools/build/v2/engine/build.sh 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -245,7 +245,7 @@
 YYACC_SOURCES="yyacc.c"
 MKJAMBASE_SOURCES="mkjambase.c"
 BJAM_SOURCES="\
- command.c compile.c constants.c debug.c expand.c glob.c hash.c\
+ command.c compile.c constants.c debug.c expand.c function.c glob.c hash.c\
  hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c\
  object.c option.c output.c parse.c pathunix.c regexp.c\
  rules.c scan.c search.c subst.c timestamp.c variable.c modules.c\

Modified: trunk/tools/build/v2/engine/builtins.c
==============================================================================
--- trunk/tools/build/v2/engine/builtins.c (original)
+++ trunk/tools/build/v2/engine/builtins.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -69,20 +69,20 @@
 #define C0 (OBJECT *)0
 
 #if defined( OS_NT ) || defined( OS_CYGWIN )
- LIST * builtin_system_registry ( PARSE *, FRAME * );
- LIST * builtin_system_registry_names( PARSE *, FRAME * );
+ LIST * builtin_system_registry ( FRAME *, int );
+ LIST * builtin_system_registry_names( FRAME *, int );
 #endif
 
 int glob( const char * s, const char * c );
 
 void backtrace ( FRAME * );
 void backtrace_line ( FRAME * );
-void print_source_line( PARSE * );
+void print_source_line( FRAME * );
 
 
-RULE * bind_builtin( const char * name_, LIST * (* f)( PARSE *, FRAME * ), int flags, const char * * args )
+RULE * bind_builtin( const char * name_, LIST * (* f)( FRAME *, int flags ), int flags, const char * * args )
 {
- PARSE * p;
+ FUNCTION * func;
     RULE * result;
     argument_list* arg_list = 0;
     OBJECT * name = object_new( name_ );
@@ -93,11 +93,11 @@
         lol_build( arg_list->data, args );
     }
 
- p = parse_make( f, P0, P0, P0, C0, C0, flags );
+ func = function_builtin( f, flags );
 
- result = new_rule_body( root_module(), name, arg_list, p, 1 );
+ result = new_rule_body( root_module(), name, arg_list, func, 1 );
 
- parse_free( p );
+ function_free( func );
 
     object_free( name );
 
@@ -434,7 +434,7 @@
  * The CALC rule performs simple mathematical operations on two arguments.
  */
 
-LIST * builtin_calc( PARSE * parse, FRAME * frame )
+LIST * builtin_calc( FRAME * frame, int flags )
 {
     LIST * arg = lol_get( frame->args, 0 );
 
@@ -488,7 +488,7 @@
  * targets and sources as TARGETs.
  */
 
-LIST * builtin_depends( PARSE * parse, FRAME * frame )
+LIST * builtin_depends( FRAME * frame, int flags )
 {
     LIST * targets = lol_get( frame->args, 0 );
     LIST * sources = lol_get( frame->args, 1 );
@@ -502,7 +502,7 @@
         /* TARGET, creating it if needed. The internal include */
         /* TARGET shares the name of its parent. */
 
- if ( parse->num )
+ if ( flags )
         {
             if ( !t->includes )
             {
@@ -534,7 +534,7 @@
  * argument.
  */
 
-LIST * builtin_rebuilds( PARSE * parse, FRAME * frame )
+LIST * builtin_rebuilds( FRAME * frame, int flags )
 {
     LIST * targets = lol_get( frame->args, 0 );
     LIST * rebuilds = lol_get( frame->args, 1 );
@@ -557,7 +557,7 @@
  * taken.
  */
 
-LIST * builtin_echo( PARSE * parse, FRAME * frame )
+LIST * builtin_echo( FRAME * frame, int flags )
 {
     list_print( lol_get( frame->args, 0 ) );
     printf( "\n" );
@@ -573,7 +573,7 @@
  * with a failure status.
  */
 
-LIST * builtin_exit( PARSE * parse, FRAME * frame )
+LIST * builtin_exit( FRAME * frame, int flags )
 {
     list_print( lol_get( frame->args, 0 ) );
     printf( "\n" );
@@ -596,11 +596,11 @@
  * It binds each target as a TARGET.
  */
 
-LIST * builtin_flags( PARSE * parse, FRAME * frame )
+LIST * builtin_flags( FRAME * frame, int flags )
 {
     LIST * l = lol_get( frame->args, 0 );
     for ( ; l; l = list_next( l ) )
- bindtarget( l->value )->flags |= parse->num;
+ bindtarget( l->value )->flags |= flags;
     return L0;
 }
 
@@ -697,7 +697,7 @@
 }
 
 
-LIST * builtin_glob( PARSE * parse, FRAME * frame )
+LIST * builtin_glob( FRAME * frame, int flags )
 {
     LIST * l = lol_get( frame->args, 0 );
     LIST * r = lol_get( frame->args, 1 );
@@ -870,7 +870,7 @@
 }
 
 
-LIST * builtin_glob_recursive( PARSE * parse, FRAME * frame )
+LIST * builtin_glob_recursive( FRAME * frame, int flags )
 {
     LIST * result = L0;
     LIST * l = lol_get( frame->args, 0 );
@@ -884,7 +884,7 @@
  * builtin_match() - MATCH rule, regexp matching.
  */
 
-LIST * builtin_match( PARSE * parse, FRAME * frame )
+LIST * builtin_match( FRAME * frame, int flags )
 {
     LIST * l;
     LIST * r;
@@ -930,7 +930,7 @@
     return result;
 }
 
-LIST * builtin_split_by_characters( PARSE * parse, FRAME * frame )
+LIST * builtin_split_by_characters( FRAME * frame, int flags )
 {
     LIST * l1 = lol_get( frame->args, 0 );
     LIST * l2 = lol_get( frame->args, 1 );
@@ -956,7 +956,7 @@
     return result;
 }
 
-LIST * builtin_hdrmacro( PARSE * parse, FRAME * frame )
+LIST * builtin_hdrmacro( FRAME * frame, int flags )
 {
   LIST * l = lol_get( frame->args, 0 );
 
@@ -992,7 +992,7 @@
 }
 
 
-LIST * builtin_rulenames( PARSE * parse, FRAME * frame )
+LIST * builtin_rulenames( FRAME * frame, int flags )
 {
     LIST * arg0 = lol_get( frame->args, 0 );
     LIST * result = L0;
@@ -1035,7 +1035,7 @@
 }
 
 
-LIST * builtin_varnames( PARSE * parse, FRAME * frame )
+LIST * builtin_varnames( FRAME * frame, int flags )
 {
     LIST * arg0 = lol_get( frame->args, 0 );
     LIST * result = L0;
@@ -1060,7 +1060,7 @@
  * Clears all rules and variables from the given module.
  */
 
-LIST * builtin_delete_module( PARSE * parse, FRAME * frame )
+LIST * builtin_delete_module( FRAME * frame, int flags )
 {
     LIST * arg0 = lol_get( frame->args, 0 );
     LIST * result = L0;
@@ -1100,7 +1100,7 @@
  * variables.
  */
 
-LIST * builtin_import( PARSE * parse, FRAME * frame )
+LIST * builtin_import( FRAME * frame, int flags )
 {
     LIST * source_module_list = lol_get( frame->args, 0 );
     LIST * source_rules = lol_get( frame->args, 1 );
@@ -1164,7 +1164,7 @@
  * is issued.
  */
 
-LIST * builtin_export( PARSE * parse, FRAME * frame )
+LIST * builtin_export( FRAME * frame, int flags )
 {
     LIST * module_list = lol_get( frame->args, 0 );
     LIST * rules = lol_get( frame->args, 1 );
@@ -1190,12 +1190,12 @@
  * indicated for a given procedure in debug output or an error backtrace.
  */
 
-static void get_source_line( PARSE * procedure, const char * * file, int * line )
+static void get_source_line( FRAME * frame, const char * * file, int * line )
 {
- if ( procedure )
+ if ( frame->file )
     {
- const char * f = object_str( procedure->file );
- int l = procedure->line;
+ const char * f = object_str( frame->file );
+ int l = frame->line;
         if ( !strcmp( f, "+" ) )
         {
             f = "jambase.c";
@@ -1212,12 +1212,12 @@
 }
 
 
-void print_source_line( PARSE * p )
+void print_source_line( FRAME * frame )
 {
     const char * file;
     int line;
 
- get_source_line( p, &file, &line );
+ get_source_line( frame, &file, &line );
     if ( line < 0 )
         printf( "(builtin):" );
     else
@@ -1238,7 +1238,7 @@
     }
     else
     {
- print_source_line( frame->procedure );
+ print_source_line( frame );
         printf( " in %s\n", frame->rulename );
     }
 }
@@ -1264,7 +1264,7 @@
  * period.
  */
 
-LIST * builtin_backtrace( PARSE * parse, FRAME * frame )
+LIST * builtin_backtrace( FRAME * frame, int flags )
 {
     LIST * levels_arg = lol_get( frame->args, 0 );
     int levels = levels_arg ? atoi( object_str( levels_arg->value ) ) : (int)( (unsigned int)(-1) >> 1 ) ;
@@ -1275,7 +1275,7 @@
         const char * file;
         int line;
         char buf[32];
- get_source_line( frame->procedure, &file, &line );
+ get_source_line( frame, &file, &line );
         sprintf( buf, "%d", line );
         result = list_new( result, object_new( file ) );
         result = list_new( result, object_new( buf ) );
@@ -1298,7 +1298,7 @@
  * behavior.
  */
 
-LIST * builtin_caller_module( PARSE * parse, FRAME * frame )
+LIST * builtin_caller_module( FRAME * frame, int flags )
 {
     LIST * levels_arg = lol_get( frame->args, 0 );
     int levels = levels_arg ? atoi( object_str( levels_arg->value ) ) : 0 ;
@@ -1328,7 +1328,7 @@
  * Usage: pwd = [ PWD ] ;
  */
 
-LIST * builtin_pwd( PARSE * parse, FRAME * frame )
+LIST * builtin_pwd( FRAME * frame, int flags )
 {
     return pwd();
 }
@@ -1338,7 +1338,7 @@
  * Adds targets to the list of target that jam will attempt to update.
  */
 
-LIST * builtin_update( PARSE * parse, FRAME * frame )
+LIST * builtin_update( FRAME * frame, int flags )
 {
     LIST * result = list_copy( L0, targets_to_update() );
     LIST * arg1 = lol_get( frame->args, 0 );
@@ -1358,7 +1358,7 @@
    Third parameter, if non-empty, specifies that the -n option should have
    no effect -- that is, all out-of-date targets should be rebuild.
 */
-LIST * builtin_update_now( PARSE * parse, FRAME * frame )
+LIST * builtin_update_now( FRAME * frame, int flags )
 {
     LIST * targets = lol_get( frame->args, 0 );
     LIST * log = lol_get( frame->args, 1 );
@@ -1437,7 +1437,7 @@
         return L0;
 }
 
-LIST * builtin_search_for_target( PARSE * parse, FRAME * frame )
+LIST * builtin_search_for_target( FRAME * frame, int flags )
 {
     LIST * arg1 = lol_get( frame->args, 0 );
     LIST * arg2 = lol_get( frame->args, 1 );
@@ -1446,7 +1446,7 @@
 }
 
 
-LIST * builtin_import_module( PARSE * parse, FRAME * frame )
+LIST * builtin_import_module( FRAME * frame, int flags )
 {
     LIST * arg1 = lol_get( frame->args, 0 );
     LIST * arg2 = lol_get( frame->args, 1 );
@@ -1456,14 +1456,14 @@
 }
 
 
-LIST * builtin_imported_modules( PARSE * parse, FRAME * frame )
+LIST * builtin_imported_modules( FRAME * frame, int flags )
 {
     LIST * arg0 = lol_get( frame->args, 0 );
     return imported_modules( bindmodule( arg0 ? arg0->value : 0 ) );
 }
 
 
-LIST * builtin_instance( PARSE * parse, FRAME * frame )
+LIST * builtin_instance( FRAME * frame, int flags )
 {
     LIST * arg1 = lol_get( frame->args, 0 );
     LIST * arg2 = lol_get( frame->args, 1 );
@@ -1474,14 +1474,14 @@
 }
 
 
-LIST * builtin_sort( PARSE * parse, FRAME * frame )
+LIST * builtin_sort( FRAME * frame, int flags )
 {
     LIST * arg1 = lol_get( frame->args, 0 );
     return list_sort( arg1 );
 }
 
 
-LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
+LIST * builtin_normalize_path( FRAME * frame, int flags )
 {
     LIST * arg = lol_get( frame->args, 0 );
 
@@ -1603,7 +1603,7 @@
 }
 
 
-LIST * builtin_native_rule( PARSE * parse, FRAME * frame )
+LIST * builtin_native_rule( FRAME * frame, int flags )
 {
     LIST * module_name = lol_get( frame->args, 0 );
     LIST * rule_name = lol_get( frame->args, 1 );
@@ -1630,7 +1630,7 @@
 }
 
 
-LIST * builtin_has_native_rule( PARSE * parse, FRAME * frame )
+LIST * builtin_has_native_rule( FRAME * frame, int flags )
 {
     LIST * module_name = lol_get( frame->args, 0 );
     LIST * rule_name = lol_get( frame->args, 1 );
@@ -1651,7 +1651,7 @@
 }
 
 
-LIST * builtin_user_module( PARSE * parse, FRAME * frame )
+LIST * builtin_user_module( FRAME * frame, int flags )
 {
     LIST * module_name = lol_get( frame->args, 0 );
     for ( ; module_name; module_name = module_name->next )
@@ -1663,7 +1663,7 @@
 }
 
 
-LIST * builtin_nearest_user_location( PARSE * parse, FRAME * frame )
+LIST * builtin_nearest_user_location( FRAME * frame, int flags )
 {
     FRAME * nearest_user_frame =
         frame->module->user_module ? frame : frame->prev_user;
@@ -1676,7 +1676,7 @@
         int line;
         char buf[32];
 
- get_source_line( nearest_user_frame->procedure, &file, &line );
+ get_source_line( nearest_user_frame, &file, &line );
         sprintf( buf, "%d", line );
         result = list_new( result, object_new( file ) );
         result = list_new( result, object_new( buf ) );
@@ -1685,7 +1685,7 @@
 }
 
 
-LIST * builtin_check_if_file( PARSE * parse, FRAME * frame )
+LIST * builtin_check_if_file( FRAME * frame, int flags )
 {
     LIST * name = lol_get( frame->args, 0 );
     return file_is_file( name->value ) == 1
@@ -1694,7 +1694,7 @@
 }
 
 
-LIST * builtin_md5( PARSE * parse, FRAME * frame )
+LIST * builtin_md5( FRAME * frame, int flags )
 {
     LIST * l = lol_get( frame->args, 0 );
     const char* s = object_str( l->value );
@@ -1715,7 +1715,7 @@
     return list_new( L0, object_new( hex_output ) );
 }
 
-LIST *builtin_file_open( PARSE * parse, FRAME * frame )
+LIST *builtin_file_open( FRAME * frame, int flags )
 {
     const char * name = object_str( lol_get( frame->args, 0 )->value );
     const char * mode = object_str( lol_get( frame->args, 1 )->value );
@@ -1742,7 +1742,7 @@
     }
 }
 
-LIST *builtin_pad( PARSE *parse, FRAME *frame )
+LIST *builtin_pad( FRAME * frame, int flags )
 {
     OBJECT * string = lol_get( frame->args, 0 )->value;
     const char * width_s = object_str( lol_get( frame->args, 1 )->value );
@@ -1767,7 +1767,7 @@
     }
 }
 
-LIST *builtin_precious( PARSE * parse, FRAME * frame )
+LIST *builtin_precious( FRAME * frame, int flags )
 {
     LIST * targets = lol_get(frame->args, 0);
 
@@ -1780,7 +1780,7 @@
     return L0;
 }
 
-LIST *builtin_self_path( PARSE * parse, FRAME * frame )
+LIST *builtin_self_path( FRAME * frame, int flags )
 {
     extern const char * saved_argv0;
     char * p = executable_path( saved_argv0 );
@@ -1796,7 +1796,7 @@
     }
 }
 
-LIST *builtin_makedir( PARSE * parse, FRAME * frame )
+LIST *builtin_makedir( FRAME * frame, int flags )
 {
     LIST * path = lol_get( frame->args, 0 );
 
@@ -1813,7 +1813,7 @@
 
 #ifdef HAVE_PYTHON
 
-LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
+LIST * builtin_python_import_rule( FRAME * frame, int flags )
 {
     static int first_time = 1;
     const char * python_module = object_str( lol_get( frame->args, 0 )->value );
@@ -1944,7 +1944,6 @@
     inner->prev = 0;
     inner->prev_user = 0;
     inner->module = bindmodule( constant_python_interface );
- inner->procedure = 0;
 
     /* Extract the rule name and arguments from 'args'. */
 
@@ -2164,7 +2163,7 @@
         int line;
         char buf[ 32 ];
 
- get_source_line( f->procedure, &file, &line );
+ get_source_line( f, &file, &line );
         sprintf( buf, "%d", line );
 
         /* PyTuple_SetItem steals reference. */
@@ -2277,7 +2276,7 @@
     return s;
 }
 
-LIST * builtin_shell( PARSE * parse, FRAME * frame )
+LIST * builtin_shell( FRAME * frame, int flags )
 {
     LIST * command = lol_get( frame->args, 0 );
     LIST * result = 0;
@@ -2357,7 +2356,7 @@
 
 #else /* #ifdef HAVE_POPEN */
 
-LIST * builtin_shell( PARSE * parse, FRAME * frame )
+LIST * builtin_shell( FRAME * frame, int flags )
 {
     return L0;
 }

Modified: trunk/tools/build/v2/engine/builtins.h
==============================================================================
--- trunk/tools/build/v2/engine/builtins.h (original)
+++ trunk/tools/build/v2/engine/builtins.h 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -21,47 +21,47 @@
 void init_sequence();
 void init_order();
 
-LIST *builtin_calc( PARSE *parse, FRAME *args );
-LIST *builtin_depends( PARSE *parse, FRAME *args );
-LIST *builtin_rebuilds( PARSE *parse, FRAME *args );
-LIST *builtin_echo( PARSE *parse, FRAME *args );
-LIST *builtin_exit( PARSE *parse, FRAME *args );
-LIST *builtin_flags( PARSE *parse, FRAME *args );
-LIST *builtin_glob( PARSE *parse, FRAME *args );
-LIST *builtin_glob_recursive( PARSE *parse, FRAME *frame );
-LIST *builtin_subst( PARSE *parse, FRAME *args );
-LIST *builtin_match( PARSE *parse, FRAME *args );
-LIST *builtin_split_by_characters( PARSE *parse, FRAME *args );
-LIST *builtin_hdrmacro( PARSE *parse, FRAME *args );
-LIST *builtin_rulenames( PARSE *parse, FRAME *args );
-LIST *builtin_varnames( PARSE *parse, FRAME *args );
-LIST *builtin_delete_module( PARSE *parse, FRAME *args );
-LIST *builtin_import( PARSE *parse, FRAME *args );
-LIST *builtin_export( PARSE *parse, FRAME *args );
-LIST *builtin_caller_module( PARSE *parse, FRAME *args );
-LIST *builtin_backtrace( PARSE *parse, FRAME *args );
-LIST *builtin_pwd( PARSE *parse, FRAME *args );
-LIST *builtin_update( PARSE *parse, FRAME *args );
-LIST *builtin_update_now( PARSE *parse, FRAME *args );
-LIST *builtin_search_for_target( PARSE *parse, FRAME *args );
-LIST *builtin_import_module( PARSE *parse, FRAME *args );
-LIST *builtin_imported_modules( PARSE *parse, FRAME *frame );
-LIST *builtin_instance( PARSE *parse, FRAME *frame );
-LIST *builtin_sort( PARSE *parse, FRAME *frame );
-LIST *builtin_normalize_path( PARSE *parse, FRAME *frame );
-LIST *builtin_native_rule( PARSE *parse, FRAME *frame );
-LIST *builtin_has_native_rule( PARSE *parse, FRAME *frame );
-LIST *builtin_user_module( PARSE *parse, FRAME *frame );
-LIST *builtin_nearest_user_location( PARSE *parse, FRAME *frame );
-LIST *builtin_check_if_file( PARSE *parse, FRAME *frame );
-LIST *builtin_python_import_rule( PARSE *parse, FRAME *frame );
-LIST *builtin_shell( PARSE *parse, FRAME *frame );
-LIST *builtin_md5( PARSE *parse, FRAME *frame );
-LIST *builtin_file_open( PARSE *parse, FRAME *frame );
-LIST *builtin_pad( PARSE *parse, FRAME *frame );
-LIST *builtin_precious( PARSE *parse, FRAME *frame );
-LIST *builtin_self_path( PARSE *parse, FRAME *frame );
-LIST *builtin_makedir( PARSE *parse, FRAME *frame );
+LIST *builtin_calc( FRAME * frame, int flags );
+LIST *builtin_depends( FRAME * frame, int flags );
+LIST *builtin_rebuilds( FRAME * frame, int flags );
+LIST *builtin_echo( FRAME * frame, int flags );
+LIST *builtin_exit( FRAME * frame, int flags );
+LIST *builtin_flags( FRAME * frame, int flags );
+LIST *builtin_glob( FRAME * frame, int flags );
+LIST *builtin_glob_recursive( FRAME * frame, int flags );
+LIST *builtin_subst( FRAME * frame, int flags );
+LIST *builtin_match( FRAME * frame, int flags );
+LIST *builtin_split_by_characters( FRAME * frame, int flags );
+LIST *builtin_hdrmacro( FRAME * frame, int flags );
+LIST *builtin_rulenames( FRAME * frame, int flags );
+LIST *builtin_varnames( FRAME * frame, int flags );
+LIST *builtin_delete_module( FRAME * frame, int flags );
+LIST *builtin_import( FRAME * frame, int flags );
+LIST *builtin_export( FRAME * frame, int flags );
+LIST *builtin_caller_module( FRAME * frame, int flags );
+LIST *builtin_backtrace( FRAME * frame, int flags );
+LIST *builtin_pwd( FRAME * frame, int flags );
+LIST *builtin_update( FRAME * frame, int flags );
+LIST *builtin_update_now( FRAME * frame, int flags );
+LIST *builtin_search_for_target( FRAME * frame, int flags );
+LIST *builtin_import_module( FRAME * frame, int flags );
+LIST *builtin_imported_modules( FRAME * frame, int flags );
+LIST *builtin_instance( FRAME * frame, int flags );
+LIST *builtin_sort( FRAME * frame, int flags );
+LIST *builtin_normalize_path( FRAME * frame, int flags );
+LIST *builtin_native_rule( FRAME * frame, int flags );
+LIST *builtin_has_native_rule( FRAME * frame, int flags );
+LIST *builtin_user_module( FRAME * frame, int flags );
+LIST *builtin_nearest_user_location( FRAME * frame, int flags );
+LIST *builtin_check_if_file( FRAME * frame, int flags );
+LIST *builtin_python_import_rule( FRAME * frame, int flags );
+LIST *builtin_shell( FRAME * frame, int flags );
+LIST *builtin_md5( FRAME * frame, int flags );
+LIST *builtin_file_open( FRAME * frame, int flags );
+LIST *builtin_pad( FRAME * frame, int flags );
+LIST *builtin_precious( FRAME * frame, int flags );
+LIST *builtin_self_path( FRAME * frame, int flags );
+LIST *builtin_makedir( FRAME * frame, int flags );
 
 void backtrace( FRAME *frame );
 extern int last_update_now_status;

Modified: trunk/tools/build/v2/engine/compile.c
==============================================================================
--- trunk/tools/build/v2/engine/compile.c (original)
+++ trunk/tools/build/v2/engine/compile.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -92,7 +92,7 @@
 /* Internal functions from builtins.c */
 void backtrace( FRAME * frame );
 void backtrace_line( FRAME * frame );
-void print_source_line( PARSE * p );
+void print_source_line( FRAME * frame );
 
 struct frame * frame_before_python_call;
 
@@ -105,7 +105,8 @@
     lol_init(frame->args);
     frame->module = root_module();
     frame->rulename = "module scope";
- frame->procedure = 0;
+ frame->file = 0;
+ frame->line = -1;
 }
 
 
@@ -115,459 +116,18 @@
 }
 
 
-/*
- * compile_append() - append list results of two statements
- *
- * parse->left more compile_append() by left-recursion
- * parse->right single rule
- */
-
-LIST * compile_append( PARSE * parse, FRAME * frame )
-{
- /* Append right to left. */
- return list_append(
- parse_evaluate( parse->left, frame ),
- parse_evaluate( parse->right, frame ) );
-}
-
-
-/*
- * compile_eval() - evaluate if to determine which leg to compile
- *
- * Returns:
- * list if expression true - compile 'then' clause
- * L0 if expression false - compile 'else' clause
- */
-
-static int lcmp( LIST * t, LIST * s )
-{
- int status = 0;
-
- while ( !status && ( t || s ) )
- {
- const char *st = t ? object_str( t->value ) : "";
- const char *ss = s ? object_str( s->value ) : "";
-
- status = strcmp( st, ss );
-
- t = t ? list_next( t ) : t;
- s = s ? list_next( s ) : s;
- }
-
- return status;
-}
-
-LIST * compile_eval( PARSE * parse, FRAME * frame )
-{
- LIST * ll;
- LIST * lr;
- LIST * s;
- LIST * t;
- int status = 0;
-
- /* Short circuit lr eval for &&, ||, and 'in'. */
-
- ll = parse_evaluate( parse->left, frame );
- lr = 0;
-
- switch ( parse->num )
- {
- case EXPR_AND:
- case EXPR_IN : if ( ll ) goto eval; break;
- case EXPR_OR : if ( !ll ) goto eval; break;
- default: eval: lr = parse_evaluate( parse->right, frame );
- }
-
- /* Now eval. */
- switch ( parse->num )
- {
- case EXPR_NOT: if ( !ll ) status = 1; break;
- case EXPR_AND: if ( ll && lr ) status = 1; break;
- case EXPR_OR : if ( ll || lr ) status = 1; break;
-
- case EXPR_IN:
- /* "a in b": make sure each of ll is equal to something in lr. */
- for ( t = ll; t; t = list_next( t ) )
- {
- for ( s = lr; s; s = list_next( s ) )
- if ( object_equal( t->value, s->value ) )
- break;
- if ( !s ) break;
- }
- /* No more ll? Success. */
- if ( !t ) status = 1;
- break;
-
- case EXPR_EXISTS: if ( lcmp( ll, L0 ) != 0 ) status = 1; break;
- case EXPR_EQUALS: if ( lcmp( ll, lr ) == 0 ) status = 1; break;
- case EXPR_NOTEQ : if ( lcmp( ll, lr ) != 0 ) status = 1; break;
- case EXPR_LESS : if ( lcmp( ll, lr ) < 0 ) status = 1; break;
- case EXPR_LESSEQ: if ( lcmp( ll, lr ) <= 0 ) status = 1; break;
- case EXPR_MORE : if ( lcmp( ll, lr ) > 0 ) status = 1; break;
- case EXPR_MOREEQ: if ( lcmp( ll, lr ) >= 0 ) status = 1; break;
- }
-
- if ( DEBUG_IF )
- {
- debug_compile( 0, "if", frame );
- list_print( ll );
- printf( "(%d) ", status );
- list_print( lr );
- printf( "\n" );
- }
-
- /* Find something to return. */
- /* In odd circumstances (like "" = "") */
- /* we'll have to return a new string. */
-
- if ( !status ) t = 0;
- else if ( ll ) t = ll, ll = 0;
- else if ( lr ) t = lr, lr = 0;
- else t = list_new( L0, object_new( "1" ) );
-
- if ( ll ) list_free( ll );
- if ( lr ) list_free( lr );
- return t;
-}
-
-
-/*
- * compile_foreach() - compile the "for x in y" statement
- *
- * Compile_foreach() resets the given variable name to each specified
- * value, executing the commands enclosed in braces for each iteration.
- *
- * parse->string index variable
- * parse->left variable values
- * parse->right rule to compile
- */
-
-LIST * compile_foreach( PARSE * parse, FRAME * frame )
-{
- LIST * nv = parse_evaluate( parse->left, frame );
- LIST * l;
- SETTINGS * s = 0;
-
- if ( parse->num )
- {
- s = addsettings( s, VAR_SET, parse->string, L0 );
- pushsettings( s );
- }
-
- /* Call var_set to reset $(parse->string) for each val. */
-
- for ( l = nv; l; l = list_next( l ) )
- {
- LIST * val = list_new( L0, object_copy( l->value ) );
- var_set( parse->string, val, VAR_SET );
- list_free( parse_evaluate( parse->right, frame ) );
- }
-
- if ( parse->num )
- {
- popsettings( s );
- freesettings( s );
- }
-
- list_free( nv );
-
- return L0;
-}
-
-/*
- * compile_if() - compile 'if' rule
- *
- * parse->left condition tree
- * parse->right then tree
- * parse->third else tree
- */
-
-LIST * compile_if( PARSE * p, FRAME * frame )
-{
- LIST * l = parse_evaluate( p->left, frame );
- if ( l )
- {
- list_free( l );
- return parse_evaluate( p->right, frame );
- }
- return parse_evaluate( p->third, frame );
-}
-
-
-LIST * compile_while( PARSE * p, FRAME * frame )
-{
- LIST * r = 0;
- LIST * l;
- while ( ( l = parse_evaluate( p->left, frame ) ) )
- {
- list_free( l );
- if ( r ) list_free( r );
- r = parse_evaluate( p->right, frame );
- }
- return r;
-}
-
-
-/*
- * compile_include() - support for 'include' - call include() on file
- *
- * parse->left list of files to include (can only do 1)
- */
-
-LIST * compile_include( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "include", frame);
- list_print( nt );
- printf( "\n" );
- }
-
- if ( nt )
- {
- TARGET * t = bindtarget( nt->value );
-
- /* DWA 2001/10/22 - Perforce Jam cleared the arguments here, which
- * prevents an included file from being treated as part of the body of a
- * rule. I did not see any reason to do that, so I lifted the
- * restriction.
- */
-
- /* Bind the include file under the influence of */
- /* "on-target" variables. Though they are targets, */
- /* include files are not built with make(). */
-
- pushsettings( t->settings );
- /* We don't expect that file to be included is generated by some
- action. Therefore, pass 0 as third argument.
- If the name resolves to directory, let it error out. */
- object_free( t->boundname );
- t->boundname = search( t->name, &t->time, 0, 0 );
- popsettings( t->settings );
-
- parse_file( t->boundname, frame );
- }
-
- list_free( nt );
-
- return L0;
-}
-
-static LIST* evaluate_in_module ( OBJECT * module_name, PARSE * p, FRAME* frame)
-{
- LIST* result;
-
- module_t* outer_module = frame->module;
- frame->module = module_name ? bindmodule( module_name ) : root_module();
-
- if ( outer_module != frame->module )
- {
- exit_module( outer_module );
- enter_module( frame->module );
- }
-
- result = parse_evaluate( p, frame );
-
- if ( outer_module != frame->module )
- {
- exit_module( frame->module );
- enter_module( outer_module );
- frame->module = outer_module;
- }
-
- return result;
-}
-
-
-LIST * compile_module( PARSE * p, FRAME * frame )
-{
- /* Here we are entering a module declaration block. */
- LIST * module_name = parse_evaluate( p->left, frame );
- LIST * result = evaluate_in_module( module_name ? module_name->value : 0,
- p->right, frame );
- list_free( module_name );
- return result;
-}
-
-
-LIST * compile_class( PARSE * p, FRAME * frame )
-{
- /** Todo: check for empty class name.
- Check for class redeclaration. */
-
- OBJECT * class_module = 0;
-
- LIST * name = parse_evaluate( p->left->right, frame );
- LIST * bases = 0;
-
- if ( p->left->left )
- bases = parse_evaluate( p->left->left->right, frame );
-
- class_module = make_class_module( name, bases, frame );
- evaluate_in_module( class_module, p->right, frame );
- object_free( class_module );
-
- return L0;
-}
-
-
-/*
- * compile_list() - expand and return a list.
- *
- * parse->string - character string to expand.
- */
-
-LIST * compile_list( PARSE * parse, FRAME * frame )
-{
- /* s is a copyable string */
- OBJECT * o = parse->string;
- const char * s = object_str( o );
- return var_expand( L0, s, s + strlen( s ), frame->args, o );
-}
-
-
-/*
- * compile_local() - declare (and set) local variables.
- *
- * parse->left list of variables
- * parse->right list of values
- * parse->third rules to execute
- */
-
-LIST * compile_local( PARSE * parse, FRAME * frame )
-{
- LIST * l;
- SETTINGS * s = 0;
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * ns = parse_evaluate( parse->right, frame );
- LIST * result;
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "local", frame );
- list_print( nt );
- printf( " = " );
- list_print( ns );
- printf( "\n" );
- }
-
- /* Initial value is ns. */
- for ( l = nt; l; l = list_next( l ) )
- s = addsettings( s, VAR_SET, l->value, list_copy( L0, ns ) );
-
- list_free( ns );
- list_free( nt );
-
- /* Note that callees of the current context get this "local" variable,
- * making it not so much local as layered.
- */
-
- pushsettings( s );
- result = parse_evaluate( parse->third, frame );
- popsettings( s );
-
- freesettings( s );
-
- return result;
-}
-
-
-/*
- * compile_null() - do nothing -- a stub for parsing.
- */
-
-LIST * compile_null( PARSE * parse, FRAME * frame )
-{
- return L0;
-}
-
-
-/*
- * compile_on() - run rule under influence of on-target variables
- *
- * parse->left list of files to include (can only do 1).
- * parse->right rule to run.
- *
- * EXPERIMENTAL!
- */
-
-LIST * compile_on( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * result = 0;
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "on", frame );
- list_print( nt );
- printf( "\n" );
- }
-
- if ( nt )
- {
- TARGET * t = bindtarget( nt->value );
- pushsettings( t->settings );
- result = parse_evaluate( parse->right, frame );
- popsettings( t->settings );
- }
-
- list_free( nt );
-
- return result;
-}
-
-
-/*
- * compile_rule() - compile a single user defined rule.
- *
- * parse->string name of user defined rule.
- * parse->left parameters (list of lists) to rule, recursing left.
- *
- * Wrapped around evaluate_rule() so that headers() can share it.
- */
-
-LIST * compile_rule( PARSE * parse, FRAME * frame )
-{
- FRAME inner[ 1 ];
- LIST * result;
- PARSE * p;
-
- /* Build up the list of arg lists. */
- frame_init( inner );
- inner->prev = frame;
- inner->prev_user = frame->module->user_module ? frame : frame->prev_user;
- inner->module = frame->module; /* This gets fixed up in evaluate_rule(), below. */
- inner->procedure = parse;
- /* Special-case LOL of length 1 where the first list is totally empty.
- This is created when calling functions with no parameters, due to
- the way jam grammar is written. This is OK when one jam function
- calls another, but really not good when Jam function calls Python. */
- if ( parse->left->left == NULL && parse->left->right->func == compile_null)
- ;
- else
- for ( p = parse->left; p; p = p->left )
- lol_add( inner->args, parse_evaluate( p->right, frame ) );
-
- /* And invoke the rule. */
- result = evaluate_rule( parse->string, inner );
- frame_free( inner );
- return result;
-}
-
-
 static void argument_error( const char * message, RULE * rule, FRAME * frame, LIST * arg )
 {
     LOL * actual = frame->args;
- assert( frame->procedure != 0 );
+ assert( rule->procedure != 0 );
     backtrace_line( frame->prev );
     printf( "*** argument error\n* rule %s ( ", frame->rulename );
     lol_print( rule->arguments->data );
     printf( " )\n* called with: ( " );
     lol_print( actual );
     printf( " )\n* %s %s\n", message, arg ? object_str ( arg->value ) : "" );
- print_source_line( rule->procedure );
+ function_location( rule->procedure, &frame->file, &frame->line );
+ print_source_line( frame );
     printf( "see definition of rule '%s' being called\n", object_str( rule->name ) );
     backtrace( frame->prev );
     exit( 1 );
@@ -949,25 +509,7 @@
     profile_frame prof[1];
     module_t * prev_module = frame->module;
 
- LIST * l;
- {
- LOL arg_context_, * arg_context = &arg_context_;
- if ( !frame->prev )
- lol_init(arg_context);
- else
- arg_context = frame->prev->args;
- l = var_expand( L0, object_str( rulename ), object_str( rulename )+strlen(object_str( rulename )), arg_context, 0 );
- }
-
- if ( !l )
- {
- backtrace_line( frame->prev );
- printf( "warning: rulename %s expands to empty string\n", object_str( rulename ) );
- backtrace( frame->prev );
- return result;
- }
-
- rule = bindrule( l->value, frame->module );
+ rule = bindrule( rulename, frame->module );
     rulename = rule->name;
 
 #ifdef HAVE_PYTHON
@@ -1005,17 +547,11 @@
     }
 #endif
 
- /* Drop the rule name. */
- l = list_pop_front( l );
-
- /* Tack the rest of the expansion onto the front of the first argument. */
- frame->args->list[0] = list_append( l, lol_get( frame->args, 0 ) );
-
     if ( DEBUG_COMPILE )
     {
         /* Try hard to indicate in which module the rule is going to execute. */
         if ( rule->module != frame->module
- && rule->procedure != 0 && !object_equal( rulename, rule->procedure->rulename ) )
+ && rule->procedure != 0 && !object_equal( rulename, function_rulename( rule->procedure ) ) )
         {
             char buf[256] = "";
             strncat( buf, object_str( rule->module->name ), sizeof( buf ) - 1 );
@@ -1047,7 +583,7 @@
         frame->rulename = object_str( rulename );
         /* And enter record profile info. */
         if ( DEBUG_PROFILE )
- profile_enter( rule->procedure->rulename, prof );
+ profile_enter( function_rulename( rule->procedure ), prof );
     }
 
     /* Check traditional targets $(<) and sources $(>). */
@@ -1126,21 +662,22 @@
     }
 
     /* Now recursively compile any parse tree associated with this rule.
- * parse_refer()/parse_free() call pair added to ensure rule not freed
+ * function_refer()/function_free() call pair added to ensure rule not freed
      * during use.
      */
     if ( rule->procedure )
     {
         SETTINGS * local_args = collect_arguments( rule, frame );
- PARSE * parse = rule->procedure;
- parse_refer( parse );
+ FUNCTION * function = rule->procedure;
+
+ function_refer( function );
 
         pushsettings( local_args );
- result = parse_evaluate( parse, frame );
+ result = function_run( function, frame, stack_global() );
         popsettings( local_args );
         freesettings( local_args );
 
- parse_free( parse );
+ function_free( function );
     }
 
     if ( frame->module != prev_module )
@@ -1179,7 +716,6 @@
     inner->prev_user = caller_frame->module->user_module ?
         caller_frame : caller_frame->prev_user;
     inner->module = caller_frame->module;
- inner->procedure = 0;
 
     va_start( va, caller_frame );
     for ( ; ; )
@@ -1199,212 +735,6 @@
 }
 
 
-/*
- * compile_rules() - compile a chain of rules
- *
- * parse->left single rule
- * parse->right more compile_rules() by right-recursion
- */
-
-LIST * compile_rules( PARSE * parse, FRAME * frame )
-{
- /* Ignore result from first statement; return the 2nd. */
- /* Optimize recursion on the right by looping. */
- do list_free( parse_evaluate( parse->left, frame ) );
- while ( ( parse = parse->right )->func == compile_rules );
- return parse_evaluate( parse, frame );
-}
-
-
-/*
- * assign_var_mode() - convert ASSIGN_XXX compilation flag into corresponding
- * VAR_XXX variable set flag.
- */
-
-static int assign_var_mode( int parsenum, char const * * tracetext )
-{
- char const * trace;
- int setflag;
- switch ( parsenum )
- {
- case ASSIGN_SET : setflag = VAR_SET ; trace = "=" ; break;
- case ASSIGN_APPEND : setflag = VAR_APPEND ; trace = "+="; break;
- case ASSIGN_DEFAULT: setflag = VAR_DEFAULT; trace = "?="; break;
- default: setflag = VAR_SET ; trace = "" ; break;
- }
- if ( tracetext )
- *tracetext = trace ;
- return setflag;
-}
-
-/*
- * compile_set() - compile the "set variable" statement
- *
- * parse->left variable names
- * parse->right variable values
- * parse->num ASSIGN_SET/APPEND/DEFAULT
- */
-
-LIST * compile_set( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * ns = parse_evaluate( parse->right, frame );
- LIST * l;
- char const * trace;
- int setflag = assign_var_mode( parse->num, &trace );
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "set", frame );
- list_print( nt );
- printf( " %s ", trace );
- list_print( ns );
- printf( "\n" );
- }
-
- /* Call var_set to set variable. var_set keeps ns, so need to copy it. */
- for ( l = nt; l; l = list_next( l ) )
- var_set( l->value, list_copy( L0, ns ), setflag );
- list_free( nt );
- return ns;
-}
-
-
-/*
- * compile_setcomp() - support for `rule` - save parse tree.
- *
- * parse->string rule name
- * parse->left rules for rule
- * parse->right optional list-of-lists describing arguments
- */
-
-LIST * compile_setcomp( PARSE * parse, FRAME * frame )
-{
- argument_list * arg_list = 0;
-
- /* Create new LOL describing argument requirements if supplied. */
- if ( parse->right )
- {
- PARSE * p;
- arg_list = args_new();
- for ( p = parse->right; p; p = p->left )
- lol_add( arg_list->data, parse_evaluate( p->right, frame ) );
- }
-
- new_rule_body( frame->module, parse->string, arg_list, parse->left, !parse->num );
- return L0;
-}
-
-
-/*
- * compile_setexec() - support for `actions` - save execution string.
- *
- * parse->string rule name
- * parse->string1 OS command string
- * parse->num flags
- * parse->left `bind` variables
- *
- * Note that the parse flags (as defined in compile.h) are transferred directly
- * to the rule flags (as defined in rules.h).
- */
-
-LIST * compile_setexec( PARSE * parse, FRAME * frame )
-{
- LIST * bindlist = parse_evaluate( parse->left, frame );
- new_rule_actions( frame->module, parse->string, parse->string1, bindlist, parse->num );
- return L0;
-}
-
-
-/*
- * compile_settings() - compile the "on =" (set variable on exec) statement.
- *
- * parse->left variable names
- * parse->right target name
- * parse->third variable value
- * parse->num ASSIGN_SET/APPEND
- */
-
-LIST * compile_settings( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * ns = parse_evaluate( parse->third, frame );
- LIST * targets = parse_evaluate( parse->right, frame );
- LIST * ts;
- char const * trace;
- int setflag = assign_var_mode( parse->num, &trace );
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "set", frame );
- list_print( nt );
- printf( " on " );
- list_print( targets );
- printf( " %s ", trace );
- list_print( ns );
- printf( "\n" );
- }
-
- /* Call addsettings() to save variable setting. addsettings() keeps ns, so
- * need to copy it. Pass append flag to addsettings().
- */
- for ( ts = targets; ts; ts = list_next( ts ) )
- {
- TARGET * t = bindtarget( ts->value );
- LIST * l;
-
- for ( l = nt; l; l = list_next( l ) )
- t->settings = addsettings( t->settings, setflag, l->value,
- list_copy( (LIST *)0, ns ) );
- }
-
- list_free( nt );
- list_free( targets );
- return ns;
-}
-
-
-/*
- * compile_switch() - compile 'switch' rule.
- *
- * parse->left switch value (only 1st used)
- * parse->right cases
- *
- * cases->left 1st case
- * cases->right next cases
- *
- * case->string argument to match
- * case->left parse tree to execute
- */
-
-LIST * compile_switch( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * result = 0;
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "switch", frame );
- list_print( nt );
- printf( "\n" );
- }
-
- /* Step through cases. */
- for ( parse = parse->right; parse; parse = parse->right )
- {
- if ( !glob( object_str( parse->left->string ), nt ? object_str( nt->value ) : "" ) )
- {
- /* Get & exec parse tree for this case. */
- parse = parse->left->left;
- result = parse_evaluate( parse, frame );
- break;
- }
- }
-
- list_free( nt );
- return result;
-}
-
 
 /*
  * debug_compile() - printf with indent to show rule expansion.
@@ -1419,7 +749,7 @@
     {
         int i;
 
- print_source_line( frame->procedure );
+ print_source_line( frame );
 
         i = ( level + 1 ) * 2;
         while ( i > 35 )

Modified: trunk/tools/build/v2/engine/compile.h
==============================================================================
--- trunk/tools/build/v2/engine/compile.h (original)
+++ trunk/tools/build/v2/engine/compile.h 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -24,26 +24,6 @@
 
 void compile_builtins();
 
-LIST *compile_append( PARSE *parse, FRAME *frame );
-LIST *compile_foreach( PARSE *parse, FRAME *frame );
-LIST *compile_if( PARSE *parse, FRAME *frame );
-LIST *compile_eval( PARSE *parse, FRAME *args );
-LIST *compile_include( PARSE *parse, FRAME *frame );
-LIST *compile_list( PARSE *parse, FRAME *frame );
-LIST *compile_local( PARSE *parse, FRAME *frame );
-LIST *compile_module( PARSE *parse, FRAME *frame );
-LIST *compile_class( PARSE *parse, FRAME *frame );
-LIST *compile_null( PARSE *parse, FRAME *frame );
-LIST *compile_on( PARSE *parse, FRAME *frame );
-LIST *compile_rule( PARSE *parse, FRAME *frame );
-LIST *compile_rules( PARSE *parse, FRAME *frame );
-LIST *compile_set( PARSE *parse, FRAME *frame );
-LIST *compile_setcomp( PARSE *parse, FRAME *frame );
-LIST *compile_setexec( PARSE *parse, FRAME *frame );
-LIST *compile_settings( PARSE *parse, FRAME *frame );
-LIST *compile_switch( PARSE *parse, FRAME *frame );
-LIST *compile_while( PARSE *parse, FRAME *frame );
-
 LIST *evaluate_rule( OBJECT * rulename, FRAME * frame );
 LIST *call_rule( OBJECT * rulename, FRAME * caller_frame, ...);
 

Modified: trunk/tools/build/v2/engine/constants.c
==============================================================================
--- trunk/tools/build/v2/engine/constants.c (original)
+++ trunk/tools/build/v2/engine/constants.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -19,6 +19,7 @@
 
 void constants_init( void )
 {
+ constant_empty = object_new( "" );
     constant_builtin = object_new( "(builtin)" );
     constant_other = object_new( "[OTHER]" );
     constant_total = object_new( "[TOTAL]" );
@@ -40,6 +41,7 @@
 
 void constants_done( void )
 {
+ object_free( constant_empty );
     object_free( constant_builtin );
     object_free( constant_other );
     object_free( constant_total );
@@ -59,6 +61,7 @@
     object_free( constant_MAIN_PYTHON );
 }
 
+OBJECT * constant_empty;
 OBJECT * constant_builtin;
 OBJECT * constant_other;
 OBJECT * constant_total;

Modified: trunk/tools/build/v2/engine/constants.h
==============================================================================
--- trunk/tools/build/v2/engine/constants.h (original)
+++ trunk/tools/build/v2/engine/constants.h 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -16,6 +16,7 @@
 void constants_init( void );
 void constants_done( void );
 
+extern OBJECT * constant_empty; /* "" */
 extern OBJECT * constant_builtin; /* "(builtin)" */
 extern OBJECT * constant_other; /* "[OTHER]" */
 extern OBJECT * constant_total; /* "[TOTAL]" */

Modified: trunk/tools/build/v2/engine/frames.c
==============================================================================
--- trunk/tools/build/v2/engine/frames.c (original)
+++ trunk/tools/build/v2/engine/frames.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -13,7 +13,8 @@
     lol_init(frame->args);
     frame->module = root_module();
     frame->rulename = "module scope";
- frame->procedure = 0;
+ frame->file = 0;
+ frame->line = -1;
 }
 
 void frame_free( FRAME* frame )

Modified: trunk/tools/build/v2/engine/frames.h
==============================================================================
--- trunk/tools/build/v2/engine/frames.h (original)
+++ trunk/tools/build/v2/engine/frames.h 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -20,7 +20,8 @@
     FRAME * prev_user;
     LOL args[ 1 ];
     module_t * module;
- PARSE * procedure;
+ OBJECT * file;
+ int line;
     const char * rulename;
 };
 

Added: trunk/tools/build/v2/engine/function.c
==============================================================================
--- (empty file)
+++ trunk/tools/build/v2/engine/function.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -0,0 +1,3019 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+#include "lists.h"
+#include "pathsys.h"
+#include "mem.h"
+#include "constants.h"
+#include "jam.h"
+#include "frames.h"
+#include "function.h"
+#include "rules.h"
+#include "variable.h"
+#include "compile.h"
+#include "search.h"
+#include "class.h"
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+# ifdef OS_CYGWIN
+# include <sys/cygwin.h>
+# include <windows.h>
+# endif
+
+#define INSTR_PUSH_EMPTY 0
+#define INSTR_PUSH_CONSTANT 1
+#define INSTR_PUSH_ARG 2
+#define INSTR_PUSH_VAR 3
+#define INSTR_PUSH_GROUP 4
+#define INSTR_PUSH_RESULT 5
+#define INSTR_PUSH_APPEND 6
+#define INSTR_SWAP 7
+
+#define INSTR_JUMP_EMPTY 8
+#define INSTR_JUMP_NOT_EMPTY 9
+
+#define INSTR_JUMP 10
+#define INSTR_JUMP_LT 11
+#define INSTR_JUMP_LE 12
+#define INSTR_JUMP_GT 13
+#define INSTR_JUMP_GE 14
+#define INSTR_JUMP_EQ 15
+#define INSTR_JUMP_NE 16
+#define INSTR_JUMP_IN 17
+#define INSTR_JUMP_NOT_IN 18
+
+#define INSTR_JUMP_NOT_GLOB 19
+
+#define INSTR_TRY_POP_FRONT 20
+
+#define INSTR_SET_RESULT 21
+#define INSTR_RETURN 22
+#define INSTR_POP 23
+
+#define INSTR_PUSH_LOCAL 24
+#define INSTR_POP_LOCAL 25
+#define INSTR_SET 26
+#define INSTR_APPEND 27
+#define INSTR_DEFAULT 28
+
+#define INSTR_PUSH_LOCAL_GROUP 29
+#define INSTR_POP_LOCAL_GROUP 30
+#define INSTR_SET_GROUP 31
+#define INSTR_APPEND_GROUP 32
+#define INSTR_DEFAULT_GROUP 33
+
+#define INSTR_PUSH_ON 34
+#define INSTR_POP_ON 35
+#define INSTR_SET_ON 36
+#define INSTR_APPEND_ON 37
+#define INSTR_DEFAULT_ON 38
+
+#define INSTR_CALL_RULE 39
+
+#define INSTR_APPLY_MODIFIERS 40
+#define INSTR_APPLY_INDEX 41
+#define INSTR_APPLY_INDEX_MODIFIERS 42
+#define INSTR_APPLY_MODIFIERS_GROUP 43
+#define INSTR_APPLY_INDEX_GROUP 44
+#define INSTR_APPLY_INDEX_MODIFIERS_GROUP 45
+#define INSTR_COMBINE_STRINGS 46
+
+#define INSTR_INCLUDE 47
+#define INSTR_RULE 48
+#define INSTR_ACTIONS 49
+#define INSTR_PUSH_MODULE 50
+#define INSTR_POP_MODULE 51
+#define INSTR_CLASS 52
+
+typedef struct instruction
+{
+ unsigned int op_code;
+ int arg;
+} instruction;
+
+typedef struct _subfunction
+{
+ OBJECT * name;
+ FUNCTION * code;
+ int arguments;
+ int local;
+} SUBFUNCTION;
+
+typedef struct _subaction
+{
+ OBJECT * name;
+ OBJECT * command;
+ int flags;
+} SUBACTION;
+
+#define FUNCTION_BUILTIN 0
+#define FUNCTION_JAM 1
+
+struct _function
+{
+ int type;
+ int reference_count;
+ OBJECT * rulename;
+};
+
+typedef struct _builtin_function
+{
+ int type;
+ int reference_count;
+ OBJECT * rulename;
+ LIST * ( * func )( FRAME *, int flags );
+ int flags;
+} BUILTIN_FUNCTION;
+
+typedef struct _jam_function
+{
+ int type;
+ int reference_count;
+ OBJECT * rulename;
+ instruction * code;
+ int num_constants;
+ OBJECT * * constants;
+ int num_subfunctions;
+ SUBFUNCTION * functions;
+ int num_subactions;
+ SUBACTION * actions;
+ OBJECT * file;
+ int line;
+} JAM_FUNCTION;
+
+
+struct _stack
+{
+ void * data;
+};
+
+static void * stack;
+
+STACK * stack_global()
+{
+ static STACK result;
+ if ( !stack )
+ {
+ int size = 1 << 21;
+ stack = BJAM_MALLOC( size );
+ result.data = (char *)stack + size;
+ }
+ return &result;
+}
+
+void stack_push( STACK * s, LIST * l )
+{
+ *--(*(LIST * * *)&s->data) = l;
+}
+
+LIST * stack_pop( STACK * s )
+{
+ return *(*(LIST * * *)&s->data)++;
+}
+
+LIST * stack_top(STACK * s)
+{
+ return *(LIST * *)s->data;
+}
+
+LIST * stack_at( STACK * s, int n )
+{
+ return *((LIST * *)s->data + n);
+}
+
+void stack_set( STACK * s, int n, LIST * value )
+{
+ *((LIST * *)s->data + n) = value;
+}
+
+void * stack_get( STACK * s )
+{
+ return (LIST * *)s->data;
+}
+
+void * stack_allocate( STACK * s, int size )
+{
+ *(char * *)&s->data -= size;
+ return s->data;
+}
+
+void stack_deallocate( STACK * s, int size )
+{
+ *(char * *)&s->data += size;
+}
+
+LIST * frame_get_local( FRAME * frame, int idx )
+{
+ /* The only local variables are the arguments */
+ return list_copy( L0, lol_get( frame->args, idx ) );
+}
+
+static OBJECT * function_get_constant( JAM_FUNCTION * function, int idx )
+{
+ return function->constants[ idx ];
+}
+
+static LIST * function_get_variable( JAM_FUNCTION * function, FRAME * frame, int idx )
+{
+ return list_copy( L0, var_get( function->constants[idx] ) );
+}
+
+static void function_set_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ var_set( function->constants[idx], value, VAR_SET );
+}
+
+static LIST * function_swap_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ return var_swap( function->constants[idx], value );
+}
+
+static void function_append_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ var_set( function->constants[idx], value, VAR_APPEND );
+}
+
+static void function_default_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ var_set( function->constants[idx], value, VAR_DEFAULT );
+}
+
+static void function_set_rule( JAM_FUNCTION * function, FRAME * frame, STACK * s, int idx )
+{
+ SUBFUNCTION * sub = function->functions + idx;
+ argument_list * args = 0;
+
+ if ( sub->arguments )
+ {
+ int i;
+ args = args_new();
+ for ( i = sub->arguments; i > 0; --i )
+ {
+ lol_add( args->data, stack_at( s, i - 1 ) );
+ }
+
+ for ( i = 0; i < sub->arguments; ++i )
+ {
+ stack_pop( s );
+ }
+ }
+
+ new_rule_body( frame->module, sub->name, args, sub->code, !sub->local );
+}
+
+static void function_set_actions( JAM_FUNCTION * function, FRAME * frame, STACK * s, int idx )
+{
+ SUBACTION * sub = function->actions + idx;
+ LIST * bindlist = stack_pop( s );
+
+ new_rule_actions( frame->module, sub->name, sub->command, bindlist, sub->flags );
+}
+
+/*
+ * returns the index if name is "<", ">", "1", "2", ... or "19"
+ * otherwise returns -1.
+ */
+
+static int get_argument_index( const char * s )
+{
+ if( s[ 0 ] != '\0')
+ {
+ if( s[ 1 ] == '\0' )
+ {
+ switch ( s[ 0 ] )
+ {
+ case '<': return 0;
+ case '>': return 1;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return s[ 0 ] - '1';
+ }
+ }
+ else if ( s[ 0 ] == '1' && s[ 2 ] == '\0' )
+ {
+ switch( s[ 1 ] )
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return s[ 1 ] - '0' + 10 - 1;
+ }
+ }
+ }
+ return -1;
+}
+
+static LIST * function_get_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name )
+{
+ int idx = get_argument_index( object_str( name ) );
+ if( idx != -1 )
+ {
+ return list_copy( L0, lol_get( frame->args, idx ) );
+ }
+ else
+ {
+ return list_copy( L0, var_get( name ) );
+ }
+}
+
+static void function_set_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value)
+{
+ var_set( name, value, VAR_SET );
+}
+
+static LIST * function_swap_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value )
+{
+ return var_swap( name, value );
+}
+
+static void function_append_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value)
+{
+ var_set( name, value, VAR_APPEND );
+}
+
+static void function_default_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value )
+{
+ var_set( name, value, VAR_DEFAULT );
+}
+
+static LIST * function_call_rule( JAM_FUNCTION * function, FRAME * frame, STACK * s, int n_args, const char * unexpanded, OBJECT * file, int line )
+{
+ FRAME inner[ 1 ];
+ int i;
+ LIST * first = stack_pop( s );
+ LIST * result = L0;
+ OBJECT * rulename;
+
+ frame->file = file;
+ frame->line = line;
+
+ if ( !first )
+ {
+ backtrace_line( frame );
+ printf( "warning: rulename %s expands to empty string\n", unexpanded );
+ backtrace( frame );
+ return result;
+ }
+
+ rulename = object_copy( first->value );
+
+ frame_init( inner );
+
+ inner->prev = frame;
+ inner->prev_user = frame->module->user_module ? frame : frame->prev_user;
+ inner->module = frame->module; /* This gets fixed up in evaluate_rule(), below. */
+
+ for( i = 0; i < n_args; ++i )
+ {
+ lol_add( inner->args, stack_at( s, n_args - i - 1 ) );
+ }
+
+ for( i = 0; i < n_args; ++i )
+ {
+ stack_pop( s );
+ }
+
+ if ( inner->args->count == 0 )
+ {
+ lol_add( inner->args, list_pop_front( first ) );
+ }
+ else
+ {
+ LIST * * l = &inner->args->list[0];
+ *l = list_append( list_pop_front( first ), *l );
+ }
+
+ result = evaluate_rule( rulename, inner );
+ frame_free( inner );
+ object_free( rulename );
+ return result;
+}
+
+/* Variable expansion */
+
+typedef struct
+{
+ int sub1;
+ int sub2;
+} subscript_t;
+
+typedef struct
+{
+ PATHNAME f; /* :GDBSMR -- pieces */
+ char parent; /* :P -- go to parent directory */
+ char filemods; /* one of the above applied */
+ char downshift; /* :L -- downshift result */
+ char upshift; /* :U -- upshift result */
+ char to_slashes; /* :T -- convert "\" to "/" */
+ char to_windows; /* :W -- convert cygwin to native paths */
+ PATHPART empty; /* :E -- default for empties */
+ PATHPART join; /* :J -- join list with char */
+} VAR_EDITS;
+
+static LIST * apply_modifiers_impl( LIST * result, string * buf, VAR_EDITS * edits, int n, LIST * iter, LIST * end );
+static void get_iters( subscript_t subscript, LIST * * first, LIST * * last, int length );
+static void var_edit_file( const char * in, string * out, VAR_EDITS * edits );
+static void var_edit_shift( string * out, size_t pos, VAR_EDITS * edits );
+static int var_edit_parse( const char * mods, VAR_EDITS * edits, int havezeroed );
+
+
+/*
+ * var_edit_parse() - parse : modifiers into PATHNAME structure
+ *
+ * The : modifiers in a $(varname:modifier) currently support replacing or
+ * omitting elements of a filename, and so they are parsed into a PATHNAME
+ * structure (which contains pointers into the original string).
+ *
+ * Modifiers of the form "X=value" replace the component X with the given value.
+ * Modifiers without the "=value" cause everything but the component X to be
+ * omitted. X is one of:
+ *
+ * G <grist>
+ * D directory name
+ * B base name
+ * S .suffix
+ * M (member)
+ * R root directory - prepended to whole path
+ *
+ * This routine sets:
+ *
+ * f->f_xxx.ptr = 0
+ * f->f_xxx.len = 0
+ * -> leave the original component xxx
+ *
+ * f->f_xxx.ptr = string
+ * f->f_xxx.len = strlen( string )
+ * -> replace component xxx with string
+ *
+ * f->f_xxx.ptr = ""
+ * f->f_xxx.len = 0
+ * -> omit component xxx
+ *
+ * var_edit_file() below and path_build() obligingly follow this convention.
+ */
+
+static int var_edit_parse( const char * mods, VAR_EDITS * edits, int havezeroed )
+{
+ while ( *mods )
+ {
+ PATHPART * fp;
+
+ switch ( *mods++ )
+ {
+ case 'L': edits->downshift = 1; continue;
+ case 'U': edits->upshift = 1; continue;
+ case 'P': edits->parent = edits->filemods = 1; continue;
+ case 'E': fp = &edits->empty; goto strval;
+ case 'J': fp = &edits->join; goto strval;
+ case 'G': fp = &edits->f.f_grist; goto fileval;
+ case 'R': fp = &edits->f.f_root; goto fileval;
+ case 'D': fp = &edits->f.f_dir; goto fileval;
+ case 'B': fp = &edits->f.f_base; goto fileval;
+ case 'S': fp = &edits->f.f_suffix; goto fileval;
+ case 'M': fp = &edits->f.f_member; goto fileval;
+ case 'T': edits->to_slashes = 1; continue;
+ case 'W': edits->to_windows = 1; continue;
+ default:
+ break; /* Should complain, but so what... */
+ }
+
+ fileval:
+ /* Handle :CHARS, where each char (without a following =) selects a
+ * particular file path element. On the first such char, we deselect all
+ * others (by setting ptr = "", len = 0) and for each char we select
+ * that element (by setting ptr = 0).
+ */
+ edits->filemods = 1;
+
+ if ( *mods != '=' )
+ {
+ if ( !havezeroed++ )
+ {
+ int i;
+ for ( i = 0; i < 6; ++i )
+ {
+ edits->f.part[ i ].len = 0;
+ edits->f.part[ i ].ptr = "";
+ }
+ }
+
+ fp->ptr = 0;
+ continue;
+ }
+
+ strval:
+ /* Handle :X=value, or :X */
+ if ( *mods != '=' )
+ {
+ fp->ptr = "";
+ fp->len = 0;
+ }
+ else
+ {
+ fp->ptr = ++mods;
+ fp->len = strlen( mods );
+ mods += fp->len;
+ }
+ }
+
+ return havezeroed;
+}
+
+/*
+ * var_edit_file() - copy input target name to output, modifying filename.
+ */
+
+static void var_edit_file( const char * in, string * out, VAR_EDITS * edits )
+{
+ if ( edits->filemods )
+ {
+ PATHNAME pathname;
+
+ /* Parse apart original filename, putting parts into "pathname". */
+ path_parse( in, &pathname );
+
+ /* Replace any pathname with edits->f */
+ if ( edits->f.f_grist .ptr ) pathname.f_grist = edits->f.f_grist;
+ if ( edits->f.f_root .ptr ) pathname.f_root = edits->f.f_root;
+ if ( edits->f.f_dir .ptr ) pathname.f_dir = edits->f.f_dir;
+ if ( edits->f.f_base .ptr ) pathname.f_base = edits->f.f_base;
+ if ( edits->f.f_suffix.ptr ) pathname.f_suffix = edits->f.f_suffix;
+ if ( edits->f.f_member.ptr ) pathname.f_member = edits->f.f_member;
+
+ /* If requested, modify pathname to point to parent. */
+ if ( edits->parent )
+ path_parent( &pathname );
+
+ /* Put filename back together. */
+ path_build( &pathname, out, 0 );
+ }
+ else
+ {
+ string_append( out, in );
+ }
+}
+
+/*
+ * var_edit_shift() - do upshift/downshift mods.
+ */
+
+static void var_edit_shift( string * out, size_t pos, VAR_EDITS * edits )
+{
+ if ( edits->upshift || edits->downshift || edits->to_windows || edits->to_slashes )
+ {
+ /* Handle upshifting, downshifting and slash translation now. */
+ char * p;
+# ifdef OS_CYGWIN
+ if ( edits->to_windows )
+ {
+ /* FIXME: skip grist */
+ char result[ MAX_PATH + 1 ];
+ cygwin_conv_to_win32_path( out->value + pos, result );
+ assert( strlen( result ) <= MAX_PATH );
+ string_truncate( out, pos );
+ string_append( out, result );
+ edits->to_slashes = 0;
+ }
+# endif
+ for ( p = out->value + pos; *p; ++p)
+ {
+ if ( edits->upshift )
+ *p = toupper( *p );
+ else if ( edits->downshift )
+ *p = tolower( *p );
+ if ( edits->to_slashes && ( *p == '\\' ) )
+ *p = '/';
+ }
+ }
+}
+
+/*
+ * Reads n LISTs from the top of the STACK and
+ * combines them to form VAR_EDITS.
+ *
+ * returns the number of VAR_EDITS pushed onto
+ * the STACK.
+ */
+
+static int expand_modifiers( STACK * s, int n )
+{
+ int i;
+ int total = 1;
+ LIST * * args = stack_get( s );
+ for( i = 0; i < n; ++i)
+ total *= list_length( args[i] );
+
+ if ( total != 0 )
+ {
+ VAR_EDITS * out = stack_allocate( s, total * sizeof(VAR_EDITS) );
+ LIST * * iter = stack_allocate( s, n * sizeof(LIST *) );
+ for (i = 0; i < n; ++i )
+ {
+ iter[i] = args[i];
+ }
+ i = 0;
+ {
+ int havezeroed;
+ loop:
+ memset( out, 0, sizeof( *out ) );
+ havezeroed = 0;
+ for (i = 0; i < n; ++i )
+ {
+ havezeroed = var_edit_parse( object_str( iter[i]->value ), out, havezeroed );
+ }
+ ++out;
+ while ( --i >= 0 )
+ {
+ if ( iter[i]->next )
+ {
+ iter[i] = iter[i]->next;
+ goto loop;
+ }
+ else
+ {
+ iter[i] = args[i];
+ }
+ }
+ }
+ stack_deallocate( s, n * sizeof( LIST * ) );
+ }
+ return total;
+}
+
+static LIST * apply_modifiers( STACK * s, int n )
+{
+ LIST * value = stack_top( s );
+ LIST * result = L0;
+ VAR_EDITS * edits = (VAR_EDITS *)( (LIST * *)stack_get( s ) + 1 );
+ string buf[1];
+ string_new( buf );
+ result = apply_modifiers_impl( result, buf, edits, n, value, L0 );
+ string_free( buf );
+ return result;
+}
+
+/*
+ * Parse a string of the form "1-2", "-2--1", "2-"
+ * and return the two subscripts.
+ */
+
+subscript_t parse_subscript( const char * s )
+{
+ subscript_t result;
+ result.sub1 = 0;
+ result.sub2 = 0;
+ do /* so we can use "break" */
+ {
+ /* Allow negative subscripts. */
+ if ( !isdigit( *s ) && ( *s != '-' ) )
+ {
+ result.sub2 = 0;
+ break;
+ }
+ result.sub1 = atoi( s );
+
+ /* Skip over the first symbol, which is either a digit or dash. */
+ ++s;
+ while ( isdigit( *s ) ) ++s;
+
+ if ( *s == '\0' )
+ {
+ result.sub2 = result.sub1;
+ break;
+ }
+
+ if ( *s != '-' )
+ {
+ result.sub2 = 0;
+ break;
+ }
+
+ ++s;
+
+ if ( *s == '\0' )
+ {
+ result.sub2 = -1;
+ break;
+ }
+
+ if ( !isdigit( *s ) && ( *s != '-' ) )
+ {
+ result.sub2 = 0;
+ break;
+ }
+
+ /* First, compute the index of the last element. */
+ result.sub2 = atoi( s );
+ while ( isdigit( *++s ) );
+
+ if ( *s != '\0' )
+ result.sub2 = 0;
+
+ } while ( 0 );
+ return result;
+}
+
+static LIST * apply_subscript( STACK * s )
+{
+ LIST * value = stack_top( s );
+ LIST * indices = stack_at( s, 1 );
+ LIST * result = L0;
+ int length = list_length( value );
+ string buf[1];
+ string_new( buf );
+ for ( ; indices; indices = list_next( indices ) )
+ {
+ LIST * iter = value;
+ LIST * end;
+ subscript_t subscript = parse_subscript( object_str( indices->value ) );
+ get_iters( subscript, &iter, &end, length );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ result = list_new( result, object_copy( iter->value ) );
+ }
+ }
+ string_free( buf );
+ return result;
+}
+
+/*
+ * Reads the LIST from first and applies subscript to it.
+ * The results are written to *first and *last.
+ */
+
+static void get_iters( subscript_t subscript, LIST * * first, LIST * * last, int length )
+{
+ int start;
+ int size;
+ LIST * iter;
+ LIST * end;
+ {
+
+ if ( subscript.sub1 < 0 )
+ start = length + subscript.sub1;
+ else if( subscript.sub1 > length )
+ start = length;
+ else
+ start = subscript.sub1 - 1;
+
+ if ( subscript.sub2 < 0 )
+ size = length + 1 + subscript.sub2 - start;
+ else
+ size = subscript.sub2 - start;
+
+ /*
+ * HACK: When the first subscript is before the start of the
+ * list, it magically becomes the beginning of the list.
+ * This is inconsistent, but needed for backwards
+ * compatibility.
+ */
+ if ( start < 0 )
+ start = 0;
+
+ /* The "sub2 < 0" test handles the semantic error of sub2 <
+ * sub1.
+ */
+ if ( size < 0 )
+ size = 0;
+
+ if ( start + size > length )
+ size = length - start;
+ }
+
+ iter = *first;
+ while ( start-- > 0 )
+ iter = list_next( iter );
+
+ end = iter;
+ while ( size-- > 0 )
+ end = list_next( end );
+
+ *first = iter;
+ *last = end;
+}
+
+static LIST * apply_modifiers_empty( LIST * result, string * buf, VAR_EDITS * edits, int n)
+{
+ int i;
+ for ( i = 0; i < n; ++i )
+ {
+ if ( edits[i].empty.ptr )
+ {
+ /** FIXME: is empty.ptr always null-terminated? */
+ var_edit_file( edits[i].empty.ptr, buf, edits + i );
+ var_edit_shift( buf, 0, edits + i );
+ result = list_new( result, object_new( buf->value ) );
+ string_truncate( buf, 0 );
+ }
+ }
+ return result;
+}
+
+static LIST * apply_modifiers_non_empty( LIST * result, string * buf, VAR_EDITS * edits, int n, LIST * begin, LIST * end )
+{
+ int i;
+ LIST * iter;
+ for ( i = 0; i < n; ++i )
+ {
+ if ( edits[i].join.ptr )
+ {
+ var_edit_file( object_str( begin->value ), buf, edits + i );
+ var_edit_shift( buf, 0, edits + i );
+ for ( iter = list_next( begin ); iter != end; iter = list_next( iter ) )
+ {
+ size_t size;
+ string_append( buf, edits[i].join.ptr );
+ size = buf->size;
+ var_edit_file( object_str( iter->value ), buf, edits + i );
+ var_edit_shift( buf, size, edits + i );
+ }
+ result = list_new( result, object_new( buf->value ) );
+ string_truncate( buf, 0 );
+ }
+ else
+ {
+ for ( iter = begin; iter != end; iter = iter->next )
+ {
+ var_edit_file( object_str( iter->value ), buf, edits + i );
+ var_edit_shift( buf, 0, edits + i );
+ result = list_new( result, object_new( buf->value ) );
+ string_truncate( buf, 0 );
+ }
+ }
+ }
+ return result;
+}
+
+static LIST * apply_modifiers_impl( LIST * result, string * buf, VAR_EDITS * edits, int n, LIST * iter, LIST * end )
+{
+ if ( iter != end )
+ {
+ return apply_modifiers_non_empty( result, buf, edits, n, iter, end );
+ }
+ else
+ {
+ return apply_modifiers_empty( result, buf, edits, n );
+ }
+}
+
+static LIST * apply_subscript_and_modifiers( STACK * s, int n )
+{
+ LIST * value = stack_top( s );
+ LIST * indices = stack_at( s, 1 );
+ LIST * result = L0;
+ VAR_EDITS * edits = (VAR_EDITS *)((LIST * *)stack_get( s ) + 2);
+ int length = list_length( value );
+ string buf[1];
+ string_new( buf );
+ for ( ; indices; indices = list_next( indices ) )
+ {
+ LIST * iter = value;
+ LIST * end;
+ subscript_t sub = parse_subscript( object_str( indices->value ) );
+ get_iters( sub, &iter, &end, length );
+ result = apply_modifiers_impl( result, buf, edits, n, iter, end );
+ }
+ string_free( buf );
+ return result;
+}
+
+typedef struct expansion_item
+{
+ LIST * elem;
+ LIST * saved;
+ int size;
+} expansion_item;
+
+static LIST * expand( expansion_item * elem, int length )
+{
+ LIST * result = L0;
+ string buf[1];
+ int size = 0;
+ int i;
+ assert( length > 0 );
+ for ( i = 0; i < length; ++i )
+ {
+ int max = 0;
+ LIST * l;
+ if ( !elem[i].elem ) return result;
+ for ( l = elem[i].elem; l; l = l->next )
+ {
+ int len = strlen( object_str( l->value ) );
+ if ( len > max ) max = len;
+ }
+ size += max;
+ }
+ string_new( buf );
+ string_reserve( buf, size );
+ i = 0;
+ {
+ loop:
+ for ( ; i < length; ++i )
+ {
+ elem[i].size = buf->size;
+ string_append( buf, object_str( elem[i].elem->value ) );
+ }
+ result = list_new( result, object_new( buf->value ) );
+ while ( --i >= 0 )
+ {
+ if(elem[i].elem->next)
+ {
+ elem[i].elem = elem[i].elem->next;
+ string_truncate( buf, elem[i].size );
+ goto loop;
+ }
+ else
+ {
+ elem[i].elem = elem[i].saved;
+ }
+ }
+ }
+ string_free( buf );
+ return result;
+}
+
+struct dynamic_array
+{
+ int size;
+ int capacity;
+ void * data;
+};
+
+static void dynamic_array_init( struct dynamic_array * array )
+{
+ array->size = 0;
+ array->capacity = 0;
+ array->data = 0;
+}
+
+static void dynamic_array_free( struct dynamic_array * array )
+{
+ BJAM_FREE( array->data );
+}
+
+static void dynamic_array_push_impl( struct dynamic_array * array, void * value, int unit_size )
+{
+ if ( array->capacity == 0 )
+ {
+ array->capacity = 2;
+ array->data = BJAM_MALLOC( array->capacity * unit_size );
+ }
+ else if ( array->capacity == array->size )
+ {
+ void * new_data;
+ array->capacity *= 2;
+ new_data = BJAM_MALLOC( array->capacity * unit_size );
+ memcpy( new_data, array->data, array->size * unit_size );
+ BJAM_FREE( array->data );
+ array->data = new_data;
+ }
+ memcpy( (char *)array->data + array->size * unit_size, value, unit_size );
+ ++array->size;
+}
+
+#define dynamic_array_push( array, value ) ( dynamic_array_push_impl( array, &value, sizeof(value) ) )
+#define dynamic_array_at( type, array, idx ) (((type *)(array)->data)[idx])
+
+/*
+ * struct compiler
+ */
+
+struct label_info
+{
+ int absolute_position;
+ struct dynamic_array uses[1];
+};
+
+struct stored_rule
+{
+ OBJECT * name;
+ PARSE * parse;
+ int arguments;
+ int local;
+};
+
+typedef struct compiler
+{
+ struct dynamic_array code[1];
+ struct dynamic_array constants[1];
+ struct dynamic_array labels[1];
+ struct dynamic_array rules[1];
+ struct dynamic_array actions[1];
+} compiler;
+
+static void compiler_init( compiler * c )
+{
+ dynamic_array_init( c->code );
+ dynamic_array_init( c->constants );
+ dynamic_array_init( c->labels );
+ dynamic_array_init( c->rules );
+ dynamic_array_init( c->actions );
+}
+
+static void compiler_free( compiler * c )
+{
+ int i;
+ dynamic_array_free( c->actions );
+ dynamic_array_free( c->rules );
+ for ( i = 0; i < c->labels->size; ++i )
+ {
+ dynamic_array_free( dynamic_array_at( struct label_info, c->labels, i ).uses );
+ }
+ dynamic_array_free( c->labels );
+ dynamic_array_free( c->constants );
+ dynamic_array_free( c->code );
+}
+
+static void compile_emit_instruction( compiler * c, instruction instr )
+{
+ dynamic_array_push( c->code, instr );
+}
+
+static int compile_new_label( compiler * c )
+{
+ int result = c->labels->size;
+ struct label_info info;
+ info.absolute_position = -1;
+ dynamic_array_init( info.uses );
+ dynamic_array_push( c->labels, info );
+ return result;
+}
+
+static void compile_set_label( compiler * c, int label )
+{
+ struct label_info * l = &dynamic_array_at( struct label_info, c->labels, label );
+ int pos = c->code->size;
+ int i;
+ assert( l->absolute_position == -1 );
+ l->absolute_position = pos;
+ for ( i = 0; i < l->uses->size; ++i )
+ {
+ int id = dynamic_array_at( int, l->uses, i );
+ int offset = (int)(pos - id - 1);
+ dynamic_array_at( instruction, c->code, id ).arg = offset;
+ }
+}
+
+static void compile_emit( compiler * c, unsigned int op_code, int arg )
+{
+ instruction instr;
+ instr.op_code = op_code;
+ instr.arg = arg;
+ compile_emit_instruction( c, instr );
+}
+
+static void compile_emit_branch( compiler * c, unsigned int op_code, int label )
+{
+ struct label_info * l = &dynamic_array_at( struct label_info, c->labels, label );
+ int pos = c->code->size;
+ instruction instr;
+ instr.op_code = op_code;
+ if ( l->absolute_position == -1 )
+ {
+ instr.arg = 0;
+ dynamic_array_push( l->uses, pos );
+ }
+ else
+ {
+ instr.arg = (int)( l->absolute_position - pos - 1 );
+ }
+ compile_emit_instruction( c, instr );
+}
+
+static int compile_emit_constant( compiler * c, OBJECT * value )
+{
+ OBJECT * copy = object_copy( value );
+ dynamic_array_push( c->constants, copy );
+ return c->constants->size - 1;
+}
+
+static int compile_emit_rule( compiler * c, OBJECT * name, PARSE * parse, int arguments, int local )
+{
+ struct stored_rule rule;
+ rule.name = object_copy( name );
+ rule.parse = parse;
+ rule.arguments = arguments;
+ rule.local = local;
+ dynamic_array_push( c->rules, rule );
+ return (int)( c->rules->size - 1 );
+}
+
+static int compile_emit_actions( compiler * c, OBJECT * name, OBJECT * command, int flags )
+{
+ SUBACTION a;
+ a.name = object_copy( name );
+ a.command = object_copy( command );
+ a.flags = flags;
+ dynamic_array_push( c->actions, a );
+ return (int)( c->actions->size - 1 );
+}
+
+static JAM_FUNCTION * compile_to_function( compiler * c )
+{
+ JAM_FUNCTION * result = BJAM_MALLOC( sizeof(JAM_FUNCTION) );
+ int i;
+ result->type = FUNCTION_JAM;
+ result->reference_count = 1;
+
+ result->rulename = 0;
+
+ result->code = BJAM_MALLOC( c->code->size * sizeof(instruction) );
+ memcpy( result->code, c->code->data, c->code->size * sizeof(instruction) );
+
+ result->constants = BJAM_MALLOC( c->constants->size * sizeof(OBJECT *) );
+ memcpy( result->constants, c->constants->data, c->constants->size * sizeof(OBJECT *) );
+ result->num_constants = c->constants->size;
+
+ result->num_subfunctions = c->rules->size;
+ result->functions = BJAM_MALLOC( c->rules->size * sizeof(SUBFUNCTION) );
+ for ( i = 0; i < c->rules->size; ++i )
+ {
+ struct stored_rule * rule = &dynamic_array_at( struct stored_rule, c->rules, i );
+ result->functions[i].name = rule->name;
+ result->functions[i].code = function_compile( rule->parse );
+ result->functions[i].arguments = rule->arguments;
+ result->functions[i].local = rule->local;
+ }
+
+ result->actions = BJAM_MALLOC( c->actions->size * sizeof(SUBACTION) );
+ memcpy( result->actions, c->actions->data, c->actions->size * sizeof(SUBACTION) );
+ result->num_subactions = c->actions->size;
+
+ result->file = 0;
+ result->line = -1;
+
+ return result;
+}
+
+/*
+ * Parsing of variable expansions
+ */
+
+typedef struct VAR_PARSE_GROUP
+{
+ struct dynamic_array elems[1];
+} VAR_PARSE_GROUP;
+
+#define VAR_PARSE_TYPE_VAR 0
+#define VAR_PARSE_TYPE_STRING 1
+
+typedef struct _var_parse
+{
+ int type; /* string or variable */
+} VAR_PARSE;
+
+typedef struct
+{
+ int type;
+ VAR_PARSE_GROUP * name;
+ VAR_PARSE_GROUP * subscript;
+ struct dynamic_array modifiers[1];
+} VAR_PARSE_VAR;
+
+typedef struct
+{
+ int type;
+ OBJECT * s;
+} VAR_PARSE_STRING;
+
+static void var_parse_free( VAR_PARSE * );
+
+/*
+ * VAR_PARSE_GROUP
+ */
+
+static VAR_PARSE_GROUP * var_parse_group_new()
+{
+ VAR_PARSE_GROUP * result = BJAM_MALLOC( sizeof( VAR_PARSE_GROUP ) );
+ dynamic_array_init( result->elems );
+ return result;
+}
+
+static void var_parse_group_free( VAR_PARSE_GROUP * group )
+{
+ int i;
+ for ( i = 0; i < group->elems->size; ++i )
+ {
+ var_parse_free( dynamic_array_at( VAR_PARSE *, group->elems, i ) );
+ }
+ dynamic_array_free( group->elems );
+ BJAM_FREE( group );
+}
+
+static void var_parse_group_add( VAR_PARSE_GROUP * group, VAR_PARSE * elem )
+{
+ dynamic_array_push( group->elems, elem );
+}
+
+static void var_parse_group_maybe_add_constant( VAR_PARSE_GROUP * group, const char * start, const char * end )
+{
+ if ( start != end )
+ {
+ string buf[1];
+ VAR_PARSE_STRING * value = (VAR_PARSE_STRING *)BJAM_MALLOC( sizeof(VAR_PARSE_STRING) );
+ value->type = VAR_PARSE_TYPE_STRING;
+ string_new( buf );
+ string_append_range( buf, start, end );
+ value->s = object_new( buf->value );
+ string_free( buf );
+ var_parse_group_add( group, (VAR_PARSE *)value );
+ }
+}
+
+/*
+ * VAR_PARSE_VAR
+ */
+
+static VAR_PARSE_VAR * var_parse_var_new()
+{
+ VAR_PARSE_VAR * result = BJAM_MALLOC( sizeof( VAR_PARSE_VAR ) );
+ result->type = VAR_PARSE_TYPE_VAR;
+ result->name = var_parse_group_new();
+ result->subscript = 0;
+ dynamic_array_init( result->modifiers );
+ return result;
+}
+
+static void var_parse_var_free( VAR_PARSE_VAR * var )
+{
+ int i;
+ var_parse_group_free( var->name );
+ if ( var->subscript )
+ var_parse_group_free( var->subscript );
+ for( i = 0; i < var->modifiers->size; ++i )
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, var->modifiers, i ) );
+ dynamic_array_free( var->modifiers );
+ BJAM_FREE( var );
+}
+
+static VAR_PARSE_GROUP * var_parse_var_new_modifier( VAR_PARSE_VAR * var )
+{
+ VAR_PARSE_GROUP * result = var_parse_group_new();
+ dynamic_array_push( var->modifiers, result );
+ return result;
+}
+
+/*
+ * VAR_PARSE_STRING
+ */
+
+static void var_parse_string_free( VAR_PARSE_STRING * string )
+{
+ object_free( string->s );
+ BJAM_FREE( string );
+}
+
+/*
+ * VAR_PARSE
+ */
+
+static void var_parse_free( VAR_PARSE * parse )
+{
+ if ( parse->type == VAR_PARSE_TYPE_VAR )
+ {
+ var_parse_var_free( (VAR_PARSE_VAR *)parse );
+ }
+ else if ( parse->type == VAR_PARSE_TYPE_STRING )
+ {
+ var_parse_string_free( (VAR_PARSE_STRING *)parse );
+ }
+ else
+ {
+ assert(!"Invalid type");
+ }
+}
+
+/*
+ * Compile VAR_PARSE
+ */
+
+static void var_parse_group_compile( const VAR_PARSE_GROUP * parse, compiler * c );
+
+static void var_parse_var_compile( const VAR_PARSE_VAR * parse, compiler * c )
+{
+ int expand_name = 0;
+ /* If there are modifiers, emit them in reverse order. */
+ if ( parse->modifiers->size > 0 )
+ {
+ int i;
+ for ( i = 0; i < parse->modifiers->size; ++i )
+ {
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, parse->modifiers, parse->modifiers->size - i - 1 ), c );
+ }
+ }
+
+ /* If there's a subscript, emit it. */
+ if ( parse->subscript )
+ {
+ var_parse_group_compile( parse->subscript, c );
+ }
+
+ /* If the variable name is empty, look it up. */
+ if ( parse->name->elems->size == 0 )
+ {
+ compile_emit( c, INSTR_PUSH_VAR, compile_emit_constant( c, constant_empty ) );
+ }
+ /* If the variable name doesn't need to be expanded, look it up. */
+ else if ( parse->name->elems->size == 1 &&
+ dynamic_array_at( VAR_PARSE *, parse->name->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
+ {
+ OBJECT * name = ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, parse->name->elems, 0 ) )->s;
+ int idx = get_argument_index( object_str( name ) );
+ if ( idx != -1 )
+ {
+ compile_emit( c, INSTR_PUSH_ARG, idx );
+ }
+ else
+ {
+ compile_emit( c, INSTR_PUSH_VAR, compile_emit_constant( c, name ) );
+ }
+ }
+ /* Otherwise, push the var names and use the group instruction. */
+ else
+ {
+ var_parse_group_compile( parse->name, c );
+ expand_name = 1;
+ }
+
+ /** Select the instruction for expanding the variable. */
+ if ( !parse->modifiers->size && !parse->subscript && !expand_name )
+ {
+ /* Nothing to do */
+ }
+ else if ( !parse->modifiers->size && !parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_PUSH_GROUP, 0 );
+ }
+ else if ( !parse->modifiers->size && parse->subscript && !expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX, 0 );
+ }
+ else if ( !parse->modifiers->size && parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX_GROUP, 0 );
+ }
+ if ( parse->modifiers->size && !parse->subscript && !expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_MODIFIERS, parse->modifiers->size );
+ }
+ else if ( parse->modifiers->size && !parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_MODIFIERS_GROUP, parse->modifiers->size );
+ }
+ else if ( parse->modifiers->size && parse->subscript && !expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS, parse->modifiers->size );
+ }
+ else if ( parse->modifiers->size && parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS_GROUP, parse->modifiers->size );
+ }
+}
+
+static void var_parse_string_compile( const VAR_PARSE_STRING * parse, compiler * c )
+{
+ compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, parse->s ) );
+}
+
+static void var_parse_compile( const VAR_PARSE * parse, compiler * c )
+{
+ if( parse->type == VAR_PARSE_TYPE_VAR )
+ {
+ var_parse_var_compile( (const VAR_PARSE_VAR *)parse, c );
+ }
+ else if( parse->type == VAR_PARSE_TYPE_STRING )
+ {
+ var_parse_string_compile( (const VAR_PARSE_STRING *)parse, c );
+ }
+}
+
+static void var_parse_group_compile( const VAR_PARSE_GROUP * parse, compiler * c )
+{
+ /* Emit the elements in reverse order. */
+ int i;
+ for( i = 0; i < parse->elems->size; ++i)
+ {
+ var_parse_compile( dynamic_array_at( VAR_PARSE *, parse->elems, parse->elems->size - i - 1 ), c );
+ }
+ /* If there're no elements, emit an empty string. */
+ if ( parse->elems->size == 0 )
+ {
+ compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, constant_empty ) );
+ }
+ /* If there's more than one element, combine them. */
+ if ( parse->elems->size > 1 )
+ {
+ compile_emit( c, INSTR_COMBINE_STRINGS, parse->elems->size );
+ }
+}
+
+/*
+ * Parse VAR_PARSE_VAR
+ */
+
+static VAR_PARSE * parse_variable( const char * * string );
+static int try_parse_variable( const char * * s_, const char * * string, VAR_PARSE_GROUP * out);
+static void balance_parentheses( const char * * s_, const char * * string, VAR_PARSE_GROUP * out);
+
+/*
+ * Parses a string that can contain variables to expand.
+ */
+
+static VAR_PARSE_GROUP * parse_expansion( const char * * string )
+{
+ VAR_PARSE_GROUP * result = var_parse_group_new();
+ const char * s = *string;
+ for (;;)
+ {
+ if(try_parse_variable( &s, string, result )) {}
+ else if(s[0] == '\0')
+ {
+ var_parse_group_maybe_add_constant( result, *string, s );
+ return result;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+}
+
+/*
+ * Checks whether the string a *s_ starts with
+ * a variable expansion "$(". *string should point
+ * to the first unemitted character before *s.
+ * If *s_ starts with variable expansion, appends
+ * elements to out up to the closing ")", and
+ * adjusts *s_ and *string to point to next character.
+ * Returns 1 if s_ starts with a variable, 0 otherwise.
+ */
+
+static int try_parse_variable( const char * * s_, const char * * string, VAR_PARSE_GROUP * out)
+{
+ const char * s = *s_;
+ if(s[0] == '$' && s[1] == '(')
+ {
+ var_parse_group_maybe_add_constant( out, *string, s );
+ s += 2;
+ var_parse_group_add( out, parse_variable( &s ) );
+ *string = s;
+ *s_ = s;
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static const char * current_file = "";
+static int current_line;
+
+static void parse_error( const char * message )
+{
+ printf( "%s:%d: %s\n", current_file, current_line, message );
+ exit(1);
+}
+
+/*
+ * Parses a single variable up to the closing ")" and
+ * adjusts *string to point to the next character. *string
+ * should point to the character immediately after
+ * the initial "$("
+ */
+
+static VAR_PARSE * parse_variable( const char * * string )
+{
+ VAR_PARSE_VAR * result = var_parse_var_new();
+ VAR_PARSE_GROUP * name = result->name;
+ const char * s = *string;
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, name ) ) {}
+ else if ( s[0] == ':' )
+ {
+ VAR_PARSE_GROUP * mod;
+ var_parse_group_maybe_add_constant( name, *string, s );
+ ++s;
+ *string = s;
+ mod = var_parse_var_new_modifier( result );
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, mod ) ) {}
+ else if ( s[0] == ')' )
+ {
+ var_parse_group_maybe_add_constant( mod, *string, s );
+ ++s;
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else if ( s[0] == '(' )
+ {
+ ++s;
+ balance_parentheses( &s, string, mod );
+ }
+ else if ( s[0] == ':' )
+ {
+ var_parse_group_maybe_add_constant( mod, *string, s );
+ ++s;
+ *string = s;
+ mod = var_parse_var_new_modifier( result );
+ }
+ else if ( s[0] == '[' )
+ {
+ parse_error("unexpected subscript");
+ }
+ else if ( s[0] == '\0' )
+ {
+ parse_error( "unbalanced parentheses" );
+ }
+ else
+ {
+ ++s;
+ }
+ }
+ }
+ else if ( s[0] == '[' )
+ {
+ VAR_PARSE_GROUP * subscript = var_parse_group_new();
+ result->subscript = subscript;
+ var_parse_group_maybe_add_constant( name, *string, s );
+ ++s;
+ *string = s;
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, subscript ) ) {}
+ else if ( s[0] == ']' )
+ {
+ var_parse_group_maybe_add_constant( subscript, *string, s );
+ ++s;
+ *string = s;
+ if ( s[0] == '\0' )
+ {
+ parse_error( "unbalanced parentheses" );
+ }
+ else if ( s[0] == ')' || s[0] == ':' )
+ {
+ break;
+ }
+ else
+ {
+ parse_error( "unexpected text following []" );
+ }
+ }
+ else if ( isdigit( s[0] ) || s[0] == '-' )
+ {
+ ++s;
+ }
+ else
+ {
+ parse_error( "malformed subscript" );
+ }
+ }
+ }
+ else if ( s[0] == ')' )
+ {
+ var_parse_group_maybe_add_constant( name, *string, s );
+ ++s;
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else if ( s[0] == '(' )
+ {
+ ++s;
+ balance_parentheses( &s, string, name );
+ }
+ else if ( s[0] == '\0' )
+ {
+ parse_error( "unbalanced parentheses" );
+ }
+ else
+ {
+ ++s;
+ }
+ }
+}
+
+/*
+ * Given that *s_ points to the character after a "(",
+ * parses up to the matching ")". *string should
+ * point to the first unemitted character before *s_.
+ *
+ * When the function returns, *s_ will point to the character
+ * after the ")", and *string will point to the first
+ * unemitted character before *s_. The range from *string
+ * to *s_ does not contain any variables that need to be
+ * expanded.
+ */
+
+void balance_parentheses( const char * * s_, const char * * string, VAR_PARSE_GROUP * out)
+{
+ int depth = 1;
+ const char * s = *s_;
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, out ) ) { }
+ else if(s[0] == ':' || s[0] == '[' || s[0] == '\0')
+ {
+ parse_error( "unbalanced parentheses" );
+ }
+ else if(s[0] == ')')
+ {
+ ++s;
+ if(--depth == 0) break;
+ }
+ else if(s[0] == '(')
+ {
+ ++depth;
+ ++s;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+ *s_ = s;
+}
+
+/*
+ * Main compile
+ */
+
+#define RESULT_STACK 0
+#define RESULT_RETURN 1
+#define RESULT_NONE 2
+
+static void compile_parse( PARSE * parse, compiler * c, int result_location );
+
+static void compile_condition( PARSE * parse, compiler * c, int branch_true, int label )
+{
+ assert( parse->type == PARSE_EVAL );
+ switch ( parse->num )
+ {
+ case EXPR_EXISTS:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_NOT_EMPTY, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_EMPTY, label );
+ break;
+ }
+ case EXPR_EQUALS:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_EQ, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_NE, label );
+ break;
+ }
+ case EXPR_NOTEQ:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_NE, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_EQ, label );
+ break;
+ }
+ case EXPR_LESS:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_LT, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_GE, label );
+ break;
+ }
+ case EXPR_LESSEQ:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_LE, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_GT, label );
+ break;
+ }
+ case EXPR_MORE:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_GT, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_LE, label );
+ break;
+ }
+ case EXPR_MOREEQ:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_GE, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_LT, label );
+ break;
+ }
+ case EXPR_IN:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_IN, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_NOT_IN, label );
+ break;
+ }
+ case EXPR_AND:
+ {
+ if ( branch_true )
+ {
+ int f = compile_new_label( c );
+ compile_condition( parse->left, c, 0, f );
+ compile_condition( parse->right, c, 1, label );
+ compile_set_label( c, f );
+ }
+ else
+ {
+ compile_condition( parse->left, c, 0, label );
+ compile_condition( parse->right, c, 0, label );
+ }
+ break;
+ }
+ case EXPR_OR:
+ {
+ if ( branch_true )
+ {
+ compile_condition( parse->left, c, 1, label );
+ compile_condition( parse->right, c, 1, label );
+ }
+ else
+ {
+ int t = compile_new_label( c );
+ compile_condition( parse->left, c, 1, t );
+ compile_condition( parse->right, c, 0, label );
+ compile_set_label( c, t );
+ }
+ break;
+ }
+ case EXPR_NOT:
+ {
+ compile_condition( parse->left, c, !branch_true, label );
+ break;
+ }
+ }
+}
+
+static void adjust_result( compiler * c, int actual_location, int desired_location )
+{
+ if ( actual_location == desired_location )
+ ;
+ else if ( actual_location == RESULT_STACK && desired_location == RESULT_RETURN )
+ compile_emit( c, INSTR_SET_RESULT, 0 );
+ else if( actual_location == RESULT_STACK && desired_location == RESULT_NONE )
+ compile_emit( c, INSTR_POP, 0 );
+ else if( actual_location == RESULT_RETURN && desired_location == RESULT_STACK )
+ compile_emit( c, INSTR_PUSH_RESULT, 0 );
+ else if ( actual_location == RESULT_RETURN && desired_location == RESULT_NONE )
+ ;
+ else if ( actual_location == RESULT_NONE && desired_location == RESULT_STACK )
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ else if ( actual_location == RESULT_NONE && desired_location == RESULT_RETURN )
+ {
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ compile_emit( c, INSTR_SET_RESULT, 0 );
+ }
+ else
+ {
+ assert( !"invalid result location" );
+ }
+}
+
+static const char * parse_type( PARSE * parse )
+{
+ switch ( parse->type )
+ {
+ case PARSE_APPEND: return "append";
+ case PARSE_EVAL: return "eval";
+ case PARSE_RULES: return "rules";
+ default: return "unknown";
+ }
+}
+
+static void compile_parse( PARSE * parse, compiler * c, int result_location )
+{
+ if ( parse->type == PARSE_APPEND )
+ {
+ /*
+ * append is associative, so flip the parse tree of chained
+ * appends around to keep the stack from getting too deep.
+ */
+ compile_parse( parse->right, c, RESULT_STACK );
+ while ( parse->left->type == PARSE_APPEND )
+ {
+ compile_parse( parse->left->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_APPEND, 0 );
+ parse = parse->left;
+ }
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_APPEND, 0 );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_EVAL )
+ {
+ /* FIXME: This is only needed because of the bizarre parsing of conditions. */
+ if ( parse->num == EXPR_EXISTS )
+ {
+ compile_parse( parse->left, c, result_location );
+ }
+ else
+ {
+ printf( "%s:%d: Conditional used as list (check operator precedence).\n", object_str(parse->file), parse->line, parse->num );
+ exit( 1 );
+ }
+ }
+ else if ( parse->type == PARSE_FOREACH )
+ {
+ int var = compile_emit_constant( c, parse->string );
+ int top = compile_new_label( c );
+ int end = compile_new_label( c );
+
+ /*
+ * Evaluate the list.
+ */
+ compile_parse( parse->left, c, RESULT_STACK );
+
+ /* Localize the loop variable */
+ if ( parse->num )
+ {
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ compile_emit( c, INSTR_PUSH_LOCAL, var );
+ compile_emit( c, INSTR_SWAP, 1 );
+ }
+
+ compile_set_label( c, top );
+ compile_emit_branch( c, INSTR_TRY_POP_FRONT, end );
+ compile_emit( c, INSTR_SET, var );
+ compile_emit( c, INSTR_POP, 0 );
+
+ /* Run the loop body */
+ compile_parse( parse->right, c, RESULT_NONE );
+
+ compile_emit_branch( c, INSTR_JUMP, top );
+ compile_set_label( c, end );
+
+ if ( parse->num )
+ {
+ compile_emit( c, INSTR_POP_LOCAL, var );
+ }
+
+ adjust_result( c, RESULT_NONE, result_location);
+ }
+ else if( parse->type == PARSE_IF )
+ {
+ int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
+ int f = compile_new_label( c );
+ /* Emit the condition */
+ compile_condition( parse->left, c, 0, f );
+ /* Emit the if block */
+ compile_parse( parse->right, c, nested_result );
+ if ( parse->third->type != PARSE_NULL )
+ {
+ /* Emit the else block */
+ int end = compile_new_label( c );
+ compile_emit_branch( c, INSTR_JUMP, end );
+ compile_set_label( c, f );
+ compile_parse( parse->third, c, nested_result );
+ compile_set_label( c, end );
+ }
+ else
+ {
+ compile_set_label( c, f );
+ }
+
+ adjust_result( c, nested_result, result_location);
+ }
+ else if( parse->type == PARSE_WHILE )
+ {
+ int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
+ int test = compile_new_label( c );
+ int top = compile_new_label( c );
+ /* Jump to the loop test */
+ compile_emit_branch( c, INSTR_JUMP, test );
+ compile_set_label( c, top );
+ /* Emit the loop body */
+ compile_parse( parse->right, c, nested_result );
+ /* Emit the condition */
+ compile_set_label( c, test );
+ compile_condition( parse->left, c, 1, top );
+
+ adjust_result( c, nested_result, result_location );
+ }
+ else if ( parse->type == PARSE_INCLUDE )
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit( c, INSTR_INCLUDE, 0 );
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_MODULE )
+ {
+ int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_MODULE, 0 );
+ compile_parse( parse->right, c, nested_result );
+ compile_emit( c, INSTR_POP_MODULE, 0 );
+ adjust_result( c, nested_result, result_location );
+ }
+ else if ( parse->type == PARSE_CLASS )
+ {
+ /* Evaluate the class name. */
+ compile_parse( parse->left->right, c, RESULT_STACK );
+ /* Evaluate the base classes. */
+ if ( parse->left->left )
+ {
+ compile_parse( parse->left->left->right, c, RESULT_STACK );
+ }
+ else
+ {
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ }
+ compile_emit( c, INSTR_CLASS, 0 );
+ compile_parse( parse->right, c, RESULT_NONE );
+ compile_emit( c, INSTR_POP_MODULE, 0 );
+
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_LIST )
+ {
+ OBJECT * o = parse->string;
+ const char * s = object_str( o );
+ VAR_PARSE_GROUP * group;
+ current_file = object_str( parse->file );
+ current_line = parse->line;
+ group = parse_expansion( &s );
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_LOCAL )
+ {
+ int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
+ /*
+ * This should be left recursive group of compile_appends
+ */
+ PARSE * vars = parse->left;
+
+ /* Special case an empty list of vars */
+ if ( vars->type == PARSE_NULL )
+ {
+ compile_parse( parse->right, c, RESULT_NONE );
+ compile_parse( parse->third, c, result_location );
+ nested_result = result_location;
+ }
+ /*
+ * Check whether there is exactly one variable
+ * with a constant name
+ */
+ else if ( vars->left->type == PARSE_NULL &&
+ vars->right->type == PARSE_LIST )
+ {
+ const char * s = object_str( vars->right->string );
+ VAR_PARSE_GROUP * group;
+ current_file = object_str( parse->file );
+ current_line = parse->line;
+ group = parse_expansion( &s );
+ if ( group->elems->size == 1 &&
+ dynamic_array_at( VAR_PARSE *, group->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
+ {
+ int name = compile_emit_constant( c, ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 0 ) )->s );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_LOCAL, name );
+ compile_parse( parse->third, c, nested_result );
+ compile_emit( c, INSTR_POP_LOCAL, name );
+ }
+ else
+ {
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 );
+ compile_parse( parse->third, c, nested_result );
+ compile_emit( c, INSTR_POP_LOCAL_GROUP, 0 );
+ }
+ }
+ else
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 );
+ compile_parse( parse->third, c, nested_result );
+ compile_emit( c, INSTR_POP_LOCAL_GROUP, 0 );
+ }
+ adjust_result( c, nested_result, result_location );
+ }
+ else if ( parse->type == PARSE_ON )
+ {
+ int end = compile_new_label( c );
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit_branch( c, INSTR_PUSH_ON, end );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_POP_ON, 0 );
+ compile_set_label( c, end );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_RULE )
+ {
+ PARSE * p;
+ int n = 0;
+ VAR_PARSE_GROUP * group;
+ const char * s = object_str( parse->string );
+
+ if ( parse->left->left == NULL && parse->left->right->type == PARSE_NULL )
+ ;
+ else
+ for ( p = parse->left; p; p = p->left )
+ {
+ compile_parse( p->right, c, RESULT_STACK );
+ ++n;
+ }
+
+ current_file = object_str( parse->file );
+ current_line = parse->line;
+ group = parse_expansion( &s );
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ compile_emit( c, INSTR_CALL_RULE, n );
+ compile_emit( c, compile_emit_constant( c, parse->string ), parse->line );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_RULES )
+ {
+ do compile_parse( parse->left, c, RESULT_NONE );
+ while ( ( parse = parse->right )->type == PARSE_RULES );
+ compile_parse( parse, c, result_location );
+ }
+ else if ( parse->type == PARSE_SET )
+ {
+ PARSE * vars = parse->left;
+ unsigned int op_code;
+ unsigned int op_code_group;
+
+ switch ( parse->num )
+ {
+ case ASSIGN_SET: default: op_code = INSTR_SET; op_code_group = INSTR_SET_GROUP; break;
+ case ASSIGN_APPEND: op_code = INSTR_APPEND; op_code_group = INSTR_APPEND_GROUP; break;
+ case ASSIGN_DEFAULT: op_code = INSTR_DEFAULT; op_code_group = INSTR_DEFAULT_GROUP; break;
+ }
+
+ /*
+ * Check whether there is exactly one variable
+ * with a constant name
+ */
+ if ( vars->type == PARSE_LIST )
+ {
+ const char * s = object_str( vars->string );
+ VAR_PARSE_GROUP * group;
+ current_file = object_str( parse->file );
+ current_line = parse->line;
+ group = parse_expansion( &s );
+ if ( group->elems->size == 1 &&
+ dynamic_array_at( VAR_PARSE *, group->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
+ {
+ int name = compile_emit_constant( c, ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 0 ) )->s );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, op_code, name );
+ }
+ else
+ {
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, op_code_group, 0 );
+ }
+ }
+ else
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, op_code_group, 0 );
+ }
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_SETCOMP )
+ {
+ int n_args = 0;
+ int rule_id;
+ if ( parse->right )
+ {
+ PARSE * p;
+ for ( p = parse->right; p; p = p->left )
+ {
+ compile_parse( p->right, c, RESULT_STACK );
+ ++n_args;
+ }
+ }
+
+ rule_id = compile_emit_rule( c, parse->string, parse->left, n_args, parse->num );
+
+ compile_emit( c, INSTR_RULE, rule_id );
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_SETEXEC )
+ {
+ int actions_id = compile_emit_actions( c, parse->string, parse->string1, parse->num );
+
+ compile_parse( parse->left, c, RESULT_STACK );
+
+ compile_emit( c, INSTR_ACTIONS, actions_id );
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_SETTINGS )
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->third, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+
+ switch ( parse->num )
+ {
+ case ASSIGN_SET: default: compile_emit( c, INSTR_SET_ON, 0 ); break;
+ case ASSIGN_APPEND: compile_emit( c, INSTR_APPEND_ON, 0 ); break;
+ case ASSIGN_DEFAULT: compile_emit( c, INSTR_DEFAULT_ON, 0 ); break;
+ }
+
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_SWITCH )
+ {
+ int switch_end = compile_new_label( c );
+ compile_parse( parse->left, c, RESULT_STACK );
+
+ for ( parse = parse->right; parse; parse = parse->right )
+ {
+ int id = compile_emit_constant( c, parse->left->string );
+ int next_case = compile_new_label( c );
+ compile_emit( c, INSTR_PUSH_CONSTANT, id );
+ compile_emit_branch( c, INSTR_JUMP_NOT_GLOB, next_case );
+ compile_parse( parse->left->left, c, result_location );
+ compile_emit_branch( c, INSTR_JUMP, switch_end );
+ compile_set_label( c, next_case );
+ }
+ compile_emit( c, INSTR_POP, 0 );
+ adjust_result( c, RESULT_NONE, result_location );
+ compile_set_label( c, switch_end );
+ }
+ else if ( parse->type == PARSE_NULL )
+ {
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else
+ {
+ assert( !"unknown PARSE type." );
+ }
+}
+
+OBJECT * function_rulename( FUNCTION * function )
+{
+ return function->rulename;
+}
+
+void function_set_rulename( FUNCTION * function, OBJECT * rulename )
+{
+ function->rulename = rulename;
+}
+
+void function_location( FUNCTION * function_, OBJECT * * file, int * line )
+{
+ if ( function_->type == FUNCTION_BUILTIN )
+ {
+ *file = constant_builtin;
+ *line = -1;
+ }
+ else
+ {
+ JAM_FUNCTION * function = (JAM_FUNCTION *)function_;
+ *file = function->file;
+ *line = function->line;
+ }
+}
+
+FUNCTION * function_builtin( LIST * ( * func )( FRAME * frame, int flags ), int flags )
+{
+ BUILTIN_FUNCTION * result = BJAM_MALLOC( sizeof( BUILTIN_FUNCTION ) );
+ result->type = FUNCTION_BUILTIN;
+ result->reference_count = 1;
+ result->rulename = 0;
+ result->func = func;
+ result->flags = flags;
+ return (FUNCTION *)result;
+}
+
+FUNCTION * function_compile( PARSE * parse )
+{
+ compiler c[1];
+ JAM_FUNCTION * result;
+ compiler_init( c );
+ compile_parse( parse, c, RESULT_RETURN );
+ compile_emit( c, INSTR_RETURN, 0 );
+ result = compile_to_function( c );
+ compiler_free( c );
+ result->file = object_copy( parse->file );
+ result->line = parse->line;
+ return (FUNCTION *)result;
+}
+
+void function_refer( FUNCTION * func )
+{
+ ++func->reference_count;
+}
+
+void function_free( FUNCTION * function_ )
+{
+ int i;
+
+ if ( --function_->reference_count != 0 ) return;
+
+ if ( function_->rulename ) object_free( function_->rulename );
+
+ if ( function_->type == FUNCTION_JAM )
+ {
+ JAM_FUNCTION * func = (JAM_FUNCTION *)function_;
+
+ BJAM_FREE( func->code );
+ for ( i = 0; i < func->num_constants; ++i )
+ {
+ object_free( func->constants[i] );
+ }
+ BJAM_FREE( func->constants );
+
+ for ( i = 0; i < func->num_subfunctions; ++i )
+ {
+ object_free( func->functions[i].name );
+ function_free( func->functions[i].code );
+ }
+ BJAM_FREE( func->functions );
+
+ for ( i = 0; i < func->num_subactions; ++i )
+ {
+ object_free( func->actions[i].name );
+ object_free( func->actions[i].command );
+ }
+ BJAM_FREE( func->actions );
+
+ object_free( func->file );
+ }
+
+ BJAM_FREE( function_ );
+}
+
+/*
+ * WARNING: The instruction set is tuned for Jam and
+ * is not really generic. Be especially careful about
+ * stack push/pop.
+ */
+
+LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s )
+{
+ JAM_FUNCTION * function;
+ instruction * code;
+ LIST * l;
+ LIST * r;
+ LIST * result = L0;
+ void * saved_stack = s->data;
+
+ if ( function_->type == FUNCTION_BUILTIN )
+ {
+ BUILTIN_FUNCTION * f = (BUILTIN_FUNCTION *)function_;
+ return f->func( frame, f->flags );
+ }
+
+ function = (JAM_FUNCTION *)function_;
+ code = function->code;
+ for ( ; ; )
+ {
+ switch ( code->op_code )
+ {
+
+ /*
+ * Basic stack manipulation
+ */
+
+ case INSTR_PUSH_EMPTY:
+ {
+ stack_push( s, L0 );
+ break;
+ }
+
+ case INSTR_PUSH_CONSTANT:
+ {
+ OBJECT * value = function_get_constant( function, code->arg );
+ stack_push( s, list_new( L0, object_copy( value ) ) );
+ break;
+ }
+
+ case INSTR_PUSH_ARG:
+ {
+ stack_push( s, frame_get_local( frame, code->arg ) );
+ break;
+ }
+
+ case INSTR_PUSH_VAR:
+ {
+ stack_push( s, function_get_variable( function, frame, code->arg ) );
+ break;
+ }
+
+ case INSTR_PUSH_GROUP:
+ {
+ LIST * value = L0;
+ l = stack_pop( s );
+ for ( r = l; r; r = list_next( r ) )
+ {
+ LIST * one = function_get_named_variable( function, frame, r->value );
+ value = list_append( value, one );
+ }
+ list_free( l );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_PUSH_APPEND:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ stack_push( s, list_append( r, l ) );
+ break;
+ }
+
+ case INSTR_SWAP:
+ {
+ l = stack_top( s );
+ stack_set( s, 0, stack_at( s, code->arg ) );
+ stack_set( s, code->arg, l );
+ break;
+ }
+
+ case INSTR_POP:
+ {
+ list_free( stack_pop( s ) );
+ break;
+ }
+
+ /*
+ * Branch instructions
+ */
+
+ case INSTR_JUMP:
+ {
+ code += code->arg;
+ break;
+ }
+
+ case INSTR_JUMP_EMPTY:
+ {
+ l = stack_pop( s );
+ if ( !list_cmp( l, L0 ) ) { code += code->arg; }
+ list_free( l );
+ break;
+ }
+
+ case INSTR_JUMP_NOT_EMPTY:
+ {
+ l = stack_pop( s );
+ if( list_cmp( l, L0 ) ) { code += code->arg; }
+ list_free( l );
+ break;
+ }
+
+ case INSTR_JUMP_LT:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if ( list_cmp( l, r ) < 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_LE:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if ( list_cmp( l, r ) <= 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_GT:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if ( list_cmp( l, r ) > 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_GE:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if ( list_cmp( l, r ) >= 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_EQ:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if( list_cmp( l, r ) == 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_NE:
+ {
+ r = stack_pop(s);
+ l = stack_pop(s);
+ if( list_cmp(l, r) != 0 ) { code += code->arg; }
+ list_free(l);
+ list_free(r);
+ break;
+ }
+
+ case INSTR_JUMP_IN:
+ {
+ r = stack_pop(s);
+ l = stack_pop(s);
+ if ( list_is_sublist( l, r ) ) { code += code->arg; }
+ list_free(l);
+ list_free(r);
+ break;
+ }
+
+ case INSTR_JUMP_NOT_IN:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if( !list_is_sublist( l, r ) ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ /*
+ * For
+ */
+
+ case INSTR_TRY_POP_FRONT:
+ {
+ l = stack_pop( s );
+ if( !l )
+ {
+ code += code->arg;
+ }
+ else
+ {
+ r = list_new( L0, object_copy( l->value ) );
+ l = list_pop_front( l );
+ stack_push( s, l );
+ stack_push( s, r );
+ }
+ break;
+ }
+
+ /*
+ * Switch
+ */
+
+ case INSTR_JUMP_NOT_GLOB:
+ {
+ const char * pattern;
+ const char * match;
+ l = stack_pop( s );
+ r = stack_top( s );
+ pattern = l ? object_str( l->value ) : "";
+ match = r ? object_str( r->value ) : "";
+ if( glob( pattern, match ) )
+ {
+ code += code->arg;
+ }
+ else
+ {
+ list_free( stack_pop( s ) );
+ }
+ list_free( l );
+ break;
+ }
+
+ /*
+ * Return
+ */
+
+ case INSTR_SET_RESULT:
+ {
+ list_free( result );
+ result = stack_pop( s );
+ break;
+ }
+
+ case INSTR_PUSH_RESULT:
+ {
+ stack_push( s, result );
+ result = L0;
+ break;
+ }
+
+ case INSTR_RETURN:
+ {
+ assert( saved_stack == s->data );
+ return result;
+ }
+
+ /*
+ * Local variables
+ */
+
+ case INSTR_PUSH_LOCAL:
+ {
+ LIST * value = stack_pop( s );
+ stack_push( s, function_swap_variable( function, frame, code->arg, value ) );
+ break;
+ }
+
+ case INSTR_POP_LOCAL:
+ {
+ function_set_variable( function, frame, code->arg, stack_pop( s ) );
+ break;
+ }
+
+ case INSTR_PUSH_LOCAL_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ l = stack_pop( s );
+ for( r = l; r; r = list_next( r ) )
+ {
+ LIST * saved = function_swap_named_variable( function, frame, r->value, list_copy( L0, value ) );
+ stack_push( s, saved );
+ }
+ list_free( value );
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_POP_LOCAL_GROUP:
+ {
+ r = stack_pop( s );
+ l = list_reverse( r );
+ list_free( r );
+ for( r = l; r; r = list_next( r ) )
+ {
+ function_set_named_variable( function, frame, r->value, stack_pop( s ) );
+ }
+ list_free( l );
+ break;
+ }
+
+ /*
+ * on $(TARGET) variables
+ */
+
+ case INSTR_PUSH_ON:
+ {
+ LIST * targets = stack_top( s );
+ if ( targets )
+ {
+ /*
+ * FIXME: push the state onto the stack instead of
+ * using pushsettings.
+ */
+ TARGET * t = bindtarget( targets->value );
+ pushsettings( t->settings );
+ }
+ else
+ {
+ /*
+ * [ on $(TARGET) ... ] is ignored if $(TARGET) is empty.
+ */
+ list_free( stack_pop( s ) );
+ stack_push( s, L0 );
+ code += code->arg;
+ }
+ break;
+ }
+
+ case INSTR_POP_ON:
+ {
+ LIST * result = stack_pop( s );
+ LIST * targets = stack_pop( s );
+ if ( targets )
+ {
+ TARGET * t = bindtarget( targets->value );
+ popsettings( t->settings );
+ }
+ list_free( targets );
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_SET_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LIST * ts;
+ for ( ts = targets; ts; ts = list_next( ts ) )
+ {
+ TARGET * t = bindtarget( ts->value );
+ LIST * l;
+
+ for ( l = vars; l; l = list_next( l ) )
+ t->settings = addsettings( t->settings, VAR_SET, l->value,
+ list_copy( L0, value ) );
+ }
+ list_free( vars );
+ list_free( targets );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_APPEND_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LIST * ts;
+ for ( ts = targets; ts; ts = list_next( ts ) )
+ {
+ TARGET * t = bindtarget( ts->value );
+ LIST * l;
+
+ for ( l = vars; l; l = list_next( l ) )
+ t->settings = addsettings( t->settings, VAR_APPEND, l->value,
+ list_copy( L0, value ) );
+ }
+ list_free( vars );
+ list_free( targets );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_DEFAULT_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LIST * ts;
+ for ( ts = targets; ts; ts = list_next( ts ) )
+ {
+ TARGET * t = bindtarget( ts->value );
+ LIST * l;
+
+ for ( l = vars; l; l = list_next( l ) )
+ t->settings = addsettings( t->settings, VAR_DEFAULT, l->value,
+ list_copy( L0, value ) );
+ }
+ list_free( vars );
+ list_free( targets );
+ stack_push( s, value );
+ break;
+ }
+
+ /*
+ * Variable setting
+ */
+
+ case INSTR_SET:
+ {
+ function_set_variable( function, frame, code->arg, list_copy( L0, stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_APPEND:
+ {
+ function_append_variable( function, frame, code->arg, list_copy( L0, stack_top( s ) ) );
+ break;
+ }
+ case INSTR_DEFAULT:
+ {
+ function_default_variable( function, frame, code->arg, list_copy( L0, stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_SET_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ for( r = vars; r; r = list_next( r ) )
+ function_set_named_variable( function, frame, r->value, list_copy( L0, value ) );
+ list_free( vars );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_APPEND_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ for( r = vars; r; r = list_next( r ) )
+ function_append_named_variable( function, frame, r->value, list_copy( L0, value ) );
+ list_free( vars );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_DEFAULT_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ for( r = vars; r; r = list_next( r ) )
+ function_default_named_variable( function, frame, r->value, list_copy( L0, value ) );
+ list_free( vars );
+ stack_push( s, value );
+ break;
+ }
+
+ /*
+ * Rules
+ */
+
+ case INSTR_CALL_RULE:
+ {
+ const char * unexpanded =
+ object_str( function_get_constant( function, code[1].op_code ) );
+ LIST * result = function_call_rule( function, frame, s, code->arg, unexpanded, function->file, code[1].arg );
+ stack_push( s, result );
+ ++code;
+ break;
+ }
+
+ case INSTR_RULE:
+ {
+ function_set_rule( function, frame, s, code->arg );
+ break;
+ }
+
+ case INSTR_ACTIONS:
+ {
+ function_set_actions( function, frame, s, code->arg );
+ break;
+ }
+
+ /*
+ * Variable expansion
+ */
+
+ case INSTR_APPLY_MODIFIERS:
+ {
+ int n;
+ int i;
+ l = stack_pop( s );
+ n = expand_modifiers( s, code->arg );
+ stack_push( s, l );
+ l = apply_modifiers( s, n );
+ list_free( stack_pop( s ) );
+ stack_deallocate( s, n * sizeof( VAR_EDITS ) );
+ for ( i = 0; i < code->arg; ++i )
+ list_free( stack_pop( s ) ); /* pop modifiers */
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_APPLY_INDEX:
+ {
+ l = apply_subscript( s );
+ list_free( stack_pop( s ) );
+ list_free( stack_pop( s ) );
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_APPLY_INDEX_MODIFIERS:
+ {
+ int i;
+ int n;
+ l = stack_pop( s );
+ r = stack_pop( s );
+ n = expand_modifiers( s, code->arg );
+ stack_push( s, r );
+ stack_push( s, l );
+ l = apply_subscript_and_modifiers( s, n );
+ list_free( stack_pop( s ) );
+ list_free( stack_pop( s ) );
+ stack_deallocate( s, n * sizeof( VAR_EDITS ) );
+ for ( i = 0; i < code->arg; ++i )
+ list_free( stack_pop( s ) ); /* pop modifiers */
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_APPLY_MODIFIERS_GROUP:
+ {
+ int i;
+ LIST * vars = stack_pop( s );
+ int n = expand_modifiers( s, code->arg );
+ LIST * result = L0;
+ for( l = vars; l; l = list_next( l ) )
+ {
+ stack_push( s, function_get_named_variable( function, frame, l->value ) );
+ result = list_append( result, apply_modifiers( s, n ) );
+ list_free( stack_pop( s ) );
+ }
+ list_free( vars );
+ stack_deallocate( s, n * sizeof( VAR_EDITS ) );
+ for ( i = 0; i < code->arg; ++i )
+ list_free( stack_pop( s ) ); /* pop modifiers */
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_APPLY_INDEX_GROUP:
+ {
+ LIST * vars = stack_pop( s );
+ LIST * result = L0;
+ for( l = vars; l; l = list_next( l ) )
+ {
+ stack_push( s, function_get_named_variable( function, frame, l->value ) );
+ result = list_append( result, apply_subscript( s ) );
+ list_free( stack_pop( s ) );
+ }
+ list_free( vars );
+ list_free( stack_pop( s ) );
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_APPLY_INDEX_MODIFIERS_GROUP:
+ {
+ int i;
+ LIST * vars = stack_pop( s );
+ LIST * r = stack_pop( s );
+ int n = expand_modifiers( s, code->arg );
+ LIST * result = L0;
+ stack_push( s, r );
+ for( l = vars; l; l = list_next( l ) )
+ {
+ stack_push( s, function_get_named_variable( function, frame, l->value ) );
+ result = list_append( result, apply_subscript_and_modifiers( s, n ) );
+ list_free( stack_pop( s ) );
+ }
+ list_free( stack_pop( s ) );
+ list_free( vars );
+ stack_deallocate( s, n * sizeof( VAR_EDITS ) );
+ for ( i = 0; i < code->arg; ++i )
+ list_free( stack_pop( s ) ); /* pop modifiers */
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_COMBINE_STRINGS:
+ {
+ LIST * result;
+ size_t buffer_size = code->arg * sizeof( expansion_item );
+ LIST * * stack_pos = stack_get( s );
+ expansion_item * items = stack_allocate( s, buffer_size );
+ int i;
+ for( i = 0; i < code->arg; ++i )
+ {
+ items[i].elem = items[i].saved = stack_pos[i];
+ }
+ result = expand( items, code->arg );
+ stack_deallocate( s, buffer_size );
+ for( i = 0; i < code->arg; ++i )
+ {
+ list_free( stack_pop( s ) );
+ }
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_INCLUDE:
+ {
+ LIST * nt = stack_pop( s );
+
+ if ( nt )
+ {
+ TARGET * t = bindtarget( nt->value );
+ list_free( nt );
+
+ /* DWA 2001/10/22 - Perforce Jam cleared the arguments here, which
+ * prevents an included file from being treated as part of the body of a
+ * rule. I did not see any reason to do that, so I lifted the
+ * restriction.
+ */
+
+ /* Bind the include file under the influence of */
+ /* "on-target" variables. Though they are targets, */
+ /* include files are not built with make(). */
+
+ pushsettings( t->settings );
+ /* We don't expect that file to be included is generated by some
+ action. Therefore, pass 0 as third argument.
+ If the name resolves to directory, let it error out. */
+ object_free( t->boundname );
+ t->boundname = search( t->name, &t->time, 0, 0 );
+ popsettings( t->settings );
+
+ parse_file( t->boundname, frame );
+ }
+
+ break;
+ }
+
+ /*
+ * Classes and modules
+ */
+
+ case INSTR_PUSH_MODULE:
+ {
+ LIST * module_name = stack_pop( s );
+
+ module_t * outer_module = frame->module;
+ frame->module = module_name ? bindmodule( module_name->value ) : root_module();
+
+ list_free( module_name );
+
+ if ( outer_module != frame->module )
+ {
+ exit_module( outer_module );
+ enter_module( frame->module );
+ }
+
+ *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) = outer_module;
+
+ break;
+ }
+
+ case INSTR_POP_MODULE:
+ {
+ module_t * outer_module = *(module_t * *)stack_get( s );
+ stack_deallocate( s, sizeof( module_t * ) );
+ if ( outer_module != frame->module )
+ {
+ exit_module( frame->module );
+ enter_module( outer_module );
+ frame->module = outer_module;
+ }
+ break;
+ }
+
+ case INSTR_CLASS:
+ {
+ LIST * bases = stack_pop( s );
+ LIST * name = stack_pop( s );
+ OBJECT * class_module = make_class_module( name, bases, frame );
+
+ module_t * outer_module = frame->module;
+ frame->module = bindmodule( class_module );
+ object_free( class_module );
+
+ if ( outer_module != frame->module )
+ {
+ exit_module( outer_module );
+ enter_module( frame->module );
+ }
+
+ *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) = outer_module;
+
+ break;
+ }
+
+ }
+ ++code;
+ }
+}
+
+void function_done( void )
+{
+ BJAM_FREE( stack );
+}

Added: trunk/tools/build/v2/engine/function.h
==============================================================================
--- (empty file)
+++ trunk/tools/build/v2/engine/function.h 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+#ifndef FUNCTION_SW20111123_H
+#define FUNCTION_SW20111123_H
+
+#include "object.h"
+#include "frames.h"
+#include "lists.h"
+#include "parse.h"
+
+typedef struct _function FUNCTION;
+typedef struct _stack STACK;
+
+STACK * stack_global( void );
+void stack_push( STACK * s, LIST * l );
+LIST * stack_pop( STACK * s );
+
+FUNCTION * function_compile( PARSE * parse );
+FUNCTION * function_builtin( LIST * ( * func )( FRAME * frame, int flags ), int flags );
+void function_refer( FUNCTION * );
+void function_free( FUNCTION * );
+OBJECT * function_rulename( FUNCTION * );
+void function_set_rulename( FUNCTION *, OBJECT * );
+void function_location( FUNCTION *, OBJECT * *, int * );
+LIST * function_run( FUNCTION * function, FRAME * frame, STACK * s );
+
+void function_done( void );
+
+#endif

Modified: trunk/tools/build/v2/engine/jam.c
==============================================================================
--- trunk/tools/build/v2/engine/jam.c (original)
+++ trunk/tools/build/v2/engine/jam.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -126,6 +126,7 @@
 #include "class.h"
 #include "execcmd.h"
 #include "constants.h"
+#include "function.h"
 
 /* Macintosh is "special" */
 #ifdef OS_MAC
@@ -619,6 +620,7 @@
     regex_done();
     exec_done();
     pwd_done();
+ function_done();
     list_done();
     constants_done();
     object_done();

Modified: trunk/tools/build/v2/engine/jamgram.c
==============================================================================
--- trunk/tools/build/v2/engine/jamgram.c (original)
+++ trunk/tools/build/v2/engine/jamgram.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -80,29 +80,29 @@
 
 # define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
 
-# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define F0 -1
 # define P0 (PARSE *)0
 # define S0 (OBJECT *)0
 
-# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
-# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
-# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
-# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
-# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
-# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
-# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
-# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
-# define pclass( l,r ) parse_make( compile_class,l,r,P0,S0,S0,0 )
-# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
-# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
-# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
-# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
-# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
-# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
-# define psetc( s,p,a,l ) parse_make( compile_setcomp,p,a,P0,s,S0,l )
-# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
-# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
-# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define pappend( l,r ) parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
+# define peval( c,l,r ) parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
+# define pfor( s,l,r,x ) parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( PARSE_IF,l,r,t,S0,S0,0 )
+# define pincl( l ) parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
+# define pclass( l,r ) parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
+# define pon( l,r ) parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( PARSE_SET,l,r,P0,S0,S0,a )
+# define pset1( l,r,t,a ) parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
+# define psetc( s,p,a,l ) parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
+# define psete( s,l,s1,f ) parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
+# define pwhile( l,r ) parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
 
 # define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
 # define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )

Modified: trunk/tools/build/v2/engine/jamgram.y
==============================================================================
--- trunk/tools/build/v2/engine/jamgram.y (original)
+++ trunk/tools/build/v2/engine/jamgram.y 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -105,29 +105,29 @@
 
 # define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
 
-# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define F0 -1
 # define P0 (PARSE *)0
 # define S0 (OBJECT *)0
 
-# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
-# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
-# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
-# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
-# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
-# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
-# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
-# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
-# define pclass( l,r ) parse_make( compile_class,l,r,P0,S0,S0,0 )
-# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
-# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
-# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
-# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
-# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
-# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
-# define psetc( s,p,a,l ) parse_make( compile_setcomp,p,a,P0,s,S0,l )
-# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
-# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
-# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define pappend( l,r ) parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
+# define peval( c,l,r ) parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
+# define pfor( s,l,r,x ) parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( PARSE_IF,l,r,t,S0,S0,0 )
+# define pincl( l ) parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
+# define pclass( l,r ) parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
+# define pon( l,r ) parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( PARSE_SET,l,r,P0,S0,S0,a )
+# define pset1( l,r,t,a ) parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
+# define psetc( s,p,a,l ) parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
+# define psete( s,l,s1,f ) parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
+# define pwhile( l,r ) parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
 
 # define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
 # define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )

Modified: trunk/tools/build/v2/engine/jamgram.yy
==============================================================================
--- trunk/tools/build/v2/engine/jamgram.yy (original)
+++ trunk/tools/build/v2/engine/jamgram.yy 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -61,29 +61,29 @@
 
 # define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
 
-# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define F0 -1
 # define P0 (PARSE *)0
 # define S0 (OBJECT *)0
 
-# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
-# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
-# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
-# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
-# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
-# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
-# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
-# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
-# define pclass( l,r ) parse_make( compile_class,l,r,P0,S0,S0,0 )
-# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
-# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
-# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
-# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
-# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
-# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
-# define psetc( s,p,a,l ) parse_make( compile_setcomp,p,a,P0,s,S0,l )
-# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
-# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
-# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define pappend( l,r ) parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
+# define peval( c,l,r ) parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
+# define pfor( s,l,r,x ) parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( PARSE_IF,l,r,t,S0,S0,0 )
+# define pincl( l ) parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
+# define pclass( l,r ) parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
+# define pon( l,r ) parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( PARSE_SET,l,r,P0,S0,S0,a )
+# define pset1( l,r,t,a ) parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
+# define psetc( s,p,a,l ) parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
+# define psete( s,l,s1,f ) parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
+# define pwhile( l,r ) parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
 
 # define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
 # define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )

Modified: trunk/tools/build/v2/engine/lists.c
==============================================================================
--- trunk/tools/build/v2/engine/lists.c (original)
+++ trunk/tools/build/v2/engine/lists.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -202,6 +202,43 @@
     return result;
 }
 
+LIST * list_reverse( LIST * l )
+{
+ LIST * result = L0;
+ for ( ; l; l = l->next )
+ {
+ result = list_append( list_new(L0, object_copy( l->value ) ), result );
+ }
+ return result;
+}
+
+int list_cmp( LIST * t, LIST * s )
+{
+ int status = 0;
+
+ while ( !status && ( t || s ) )
+ {
+ const char *st = t ? object_str( t->value ) : "";
+ const char *ss = s ? object_str( s->value ) : "";
+
+ status = strcmp( st, ss );
+
+ t = t ? list_next( t ) : t;
+ s = s ? list_next( s ) : s;
+ }
+
+ return status;
+}
+
+int list_is_sublist( LIST * sub, LIST * l )
+{
+ for ( ; sub; sub = sub->next )
+ {
+ if ( !list_in( l, sub->value ) )
+ return 0;
+ }
+ return 1;
+}
 
 /*
  * list_print() - print a list of strings to stdout

Modified: trunk/tools/build/v2/engine/lists.h
==============================================================================
--- trunk/tools/build/v2/engine/lists.h (original)
+++ trunk/tools/build/v2/engine/lists.h 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -87,6 +87,9 @@
 LIST * list_sort( LIST *l);
 LIST * list_unique( LIST *sorted_list);
 int list_in(LIST* l, OBJECT* value);
+LIST * list_reverse( LIST * );
+int list_cmp( LIST * lhs, LIST * rhs );
+int list_is_sublist( LIST * sub, LIST * l );
 void list_done();
 
 # define list_next( l ) ((l)->next)

Modified: trunk/tools/build/v2/engine/modules.c
==============================================================================
--- trunk/tools/build/v2/engine/modules.c (original)
+++ trunk/tools/build/v2/engine/modules.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -89,7 +89,7 @@
         args_free( rule->arguments );
     object_free( rule->name );
     if ( rule->procedure )
- parse_free( rule->procedure );
+ function_free( rule->procedure );
 }
 
 

Modified: trunk/tools/build/v2/engine/modules/order.c
==============================================================================
--- trunk/tools/build/v2/engine/modules/order.c (original)
+++ trunk/tools/build/v2/engine/modules/order.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -12,7 +12,7 @@
 /* Use quite klugy approach: when we add order dependency from 'a' to 'b',
    just append 'b' to of value of variable 'a'.
 */
-LIST *add_pair( PARSE *parse, FRAME *frame )
+LIST *add_pair( FRAME *frame, int flags )
 {
     LIST* arg = lol_get( frame->args, 0 );
 
@@ -74,7 +74,7 @@
     BJAM_FREE(colors);
 }
 
-LIST *order( PARSE *parse, FRAME *frame )
+LIST *order( FRAME *frame, int flags )
 {
     LIST* arg = lol_get( frame->args, 0 );
     LIST* tmp;

Modified: trunk/tools/build/v2/engine/modules/path.c
==============================================================================
--- trunk/tools/build/v2/engine/modules/path.c (original)
+++ trunk/tools/build/v2/engine/modules/path.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -6,7 +6,7 @@
 #include "../timestamp.h"
 #include "../object.h"
 
-LIST *path_exists( PARSE *parse, FRAME *frame )
+LIST *path_exists( FRAME *frame, int flags )
 {
     LIST* l = lol_get( frame->args, 0 );
 

Modified: trunk/tools/build/v2/engine/modules/property-set.c
==============================================================================
--- trunk/tools/build/v2/engine/modules/property-set.c (original)
+++ trunk/tools/build/v2/engine/modules/property-set.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -41,7 +41,7 @@
 }
 */
 
-LIST *property_set_create( PARSE *parse, FRAME *frame )
+LIST *property_set_create( FRAME *frame, int flags )
 {
     LIST* properties = lol_get( frame->args, 0 );
     LIST* sorted = 0;

Modified: trunk/tools/build/v2/engine/modules/regex.c
==============================================================================
--- trunk/tools/build/v2/engine/modules/regex.c (original)
+++ trunk/tools/build/v2/engine/modules/regex.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -25,7 +25,7 @@
     return $(result) ;
 }
 */
-LIST *regex_transform( PARSE *parse, FRAME *frame )
+LIST *regex_transform( FRAME *frame, int flags )
 {
     LIST* l = lol_get( frame->args, 0 );
     LIST* pattern = lol_get( frame->args, 1 );

Modified: trunk/tools/build/v2/engine/modules/sequence.c
==============================================================================
--- trunk/tools/build/v2/engine/modules/sequence.c (original)
+++ trunk/tools/build/v2/engine/modules/sequence.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -10,7 +10,7 @@
 # endif
 
 
-LIST *sequence_select_highest_ranked( PARSE *parse, FRAME *frame )
+LIST *sequence_select_highest_ranked( FRAME *frame, int flags )
 {
    /* Returns all of 'elements' for which corresponding element in parallel */
    /* list 'rank' is equal to the maximum value in 'rank'. */

Modified: trunk/tools/build/v2/engine/modules/set.c
==============================================================================
--- trunk/tools/build/v2/engine/modules/set.c (original)
+++ trunk/tools/build/v2/engine/modules/set.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -17,7 +17,7 @@
     }
     return $(result) ;
 */
-LIST *set_difference( PARSE *parse, FRAME *frame )
+LIST *set_difference( FRAME *frame, int flags )
 {
 
     LIST* b = lol_get( frame->args, 0 );

Modified: trunk/tools/build/v2/engine/native.c
==============================================================================
--- trunk/tools/build/v2/engine/native.c (original)
+++ trunk/tools/build/v2/engine/native.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -6,12 +6,8 @@
 #include "hash.h"
 #include "object.h"
 
-# define P0 (PARSE *)0
-# define C0 (OBJECT *)0
-
-
 void declare_native_rule( const char * module, const char * rule, const char * * args,
- LIST * (*f)( PARSE *, FRAME * ), int version )
+ LIST * (*f)( FRAME *, int ), int version )
 {
     OBJECT * module_obj = 0;
     module_t * m;
@@ -40,7 +36,7 @@
         {
             n.arguments = 0;
         }
- n.procedure = parse_make( f, P0, P0, P0, C0, C0, 0 );
+ n.procedure = function_builtin( f, 0 );
         n.version = version;
         hashenter(m->native_rules, (HASHDATA**)&np);
     }

Modified: trunk/tools/build/v2/engine/native.h
==============================================================================
--- trunk/tools/build/v2/engine/native.h (original)
+++ trunk/tools/build/v2/engine/native.h 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -11,7 +11,7 @@
 {
     OBJECT * name;
     argument_list * arguments;
- PARSE * procedure;
+ FUNCTION * procedure;
     /* Version of the interface that the native rule provides.
        It's possible that we want to change the set parameter
        for existing native rule. In that case, version number
@@ -27,7 +27,7 @@
 typedef struct native_rule_t native_rule_t ;
 
 void declare_native_rule( const char * module, const char * rule, const char * * args,
- LIST * (*f)( PARSE *, FRAME * ), int version );
+ LIST * (*f)( FRAME *, int ), int version );
 
 
 

Modified: trunk/tools/build/v2/engine/parse.c
==============================================================================
--- trunk/tools/build/v2/engine/parse.c (original)
+++ trunk/tools/build/v2/engine/parse.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -17,6 +17,7 @@
 #include "object.h"
 #include "modules.h"
 #include "frames.h"
+#include "function.h"
 
 /*
  * parse.c - make and destroy parse trees as driven by the parser
@@ -41,6 +42,7 @@
     for ( ; ; )
     {
         PARSE * p;
+ FUNCTION * func;
 
         /* Filled by yyparse() calling parse_save(). */
         yypsave = 0;
@@ -50,8 +52,10 @@
             break;
 
         /* Run the parse tree. */
- list_free( parse_evaluate( p, frame ) );
+ func = function_compile( p );
         parse_free( p );
+ list_free( function_run( func, frame, stack_global() ) );
+ function_free( func );
     }
 }
 
@@ -63,7 +67,7 @@
 
 
 PARSE * parse_make(
- LIST * (* func)( PARSE *, FRAME * ),
+ int type,
     PARSE * left,
     PARSE * right,
     PARSE * third,
@@ -73,7 +77,7 @@
 {
     PARSE * p = (PARSE *)BJAM_MALLOC( sizeof( PARSE ) );
 
- p->func = func;
+ p->type = type;
     p->left = left;
     p->right = right;
     p->third = third;
@@ -126,10 +130,3 @@
 
     BJAM_FREE( (char *)p );
 }
-
-
-LIST * parse_evaluate( PARSE * p, FRAME * frame )
-{
- frame->procedure = p;
- return (*p->func)( p, frame );
-}

Modified: trunk/tools/build/v2/engine/parse.h
==============================================================================
--- trunk/tools/build/v2/engine/parse.h (original)
+++ trunk/tools/build/v2/engine/parse.h 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -21,12 +21,32 @@
  * parse.h - make and destroy parse trees as driven by the parser.
  */
 
+#define PARSE_APPEND 0
+#define PARSE_FOREACH 1
+#define PARSE_IF 2
+#define PARSE_EVAL 3
+#define PARSE_INCLUDE 4
+#define PARSE_LIST 5
+#define PARSE_LOCAL 6
+#define PARSE_MODULE 7
+#define PARSE_CLASS 8
+#define PARSE_NULL 9
+#define PARSE_ON 10
+#define PARSE_RULE 11
+#define PARSE_RULES 12
+#define PARSE_SET 13
+#define PARSE_SETCOMP 14
+#define PARSE_SETEXEC 15
+#define PARSE_SETTINGS 16
+#define PARSE_SWITCH 17
+#define PARSE_WHILE 18
+
 /*
  * Parse tree node.
  */
 
 struct _PARSE {
- LIST * (* func)( PARSE *, FRAME * );
+ int type;
     PARSE * left;
     PARSE * right;
     PARSE * third;
@@ -34,7 +54,6 @@
     OBJECT * string1;
     int num;
     int refs;
-/* module * module; */
     OBJECT * rulename;
     OBJECT * file;
     int line;
@@ -44,7 +63,7 @@
 void parse_save( PARSE * );
 
 PARSE * parse_make(
- LIST * (* func)( PARSE *, FRAME * ),
+ int type,
     PARSE * left,
     PARSE * right,
     PARSE * third,

Modified: trunk/tools/build/v2/engine/rules.c
==============================================================================
--- trunk/tools/build/v2/engine/rules.c (original)
+++ trunk/tools/build/v2/engine/rules.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -45,7 +45,7 @@
  */
 
 static void set_rule_actions( RULE *, rule_actions * );
-static void set_rule_body ( RULE *, argument_list *, PARSE * procedure );
+static void set_rule_body ( RULE *, argument_list *, FUNCTION * procedure );
 
 static struct hash * targethash = 0;
 
@@ -93,7 +93,7 @@
     if ( hashenter( demand_rules( target_module ), (HASHDATA * *)&r ) )
     {
         r->name = object_copy( rulename );
- r->procedure = (PARSE *)0;
+ r->procedure = 0;
         r->module = 0;
         r->actions = 0;
         r->arguments = 0;
@@ -136,7 +136,7 @@
     object_free( r->name );
     r->name = 0;
     if ( r->procedure )
- parse_free( r->procedure );
+ function_free( r->procedure );
     r->procedure = 0;
     if ( r->arguments )
         args_free( r->arguments );
@@ -659,7 +659,7 @@
  * set_rule_body() - set the argument list and procedure of the given rule.
  */
 
-static void set_rule_body( RULE * rule, argument_list * args, PARSE * procedure )
+static void set_rule_body( RULE * rule, argument_list * args, FUNCTION * procedure )
 {
     if ( args )
         args_refer( args );
@@ -668,9 +668,9 @@
     rule->arguments = args;
 
     if ( procedure )
- parse_refer( procedure );
+ function_refer( procedure );
     if ( rule->procedure )
- parse_free( rule->procedure );
+ function_free( rule->procedure );
     rule->procedure = procedure;
 }
 
@@ -719,7 +719,7 @@
  * exported to the global module as modulename.rulename.
  */
 
-RULE * new_rule_body( module_t * m, OBJECT * rulename, argument_list * args, PARSE * procedure, int exported )
+RULE * new_rule_body( module_t * m, OBJECT * rulename, argument_list * args, FUNCTION * procedure, int exported )
 {
     RULE * local = define_rule( m, rulename, m );
     local->exported = exported;
@@ -730,8 +730,8 @@
      * can use, e.g. in profiling output. Only do this once, since this could be
      * called multiple times with the same procedure.
      */
- if ( procedure->rulename == 0 )
- procedure->rulename = global_rule_name( local );
+ if ( function_rulename( procedure ) == 0 )
+ function_set_rulename( procedure, global_rule_name( local ) );
 
     return local;
 }

Modified: trunk/tools/build/v2/engine/rules.h
==============================================================================
--- trunk/tools/build/v2/engine/rules.h (original)
+++ trunk/tools/build/v2/engine/rules.h 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -15,7 +15,7 @@
 
 #include "modules.h"
 #include "jam.h"
-#include "parse.h"
+#include "function.h"
 
 
 /*
@@ -81,7 +81,7 @@
 struct _rule
 {
     OBJECT * name;
- PARSE * procedure; /* parse tree from RULE */
+ FUNCTION * procedure;
     argument_list * arguments; /* argument checking info, or NULL for unchecked
                                  */
     rule_actions * actions; /* build actions, or NULL for no actions */
@@ -260,7 +260,7 @@
 /* Rule related functions. */
 RULE * bindrule ( OBJECT * rulename, module_t * );
 RULE * import_rule ( RULE * source, module_t *, OBJECT * name );
-RULE * new_rule_body ( module_t *, OBJECT * rulename, argument_list *, PARSE * procedure, int exprt );
+RULE * new_rule_body ( module_t *, OBJECT * rulename, argument_list *, FUNCTION * func, int exprt );
 RULE * new_rule_actions( module_t *, OBJECT * rulename, OBJECT * command, LIST * bindlist, int flags );
 void rule_free ( RULE * );
 

Modified: trunk/tools/build/v2/engine/subst.c
==============================================================================
--- trunk/tools/build/v2/engine/subst.c (original)
+++ trunk/tools/build/v2/engine/subst.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -5,9 +5,9 @@
 
 #include "object.h"
 #include "lists.h"
-#include "parse.h"
 #include "compile.h"
 #include "frames.h"
+#include "builtins.h"
 
 struct regex_entry
 {
@@ -35,10 +35,7 @@
     return e->regex;
 }
 
-LIST*
-builtin_subst(
- PARSE *parse,
- FRAME *frame )
+LIST * builtin_subst( FRAME * frame, int flags )
 {
   LIST* result = L0;
   LIST* arg1 = lol_get( frame->args, 0 );

Modified: trunk/tools/build/v2/engine/w32_getreg.c
==============================================================================
--- trunk/tools/build/v2/engine/w32_getreg.c (original)
+++ trunk/tools/build/v2/engine/w32_getreg.c 2011-11-29 19:00:35 EST (Tue, 29 Nov 2011)
@@ -57,10 +57,7 @@
     return p->value;
 }
 
-LIST*
-builtin_system_registry(
- PARSE *parse,
- FRAME *frame )
+LIST * builtin_system_registry( FRAME * frame, int flags )
 {
     char const* path = object_str( lol_get(frame->args, 0)->value );
     LIST* result = L0;
@@ -187,10 +184,7 @@
     return result;
 }
 
-LIST*
-builtin_system_registry_names(
- PARSE *parse,
- FRAME *frame )
+LIST * builtin_system_registry_names( FRAME * frame, int flags )
 {
     char const* path = object_str( lol_get(frame->args, 0)->value );
     char const* result_type = object_str( lol_get(frame->args, 1)->value );


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk