~ubuntu-branches/ubuntu/vivid/nqp/vivid-proposed

« back to all changes in this revision

Viewing changes to src/how/NQPParametricRoleHOW.nqp

  • Committer: Package Import Robot
  • Author(s): Alessandro Ghedini
  • Date: 2013-11-01 12:09:18 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20131101120918-kx51sl0sxl3exsxi
Tags: 2013.10-1
* New upstream release
* Bump versioned (Build-)Depends on parrot
* Update patches
* Install new README.pod
* Fix vcs-field-not-canonical
* Do not install rubyish examples
* Do not Depends on parrot-devel anymore
* Add 07_disable-serialization-tests.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# This implements a parametric role (that is, one that has yet to be
 
2
# parameterized to get a concrete role that we can actually compose
 
3
# into a class or mix into an object). It also contains the logic to
 
4
# reify it into an actual role.
 
5
knowhow NQPParametricRoleHOW {
 
6
    ##
 
7
    ## Attributes
 
8
    ##
 
9
 
 
10
    # Name of the parametric role.
 
11
    has $!name;
 
12
 
 
13
    # Attributes and methods.
 
14
    has @!attributes;
 
15
    has %!methods;
 
16
    has @!multi_methods_to_incorporate;
 
17
 
 
18
    # Other roles that this one does.
 
19
    has @!roles;
 
20
 
 
21
    # Have we been composed?
 
22
    has $!composed;
 
23
 
 
24
    # The body block of the role. (If we were to support multiple role
 
25
    # variants with the same name, this would be a multi. However, we
 
26
    # don't do that in NQP.)
 
27
    has $!body_block;
 
28
 
 
29
    my $archetypes := Archetypes.new( :nominal(1), :composable(1), :parametric(1) );
 
30
    method archetypes() {
 
31
        $archetypes
 
32
    }
 
33
 
 
34
    ##
 
35
    ## Declarative
 
36
    ##
 
37
 
 
38
    # Creates a new instance of this meta-class.
 
39
    method new(:$name!) {
 
40
        my $obj := nqp::create(self);
 
41
        $obj.BUILD(:name($name));
 
42
        $obj
 
43
    }
 
44
 
 
45
    method BUILD(:$name!) {
 
46
        $!name := $name;
 
47
        @!attributes := nqp::list();
 
48
        %!methods := nqp::hash();
 
49
        @!multi_methods_to_incorporate := nqp::list();
 
50
        @!roles := nqp::list();
 
51
        $!composed := 0;
 
52
    }
 
53
 
 
54
    # Create a new meta-class instance, and then a new type object
 
55
    # to go with it, and return that.
 
56
    method new_type(:$name = '<anon>') {
 
57
        my $metarole := self.new(:name($name));
 
58
        nqp::setwho(nqp::newtype($metarole, 'Uninstantiable'), {});
 
59
    }
 
60
    
 
61
    method set_body_block($obj, $body_block) {
 
62
        $!body_block := $body_block;
 
63
    }
 
64
 
 
65
    method add_method($obj, $name, $code_obj) {
 
66
        if nqp::existskey(%!methods, $name) {
 
67
            nqp::die("This role already has a method named " ~ $name);
 
68
        }
 
69
        %!methods{$name} := $code_obj;
 
70
    }
 
71
 
 
72
    method add_multi_method($obj, $name, $code_obj) {
 
73
        my %todo;
 
74
        %todo<name> := $name;
 
75
        %todo<code> := $code_obj;
 
76
        nqp::push(@!multi_methods_to_incorporate, %todo);
 
77
        $code_obj;
 
78
    }
 
79
 
 
80
    method add_attribute($obj, $meta_attr) {
 
81
        my $name := $meta_attr.name;
 
82
        for @!attributes {
 
83
            if $_.name eq $name {
 
84
                nqp::die("This role already has an attribute named " ~ $name);
 
85
            }
 
86
        }
 
87
        nqp::push(@!attributes, $meta_attr);
 
88
    }
 
89
 
 
90
    method add_parent($obj, $parent) {
 
91
        nqp::die("A role cannot inherit from a class")
 
92
    }
 
93
 
 
94
    method add_role($obj, $role) {
 
95
        nqp::push(@!roles, $role);
 
96
    }
 
97
 
 
98
    # Compose the role. Beyond this point, no changes are allowed.
 
99
    method compose($obj) {
 
100
        $!composed := 1;
 
101
        nqp::settypecache($obj, [$obj.WHAT]);
 
102
        nqp::setmethcache($obj, {});
 
103
        nqp::setmethcacheauth($obj, 1);
 
104
        $obj
 
105
    }
 
106
 
 
107
 
 
108
    ##
 
109
    ## Parametricity
 
110
    ##
 
111
 
 
112
    # Method to indicate that this type is parametric.
 
113
    method parametric($obj) {
 
114
        1
 
115
    }
 
116
    
 
117
    # Curries this parametric role with arguments.
 
118
    method curry($obj, *@args) {
 
119
        NQPCurriedRoleHOW.new_type($obj, |@args)
 
120
    }
 
121
 
 
122
    # This specializes the role for the given class and builds a concrete
 
123
    # role.
 
124
    method specialize($obj, $class_arg, *@args) {
 
125
        # Run the body block to capture the arguments into the correct
 
126
        # type argument context.
 
127
        my $pad := $!body_block($class_arg, |@args);
 
128
 
 
129
        # Construct a new concrete role.
 
130
        my $irole := NQPConcreteRoleHOW.new_type(:name($!name), :instance_of($obj));
 
131
 
 
132
        # Copy attributes. (Nothing to reify in NQP as we don't currently
 
133
        # have parametric types that may end up in the signature.)
 
134
        for @!attributes {
 
135
            $irole.HOW.add_attribute($irole, $_);
 
136
        }
 
137
 
 
138
        # Capture methods in the correct lexical context.
 
139
        for %!methods {
 
140
            my $name := nqp::iterkey_s($_);
 
141
            my $meth := nqp::can(nqp::iterval($_), 'instantiate_generic')
 
142
                ?? nqp::iterval($_).instantiate_generic($pad)
 
143
                !! nqp::iterval($_).clone();
 
144
            if nqp::substr($name, 0, 12) eq '!!LATENAME!!' {
 
145
                $name := nqp::atkey($pad, nqp::substr($name, 12));
 
146
                $meth.'!set_name'($name);
 
147
            }
 
148
            $irole.HOW.add_method($irole, $name, $meth);
 
149
        }
 
150
        for @!multi_methods_to_incorporate {
 
151
            $irole.HOW.add_multi_method($irole, $_<name>, $_<code>.clone());
 
152
        }
 
153
 
 
154
        # Copy roles, instantiating them as we go.
 
155
        for @!roles {
 
156
            my $specialized := $_.HOW.specialize($_, $class_arg);
 
157
            $irole.HOW.add_role($irole, $specialized);
 
158
        }
 
159
 
 
160
        # Compose and return produced role.
 
161
        $irole.HOW.compose($irole);
 
162
        return $irole;
 
163
    }
 
164
 
 
165
    ##
 
166
    ## Introspecty
 
167
    ##
 
168
 
 
169
    method methods($obj, :$local) {
 
170
        my @meths;
 
171
        for %!methods {
 
172
            nqp::push(@meths, nqp::iterval($_));
 
173
        }
 
174
        @meths
 
175
    }
 
176
 
 
177
    method method_table($obj) {
 
178
        %!methods
 
179
    }
 
180
 
 
181
    method name($obj) {
 
182
        $!name
 
183
    }
 
184
 
 
185
    method attributes($obj, :$local) {
 
186
        my @attrs;
 
187
        for @!attributes {
 
188
            nqp::push(@attrs, $_);
 
189
        }
 
190
        @attrs
 
191
    }
 
192
 
 
193
    method roles($obj) {
 
194
        @!roles
 
195
    }
 
196
}