1
class Perl6::Compiler::Package;
3
# The block associated with this package.
6
# This is the name of the HOW this package is based on.
9
# The name of the package.
12
# The scope of the package.
15
# Table of methods we're adding (name => PAST::Block).
18
# Table of methods we're adding to the meta model
21
# List attributes meta-data hashes. Should be Attribute class instances one day.
27
# List of colonpair adverbs.
31
method block($block?) {
32
if $block { $!block := $block }
38
if $how { $!how := $how }
44
if $name { $!name := $name }
49
method scope($scope?) {
50
if $scope { $!scope := $scope }
54
# Accessor for methods hash.
56
unless $!methods { $!methods := Q:PIR { %r = root_new ['parrot';'Hash'] } }
60
# Accessor for meta_methods hash.
61
method meta_methods() {
62
unless $!meta_methods { $!meta_methods := Q:PIR { %r = root_new ['parrot';'Hash'] } }
66
# Accessor for attributes list.
68
unless $!attributes { $!attributes := PAST::Node.new() }
72
# Checks if there is already an attribute with the given name.
73
method has_attribute($name) {
76
if $_<name> eq $name {
84
# Accessor for traits list.
86
unless $!traits { $!traits := PAST::Node.new() }
90
# Accessor for traits list.
91
method name_adverbs() {
92
unless $!name_adverbs { $!name_adverbs := PAST::Node.new() }
96
# This method drives the code generation and fixes up the block.
97
method finish($block) {
98
my $decl := PAST::Stmts.new();
100
# Emit code to install the current scope as $*SCOPE.
101
$decl.push(PAST::Op.new( :pasttype('bind'),
102
PAST::Var.new( :scope('lexical'), :name('$*SCOPE'), :isdecl(1) ),
106
# Create or look up meta-class.
108
my @how := Perl6::Grammar::parse_name(~$how);
109
my $metaclass := PAST::Var.new( :name(@how.pop), :namespace(@how), :scope('package') );
110
my $obj_reg := PAST::Var.new( :name('obj'), :scope('register') );
111
my $meta_reg := PAST::Var.new( :name('meta'), :scope('register') );
112
my $name := $!name ?? ~$!name !! '';
113
if $!scope ne 'augment' {
114
my $new_call := PAST::Op.new(
115
:pasttype('callmethod'), :name('new'),
118
for @(self.name_adverbs) {
120
$param.named(~$_[1].value());
121
$new_call.push($param);
123
$decl.push(PAST::Op.new(
125
PAST::Var.new( :name('obj'), :scope('register'), :isdecl(1) ),
130
# Augment, so look up existing class.
131
unless $name { pir::die('Cannot augment an anonymous package') }
132
my @name := Perl6::Grammar::parse_name($name);
133
$decl.push(PAST::Op.new(
135
PAST::Var.new( :name('obj'), :scope('register'), :isdecl(1) ),
136
PAST::Var.new( :name(@name.pop), :namespace(@name), :scope('package') )
139
$decl.push(PAST::Op.new(
141
PAST::Var.new( :name('meta'), :scope('register'), :isdecl(1) ),
142
PAST::Op.new( :pasttype('callmethod'), :name('HOW'), $obj_reg )
148
$_.unshift($obj_reg);
154
my %meta_methods := $!meta_methods;
156
$decl.push(PAST::Op.new(
157
:pasttype('callmethod'),
158
:name('add_meta_method'),
159
$meta_reg, $obj_reg, ~$_, %meta_methods{~$_}<code_ref>
164
my %methods := $!methods;
166
$decl.push(PAST::Op.new(
167
:pasttype('callmethod'),
169
$meta_reg, $obj_reg, ~$_, %methods{~$_}<code_ref>
174
my $attr_list := self.attributes();
176
my $attr := PAST::Op.new(
177
:pasttype('callmethod'),
179
PAST::Var.new( :name('Attribute'), :namespace(''), :scope('package') ),
180
PAST::Val.new( :value($_<name>), :named('name') ),
181
PAST::Val.new( :value($_<accessor>), :named('has_accessor') )
183
if pir::defined($_<rw>) {
184
$attr.push(PAST::Val.new( :value($_<rw>), :named('rw') ));
187
$_<build>.named('build');
188
$attr.push($_<build>);
191
$_<handles>.named('handles');
192
$attr.push($_<handles>);
194
if $_<type> ~~ PAST::Node {
195
$_<type>.named('type');
196
$attr.push($_<type>);
199
$attr.push(PAST::Var.new(
200
:name('Mu'), :namespace([]), :scope('package'), :named('type')
203
$decl.push(PAST::Op.new(
204
:pasttype('callmethod'),
205
:name('add_attribute'),
206
$meta_reg, $obj_reg, $attr
210
# Finally, compose call, and we're done with the decls.
211
$decl.push(PAST::Op.new( :pasttype('callmethod'), :name('compose'), $meta_reg, $obj_reg ));
213
# Check scope and put decls in the right place.
214
if $!scope eq 'anon' || $!name eq '' {
215
$block.blocktype('immediate');
218
elsif $!scope eq 'our' || $!scope eq 'augment' {
219
my $init_decl_name := $block.unique('!class_init_');
220
my @ns := Perl6::Grammar::parse_name($name);
221
$block.push(PAST::Block.new( :name($init_decl_name), :blocktype('declaration'), $decl ));
222
my @PACKAGE := Q:PIR { %r = get_hll_global ['Perl6'; 'Actions'], '@PACKAGE' };
223
@PACKAGE[0].block.loadinit().push(PAST::Op.new(
225
PAST::Var.new( :name($init_decl_name), :namespace(@ns), :scope('package') )
227
$block.blocktype('immediate');
228
$block.namespace(@ns);
230
elsif $!scope eq 'my' {
231
# Install a binding of the declaration to a name in the lexpad.
232
$decl := PAST::Block.new( :blocktype('immediate'), $decl );
233
@Perl6::Actions::BLOCK[0][0].push(PAST::Var.new(
234
:name($!name), :isdecl(1), :viviself($decl), :scope('lexical')
236
@Perl6::Actions::BLOCK[0].symbol($!name, :scope('lexical'), :does_abstraction(1));
237
$block.blocktype('immediate');
238
$block.push(PAST::Var.new( :name($!name), :scope('lexical') ));
241
pir::die("Scope declarator " ~ $!scope ~ " is not supported on packages");