** Checkpoint before directory reorg. **
[kakapo:kakapo.git] / src / Global.nqp
1 # Copyright (C) 2009, Austin Hastings. See accompanying LICENSE file, or 
2 # http://www.opensource.org/licenses/artistic-license-2.0.php for license.
3
4 =module Global
5
6 Provides cross-module import and export, and serves as a global symbol registry.
7
8 =cut
9
10 module Global;
11
12 =sub export(*@symbols, :$as?, :@tags?)
13
14 Adds a list of symbols - either String names or Subs - to one or more export 
15 groups.
16
17 If a String is passed to identify the symbol, then the String will be the export
18 name of the symbol.
19
20 The symbol is added to all of the export groups named in C<@tags>.  This allows
21 definition of partially overlapping tag sets, by adding the common symbols to
22 multiple tags:
23
24     Global::export('c1', 'c2', 'c3', :tags('A', 'B'));
25     Global::export('a1', 'a2', :tags('A'));     # A include a1, a2, c1, c2, c3
26     Global::export('b1', :tags('B'));           # B includes b1, c1, c2, c3
27
28 If no tags are specified, the tag 'DEFAULT' is used. (This is the same tag used
29 by C<import> when no other tags are specified.)
30
31 The option C<:as($name)> can only be used with a single symbol. In this case,
32 the symbol - which in this case may be an object, or the String name of an 
33 object - is added to the specified export tags under the C<$name> given. (This
34 can be used to export dynamically created objects, or to export some other 
35 module's code under your own name.)
36
37 =cut
38
39 sub export($symbol, *@symbols, :$as?, :$namespace?, :@tags?) {
40         unless @symbols { @symbols := Array::empty(); }
41         @symbols.unshift($symbol);
42         if ! Parrot::defined(@tags) { @tags := Array::new('DEFAULT'); }
43         elsif Parrot::isa(@tags, 'String') { @tags := Array::new(@tags); }
44         
45         my $source_nsp := Parrot::defined($namespace)
46                 ?? $namespace
47                 !! Parrot::caller_namespace(2);
48         
49         if Parrot::isa($source_nsp, 'String') {
50                 $source_nsp := Parrot::get_namespace($source_nsp);
51         }
52
53         my $export_nsp := $source_nsp.make_namespace('EXPORT');
54         
55         @tags.push('ALL');
56         
57         for @tags {
58                 my $tag_nsp := $export_nsp.make_namespace(~ $_);
59                 
60                 if Parrot::defined($as) {
61                         my $export_sym := $symbol;
62                         if Parrot::isa($export_sym, 'String') {
63                                 $export_sym := $source_nsp.get_sym($export_sym);
64                         }
65                         
66                         $tag_nsp{$as} := $export_sym;
67                 }
68                 else {
69                         $source_nsp.export_to($tag_nsp, @symbols);
70                 }
71         }
72 }
73
74 =sub register_global($name, $object, :$namespace?)
75
76 Registers a symbol C<$name> in the Global:: namespace, bound to C<$object>.
77
78 This function is used to create global variables. The C<:namespace()> option
79 may be specified to use another namespace in preference to Global.
80
81 The intended usage pattern is that the Global namespace serves as a D<Registry>
82 for locating shared objects and services.
83
84 =cut
85
86 sub register_global($name, $object, :$namespace?) {
87         unless $namespace { $namespace := 'Global'; }
88
89         my $nsp := Parrot::get_namespace($namespace);
90         $nsp{$name} := $object;
91         export($name, :namespace($namespace));
92 }
93
94 =sub use($module?, :import('TAG', ...)?, :symbols('name', ...)?)
95
96 Imports global symbols into the caller's namespace. If neither C<:import> nor
97 C<:symbols> are specified, C<:import('DEFAULT')> is assumed.
98
99 The strings given to C<:import> are tag names. The C<DEFAULT> tag is one 
100 of two special tag names known to the system. Otherwise, each module may 
101 define its own tagging scheme. (The other predefined tag is C<ALL>.)
102
103 If C<:symbols> are specified, specific symbol names may be imported. The 
104 symbols must be in the target module's C<ALL> export group, as this is where
105 they are looked up. (This will normally be true, unless the same name has been
106 used for different exports in different TAGS. In which case, don't do that.)
107
108 If no C<$from> module is specified, the default is the Global:: module itself. 
109 This is a shortcut for defining global variables, in conjunction with the
110 C<register_global> function. (q.v.)
111
112 =cut
113
114 sub use($module?, :@import?, :@symbols?) {
115         if ! Parrot::defined($module) { $module := Parrot::caller_namespace(); }
116         elsif Parrot::isa($module, 'String') { $module := Parrot::get_hll_namespace($module); }
117         if ! Parrot::defined(@import) { @import := Array::empty(); }
118         elsif Parrot::isa(@import, 'String') { @import := Array::new(@import); }
119         if ! Parrot::defined(@symbols) { @symbols := Array::empty(); }
120         elsif Parrot::isa(@symbols, 'String') { @symbols := Array::new(@symbols); }
121
122         if +@import == 0 && +@symbols == 0 {
123                 @import.push('DEFAULT');
124         }       
125
126         my $export_nsp := $module.make_namespace('EXPORT');
127         my $target_nsp := Parrot::caller_namespace(2);
128
129         if $module<_ONLOAD> {
130         say("Running _ONLOAD for ", $module.get_name.join('::'));
131                 $module<_ONLOAD>();
132         }
133         
134         if @import {
135                 for @import {
136                         my $source_nsp := $export_nsp.make_namespace(~ $_);
137                         
138                         if $source_nsp.keys {
139                                 $source_nsp.export_to($target_nsp, $source_nsp.keys);
140                         }
141                 }
142         }
143         
144         if +@symbols {
145                 $export_nsp{'ALL'}.export_to($target_nsp, @symbols);
146         }
147 }