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