1# Copyright 2003 Dave Abrahams 2# Copyright 2003 Vladimir Prus 3# Distributed under the Boost Software License, Version 1.0. 4# (See accompanying file LICENSE_1_0.txt or copy at 5# http://www.boost.org/LICENSE_1_0.txt) 6 7import modules ; 8import numbers ; 9 10 11# The pattern that indirect rules must match: module%rule 12.pattern = "^([^%]*)%([^%]+)$" ; 13 14 15# 16# Type checking rules. 17# 18local rule indirect-rule ( x ) 19{ 20 if ! [ MATCH $(.pattern) : $(x) ] 21 { 22 return "expected a string of the form module%rule, but got \""$(x)"\" for argument" ; 23 } 24} 25 26 27# Make an indirect rule which calls the given rule. If context is supplied it is 28# expected to be the module in which to invoke the rule by the 'call' rule 29# below. Otherwise, the rule will be invoked in the module of this rule's 30# caller. 31# 32rule make ( rulename bound-args * : context ? ) 33{ 34 if [ MATCH $(.pattern) : $(rulename) ] 35 { 36 return $(rulename) $(bound-args) ; 37 } 38 else 39 { 40 context ?= [ CALLER_MODULE ] ; 41 context ?= "" ; 42 return $(context)%$(rulename) $(bound-args) ; 43 } 44} 45 46 47# Make an indirect rule which calls the given rule. 'rulename' may be a 48# qualified rule; if so it is returned unchanged. Otherwise, if frames is not 49# supplied, the result will be invoked (by 'call', below) in the module of the 50# caller. Otherwise, frames > 1 specifies additional call frames to back up in 51# order to find the module context. 52# 53rule make-qualified ( rulename bound-args * : frames ? ) 54{ 55 if [ MATCH $(.pattern) : $(rulename) ] 56 { 57 return $(rulename) $(bound-args) ; 58 } 59 else 60 { 61 frames ?= 1 ; 62 # If the rule name includes a Jamfile module, grab it. 63 local module-context = [ MATCH "^(Jamfile<[^>]*>)\\..*" : $(rulename) ] ; 64 65 if ! $(module-context) 66 { 67 # Take the first dot-separated element as module name. This disallows 68 # module names with dots, but allows rule names with dots. 69 module-context = [ MATCH "^([^.]*)\\..*" : $(rulename) ] ; 70 } 71 module-context ?= [ CALLER_MODULE $(frames) ] ; 72 return [ make $(rulename) $(bound-args) : $(module-context) ] ; 73 } 74} 75 76 77# Returns the module name in which the given indirect rule will be invoked. 78# 79rule get-module ( [indirect-rule] x ) 80{ 81 local m = [ MATCH $(.pattern) : $(x) ] ; 82 if ! $(m[1]) 83 { 84 m = ; 85 } 86 return $(m[1]) ; 87} 88 89 90# Returns the rulename that will be called when x is invoked. 91# 92rule get-rule ( [indirect-rule] x ) 93{ 94 local m = [ MATCH $(.pattern) : $(x) ] ; 95 return $(m[2]) ; 96} 97 98 99# Invoke the given indirect-rule. 100# 101rule call ( [indirect-rule] r args * : * ) 102{ 103 return [ modules.call-in [ get-module $(r) ] : [ get-rule $(r) ] $(args) : 104 $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) : $(10) : $(11) : 105 $(12) : $(13) : $(14) : $(15) : $(16) : $(17) : $(18) : $(19) ] ; 106} 107 108 109rule __test__ 110{ 111 import assert ; 112 113 rule foo-barr! ( x ) 114 { 115 assert.equal $(x) : x ; 116 } 117 118 assert.equal [ get-rule [ make foo-barr! ] ] : foo-barr! ; 119 assert.equal [ get-module [ make foo-barr! ] ] : [ CALLER_MODULE ] ; 120 121 call [ make foo-barr! ] x ; 122 call [ make foo-barr! x ] ; 123 call [ make foo-barr! : [ CALLER_MODULE ] ] x ; 124} 125