Skip to content

Instantly share code, notes, and snippets.

@niner
Last active January 8, 2016 13:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niner/88a97e8a1becbacab1d5 to your computer and use it in GitHub Desktop.
Save niner/88a97e8a1becbacab1d5 to your computer and use it in GitHub Desktop.
method merge_globals($target, $source) {
# Start off merging top-level symbols. Easy when there's no
# overlap. Otherwise, we need to recurse.
my %known_symbols;
for stash_hash($target) {
nqp::sayfh(nqp::getstderr(), "Known symbol " ~ $_.key);
%known_symbols{$_.key} := 1;
}
for stash_hash($source) {
my $sym := $_.key;
nqp::sayfh(
nqp::getstderr(),
"Checking symbol " ~ $sym
~ " value " ~ $_.value.HOW.name($_.value)
~ " objid " ~ nqp::objectid($_.value)
~ " where " ~ nqp::where($_.value)
~ " existing " ~ ($target){$sym}.HOW.name(($target){$sym})
~ " objid " ~ nqp::objectid(($target){$sym})
~ " where " ~ nqp::where(($target){$sym})
~ " eqaddr " ~ nqp::eqaddr(($target){$sym}, $_.value)
);
if !%known_symbols{$sym} {
nqp::sayfh(nqp::getstderr(), "unknown!");
($target){$sym} := $_.value;
}
elsif ($target){$sym} =:= $_.value {
nqp::sayfh(nqp::getstderr(), "symbol already there!");
# No problemo; a symbol can't conflict with itself.
}
else {
nqp::sayfh(nqp::getstderr(), "conflict!");
my $source_mo := $_.value.HOW;
my $source_is_stub := $source_mo.HOW.name($source_mo) eq $stub_how
|| $source_mo.HOW.name($source_mo) eq $nqp_stub_how;
nqp::sayfh(nqp::getstderr(), "source_is_stub: " ~ $source_is_stub ~ " " ~ $source_mo.HOW.name($source_mo));
my $target_mo := ($target){$sym}.HOW;
my $target_is_stub := $target_mo.HOW.name($target_mo) eq $stub_how
|| $target_mo.HOW.name($target_mo) eq $nqp_stub_how;
nqp::sayfh(nqp::getstderr(), "target_is_stub: " ~ $target_is_stub ~ " " ~ $target_mo.HOW.name($target_mo));
if $source_is_stub && $target_is_stub {
# Both stubs. We can safely merge the symbols from
# the source into the target that's importing them.
self.merge_globals(($target){$sym}.WHO, $_.value.WHO);
}
elsif $source_is_stub {
# The target has a real package, but the source is a
# stub. Also fine to merge source symbols into target.
self.merge_globals(($target){$sym}.WHO, $_.value.WHO);
}
elsif $target_is_stub {
# The tricky case: here the interesting package is the
# one in the module. So we merge the other way around
# and install that as the result.
nqp::sayfh(nqp::getstderr(), "merging symbol $sym");
self.merge_globals($_.value.WHO, ($target){$sym}.WHO);
($target){$sym} := $_.value;
}
elsif nqp::eqat($_.key, '&', 0) {
nqp::sayfh(nqp::getstderr(), "function!");
# "Latest wins" semantics for functions
($target){$sym} := $_.value;
}
else {
nqp::die("P6M Merging GLOBAL symbols failed: duplicate definition of symbol $sym");
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment