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

« back to all changes in this revision

Viewing changes to src/vm/jvm/ModuleLoader.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
knowhow ModuleLoader {
 
2
    my %modules_loaded;
 
3
    my %settings_loaded;
 
4
    
 
5
    method search_path($explicit_path) {
 
6
        my @search_paths;
 
7
        
 
8
        # Put any explicitly specified path on the start of the list.
 
9
        my $explicit;
 
10
        if !nqp::isnull($explicit_path) {
 
11
            try { my $hack; $explicit := %*COMPILING<%?OPTIONS>{$explicit_path}; }
 
12
        }
 
13
        if !nqp::isnull($explicit) && nqp::defined($explicit) {
 
14
            nqp::push(@search_paths, $explicit);
 
15
        }
 
16
        else {
 
17
            for nqp::jvmclasspaths() {
 
18
                nqp::push(@search_paths, $_)
 
19
            }
 
20
        }
 
21
        
 
22
        # Add CWD and blib.
 
23
        nqp::push(@search_paths, '.');
 
24
        nqp::push(@search_paths, 'blib');
 
25
    
 
26
        @search_paths
 
27
    }
 
28
    
 
29
    method ctxsave() {
 
30
        $*MAIN_CTX := nqp::ctxcaller(nqp::ctx());
 
31
        $*CTXSAVE := 0;
 
32
    }
 
33
    
 
34
    method load_module($module_name, *@extras, :$line, :$file) {
 
35
        # If we didn't already do so, load the module and capture
 
36
        # its mainline. Otherwise, we already loaded it so go on
 
37
        # with what we already have.
 
38
        my $module_ctx;
 
39
        my $path := nqp::join('/', nqp::split('::', $module_name));
 
40
        my @prefixes := self.search_path('module-path');
 
41
        for @prefixes -> $prefix {
 
42
            if nqp::stat("$prefix/$path.jar", 0) {
 
43
                $path := "$prefix/$path.jar";
 
44
                last;
 
45
            }
 
46
            if nqp::stat("$prefix/$path.class", 0) {
 
47
                $path := "$prefix/$path.class";
 
48
                last;
 
49
            }
 
50
        }
 
51
        if nqp::existskey(%modules_loaded, $path) {
 
52
            $module_ctx := %modules_loaded{$path};
 
53
        }
 
54
        else {
 
55
            my $*CTXSAVE := self;
 
56
            my $*MAIN_CTX := ModuleLoader;
 
57
            my $boot_mode;
 
58
            try { my $hack; $boot_mode := %*COMPILING<%?OPTIONS><bootstrap>; }
 
59
            $boot_mode := !nqp::isnull($boot_mode) && $boot_mode;
 
60
            my $preserve_global := nqp::getcurhllsym('GLOBAL');
 
61
            nqp::usecompileehllconfig() if $boot_mode;
 
62
            nqp::loadbytecode($path);
 
63
            nqp::usecompilerhllconfig() if $boot_mode;
 
64
            nqp::bindcurhllsym('GLOBAL', $preserve_global);
 
65
            %modules_loaded{$path} := $module_ctx := $*MAIN_CTX;
 
66
        }
 
67
 
 
68
        # Provided we have a mainline...
 
69
        if nqp::defined($module_ctx) {
 
70
            # Merge any globals.
 
71
            my $UNIT := nqp::ctxlexpad($module_ctx);
 
72
            unless nqp::isnull($UNIT<GLOBALish>) {
 
73
                if nqp::elems(@extras) {
 
74
                    # There can be a hash at index zero, which contains adverbs
 
75
                    # passed to the use-statement.
 
76
                    my $index := nqp::ishash(@extras[0]) ?? 1 !! 0;
 
77
                    if nqp::elems(@extras) > $index {
 
78
                        merge_globals(@extras[$index], $UNIT<GLOBALish>);
 
79
                    }
 
80
                }
 
81
            }
 
82
        }
 
83
 
 
84
        return $module_ctx;
 
85
    }
 
86
    
 
87
    # XXX This is a really dumb and minimalistic GLOBAL merger.
 
88
    # For a much more complete one, see sorear++'s work in
 
89
    # Niecza. This one will likely evolve towards that, but for 
 
90
    # now I just need something that's just good enough for the
 
91
    # immediate needs of NQP bootstrapping.
 
92
    my $stub_how := 'KnowHOW';
 
93
    sub merge_globals($target, $source) {
 
94
        # XXX For now just merge the top level symbols;
 
95
        # if there's a conflict then don't dig any deeper.
 
96
        # Obviously, just a first cut at this. :-)
 
97
        my %known_symbols;
 
98
        for $target.WHO {
 
99
            %known_symbols{nqp::iterkey_s($_)} := 1;
 
100
        }
 
101
        for $source.WHO {
 
102
            my $sym := nqp::iterkey_s($_);
 
103
            my $val := nqp::iterval($_);
 
104
            if !nqp::existskey(%known_symbols, $sym) {
 
105
                my $source_is_stub := 0;
 
106
                # XXX TODO: Exceptions.
 
107
                #try {
 
108
                    my $source_mo := $val.HOW;
 
109
                    $source_is_stub := $source_mo.WHAT.HOW.name($source_mo) eq $stub_how &&
 
110
                        !nqp::isnull(nqp::who($val)) && nqp::who($val);
 
111
                #}
 
112
                if $source_is_stub {
 
113
                    my $source := $val;
 
114
                    my $source_clone := $source.HOW.new_type(:name($source.HOW.name($source)));
 
115
                    $source_clone.HOW.compose($source_clone);
 
116
                    my %WHO_clone;
 
117
                    for nqp::who($source) {
 
118
                        %WHO_clone{nqp::iterkey_s($_)} := nqp::iterval($_);
 
119
                    }
 
120
                    nqp::setwho($source_clone, %WHO_clone);
 
121
                    ($target.WHO){$sym} := $source_clone;
 
122
                }
 
123
                else {
 
124
                    ($target.WHO){$sym} := $val;
 
125
                }
 
126
            }
 
127
            elsif ($target.WHO){$sym} =:= $val {
 
128
                # No problemo; a symbol can't conflict with itself.
 
129
            }
 
130
            else {
 
131
                my $source_mo := $val.HOW;
 
132
                my $source_is_stub := $source_mo.WHAT.HOW.name($source_mo) eq $stub_how;
 
133
                my $target_mo := ($target.WHO){$sym}.HOW;
 
134
                my $target_is_stub := $target_mo.WHAT.HOW.name($target_mo) eq $stub_how;
 
135
                if $source_is_stub && $target_is_stub {
 
136
                    # Leave target as is, and merge the nested symbols.
 
137
                    merge_globals(($target.WHO){$sym}, $val);
 
138
                }
 
139
                else {
 
140
                    nqp::die("Merging GLOBAL symbols failed: duplicate definition of symbol $sym");
 
141
                }
 
142
            }
 
143
        }
 
144
    }
 
145
    
 
146
    method load_setting($setting_name) {
 
147
        my $setting;
 
148
        
 
149
        if $setting_name ne 'NULL' {
 
150
            # Add path prefix and .setting suffix.
 
151
            my $path := "$setting_name.setting";
 
152
            my @prefixes := self.search_path('setting-path');
 
153
            for @prefixes -> $prefix {
 
154
                if nqp::stat("$prefix/$path.jar", 0) {
 
155
                    $path := "$prefix/$path.jar";
 
156
                    last;
 
157
                }
 
158
                if nqp::stat("$prefix/$path.class", 0) {
 
159
                    $path := "$prefix/$path.class";
 
160
                    last;
 
161
                }
 
162
            }
 
163
 
 
164
            # Unless we already did so, load the setting.
 
165
            unless nqp::existskey(%settings_loaded, $path) {
 
166
                my $*CTXSAVE := self;
 
167
                my $*MAIN_CTX := ModuleLoader;
 
168
                my $boot_mode;
 
169
                try { my $hack; $boot_mode := %*COMPILING<%?OPTIONS><bootstrap>; }
 
170
                $boot_mode := !nqp::isnull($boot_mode) && $boot_mode;
 
171
                my $preserve_global := nqp::getcurhllsym('GLOBAL');
 
172
                nqp::usecompileehllconfig() if $boot_mode;
 
173
                nqp::loadbytecode($path);
 
174
                nqp::usecompilerhllconfig() if $boot_mode;
 
175
                nqp::bindcurhllsym('GLOBAL', $preserve_global);
 
176
                unless nqp::defined($*MAIN_CTX) {
 
177
                    nqp::die("Unable to load setting $setting_name; maybe it is missing a YOU_ARE_HERE?");
 
178
                }
 
179
                %settings_loaded{$path} := $*MAIN_CTX;
 
180
            }
 
181
            
 
182
            $setting := %settings_loaded{$path};
 
183
        }
 
184
        
 
185
        return $setting;
 
186
    }
 
187
}
 
188
 
 
189
# Since this *is* the module loader, we can't locate it the normal way by
 
190
# GLOBAL merging. So instead we stash it away in the Parrot namespace tree.
 
191
nqp::bindcurhllsym('ModuleLoader', ModuleLoader);