Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r75763 - in branches/quickbook-dev: . boost/unordered boost/unordered/detail libs/spirit/test/qi tools/build/v2/build tools/build/v2/engine tools/build/v2/engine/modules tools/build/v2/test tools/quickbook/doc tools/quickbook/extra/cxx_committee tools/quickbook/extra/cxx_committee/html tools/quickbook/src tools/quickbook/test
From: dnljms_at_[hidden]
Date: 2011-12-01 13:07:50


Author: danieljames
Date: 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
New Revision: 75763
URL: http://svn.boost.org/trac/boost/changeset/75763

Log:
Quickbook: Merge from trunk to quickbook-dev.
Added:
   branches/quickbook-dev/tools/build/v2/engine/function.c (contents, props changed)
   branches/quickbook-dev/tools/build/v2/engine/function.h (contents, props changed)
   branches/quickbook-dev/tools/build/v2/test/core_language.jam (contents, props changed)
   branches/quickbook-dev/tools/build/v2/test/core_language.py (contents, props changed)
   branches/quickbook-dev/tools/quickbook/extra/cxx_committee/
   branches/quickbook-dev/tools/quickbook/extra/cxx_committee/Jamfile.v2 (contents, props changed)
   branches/quickbook-dev/tools/quickbook/extra/cxx_committee/html/
   branches/quickbook-dev/tools/quickbook/extra/cxx_committee/html/proposal.css (contents, props changed)
   branches/quickbook-dev/tools/quickbook/extra/cxx_committee/library_proposal.qbk (contents, props changed)
Text files modified:
   branches/quickbook-dev/boost/unordered/detail/emplace_args.hpp | 27 +
   branches/quickbook-dev/boost/unordered/detail/equivalent.hpp | 36 +
   branches/quickbook-dev/boost/unordered/detail/unique.hpp | 28
   branches/quickbook-dev/boost/unordered/unordered_map.hpp | 254 ++++++++++----
   branches/quickbook-dev/boost/unordered/unordered_set.hpp | 254 ++++++++++----
   branches/quickbook-dev/boostcpp.jam | 2
   branches/quickbook-dev/libs/spirit/test/qi/symbols1.cpp | 10
   branches/quickbook-dev/tools/build/v2/build/project.jam | 2
   branches/quickbook-dev/tools/build/v2/engine/build.bat | 2
   branches/quickbook-dev/tools/build/v2/engine/build.jam | 2
   branches/quickbook-dev/tools/build/v2/engine/build.sh | 2
   branches/quickbook-dev/tools/build/v2/engine/builtins.c | 123 +++---
   branches/quickbook-dev/tools/build/v2/engine/builtins.h | 82 ++--
   branches/quickbook-dev/tools/build/v2/engine/compile.c | 702 ---------------------------------------
   branches/quickbook-dev/tools/build/v2/engine/compile.h | 20 -
   branches/quickbook-dev/tools/build/v2/engine/constants.c | 3
   branches/quickbook-dev/tools/build/v2/engine/constants.h | 1
   branches/quickbook-dev/tools/build/v2/engine/expand.c | 2
   branches/quickbook-dev/tools/build/v2/engine/filent.c | 4
   branches/quickbook-dev/tools/build/v2/engine/frames.c | 3
   branches/quickbook-dev/tools/build/v2/engine/frames.h | 3
   branches/quickbook-dev/tools/build/v2/engine/jam.c | 2
   branches/quickbook-dev/tools/build/v2/engine/jamgram.c | 40 +-
   branches/quickbook-dev/tools/build/v2/engine/jamgram.y | 40 +-
   branches/quickbook-dev/tools/build/v2/engine/jamgram.yy | 40 +-
   branches/quickbook-dev/tools/build/v2/engine/lists.c | 37 ++
   branches/quickbook-dev/tools/build/v2/engine/lists.h | 3
   branches/quickbook-dev/tools/build/v2/engine/modules.c | 2
   branches/quickbook-dev/tools/build/v2/engine/modules/order.c | 4
   branches/quickbook-dev/tools/build/v2/engine/modules/path.c | 2
   branches/quickbook-dev/tools/build/v2/engine/modules/property-set.c | 2
   branches/quickbook-dev/tools/build/v2/engine/modules/regex.c | 2
   branches/quickbook-dev/tools/build/v2/engine/modules/sequence.c | 2
   branches/quickbook-dev/tools/build/v2/engine/modules/set.c | 2
   branches/quickbook-dev/tools/build/v2/engine/native.c | 8
   branches/quickbook-dev/tools/build/v2/engine/native.h | 4
   branches/quickbook-dev/tools/build/v2/engine/parse.c | 17
   branches/quickbook-dev/tools/build/v2/engine/parse.h | 25 +
   branches/quickbook-dev/tools/build/v2/engine/rules.c | 18
   branches/quickbook-dev/tools/build/v2/engine/rules.h | 6
   branches/quickbook-dev/tools/build/v2/engine/subst.c | 7
   branches/quickbook-dev/tools/build/v2/engine/w32_getreg.c | 10
   branches/quickbook-dev/tools/build/v2/test/BoostBuild.py | 41 +
   branches/quickbook-dev/tools/build/v2/test/test_all.py | 2
   branches/quickbook-dev/tools/quickbook/doc/1_6.qbk | 7
   branches/quickbook-dev/tools/quickbook/src/main_grammar.cpp | 1
   branches/quickbook-dev/tools/quickbook/test/templates-1_5.gold | 3
   branches/quickbook-dev/tools/quickbook/test/templates-1_5.quickbook | 8
   48 files changed, 772 insertions(+), 1125 deletions(-)

Modified: branches/quickbook-dev/boost/unordered/detail/emplace_args.hpp
==============================================================================
--- branches/quickbook-dev/boost/unordered/detail/emplace_args.hpp (original)
+++ branches/quickbook-dev/boost/unordered/detail/emplace_args.hpp 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -379,7 +379,32 @@
                 args.a)); \
     }
 
- BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
+ template <typename T, typename A0>
+ inline void construct_impl(T* address, emplace_args1<A0> const& args)
+ {
+ new((void*) address) T(boost::forward<A0>(args.a0));
+ }
+
+ template <typename T, typename A0, typename A1>
+ inline void construct_impl(T* address, emplace_args2<A0, A1> const& args)
+ {
+ new((void*) address) T(
+ boost::forward<A0>(args.a0),
+ boost::forward<A1>(args.a1)
+ );
+ }
+
+ template <typename T, typename A0, typename A1, typename A2>
+ inline void construct_impl(T* address, emplace_args3<A0, A1, A2> const& args)
+ {
+ new((void*) address) T(
+ boost::forward<A0>(args.a0),
+ boost::forward<A1>(args.a1),
+ boost::forward<A2>(args.a2)
+ );
+ }
+
+ BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
         BOOST_UNORDERED_CONSTRUCT_IMPL, _)
 
 #undef BOOST_UNORDERED_CONSTRUCT_IMPL

Modified: branches/quickbook-dev/boost/unordered/detail/equivalent.hpp
==============================================================================
--- branches/quickbook-dev/boost/unordered/detail/equivalent.hpp (original)
+++ branches/quickbook-dev/boost/unordered/detail/equivalent.hpp 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -115,20 +115,21 @@
         typedef typename pick::link_pointer link_pointer;
     };
 
- template <typename A, typename H, typename P>
+ template <typename A, typename T, typename H, typename P>
     struct multiset
     {
- typedef boost::unordered::detail::multiset<A, H, P> types;
+ typedef boost::unordered::detail::multiset<A, T, H, P> types;
 
- typedef A allocator;
+ typedef T value_type;
         typedef H hasher;
         typedef P key_equal;
+ typedef T key_type;
 
- typedef boost::unordered::detail::allocator_traits<A> traits;
- typedef typename traits::value_type value_type;
- typedef value_type key_type;
+ typedef typename boost::unordered::detail::rebind_wrap<
+ A, value_type>::type allocator;
 
- typedef boost::unordered::detail::pick_grouped_node<A, value_type> pick;
+ typedef boost::unordered::detail::allocator_traits<allocator> traits;
+ typedef boost::unordered::detail::pick_grouped_node<allocator, value_type> pick;
         typedef typename pick::node node;
         typedef typename pick::bucket bucket;
         typedef typename pick::link_pointer link_pointer;
@@ -137,20 +138,21 @@
         typedef boost::unordered::detail::set_extractor<value_type> extractor;
     };
 
- template <typename A, typename K, typename H, typename P>
+ template <typename A, typename K, typename M, typename H, typename P>
     struct multimap
     {
- typedef boost::unordered::detail::multimap<A, K, H, P> types;
+ typedef boost::unordered::detail::multimap<A, K, M, H, P> types;
 
- typedef A allocator;
+ typedef std::pair<K const, M> value_type;
         typedef H hasher;
         typedef P key_equal;
         typedef K key_type;
 
- typedef boost::unordered::detail::allocator_traits<A> traits;
- typedef typename traits::value_type value_type;
+ typedef typename boost::unordered::detail::rebind_wrap<
+ A, value_type>::type allocator;
 
- typedef boost::unordered::detail::pick_grouped_node<A, value_type> pick;
+ typedef boost::unordered::detail::allocator_traits<allocator> traits;
+ typedef boost::unordered::detail::pick_grouped_node<allocator, value_type> pick;
         typedef typename pick::node node;
         typedef typename pick::bucket bucket;
         typedef typename pick::link_pointer link_pointer;
@@ -451,22 +453,22 @@
         }
 
 #if defined(BOOST_NO_RVALUE_REFERENCES)
- node_pointer emplace(boost::unordered::detail::emplace_args1<
+ iterator emplace(boost::unordered::detail::emplace_args1<
                 boost::unordered::detail::please_ignore_this_overload> const&)
         {
             BOOST_ASSERT(false);
- return this->begin();
+ return iterator();
         }
 #endif
 
         template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
- node_pointer emplace(BOOST_UNORDERED_EMPLACE_ARGS)
+ iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS)
         {
             node_constructor a(this->node_alloc());
             a.construct_node();
             a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD);
 
- return emplace_impl(a);
+ return iterator(emplace_impl(a));
         }
 
         ////////////////////////////////////////////////////////////////////////

Modified: branches/quickbook-dev/boost/unordered/detail/unique.hpp
==============================================================================
--- branches/quickbook-dev/boost/unordered/detail/unique.hpp (original)
+++ branches/quickbook-dev/boost/unordered/detail/unique.hpp 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -111,20 +111,21 @@
         typedef typename pick::link_pointer link_pointer;
     };
 
- template <typename A, typename H, typename P>
+ template <typename A, typename T, typename H, typename P>
     struct set
     {
- typedef boost::unordered::detail::set<A, H, P> types;
+ typedef boost::unordered::detail::set<A, T, H, P> types;
 
- typedef A allocator;
+ typedef T value_type;
         typedef H hasher;
         typedef P key_equal;
+ typedef T key_type;
 
- typedef boost::unordered::detail::allocator_traits<A> traits;
- typedef typename traits::value_type value_type;
- typedef value_type key_type;
+ typedef typename boost::unordered::detail::rebind_wrap<
+ A, value_type>::type allocator;
 
- typedef boost::unordered::detail::pick_node<A, value_type> pick;
+ typedef boost::unordered::detail::allocator_traits<allocator> traits;
+ typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
         typedef typename pick::node node;
         typedef typename pick::bucket bucket;
         typedef typename pick::link_pointer link_pointer;
@@ -133,20 +134,21 @@
         typedef boost::unordered::detail::set_extractor<value_type> extractor;
     };
 
- template <typename A, typename K, typename H, typename P>
+ template <typename A, typename K, typename M, typename H, typename P>
     struct map
     {
- typedef boost::unordered::detail::map<A, K, H, P> types;
+ typedef boost::unordered::detail::map<A, K, M, H, P> types;
 
- typedef A allocator;
+ typedef std::pair<K const, M> value_type;
         typedef H hasher;
         typedef P key_equal;
         typedef K key_type;
 
- typedef boost::unordered::detail::allocator_traits<A> traits;
- typedef typename traits::value_type value_type;
+ typedef typename boost::unordered::detail::rebind_wrap<
+ A, value_type>::type allocator;
 
- typedef boost::unordered::detail::pick_node<A, value_type> pick;
+ typedef boost::unordered::detail::allocator_traits<allocator> traits;
+ typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
         typedef typename pick::node node;
         typedef typename pick::bucket bucket;
         typedef typename pick::link_pointer link_pointer;

Modified: branches/quickbook-dev/boost/unordered/unordered_map.hpp
==============================================================================
--- branches/quickbook-dev/boost/unordered/unordered_map.hpp (original)
+++ branches/quickbook-dev/boost/unordered/unordered_map.hpp 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -54,15 +54,9 @@
 
     private:
 
- typedef typename boost::unordered::detail::rebind_wrap<
- allocator_type, value_type>::type
- value_allocator;
-
- typedef boost::unordered::detail::allocator_traits<value_allocator>
- allocator_traits;
-
- typedef boost::unordered::detail::map<value_allocator, K, H, P>
- types;
+ typedef boost::unordered::detail::map<A, K, T, H, P> types;
+ typedef typename types::allocator value_allocator;
+ typedef typename types::traits allocator_traits;
         typedef typename types::table table;
 
     public:
@@ -224,10 +218,93 @@
         template <class... Args>
         iterator emplace_hint(const_iterator, Args&&... args)
         {
- return iterator(table_.emplace(std::forward<Args>(args)...).first);
+ return table_.emplace(std::forward<Args>(args)...).first;
         }
 #else
 
+#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
+
+ // 0 argument emplace requires special treatment in case
+ // the container is instantiated with a value type that
+ // doesn't have a default constructor.
+
+ std::pair<iterator, bool> emplace(
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type())
+ {
+ return this->emplace(boost::move(v));
+ }
+
+ iterator emplace_hint(const_iterator hint,
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type()
+ )
+ {
+ return this->emplace_hint(hint, boost::move(v));
+ }
+
+#endif
+
+ template <typename A0>
+ std::pair<iterator, bool> emplace(BOOST_FWD_REF(A0) a0)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0)
+ );
+ }
+
+ template <typename A0>
+ iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0)
+ ).first;
+ }
+
+ template <typename A0, typename A1>
+ std::pair<iterator, bool> emplace(
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1)
+ );
+ }
+
+ template <typename A0, typename A1>
+ iterator emplace_hint(const_iterator,
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1)
+ ).first;
+ }
+
+ template <typename A0, typename A1, typename A2>
+ std::pair<iterator, bool> emplace(
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1,
+ BOOST_FWD_REF(A2) a2)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1, a2)
+ );
+ }
+
+ template <typename A0, typename A1, typename A2>
+ iterator emplace_hint(const_iterator,
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1,
+ BOOST_FWD_REF(A2) a2)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1, a2)
+ ).first;
+ }
+
 #define BOOST_UNORDERED_EMPLACE(z, n, _) \
             template < \
                 BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
@@ -251,39 +328,18 @@
                     BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
             ) \
             { \
- return iterator(table_.emplace( \
+ return table_.emplace( \
                     boost::unordered::detail::create_emplace_args( \
                         BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
                             a) \
- )).first); \
+ )).first; \
             }
 
- BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
+ BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
             BOOST_UNORDERED_EMPLACE, _)
 
 #undef BOOST_UNORDERED_EMPLACE
 
-#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
-
- std::pair<iterator, bool> emplace(
- boost::unordered::detail::empty_emplace
- = boost::unordered::detail::empty_emplace(),
- value_type v = value_type())
- {
- return this->emplace(boost::move(v));
- }
-
- iterator emplace_hint(const_iterator hint,
- boost::unordered::detail::empty_emplace
- = boost::unordered::detail::empty_emplace(),
- value_type v = value_type()
- )
- {
- return this->emplace_hint(hint, boost::move(v));
- }
-
-#endif
-
 #endif
 
         std::pair<iterator, bool> insert(value_type const& x)
@@ -446,15 +502,9 @@
 
     private:
 
- typedef typename boost::unordered::detail::rebind_wrap<
- allocator_type, value_type>::type
- value_allocator;
-
- typedef boost::unordered::detail::allocator_traits<value_allocator>
- allocator_traits;
-
- typedef boost::unordered::detail::multimap<value_allocator, K, H, P>
- types;
+ typedef boost::unordered::detail::multimap<A, K, T, H, P> types;
+ typedef typename types::allocator value_allocator;
+ typedef typename types::traits allocator_traits;
         typedef typename types::table table;
 
     public:
@@ -611,16 +661,99 @@
         template <class... Args>
         iterator emplace(Args&&... args)
         {
- return iterator(table_.emplace(std::forward<Args>(args)...));
+ return table_.emplace(std::forward<Args>(args)...);
         }
 
         template <class... Args>
         iterator emplace_hint(const_iterator, Args&&... args)
         {
- return iterator(table_.emplace(std::forward<Args>(args)...));
+ return table_.emplace(std::forward<Args>(args)...);
         }
 #else
 
+#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
+
+ // 0 argument emplace requires special treatment in case
+ // the container is instantiated with a value type that
+ // doesn't have a default constructor.
+
+ iterator emplace(
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type())
+ {
+ return this->emplace(boost::move(v));
+ }
+
+ iterator emplace_hint(const_iterator hint,
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type()
+ )
+ {
+ return this->emplace_hint(hint, boost::move(v));
+ }
+
+#endif
+
+ template <typename A0>
+ iterator emplace(BOOST_FWD_REF(A0) a0)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0)
+ );
+ }
+
+ template <typename A0>
+ iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0)
+ );
+ }
+
+ template <typename A0, typename A1>
+ iterator emplace(
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1)
+ );
+ }
+
+ template <typename A0, typename A1>
+ iterator emplace_hint(const_iterator,
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1)
+ );
+ }
+
+ template <typename A0, typename A1, typename A2>
+ iterator emplace(
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1,
+ BOOST_FWD_REF(A2) a2)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1, a2)
+ );
+ }
+
+ template <typename A0, typename A1, typename A2>
+ iterator emplace_hint(const_iterator,
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1,
+ BOOST_FWD_REF(A2) a2)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1, a2)
+ );
+ }
+
 #define BOOST_UNORDERED_EMPLACE(z, n, _) \
             template < \
                 BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
@@ -629,11 +762,11 @@
                     BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
             ) \
             { \
- return iterator(table_.emplace( \
+ return table_.emplace( \
                     boost::unordered::detail::create_emplace_args( \
                         BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
                             a) \
- ))); \
+ )); \
             } \
                                                                             \
             template < \
@@ -644,39 +777,18 @@
                     BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
             ) \
             { \
- return iterator(table_.emplace( \
+ return table_.emplace( \
                     boost::unordered::detail::create_emplace_args( \
                         BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
                             a) \
- ))); \
+ )); \
             }
 
- BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
+ BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
             BOOST_UNORDERED_EMPLACE, _)
 
 #undef BOOST_UNORDERED_EMPLACE
 
-#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
-
- iterator emplace(
- boost::unordered::detail::empty_emplace
- = boost::unordered::detail::empty_emplace(),
- value_type v = value_type())
- {
- return iterator(this->emplace(boost::move(v)));
- }
-
- iterator emplace_hint(const_iterator hint,
- boost::unordered::detail::empty_emplace
- = boost::unordered::detail::empty_emplace(),
- value_type v = value_type()
- )
- {
- return iterator(this->emplace_hint(hint, boost::move(v)));
- }
-
-#endif
-
 #endif
 
         iterator insert(value_type const& x)

Modified: branches/quickbook-dev/boost/unordered/unordered_set.hpp
==============================================================================
--- branches/quickbook-dev/boost/unordered/unordered_set.hpp (original)
+++ branches/quickbook-dev/boost/unordered/unordered_set.hpp 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -52,15 +52,9 @@
 
     private:
 
- typedef typename boost::unordered::detail::rebind_wrap<
- allocator_type, value_type>::type
- value_allocator;
-
- typedef boost::unordered::detail::allocator_traits<value_allocator>
- allocator_traits;
-
- typedef boost::unordered::detail::set<value_allocator, H, P>
- types;
+ typedef boost::unordered::detail::set<A, T, H, P> types;
+ typedef typename types::allocator value_allocator;
+ typedef typename types::traits allocator_traits;
         typedef typename types::table table;
 
     public:
@@ -222,10 +216,93 @@
         template <class... Args>
         iterator emplace_hint(const_iterator, Args&&... args)
         {
- return iterator(table_.emplace(std::forward<Args>(args)...).first);
+ return table_.emplace(std::forward<Args>(args)...).first;
         }
 #else
 
+#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
+
+ // 0 argument emplace requires special treatment in case
+ // the container is instantiated with a value type that
+ // doesn't have a default constructor.
+
+ std::pair<iterator, bool> emplace(
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type())
+ {
+ return this->emplace(boost::move(v));
+ }
+
+ iterator emplace_hint(const_iterator hint,
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type()
+ )
+ {
+ return this->emplace_hint(hint, boost::move(v));
+ }
+
+#endif
+
+ template <typename A0>
+ std::pair<iterator, bool> emplace(BOOST_FWD_REF(A0) a0)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0)
+ );
+ }
+
+ template <typename A0>
+ iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0)
+ ).first;
+ }
+
+ template <typename A0, typename A1>
+ std::pair<iterator, bool> emplace(
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1)
+ );
+ }
+
+ template <typename A0, typename A1>
+ iterator emplace_hint(const_iterator,
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1)
+ ).first;
+ }
+
+ template <typename A0, typename A1, typename A2>
+ std::pair<iterator, bool> emplace(
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1,
+ BOOST_FWD_REF(A2) a2)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1, a2)
+ );
+ }
+
+ template <typename A0, typename A1, typename A2>
+ iterator emplace_hint(const_iterator,
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1,
+ BOOST_FWD_REF(A2) a2)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1, a2)
+ ).first;
+ }
+
 #define BOOST_UNORDERED_EMPLACE(z, n, _) \
             template < \
                 BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
@@ -249,39 +326,18 @@
                     BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
             ) \
             { \
- return iterator(table_.emplace( \
+ return table_.emplace( \
                     boost::unordered::detail::create_emplace_args( \
                         BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
                             a) \
- )).first); \
+ )).first; \
             }
 
- BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
+ BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
             BOOST_UNORDERED_EMPLACE, _)
 
 #undef BOOST_UNORDERED_EMPLACE
 
-#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
-
- std::pair<iterator, bool> emplace(
- boost::unordered::detail::empty_emplace
- = boost::unordered::detail::empty_emplace(),
- value_type v = value_type())
- {
- return this->emplace(boost::move(v));
- }
-
- iterator emplace_hint(const_iterator hint,
- boost::unordered::detail::empty_emplace
- = boost::unordered::detail::empty_emplace(),
- value_type v = value_type()
- )
- {
- return iterator(this->emplace_hint(hint, boost::move(v)));
- }
-
-#endif
-
 #endif
 
         std::pair<iterator, bool> insert(value_type const& x)
@@ -429,15 +485,9 @@
 
     private:
 
- typedef typename boost::unordered::detail::rebind_wrap<
- allocator_type, value_type>::type
- value_allocator;
-
- typedef boost::unordered::detail::allocator_traits<value_allocator>
- allocator_traits;
-
- typedef boost::unordered::detail::multiset<value_allocator, H, P>
- types;
+ typedef boost::unordered::detail::multiset<A, T, H, P> types;
+ typedef typename types::allocator value_allocator;
+ typedef typename types::traits allocator_traits;
         typedef typename types::table table;
 
     public:
@@ -594,16 +644,99 @@
         template <class... Args>
         iterator emplace(Args&&... args)
         {
- return iterator(table_.emplace(std::forward<Args>(args)...));
+ return table_.emplace(std::forward<Args>(args)...);
         }
 
         template <class... Args>
         iterator emplace_hint(const_iterator, Args&&... args)
         {
- return iterator(table_.emplace(std::forward<Args>(args)...));
+ return table_.emplace(std::forward<Args>(args)...);
         }
 #else
 
+#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
+
+ // 0 argument emplace requires special treatment in case
+ // the container is instantiated with a value type that
+ // doesn't have a default constructor.
+
+ iterator emplace(
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type())
+ {
+ return this->emplace(boost::move(v));
+ }
+
+ iterator emplace_hint(const_iterator hint,
+ boost::unordered::detail::empty_emplace
+ = boost::unordered::detail::empty_emplace(),
+ value_type v = value_type()
+ )
+ {
+ return this->emplace_hint(hint, boost::move(v));
+ }
+
+#endif
+
+ template <typename A0>
+ iterator emplace(BOOST_FWD_REF(A0) a0)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0)
+ );
+ }
+
+ template <typename A0>
+ iterator emplace_hint(const_iterator, BOOST_FWD_REF(A0) a0)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0)
+ );
+ }
+
+ template <typename A0, typename A1>
+ iterator emplace(
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1)
+ );
+ }
+
+ template <typename A0, typename A1>
+ iterator emplace_hint(const_iterator,
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1)
+ );
+ }
+
+ template <typename A0, typename A1, typename A2>
+ iterator emplace(
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1,
+ BOOST_FWD_REF(A2) a2)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1, a2)
+ );
+ }
+
+ template <typename A0, typename A1, typename A2>
+ iterator emplace_hint(const_iterator,
+ BOOST_FWD_REF(A0) a0,
+ BOOST_FWD_REF(A1) a1,
+ BOOST_FWD_REF(A2) a2)
+ {
+ return table_.emplace(
+ boost::unordered::detail::create_emplace_args(a0, a1, a2)
+ );
+ }
+
 #define BOOST_UNORDERED_EMPLACE(z, n, _) \
             template < \
                 BOOST_PP_ENUM_PARAMS_Z(z, n, typename A) \
@@ -612,11 +745,11 @@
                     BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
             ) \
             { \
- return iterator(table_.emplace( \
+ return table_.emplace( \
                     boost::unordered::detail::create_emplace_args( \
                         BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
                             a) \
- ))); \
+ )); \
             } \
                                                                             \
             template < \
@@ -627,39 +760,18 @@
                     BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
             ) \
             { \
- return iterator(table_.emplace( \
+ return table_.emplace( \
                     boost::unordered::detail::create_emplace_args( \
                         BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, \
                             a) \
- ))); \
+ )); \
             }
 
- BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
+ BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
             BOOST_UNORDERED_EMPLACE, _)
 
 #undef BOOST_UNORDERED_EMPLACE
 
-#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100))
-
- iterator emplace(
- boost::unordered::detail::empty_emplace
- = boost::unordered::detail::empty_emplace(),
- value_type v = value_type())
- {
- return this->emplace(boost::move(v));
- }
-
- iterator emplace_hint(const_iterator hint,
- boost::unordered::detail::empty_emplace
- = boost::unordered::detail::empty_emplace(),
- value_type v = value_type()
- )
- {
- return this->emplace_hint(hint, boost::move(v));
- }
-
-#endif
-
 #endif
 
         iterator insert(value_type const& x)

Modified: branches/quickbook-dev/boostcpp.jam
==============================================================================
--- branches/quickbook-dev/boostcpp.jam (original)
+++ branches/quickbook-dev/boostcpp.jam 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -80,7 +80,7 @@
     ECHO "error: Cannot use --layout=system with --build-type complete." ;
     ECHO "error: Please used either --layout=versioned or --layout=tagged " ;
     ECHO "error: if you wish to build multiple variants." ;
- if ! [ os.name ] = NT
+ if [ os.name ] != NT
     {
         ECHO "error: Note that --layout=system is default on Unix starting with Boost 1.40." ;
     }

Modified: branches/quickbook-dev/libs/spirit/test/qi/symbols1.cpp
==============================================================================
--- branches/quickbook-dev/libs/spirit/test/qi/symbols1.cpp (original)
+++ branches/quickbook-dev/libs/spirit/test/qi/symbols1.cpp 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -51,11 +51,12 @@
             ("Tutit")
             ("Kim")
             ("Joey")
+ ("Joeyboy")
         ;
 
         boost::mpl::true_ f = boost::mpl::bool_<boost::spirit::traits::is_parser<symbols<char, int> >::value>();
 
- // silence stupid compiler warnings
+ // silence stupid compiler warnings
         // i.e. MSVC warning C4189: 'f' : local variable is initialized but not referenced
         BOOST_TEST((f.value));
 
@@ -65,6 +66,7 @@
         BOOST_TEST((test("Tutit", sym)));
         BOOST_TEST((test("Kim", sym)));
         BOOST_TEST((test("Joey", sym)));
+ BOOST_TEST((test("Joeyboy", sym)));
         BOOST_TEST((!test("XXX", sym)));
 
         // test copy
@@ -159,12 +161,12 @@
         BOOST_TEST((test_attr("Joey", sym, i)));
         BOOST_TEST(i == 6);
         BOOST_TEST((!test_attr("XXX", sym, i)));
-
+
         // double add:
-
+
         sym.add("Joel", 265);
         BOOST_TEST((test_attr("Joel", sym, i)));
- BOOST_TEST(i == 1);
+ BOOST_TEST(i == 1);
     }
 
     { // actions

Modified: branches/quickbook-dev/tools/build/v2/build/project.jam
==============================================================================
--- branches/quickbook-dev/tools/build/v2/build/project.jam (original)
+++ branches/quickbook-dev/tools/build/v2/build/project.jam 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -263,7 +263,7 @@
     {
         errors.error Unable to load Jamfile.
             : Could not find a Jamfile in directory '$(dir)'.
- : Attempted to find it with pattern '"$(JAMFILE:J=" ")"'.
+ : Attempted to find it with pattern '"$(JAMFILE:J= )"'.
             : Please consult the documentation at 'http://www.boost.org'. ;
     }
 

Modified: branches/quickbook-dev/tools/build/v2/engine/build.bat
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/build.bat (original)
+++ branches/quickbook-dev/tools/build/v2/engine/build.bat 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/build.jam
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/build.jam (original)
+++ branches/quickbook-dev/tools/build/v2/engine/build.jam 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/build.sh
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/build.sh (original)
+++ branches/quickbook-dev/tools/build/v2/engine/build.sh 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/builtins.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/builtins.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/builtins.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/builtins.h
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/builtins.h (original)
+++ branches/quickbook-dev/tools/build/v2/engine/builtins.h 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/compile.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/compile.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/compile.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/compile.h
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/compile.h (original)
+++ branches/quickbook-dev/tools/build/v2/engine/compile.h 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/constants.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/constants.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/constants.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/constants.h
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/constants.h (original)
+++ branches/quickbook-dev/tools/build/v2/engine/constants.h 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/expand.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/expand.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/expand.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -82,7 +82,7 @@
     int depth;
 
     if ( DEBUG_VAREXP )
- printf( "expand '%.*s'\n", end - in, in );
+ printf( "expand '%.*s'\n", (int)( end - in ), in );
 
     /* This gets a lot of cases: $(<) and $(>). */
     if

Modified: branches/quickbook-dev/tools/build/v2/engine/filent.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/filent.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/filent.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -71,6 +71,7 @@
 
     if ( !d || !d->is_dir )
     {
+ object_free( dir );
         PROFILE_EXIT( FILE_DIRSCAN );
         return;
     }
@@ -117,6 +118,7 @@
         if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) )
         {
             string_free( filespec );
+ object_free( dir );
             PROFILE_EXIT( FILE_DIRSCAN );
             return;
         }
@@ -147,6 +149,7 @@
         if ( ret = ( handle < 0L ) )
         {
             string_free( filespec );
+ object_free( dir );
             PROFILE_EXIT( FILE_DIRSCAN );
             return;
         }
@@ -223,6 +226,7 @@
         }
     }
 
+ object_free( dir );
     PROFILE_EXIT( FILE_DIRSCAN );
 }
 

Modified: branches/quickbook-dev/tools/build/v2/engine/frames.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/frames.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/frames.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/frames.h
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/frames.h (original)
+++ branches/quickbook-dev/tools/build/v2/engine/frames.h 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -20,7 +20,8 @@
     FRAME * prev_user;
     LOL args[ 1 ];
     module_t * module;
- PARSE * procedure;
+ OBJECT * file;
+ int line;
     const char * rulename;
 };
 

Added: branches/quickbook-dev/tools/build/v2/engine/function.c
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/build/v2/engine/function.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/function.h
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/build/v2/engine/function.h 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/jam.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/jam.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/jam.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/jamgram.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/jamgram.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/jamgram.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/jamgram.y
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/jamgram.y (original)
+++ branches/quickbook-dev/tools/build/v2/engine/jamgram.y 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/jamgram.yy
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/jamgram.yy (original)
+++ branches/quickbook-dev/tools/build/v2/engine/jamgram.yy 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/lists.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/lists.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/lists.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/lists.h
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/lists.h (original)
+++ branches/quickbook-dev/tools/build/v2/engine/lists.h 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/modules.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/modules.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/modules.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/modules/order.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/modules/order.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/modules/order.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/modules/path.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/modules/path.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/modules/path.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/modules/property-set.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/modules/property-set.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/modules/property-set.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/modules/regex.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/modules/regex.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/modules/regex.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/modules/sequence.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/modules/sequence.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/modules/sequence.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/modules/set.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/modules/set.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/modules/set.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/native.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/native.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/native.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/native.h
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/native.h (original)
+++ branches/quickbook-dev/tools/build/v2/engine/native.h 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/parse.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/parse.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/parse.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/parse.h
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/parse.h (original)
+++ branches/quickbook-dev/tools/build/v2/engine/parse.h 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/rules.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/rules.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/rules.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/rules.h
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/rules.h (original)
+++ branches/quickbook-dev/tools/build/v2/engine/rules.h 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/subst.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/subst.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/subst.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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: branches/quickbook-dev/tools/build/v2/engine/w32_getreg.c
==============================================================================
--- branches/quickbook-dev/tools/build/v2/engine/w32_getreg.c (original)
+++ branches/quickbook-dev/tools/build/v2/engine/w32_getreg.c 2011-12-01 13:07:38 EST (Thu, 01 Dec 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 );

Modified: branches/quickbook-dev/tools/build/v2/test/BoostBuild.py
==============================================================================
--- branches/quickbook-dev/tools/build/v2/test/BoostBuild.py (original)
+++ branches/quickbook-dev/tools/build/v2/test/BoostBuild.py 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -76,19 +76,30 @@
 
 # Detect the host OS.
 windows = False
-if os.environ.get('OS', '').lower().startswith('windows') or \
- os.__dict__.has_key('uname') and \
- os.uname()[0].lower().startswith('cygwin'):
+cygwin = False
+if os.environ.get('OS', '').lower().startswith('windows'):
     windows = True
 
+if os.__dict__.has_key('uname') and \
+ os.uname()[0].lower().startswith('cygwin'):
+ windows = True
+ cygwin = True
 
 suffixes = {}
 
 
+# Configuration stating whether Boost Build is expected to automatically prepend
+# prefixes to built library targets.
+lib_prefix = "lib"
+dll_prefix = "lib"
+
 # Prepare the map of suffixes
 def prepare_suffix_map(toolset):
     global windows
     global suffixes
+ global cygwin
+ global lib_prefix
+ global dll_prefix
     suffixes = {'.exe': '', '.dll': '.so', '.lib': '.a', '.obj': '.o'}
     suffixes['.implib'] = '.no_implib_files_on_this_platform'
     if windows:
@@ -96,9 +107,19 @@
         if toolset in ["gcc"]:
             suffixes['.lib'] = '.a' # static libs have '.a' suffix with mingw...
             suffixes['.obj'] = '.o'
- suffixes['.implib'] = '.lib'
+ if cygwin:
+ suffixes['.implib'] = '.lib.a'
+ else:
+ suffixes['.implib'] = '.lib'
     if os.__dict__.has_key('uname') and (os.uname()[0] == 'Darwin'):
         suffixes['.dll'] = '.dylib'
+
+ lib_prefix = "lib"
+ dll_prefix = "lib"
+ if cygwin:
+ dll_prefix = "cyg"
+ elif windows and not toolset in ["gcc"]:
+ dll_prefix = None
 
 
 def re_remove(sequence, regex):
@@ -118,13 +139,6 @@
         sequence.remove(r)
 
 
-# Configuration stating whether Boost Build is expected to automatically prepend
-# prefixes to built library targets.
-lib_prefix = True
-dll_prefix = True
-if windows:
- dll_prefix = False
-
 
 #
 # FIXME: this is copy-pasted from TestSCons.py
@@ -795,6 +809,7 @@
 
     def adjust_lib_name(self, name):
         global lib_prefix
+ global dll_prefix
         result = name
 
         pos = string.rfind(name, ".")
@@ -803,12 +818,12 @@
             if suffix == ".lib":
                 (head, tail) = os.path.split(name)
                 if lib_prefix:
- tail = "lib" + tail
+ tail = lib_prefix + tail
                     result = os.path.join(head, tail)
             elif suffix == ".dll":
                 (head, tail) = os.path.split(name)
                 if dll_prefix:
- tail = "lib" + tail
+ tail = dll_prefix + tail
                     result = os.path.join(head, tail)
         # If we want to use this name in a Jamfile, we better convert \ to /, as
         # otherwise we would have to quote \.

Added: branches/quickbook-dev/tools/build/v2/test/core_language.jam
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/build/v2/test/core_language.jam 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -0,0 +1,1031 @@
+# 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)
+
+# Tools
+
+passed = 0 ;
+failed = 0 ;
+
+rule show-result ( id : test-result )
+{
+ ECHO $(test-result): $(id) ;
+ $(test-result) = [ CALC $($(test-result)) + 1 ] ;
+}
+
+rule check-equal ( id : values * : expected * )
+{
+ local test-result ;
+ if x$(values) = x$(expected)
+ {
+ test-result = passed ;
+ }
+ else
+ {
+ ECHO error: "[" $(values) "] != [" $(expected) "]" ;
+ test-result = failed ;
+ }
+ show-result $(id) : $(test-result) ;
+}
+
+rule mark-order ( id : result * )
+{
+ order += $(id) ;
+ return $(result) ;
+}
+
+rule check-order ( id : expected * )
+{
+ check-equal $(id) : $(order) : $(expected) ;
+ order = ;
+}
+
+# Check variable expansion
+
+{
+
+local v1 = 1 2 3 ;
+local v2 = 4 5 6 ;
+local v3 = 0 1 2 3 4 5 6 7 8 9 10 ;
+local g = g1 g2 ;
+local v4 = String/With/Mixed/Case ;
+local v5 = path\\with\\backslashes ;
+local v6 = <grist>generic/path.txt(member.txt) ;
+local v7 = <Grist1>Dir1/File1.cpp(M1.c) <Grist2>Dir2/File2.hpp(M2.c) ;
+local v8 = <Grist3>Dir3/File3.c(M3.c) <Grist4>Dir4/File4.h(M4.c) ;
+local select1 = GU BL DBST ;
+local case1 = L U ;
+local vars = 7 8 ;
+local sub = 2 1 ;
+
+check-equal var-product : $(v1)$(v2) : 14 15 16 24 25 26 34 35 36 ;
+
+check-equal var-set-grist : $(v1:G=grist) : <grist>1 <grist>2 <grist>3 ;
+check-equal var-set-grist-multi : $(v1:G=$(g)) : <g1>1 <g1>2 <g1>3 <g2>1 <g2>2 <g2>3 ;
+
+check-equal var-lower : $(v4:L) : string/with/mixed/case ;
+check-equal var-upper : $(v4:U) : STRING/WITH/MIXED/CASE ;
+check-equal var-LU : $(v4:LU) : STRING/WITH/MIXED/CASE ;
+check-equal var-slashes : $(v5:T) : path/with/backslashes ;
+check-equal var-grist : $(v6:G) : <grist> ;
+check-equal var-base : $(v6:B) : path ;
+check-equal var-suffix : $(v6:S) : .txt ;
+check-equal var-dir : $(v6:D) : generic ;
+check-equal var-member : $(v6:M) : (member.txt) ;
+check-equal var-multi : $(v6:$(select1)) : <GRIST> path generic/path.txt ;
+
+if $(OS) = CYGWIN
+{
+ local cyg-root = $(:WE=/) ;
+ local cyg1 = /cygdrive/c/path1.txt ;
+ check-equal cygwin-to-cygdrive : $(cyg1:W) : C:\\path1.txt ;
+ local cyg2 = /bin/bash ;
+ check-equal cygwin-to-windows : $(cyg2:W) : $(cyg-root)\\bin\\bash ;
+ check-equal cygwin-combine-WT : $(cyg2:WT) : $(cyg-root)\\bin\\bash ;
+
+ local cyg3 = /home/boost/devel/trunk/bin.v2/ ; # exactly 31 characters
+ local win3 = $(cyg-root)\\home\\boost\\devel\\trunk\\bin.v2\\ ;
+ # This is is the easiest way to demonstrate a bug
+ # that used to cause undefined behavior. Longer paths
+ # resulted in a use-after-free error, which happened
+ # to work most of the time.
+ check-equal cygwin-long-WU : $(cyg3:WU) : $(win3:U) ;
+
+ local cyg-grist = <grist>$(cyg1) ;
+ check-equal cygwin-grist : $(cyg-grist:W) : <grist>\\cygdrive\\c\\path1.txt ;
+
+ check-equal cygwin-WU : $(cyg2:WU) : $(cyg-root:U)\\BIN\\BASH ;
+ # behavior change: L now consistently applied after W.
+ # used to affect all except the drive letter.
+ check-equal cygwin-WL : $(cyg2:WL) : $(cyg-root:L)\\bin\\bash ;
+}
+
+# behavior change
+check-equal var-test1 : $(v7[2]:G:L) : <grist2> ;
+
+check-equal var-multi-product-smm : $(v$(vars)[$(sub)]:G=$(g):$(case1)) :
+ <g1>dir2/file2.hpp(m2.c) <G1>DIR2/FILE2.HPP(M2.C)
+ <g2>dir2/file2.hpp(m2.c) <G2>DIR2/FILE2.HPP(M2.C)
+ <g1>dir1/file1.cpp(m1.c) <G1>DIR1/FILE1.CPP(M1.C)
+ <g2>dir1/file1.cpp(m1.c) <G2>DIR1/FILE1.CPP(M1.C)
+ <g1>dir4/file4.h(m4.c) <G1>DIR4/FILE4.H(M4.C)
+ <g2>dir4/file4.h(m4.c) <G2>DIR4/FILE4.H(M4.C)
+ <g1>dir3/file3.c(m3.c) <G1>DIR3/FILE3.C(M3.C)
+ <g2>dir3/file3.c(m3.c) <G2>DIR3/FILE3.C(M3.C)
+;
+check-equal var-nopathmods : $(:E=//) : // ;
+
+# showcases all the idiosyncracies of indexing
+# key: h = high, l = low, p = positive, m = minus, e = end.
+
+check-equal var-subscript-one-p : $(v3[3]) : 2 ;
+check-equal var-subscript-one-m : $(v3[-3]) : 8 ;
+check-equal var-subscript-one-0 : $(v3[0]) : 0 ;
+check-equal var-subscript-one-h : $(v3[20]) : ;
+check-equal var-subscript-one-l : $(v3[-20]) : 0 ;
+check-equal var-subscript-range-pp : $(v3[2-4]) : 1 2 3 ;
+check-equal var-subscript-range-pm : $(v3[2--3]) : 1 2 3 4 5 6 7 8 ;
+check-equal var-subscript-range-pe : $(v3[2-]) : 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-ph : $(v3[2-20]) : 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-pl : $(v3[2--20]) : ;
+check-equal var-subscript-range-mp : $(v3[-3-10]) : 8 9 ;
+check-equal var-subscript-range-mm : $(v3[-4--2]) : 7 8 9 ;
+check-equal var-subscript-range-me : $(v3[-4-]) : 7 8 9 10 ;
+check-equal var-subscript-range-mh : $(v3[-4-20]) : 7 8 9 10 ;
+check-equal var-subscript-range-mh : $(v3[-4--20]) : ;
+check-equal var-subscript-range-0p : $(v3[0-2]) : 0 1 2 ;
+check-equal var-subscript-range-0m : $(v3[0--4]) : 0 1 2 3 4 5 6 7 8 ;
+check-equal var-subscript-range-0e : $(v3[0-]) : 0 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-0h : $(v3[0-20]) : 0 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-0l : $(v3[0--20]) : ;
+check-equal var-subscript-range-hp : $(v3[20-4]) : ;
+check-equal var-subscript-range-hm : $(v3[20--4]) : ;
+check-equal var-subscript-range-he : $(v3[20-]) : ;
+check-equal var-subscript-range-hh : $(v3[20-20]) : ;
+check-equal var-subscript-range-hl : $(v3[20--20]) : ;
+check-equal var-subscript-range-lp : $(v3[-13-4]) : 0 1 2 3 4 5 ;
+check-equal var-subscript-range-lm : $(v3[-13--4]) : 0 1 2 3 4 5 6 7 8 9 ;
+check-equal var-subscript-range-le : $(v3[-13-]) : 0 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-lh : $(v3[-13-20]) : 0 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-ll : $(v3[-13--13]) : 0 ;
+check-equal var-subscript-range-empty : $(v3[4-3]) : ;
+
+}
+
+# Check rule arguments
+
+{
+
+rule test-rule
+{
+ return $(<) $(>) $(1) $(2) $(3) $(4) $(5) $(6) $(7) $(8) $(9) $(10) $(11) $(12) $(13) $(14) $(15) $(16) $(17) $(18) $(19) ;
+}
+
+check-equal rule-arguments :
+ [ test-rule a1 : a2 : a3 : a4 : a5 : a6 : a7 : a8 : a9 : a10 : a11 : a12 : a13 : a14 : a15 : a16 : a17 : a18 : a19 ] :
+ a1 a2 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 ;
+
+rule test-rule
+{
+ return $(<:L) $(>:L) $(1:L) $(2:L) $(3:L) $(4:L) $(5:L) $(6:L) $(7:L) $(8:L) $(9:L) $(10:L) $(11:L) $(12:L) $(13:L) $(14:L) $(15:L) $(16:L) $(17:L) $(18:L) $(19:L) ;
+}
+
+# behavior change
+check-equal rule-arguments :
+ [ test-rule a1 : a2 : a3 : a4 : a5 : a6 : a7 : a8 : a9 : a10 : a11 : a12 : a13 : a14 : a15 : a16 : a17 : a18 : a19 ] :
+ a1 a2 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 ;
+
+}
+
+# Check append
+
+{
+
+local value = [ mark-order r1 : v1 v2 ] [ mark-order r2 : v3 v4 ] ;
+check-equal append : $(value) : v1 v2 v3 v4 ;
+check-order append-order : r2 r1 ;
+
+}
+
+# Check foreach
+
+{
+
+local v1 = 1 2 3 ;
+local x = old ;
+local result ;
+
+for local x in $(v1)
+{
+ result += $(x) + ;
+}
+
+check-equal foreach-local-item : $(result) : 1 + 2 + 3 + ;
+check-equal foreach-local : $(x) : old ;
+
+result = ;
+
+for x in $(v1)
+{
+ result += $(x) + ;
+}
+
+check-equal foreach-nonlocal-item : $(result) : 1 + 2 + 3 + ;
+check-equal foreach-nonlocal : $(x) : 3 ;
+
+rule call-foreach ( values * )
+{
+ for local x in $(values)
+ {
+ return $(x) ;
+ }
+}
+
+check-equal foreach-result : [ call-foreach 1 2 3 ] : ;
+
+result = ;
+local varname = x ;
+x = old ;
+
+for local $(varname) in $(v1)
+{
+ result += $(x) + ;
+}
+
+check-equal foreach-no-expand : $(result) : old + old + old + ;
+
+result = ;
+
+for local v1 in $(v1)
+{
+ result += $(v1) + ;
+}
+
+check-equal foreach-order : $(result) : 1 + 2 + 3 + ;
+
+}
+
+# Check if
+
+{
+
+if true
+{
+ mark-order r1 ;
+}
+
+check-order if-true : r1 ;
+
+if $(false)
+{
+ mark-order r1 ;
+}
+
+check-order if-false : ;
+
+if true
+{
+ mark-order r1 ;
+}
+else
+{
+ mark-order r2 ;
+}
+
+check-order if-else-true : r1 ;
+
+if $(false)
+{
+ mark-order r1 ;
+}
+else
+{
+ mark-order r2 ;
+}
+
+check-order if-else-false : r2 ;
+
+}
+
+# Check the evaluation of conditions
+
+{
+
+local test-result ;
+local v1 = "" "" "" ;
+local v2 = ;
+local v3 = a b c ;
+local v4 = a b c d ;
+local v5 = a b d ;
+local v6 = "" "" "" d ;
+
+rule test-comparison ( id : equal less greater )
+{
+ check-equal $(id)-empty-1 : [ eval-$(id) $(v1) : $(v2) ] : $(equal) ;
+ check-equal $(id)-empty-2 : [ eval-$(id) $(v1) : $(v2) ] : $(equal) ;
+ check-equal $(id)-equal : [ eval-$(id) $(v3) : $(v3) ] : $(equal) ;
+ check-equal $(id)-less-1 : [ eval-$(id) $(v3) : $(v4) ] : $(less) ;
+ check-equal $(id)-less-2 : [ eval-$(id) $(v3) : $(v5) ] : $(less) ;
+ check-equal $(id)-less-3 : [ eval-$(id) $(v4) : $(v5) ] : $(less) ;
+ check-equal $(id)-greater-1 : [ eval-$(id) $(v4) : $(v3) ] : $(greater) ;
+ check-equal $(id)-greater-2 : [ eval-$(id) $(v5) : $(v3) ] : $(greater) ;
+ check-equal $(id)-greater-3 : [ eval-$(id) $(v5) : $(v4) ] : $(greater) ;
+}
+
+rule eval-lt ( lhs * : rhs * )
+{
+ if $(lhs) < $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison lt : false true false ;
+
+rule eval-gt ( lhs * : rhs * )
+{
+ if $(lhs) > $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison gt : false false true ;
+
+rule eval-le ( lhs * : rhs * )
+{
+ if $(lhs) <= $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison le : true true false ;
+
+rule eval-ge ( lhs * : rhs * )
+{
+ if $(lhs) >= $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison ge : true false true ;
+
+rule eval-eq ( lhs * : rhs * )
+{
+ if $(lhs) = $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison eq : true false false ;
+
+rule eval-ne ( lhs * : rhs * )
+{
+ if $(lhs) != $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison ne : false true true ;
+
+rule eval-not-lt ( lhs * : rhs * )
+{
+ if ! ( $(lhs) < $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-lt : true false true ;
+
+rule eval-not-gt ( lhs * : rhs * )
+{
+ if ! ( $(lhs) > $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-gt : true true false ;
+
+rule eval-not-le ( lhs * : rhs * )
+{
+ if ! ( $(lhs) <= $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-le : false false true ;
+
+rule eval-not-ge ( lhs * : rhs * )
+{
+ if ! ( $(lhs) >= $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-ge : false true false ;
+
+rule eval-not-eq ( lhs * : rhs * )
+{
+ if ! ( $(lhs) = $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-eq : false true true ;
+
+rule eval-not-ne ( lhs * : rhs * )
+{
+ if ! ( $(lhs) != $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-ne : true false false ;
+
+local v7 = a a a a a a ;
+local v8 = c b ;
+local v9 = c d b ;
+local v10 = c a b c c b a a a ;
+
+rule test-in ( id : subset not-subset )
+{
+ check-equal $(id)-0-0 : [ eval-$(id) $(v2) : $(v2) ] : $(subset) ;
+ check-equal $(id)-0-empty : [ eval-$(id) $(v2) : $(v1) ] : $(subset) ;
+ check-equal $(id)-empty-0 : [ eval-$(id) $(v1) : $(v2) ] : $(not-subset) ;
+ check-equal $(id)-equal : [ eval-$(id) $(v3) : $(v3) ] : $(subset) ;
+ check-equal $(id)-simple : [ eval-$(id) $(v3) : $(v4) ] : $(subset) ;
+ check-equal $(id)-extra : [ eval-$(id) $(v4) : $(v3) ] : $(not-subset) ;
+ check-equal $(id)-multiple : [ eval-$(id) $(v7) : $(v3) ] : $(subset) ;
+ check-equal $(id)-unordered : [ eval-$(id) $(v8) : $(v3) ] : $(subset) ;
+ check-equal $(id)-unordered-extra : [ eval-$(id) $(v9) : $(v3) ] : $(not-subset) ;
+ check-equal $(id)-unordered-multiple : [ eval-$(id) $(v10) : $(v3) ] : $(subset) ;
+}
+
+rule eval-in ( lhs * : rhs * )
+{
+ if $(lhs) in $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-in "in" : true false ;
+
+rule eval-not-in ( lhs * : rhs * )
+{
+ if ! ( $(lhs) in $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-in not-in : false true ;
+
+rule test-truth-table ( id : tt tf ft ff )
+{
+ check-equal $(id)-tt : [ eval-$(id) 1 : 1 ] : $(tt) ;
+ check-equal $(id)-tf : [ eval-$(id) 1 : ] : $(tf) ;
+ check-equal $(id)-ft : [ eval-$(id) : 1 ] : $(ft) ;
+ check-equal $(id)-ff : [ eval-$(id) : ] : $(ff) ;
+}
+
+rule eval-and ( lhs ? : rhs ? )
+{
+ if $(lhs) && $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-truth-table and : true false false false ;
+
+rule eval-or ( lhs ? : rhs ? )
+{
+ if $(lhs) || $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-truth-table or : true true true false ;
+
+rule eval-not-and ( lhs ? : rhs ? )
+{
+ if ! ( $(lhs) && $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-truth-table not-and : false true true true ;
+
+rule eval-not-or ( lhs ? : rhs ? )
+{
+ if ! ( $(lhs) || $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-truth-table not-or : false false false true ;
+
+if [ mark-order r1 : test1 ] < [ mark-order r2 : test2 ] { }
+check-order lt-order : r1 r2 ;
+if [ mark-order r1 : test1 ] > [ mark-order r2 : test2 ] { }
+check-order gt-order : r1 r2 ;
+if [ mark-order r1 : test1 ] <= [ mark-order r2 : test2 ] { }
+check-order le-order : r1 r2 ;
+if [ mark-order r1 : test1 ] >= [ mark-order r2 : test2 ] { }
+check-order ge-order : r1 r2 ;
+if [ mark-order r1 : test1 ] = [ mark-order r2 : test2 ] { }
+check-order eq-order : r1 r2 ;
+if [ mark-order r1 : test1 ] != [ mark-order r2 : test2 ] { }
+check-order ne-order : r1 r2 ;
+if [ mark-order r1 : test1 ] in [ mark-order r2 : test2 ] { }
+check-order in-order : r1 r2 ;
+
+if [ mark-order r1 : test1 ] && [ mark-order r2 : test2 ] { }
+check-order and-order : r1 r2 ;
+if [ mark-order r1 ] && [ mark-order r2 : test2 ] { }
+check-order and-order-short-circuit : r1 ;
+
+if [ mark-order r1 ] || [ mark-order r2 : test2 ] { }
+check-order or-order : r1 r2 ;
+if [ mark-order r1 : test1 ] || [ mark-order r2 : test2 ] { }
+check-order or-order-short-circuit : r1 ;
+
+}
+
+# Check include
+
+{
+#FIXME:
+# plain include
+# include in module
+# include returns an empty list
+# rule arguments are available inside include
+}
+
+# Check local
+
+{
+
+local v1 = a b c ;
+local v2 = f g h ;
+
+{
+ local v1 ;
+ check-equal local-no-init : $(v1) : ;
+}
+
+check-equal local-restore : $(v1) : a b c ;
+
+{
+ local v1 = d e f ;
+ check-equal local-init : $(v1) : d e f ;
+}
+
+check-equal local-restore-init : $(v1) : a b c ;
+
+{
+ local v1 v2 ;
+ check-equal local-multiple-no-init : $(v1) - $(v2) : - ;
+}
+
+check-equal local-multiple-restore : $(v1) - $(v2) : a b c - f g h ;
+
+{
+ local v1 v2 = d e f ;
+ check-equal local-multiple-init : $(v1) - $(v2) : d e f - d e f ;
+}
+
+{
+ local v1 v1 = d e f ;
+ check-equal local-duplicate : $(v1) - $(v1) : d e f - d e f ;
+}
+
+check-equal local-duplicate-restore : $(v1) : a b c ;
+
+{
+ local [ mark-order r1 : v1 ] = [ mark-order r2 : d e f ] ;
+ check-order local-order : r1 r2 ;
+}
+
+}
+
+# Check module
+
+{
+#FIXME:
+# ...
+}
+
+# Check class
+{
+#FIXME:
+# ...
+}
+
+# Check on
+
+{
+
+local target1 = test-on-target1 ;
+local target2 = test-on-target2 ;
+local targets = $(target1) $(target2) ;
+local v1 v2 v3 ;
+
+VAR on $(target1) = value1 ;
+V2 on $(target2) = value2 ;
+
+check-equal on-return : [ on $(target1) return $(VAR) ] : value1 ;
+
+rule test-rule
+{
+ return $(VAR) ;
+}
+
+check-equal on-rule : [ on $(target1) test-rule ] : value1 ;
+
+check-equal on-multiple : [ on $(targets) return $(V2) ] : ;
+
+rule test-rule
+{
+ on $(target1)
+ {
+ return $(VAR) ;
+ }
+}
+
+check-equal on-block : [ test-rule ] : value1 ;
+
+# FIXME: crazy implementation artifacts:
+
+v1 on test-on-target3 = x1 ;
+on test-on-target3
+{
+ v1 on test-on-target3 += x1 ;
+ v1 = y1 ;
+ v2 on test-on-target3 += x2 ;
+ v2 = y2 ;
+ v3 = y3 ;
+}
+
+check-equal on-swap-old1 : $(v1) : x1 ;
+check-equal on-swap-old2 : [ on test-on-target3 return $(v1) ] : y1 ;
+check-equal on-swap-new1 : $(v2) : x2 ;
+check-equal on-swap-new2 : [ on test-on-target3 return $(v2) ] : y2 ;
+check-equal on-no-swap : $(v3) : y3 ;
+
+}
+
+# Check rule
+
+{
+#FIXME:
+# argument order
+# expand rule name
+}
+
+# Check rules
+
+{
+#FIXME:
+}
+
+# Check set
+
+{
+local v1 ;
+local v2 ;
+local v3 ;
+local vars = v1 v2 v3 ;
+
+v1 = x1 ;
+check-equal set-set-empty : $(v1) : x1 ;
+v2 += x2 ;
+check-equal set-append-empty : $(v2) : x2 ;
+v3 ?= x3 ;
+check-equal set-default-empty : $(v3) : x3 ;
+
+v1 = y1 ;
+check-equal set-set-non-empty : $(v1) : y1 ;
+v2 += y2 ;
+check-equal set-append-non-empty : $(v2) : x2 y2 ;
+v3 ?= y3 ;
+check-equal set-default-non-empty : $(v3) : x3 ;
+
+v1 = ;
+v2 = ;
+v3 = ;
+$(vars) = z ;
+check-equal set-set-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = ;
+v2 = ;
+v3 = ;
+$(vars) += z ;
+check-equal set-append-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = ;
+v2 = ;
+v3 = ;
+$(vars) ?= z ;
+check-equal set-default-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = x1 ;
+v2 = x2 ;
+v3 = x3 ;
+$(vars) = z ;
+check-equal set-set-non-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = x1 ;
+v2 = x2 ;
+v3 = x3 ;
+$(vars) += z ;
+check-equal set-append-non-empty-group : $(v1) - $(v2) - $(v3) : x1 z - x2 z - x3 z ;
+
+v1 = x1 ;
+v2 = x2 ;
+v3 = x3 ;
+$(vars) ?= z ;
+check-equal set-default-non-empty-group : $(v1) - $(v2) - $(v3) : x1 - x2 - x3 ;
+
+v1 = x1 ;
+v2 = ;
+v3 = x3 ;
+$(vars) = z ;
+check-equal set-set-mixed-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = x1 ;
+v2 = ;
+v3 = x3 ;
+$(vars) += z ;
+check-equal set-append-mixed-group : $(v1) - $(v2) - $(v3) : x1 z - z - x3 z ;
+
+v1 = x1 ;
+v2 = ;
+v3 = x3 ;
+$(vars) ?= z ;
+check-equal set-default-mixed-group : $(v1) - $(v2) - $(v3) : x1 - z - x3 ;
+
+vars = v1 v1 ;
+
+v1 = ;
+$(vars) = z ;
+check-equal set-set-duplicate-empty : $(v1) : z ;
+v1 = ;
+$(vars) += z ;
+check-equal set-append-duplicate-empty : $(v1) : z z ;
+v1 = ;
+$(vars) ?= z ;
+check-equal set-default-duplicate-empty : $(v1) : z ;
+
+v1 = x1 ;
+$(vars) = z ;
+check-equal set-set-duplicate-non-empty : $(v1) : z ;
+v1 = x1 ;
+$(vars) += z ;
+check-equal set-append-duplicate-non-empty : $(v1) : x1 z z ;
+v1 = x1 ;
+$(vars) ?= z ;
+check-equal set-default-duplicate-non-empty : $(v1) : x1 ;
+
+rule test-rule { v1 = x1 ; }
+check-equal set-set-result : [ test-rule ] : x1 ;
+rule test-rule { v1 += x1 ; }
+check-equal set-append-result : [ test-rule ] : x1 ;
+rule test-rule { v1 ?= x1 ; }
+check-equal set-default-result : [ test-rule ] : x1 ;
+
+[ mark-order r1 ] = [ mark-order r2 ] ;
+check-order set-set-order : r1 r2 ;
+[ mark-order r1 ] += [ mark-order r2 ] ;
+check-order set-append-order : r1 r2 ;
+[ mark-order r1 ] ?= [ mark-order r2 ] ;
+check-order set-default-order : r1 r2 ;
+
+}
+
+# Check setcomp
+
+{
+#FIXME
+# Expand arguments
+# Don't expand name
+}
+
+# Check setexec
+
+{
+#FIXME:
+# Don't expand name
+# Evaluate bindlist
+}
+
+# Check settings ;
+
+{
+
+local target1 = test-settings-target1 ;
+local target2 = test-settings-target2 ;
+local target3 = test-settings-target3 ;
+local targets = $(target2) $(target3) ;
+
+local vars = v1 v2 v3 ;
+
+v1 on $(target1) = x1 ;
+check-equal settings-set-empty : [ on $(target1) return $(v1) ] : x1 ;
+v2 on $(target1) += x2 ;
+check-equal settings-append-empty : [ on $(target1) return $(v2) ] : x2 ;
+v3 on $(target1) ?= x3 ;
+check-equal settings-default-empty : [ on $(target1) return $(v3) ] : x3 ;
+
+v1 on $(target1) = y1 ;
+check-equal settings-set-non-empty : [ on $(target1) return $(v1) ] : y1 ;
+v2 on $(target1) += y2 ;
+check-equal settings-append-non-empty : [ on $(target1) return $(v2) ] : x2 y2 ;
+v3 on $(target1) ?= y3 ;
+check-equal settings-default-non-empty : [ on $(target1) return $(v3) ] : x3 ;
+
+$(vars) on setting-target2 = z ;
+check-equal settings-set-empty-group : [ on setting-target2 return $(v1) ] - [ on setting-target2 return $(v2) ] - [ on setting-target2 return $(v3) ] : z - z - z ;
+
+$(vars) on setting-target3 += z ;
+check-equal settings-append-empty-group : [ on setting-target3 return $(v1) ] - [ on setting-target3 return $(v2) ] - [ on setting-target3 return $(v3) ] : z - z - z ;
+
+$(vars) on setting-target4 ?= z ;
+check-equal settings-default-empty-group : [ on setting-target4 return $(v1) ] - [ on setting-target4 return $(v2) ] - [ on setting-target4 return $(v3) ] : z - z - z ;
+
+v1 on $(target1) = x1 ;
+v2 on $(target1) = x2 ;
+v3 on $(target1) = x3 ;
+$(vars) on $(target1) = z ;
+check-equal settings-set-non-empty-group : [ on $(target1) return $(v1) ] - [ on $(target1) return $(v2) ] - [ on $(target1) return $(v3) ] : z - z - z ;
+
+v1 on $(target1) = x1 ;
+v2 on $(target1) = x2 ;
+v3 on $(target1) = x3 ;
+$(vars) on $(target1) += z ;
+check-equal settings-append-non-empty-group : [ on $(target1) return $(v1) ] - [ on $(target1) return $(v2) ] - [ on $(target1) return $(v3) ] : x1 z - x2 z - x3 z ;
+
+v1 on $(target1) = x1 ;
+v2 on $(target1) = x2 ;
+v3 on $(target1) = x3 ;
+$(vars) on $(target1) ?= z ;
+check-equal settings-default-non-empty-group : [ on $(target1) return $(v1) ] - [ on $(target1) return $(v2) ] - [ on $(target1) return $(v3) ] : x1 - x2 - x3 ;
+
+v1 on setting-target5 = x1 ;
+v3 on setting-target5 = x3 ;
+$(vars) on setting-target5 = z ;
+check-equal settings-set-mixed-group : [ on setting-target5 return $(v1) ] - [ on setting-target5 return $(v2) ] - [ on setting-target5 return $(v3) ] : z - z - z ;
+
+v1 on setting-target6 = x1 ;
+v3 on setting-target6 = x3 ;
+$(vars) on setting-target6 += z ;
+check-equal settings-append-mixed-group : [ on setting-target6 return $(v1) ] - [ on setting-target6 return $(v2) ] - [ on setting-target6 return $(v3) ] : x1 z - z - x3 z ;
+
+v1 on setting-target7 = x1 ;
+v3 on setting-target7 = x3 ;
+$(vars) on setting-target7 ?= z ;
+check-equal settings-default-mixed-group : [ on setting-target7 return $(v1) ] - [ on setting-target7 return $(v2) ] - [ on setting-target7 return $(v3) ] : x1 - z - x3 ;
+
+vars = v1 v1 ;
+
+$(vars) on setting-target8 = z ;
+check-equal settings-set-duplicate-empty : [ on setting-target8 return $(v1) ] : z ;
+$(vars) on setting-target9 += z ;
+check-equal settings-append-duplicate-empty : [ on setting-target9 return $(v1) ] : z z ;
+$(vars) on setting-target10 ?= z ;
+check-equal settings-default-duplicate-empty : [ on setting-target10 return $(v1) ] : z ;
+
+v1 on $(target1) = x1 ;
+$(vars) on $(target1) = z ;
+check-equal settings-set-duplicate-non-empty : [ on $(target1) return $(v1) ] : z ;
+v1 on $(target1) = x1 ;
+$(vars) on $(target1) += z ;
+check-equal settings-append-duplicate-non-empty : [ on $(target1) return $(v1) ] : x1 z z ;
+v1 on $(target1) = x1 ;
+$(vars) on $(target1) ?= z ;
+check-equal settings-default-duplicate-non-empty : [ on $(target1) return $(v1) ] : x1 ;
+
+v1 on $(target1) = ;
+v1 on $(target1) ?= z ;
+check-equal settings-default-set-but-empty : [ on $(target1) return $(v1) ] : ;
+
+v1 on $(targets) = multi ;
+check-equal settings-set-multi-empty : [ on $(target2) return $(v1) ] - [ on $(target3) return $(v1) ] : multi - multi ;
+v2 on $(targets) += multi ;
+check-equal settings-append-multi-empty : [ on $(target2) return $(v2) ] - [ on $(target3) return $(v2) ] : multi - multi ;
+v3 on $(targets) ?= multi ;
+check-equal settings-default-multi-empty : [ on $(target2) return $(v3) ] - [ on $(target3) return $(v3) ] : multi - multi ;
+
+v1 on $(targets) = multi2 ;
+check-equal settings-set-multi-empty : [ on $(target2) return $(v1) ] - [ on $(target3) return $(v1) ] : multi2 - multi2 ;
+v2 on $(targets) += multi2 ;
+check-equal settings-append-multi-empty : [ on $(target2) return $(v2) ] - [ on $(target3) return $(v2) ] : multi multi2 - multi multi2 ;
+v3 on $(targets) ?= multi2 ;
+check-equal settings-default-multi-empty : [ on $(target2) return $(v3) ] - [ on $(target3) return $(v3) ] : multi - multi ;
+
+rule test-rule { v1 on $(target1) = x1 ; }
+check-equal settings-set-result : [ test-rule ] : x1 ;
+rule test-rule { v1 on $(target1) += x1 ; }
+check-equal settings-append-result : [ test-rule ] : x1 ;
+rule test-rule { v1 on $(target1) ?= x1 ; }
+check-equal settings-default-result : [ test-rule ] : x1 ;
+
+[ mark-order r1 : var ] on [ mark-order r3 : $(target1) ] = [ mark-order r2 : value ] ;
+check-order settings-set-order : r1 r2 r3 ;
+[ mark-order r1 : var ] on [ mark-order r3 : $(target1) ] += [ mark-order r2 : value ] ;
+check-order settings-append-order : r1 r2 r3 ;
+[ mark-order r1 : var ] on [ mark-order r3 : $(target1) ] ?= [ mark-order r2 : value ] ;
+check-order settings-default-order : r1 r2 r3 ;
+
+}
+
+# Check switch
+
+{
+
+local pattern = * ;
+
+switch value
+{
+ case * : mark-order r1 ;
+}
+
+check-order switch-match-any : r1 ;
+
+switch value
+{
+ case v2 : mark-order r1 ;
+}
+
+check-order switch-no-match : ;
+
+switch value
+{
+ case $(pattern) : mark-order r1 ;
+}
+
+check-order switch-no-expand : ;
+
+switch value
+{
+ case value : mark-order r1 ;
+ case * : mark-order r2 ;
+}
+
+check-order switch-match-several : r1 ;
+
+rule test-rule ( value )
+{
+ switch $(value)
+ {
+ case value : return 1 ;
+ }
+}
+
+check-equal switch-result-match : [ test-rule value ] : 1 ;
+check-equal switch-result-match : [ test-rule v1 ] : ;
+
+switch $()
+{
+ case "" : mark-order r1 ;
+ case * : mark-order r2 ;
+}
+
+check-order switch-empty : r1 ;
+
+local values = v1 v2 v3 ;
+switch $(values)
+{
+ case v1 : mark-order r1 ;
+ case v2 : mark-order r2 ;
+ case v3 : mark-order r3 ;
+}
+
+check-order switch-multiple : r1 ;
+
+# Test glob matching
+
+switch value { case * : mark-order r1 ; }
+check-order switch-glob-star : r1 ;
+
+switch value { case va*e : mark-order r1 ; }
+check-order switch-glob-star-1 : r1 ;
+
+switch value { case *a* : mark-order r1 ; }
+check-order switch-glob-star-2 : r1 ;
+
+switch value { case *a*ue* : mark-order r1 ; }
+check-order switch-glob-star-3 : r1 ;
+
+switch value { case *[eaiou]*ue : mark-order r1 ; }
+check-order switch-glob-group : r1 ;
+
+switch value { case *[eaiou]ue : mark-order r1 ; }
+check-order switch-glob-group-fail : ;
+
+switch value { case ?a?ue : mark-order r1 ; }
+check-order switch-glob-any : r1 ;
+
+switch value { case ?lue : mark-order r1 ; }
+check-order switch-glob-any-fail : ;
+
+}
+
+# Test while
+
+{
+
+local value = 1 2 3 ;
+
+while $(value)
+{
+ mark-order r$(value[1]) ;
+ value = $(value[2-]) ;
+}
+
+check-order while-exec : r1 r2 r3 ;
+
+rule test-rule
+{
+ local value = 1 2 3 ;
+ while $(value)
+ {
+ value = $(value[2-]) ;
+ return x ;
+ }
+}
+
+check-equal while-result : [ test-rule ] : x ;
+
+}
+
+# Test summary
+
+if $(failed) = 0
+{
+ status = 0 ;
+}
+else
+{
+ status = 1 ;
+}
+
+EXIT $(passed) passed $(failed) failed : $(status) ;

Added: branches/quickbook-dev/tools/build/v2/test/core_language.py
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/build/v2/test/core_language.py 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+
+# Copyright 2002, 2003 Vladimir Prus
+# 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)
+
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0)
+
+t.set_tree(".")
+t.run_build_system(extra_args="-fcore_language.jam")
+
+t.cleanup()

Modified: branches/quickbook-dev/tools/build/v2/test/test_all.py
==============================================================================
--- branches/quickbook-dev/tools/build/v2/test/test_all.py (original)
+++ branches/quickbook-dev/tools/build/v2/test/test_all.py 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -121,7 +121,7 @@
 critical_tests = ["unit_tests", "module_actions", "startup_v1", "startup_v2"]
 
 critical_tests += ["core_d12", "core_typecheck", "core_delete_module",
- "core_varnames", "core_import_module"]
+ "core_language", "core_varnames", "core_import_module"]
 
 tests = [ "absolute_sources",
           "alias",

Modified: branches/quickbook-dev/tools/quickbook/doc/1_6.qbk
==============================================================================
--- branches/quickbook-dev/tools/quickbook/doc/1_6.qbk (original)
+++ branches/quickbook-dev/tools/quickbook/doc/1_6.qbk 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -163,9 +163,9 @@
 
 [section:table Table Titles]
 
-Table titles are not parsed as phrases, so some markup is allowd:
+Table titles are now parsed as phrases, so some markup is allowd:
 
-[table [*bold title]]
+ [table [*bold title]]
 
 Which is an empty table with a bold title. The title is no longer ended
 by a newline, but by either a closing square bracket, or two opening
@@ -236,7 +236,8 @@
         Code block
   Para 3
 
-/TODO/: Improve code generation.
+The docbook markup that this generates is pretty bad, but seems to create okay
+html.
 
 [endsect]
 

Added: branches/quickbook-dev/tools/quickbook/extra/cxx_committee/Jamfile.v2
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/quickbook/extra/cxx_committee/Jamfile.v2 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -0,0 +1,35 @@
+# Copyright (c) 2006-2009, Bernhard Reiter
+#
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http:#www.boost.org/LICENSE_1_0.txt)
+
+using quickbook ;
+
+if ! $(BOOST_ROOT)
+{
+ BOOST_ROOT = [ modules.peek : BOOST_ROOT ] ;
+}
+
+xml libproposalqbk
+ :
+ library_proposal.qbk
+ ;
+
+boostbook proposal
+ :
+ libproposalqbk
+ :
+ #<dependency>autodoc
+ <xsl:param>boost.libraries=$(BOOST_ROOT)/libs/libraries.htm
+ #<xsl:param>boost.root=../../../../
+ <xsl:param>html.stylesheet=proposal.css
+ <xsl:param>doc.standalone=1
+ <xsl:param>nav.layout=none
+ <xsl:param>toc.section.depth=2
+ <xsl:param>section.autolabel=1
+ <xsl:param>section.autolabel.max.depth=3
+ <xsl:param>chapter.autolabel=0
+ <xsl:param>navig.graphics=0
+
+ ;
\ No newline at end of file

Added: branches/quickbook-dev/tools/quickbook/extra/cxx_committee/html/proposal.css
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/quickbook/extra/cxx_committee/html/proposal.css 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -0,0 +1,511 @@
+/*=============================================================================
+ Copyright (c) 2004 Joel de Guzman
+ http://spirit.sourceforge.net/
+
+ Use, modification and distribution is subject to the Boost Software
+ License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+
+/*=============================================================================
+ Body defaults
+=============================================================================*/
+
+ body
+ {
+ margin: 1em;
+ font-family: sans-serif;
+ }
+
+/*=============================================================================
+ Paragraphs
+=============================================================================*/
+
+ p
+ {
+ text-align: left;
+ font-size: 10pt;
+ line-height: 1.15;
+ }
+
+/*=============================================================================
+ Program listings
+=============================================================================*/
+
+ /* Code on paragraphs */
+ p tt.computeroutput
+ {
+ font-size: 9pt;
+ }
+
+ pre.synopsis
+ {
+ font-size: 90%;
+ margin: 1pc 4% 0pc 4%;
+ padding: 0.5pc 0.5pc 0.5pc 0.5pc;
+ }
+
+ .programlisting,
+ .screen
+ {
+ font-size: 9pt;
+ display: block;
+ margin: 1pc 4% 0pc 4%;
+ padding: 0.5pc 0.5pc 0.5pc 0.5pc;
+ }
+
+ /* Program listings in tables don't get borders */
+ td .programlisting,
+ td .screen
+ {
+ margin: 0pc 0pc 0pc 0pc;
+ padding: 0pc 0pc 0pc 0pc;
+ }
+
+/*=============================================================================
+ Headings
+=============================================================================*/
+
+ h1, h2, h3, h4, h5, h6
+ {
+ text-align: left;
+ margin: 1em 0em 0.5em 0em;
+ font-weight: bold;
+ }
+
+ h1 { font: 140% }
+ h2 { font: bold 140% }
+ h3 { font: bold 130% }
+ h4 { font: bold 120% }
+ h5 { font: italic 110% }
+ h6 { font: italic 100% }
+
+ /* Top page titles */
+ title,
+ h1.title,
+ h2.title
+ h3.title,
+ h4.title,
+ h5.title,
+ h6.title,
+ .refentrytitle
+ {
+ font-weight: bold;
+ margin-bottom: 1pc;
+ }
+
+ h1.title { font-size: 140% }
+ h2.title { font-size: 140% }
+ h3.title { font-size: 130% }
+ h4.title { font-size: 120% }
+ h5.title { font-size: 110% }
+ h6.title { font-size: 100% }
+
+ .section h1
+ {
+ margin: 0em 0em 0.5em 0em;
+ font-size: 140%;
+ }
+
+ .section h2 { font-size: 140% }
+ .section h3 { font-size: 130% }
+ .section h4 { font-size: 120% }
+ .section h5 { font-size: 110% }
+ .section h6 { font-size: 100% }
+
+ /* Code on titles */
+ h1 tt.computeroutput { font-size: 140% }
+ h2 tt.computeroutput { font-size: 140% }
+ h3 tt.computeroutput { font-size: 130% }
+ h4 tt.computeroutput { font-size: 120% }
+ h5 tt.computeroutput { font-size: 110% }
+ h6 tt.computeroutput { font-size: 100% }
+
+/*=============================================================================
+ Author
+=============================================================================*/
+
+ h3.author
+ {
+ font-size: 100%
+ }
+
+/*=============================================================================
+ Lists
+=============================================================================*/
+
+ li
+ {
+ font-size: 10pt;
+ line-height: 1.3;
+ }
+
+ /* Unordered lists */
+ ul
+ {
+ text-align: left;
+ }
+
+ /* Ordered lists */
+ ol
+ {
+ text-align: left;
+ }
+
+/*=============================================================================
+ Links
+=============================================================================*/
+
+ a
+ {
+ text-decoration: none; /* no underline */
+ }
+
+ a:hover
+ {
+ text-decoration: underline;
+ }
+
+/*=============================================================================
+ Spirit style navigation
+=============================================================================*/
+
+ .spirit-nav
+ {
+ text-align: right;
+ }
+
+ .spirit-nav a
+ {
+ color: white;
+ padding-left: 0.5em;
+ }
+
+ .spirit-nav img
+ {
+ border-width: 0px;
+ }
+
+/*=============================================================================
+ Table of contents
+=============================================================================*/
+
+ .toc
+ {
+ margin: 1pc 4% 0pc 4%;
+ padding: 0.1pc 1pc 0.1pc 1pc;
+ font-size: 80%;
+ line-height: 1.15;
+ }
+
+ .boost-toc
+ {
+ float: right;
+ padding: 0.5pc;
+ }
+
+/*=============================================================================
+ Tables
+=============================================================================*/
+
+ .table-title,
+ div.table p.title
+ {
+ margin-left: 4%;
+ padding-right: 0.5em;
+ padding-left: 0.5em;
+ }
+
+ .informaltable table,
+ .table table
+ {
+ width: 92%;
+ margin-left: 4%;
+ margin-right: 4%;
+ }
+
+ div.informaltable table,
+ div.table table
+ {
+ padding: 4px;
+ }
+
+ /* Table Cells */
+ div.informaltable table tr td,
+ div.table table tr td
+ {
+ padding: 0.5em;
+ text-align: left;
+ font-size: 9pt;
+ }
+
+ div.informaltable table tr th,
+ div.table table tr th
+ {
+ padding: 0.5em 0.5em 0.5em 0.5em;
+ border: 1pt solid white;
+ font-size: 80%;
+ }
+
+/*=============================================================================
+ Blurbs
+=============================================================================*/
+
+ div.note,
+ div.tip,
+ div.important,
+ div.caution,
+ div.warning,
+ p.blurb
+ {
+ font-size: 9pt; /* A little bit smaller than the main text */
+ line-height: 1.2;
+ display: block;
+ margin: 1pc 4% 0pc 4%;
+ padding: 0.5pc 0.5pc 0.5pc 0.5pc;
+ }
+
+ p.blurb img
+ {
+ padding: 1pt;
+ }
+
+/*=============================================================================
+ Variable Lists
+=============================================================================*/
+
+ /* Make the terms in definition lists bold */
+ div.variablelist dl dt,
+ span.term
+ {
+ font-weight: bold;
+ font-size: 10pt;
+ }
+
+ div.variablelist table tbody tr td
+ {
+ text-align: left;
+ vertical-align: top;
+ padding: 0em 2em 0em 0em;
+ font-size: 10pt;
+ margin: 0em 0em 0.5em 0em;
+ line-height: 1;
+ }
+
+ div.variablelist dl dt
+ {
+ margin-bottom: 0.2em;
+ }
+
+ div.variablelist dl dd
+ {
+ margin: 0em 0em 0.5em 2em;
+ font-size: 10pt;
+ }
+
+ div.variablelist table tbody tr td p,
+ div.variablelist dl dd p
+ {
+ margin: 0em 0em 0.5em 0em;
+ line-height: 1;
+ }
+
+/*=============================================================================
+ Misc
+=============================================================================*/
+
+ /* Title of books and articles in bibliographies */
+ span.title
+ {
+ font-style: italic;
+ }
+
+ span.underline
+ {
+ text-decoration: underline;
+ }
+
+ span.strikethrough
+ {
+ text-decoration: line-through;
+ }
+
+ /* Copyright, Legal Notice */
+ div div.legalnotice p
+ {
+ text-align: left
+ }
+
+/*=============================================================================
+ Colors
+=============================================================================*/
+
+ @media screen
+ {
+ /* Links */
+ a
+ {
+ color: #005a9c;
+ }
+
+ a:visited
+ {
+ color: #9c5a9c;
+ }
+
+ h1 a, h2 a, h3 a, h4 a, h5 a, h6 a,
+ h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover,
+ h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited
+ {
+ text-decoration: none; /* no underline */
+ color: #000000;
+ }
+
+ /* Syntax Highlighting */
+ .keyword { color: #0000AA; }
+ .identifier { color: #000000; }
+ .special { color: #707070; }
+ .preprocessor { color: #402080; }
+ .char { color: teal; }
+ .comment { color: #800000; }
+ .string { color: teal; }
+ .number { color: teal; }
+ .white_bkd { background-color: #FFFFFF; }
+ .dk_grey_bkd { background-color: #999999; }
+
+ /* Copyright, Legal Notice */
+ .copyright
+ {
+ color: #666666;
+ font-size: small;
+ }
+
+ div div.legalnotice p
+ {
+ color: #666666;
+ }
+
+ /* Program listing */
+ pre.synopsis
+ {
+ border: 1px solid #DCDCDC;
+ }
+
+ .programlisting,
+ .screen
+ {
+ border: 1px solid #DCDCDC;
+ }
+
+ td .programlisting,
+ td .screen
+ {
+ border: 0px solid #DCDCDC;
+ }
+
+ /* Blurbs */
+ div.note,
+ div.tip,
+ div.important,
+ div.caution,
+ div.warning,
+ p.blurb
+ {
+ border: 1px solid #DCDCDC;
+ }
+
+ /* Table of contents */
+ .toc
+ {
+ border: 1px solid #DCDCDC;
+ }
+
+ /* Tables */
+ div.informaltable table tr td,
+ div.table table tr td
+ {
+ border: 1px solid #DCDCDC;
+ }
+
+ div.informaltable table tr th,
+ div.table table tr th
+ {
+ background-color: #F0F0F0;
+ border: 1px solid #DCDCDC;
+ }
+
+ /* Misc */
+ span.highlight
+ {
+ color: #00A000;
+ }
+ }
+
+ @media print
+ {
+ /* Links */
+ a
+ {
+ color: black;
+ }
+
+ a:visited
+ {
+ color: black;
+ }
+
+ .spirit-nav
+ {
+ display: none;
+ }
+
+ /* Program listing */
+ pre.synopsis
+ {
+ border: 1px solid gray;
+ }
+
+ .programlisting,
+ .screen
+ {
+ border: 1px solid gray;
+ }
+
+ td .programlisting,
+ td .screen
+ {
+ border: 0px solid #DCDCDC;
+ }
+
+ /* Table of contents */
+ .toc
+ {
+ border: 1px solid gray;
+ }
+
+ .informaltable table,
+ .table table
+ {
+ border: 1px solid gray;
+ border-collapse: collapse;
+ }
+
+ /* Tables */
+ div.informaltable table tr td,
+ div.table table tr td
+ {
+ border: 1px solid gray;
+ }
+
+ div.informaltable table tr th,
+ div.table table tr th
+ {
+ border: 1px solid gray;
+ }
+
+ /* Misc */
+ span.highlight
+ {
+ font-weight: bold;
+ }
+ }

Added: branches/quickbook-dev/tools/quickbook/extra/cxx_committee/library_proposal.qbk
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/quickbook/extra/cxx_committee/library_proposal.qbk 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -0,0 +1,104 @@
+[/
+ / Copyright (c) 2006-2009, Bernhard Reiter and René Rivera
+ / Copyright Beman Dawes 2011
+ /
+ / Distributed under the Boost Software License, Version 1.0.
+ / See http://www.boost.org/LICENSE_1_0.txt
+ /
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ /]
+
+[/ TODO: The generated docs should contain boostinspect:nolicense ]
+
+[library Sample Proposal for the C++ Standard Library
+ [quickbook 1.5]
+ [purpose Sample library proposal for the C++ committee]
+]
+
+[def (tm) '''&#8482;''']
+
+[section Title of Proposal]
+
+[variablelist
+[[Document No.] [WG21/N2101=J16/06-0171]]
+[[Date] [2011-11-30]]
+[[Project] [Programming Language C++]]
+[[Reply to] [Your Name <your-email at wherever dot com>,
+ Another Author <[@mailto:theirs_at_[hidden] theirs_at_[hidden]]>]]
+]
+
+
+[section Introduction]
+/This is just a sound bite providing overall context. For example:/
+This paper proposes an kitchen sink library component for the C++ Standard Library
+Technical Report 2. The library allows dirty dishes to be washed.
+The proposal is based on the Boost library of the same name.
+[endsect]
+
+[section Motivation and Scope]
+
+[section Why is this important?]
+TBS
+[endsect]
+
+[section What kinds of problems does it address, and what kinds of
+programmers is it intended to support?]
+TBS
+[endsect]
+
+[section Is it based on existing practice?]
+TBS
+[endsect]
+
+[section Is there a reference implementation avaialbe?]
+TBS
+[endsect]
+
+[endsect]
+
+[section Impact on the Standard]
+
+[section What does it depend on, and what depends on it?]
+TBS
+[endsect]
+
+[section Is it a pure extension, or does it require changes to
+standard components?]
+TBS
+[endsect]
+
+[section Can it be implemented using any C++11 compiler, or does it
+require compiler support?]
+TBS
+[endsect]
+
+[endsect]
+[section Important Design Decisions]
+
+[section Why did you choose the specific design that you did?]
+TBS
+[endsect]
+
+[section What alternatives did you consider, and what are the
+tradeoffs?]
+TBS
+[endsect]
+
+[section What are the consequences of your choices, for users and
+implementors?]
+TBS
+[endsect]
+
+[section What decisions are left up to implementors?]
+TBS
+[endsect]
+
+[section If there are any similar libraries in use, how do their
+design decisions compare to yours?]
+TBS
+[endsect]
+
+[endsect]
+
+
+[endsect] [/Title]

Modified: branches/quickbook-dev/tools/quickbook/src/main_grammar.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/main_grammar.cpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/main_grammar.cpp 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -370,6 +370,7 @@
>> cl::eps_p
                 ( *cl::blank_p
>> ( cl::eol_p
+ | cl::end_p
                     | cl::eps_p(local.in_list) >> (cl::ch_p('*') | '#')
                     )
                 )

Modified: branches/quickbook-dev/tools/quickbook/test/templates-1_5.gold
==============================================================================
--- branches/quickbook-dev/tools/quickbook/test/templates-1_5.gold (original)
+++ branches/quickbook-dev/tools/quickbook/test/templates-1_5.gold 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -36,4 +36,7 @@
   <para>
     Some *text* A <emphasis>paragraph</emphasis>.
   </para>
+ <para>
+ <index type="things"><title>Things</title></index>
+ </para>
 </article>

Modified: branches/quickbook-dev/tools/quickbook/test/templates-1_5.quickbook
==============================================================================
--- branches/quickbook-dev/tools/quickbook/test/templates-1_5.quickbook (original)
+++ branches/quickbook-dev/tools/quickbook/test/templates-1_5.quickbook 2011-12-01 13:07:38 EST (Thu, 01 Dec 2011)
@@ -62,3 +62,11 @@
 [block]
 [`phrase]
 [`block]
+
+[/ Trailing newline shouldn't be included]
+
+[template named_index[type title]
+'''<index type="'''[type]'''"><title>'''[title]'''</title></index>'''
+]
+
+[named_index things Things]
\ No newline at end of file


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