• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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