sub circumfix:<{}>(*@pairs) is primitive { \hash(@pairs) }
sub hash(*@pairs) is primitive {
JS::inline('new PIL2JS.Box.Constant(function (args) {
var cxt = args.shift();
var cc = args.pop();
var pairs = args[0].FETCH();
var hash = new PIL2JS.Hash();
for(var i = 0; i < pairs.length; i++) {
var pair = pairs[i].FETCH();
// my %hash = ("a", 1, "b", 2);
if(!(pair instanceof PIL2JS.Pair)) {
// pair is in fact the key; extract the value.
i++;
var value = pairs[i]
? pairs[i]
: new PIL2JS.Box.Constant(undefined);
pair = new PIL2JS.Pair(new PIL2JS.Box.Constant(pair), value);
}
// See thread "Hash creation with duplicate keys" started by Ingo
// Blechschmidt on p6l:
// http://www.nntp.perl.org/group/perl.perl6.language/22379
if(!hash.exists(pair.key)) {
// The extra new PIL2JS.Box is necessary to make the contents of hashes
// readwrite, i.e. my %a = (a => 1); %a = ... should work.
hash.add_pair(new PIL2JS.Pair(
new PIL2JS.Box.ReadOnly(pair.key),
new PIL2JS.Box(pair.value.FETCH())
));
}
}
cc(new PIL2JS.Box.Constant(hash));
})')(@pairs);
}
method postcircumfix:<{}>(%self: *@keys) is rw {
die "Can't use object of type {%self.ref} as a hash!"
unless %self.isa("Hash");
JS::inline('new PIL2JS.Box.Constant(function (args) {
var cxt = args.shift();
var cc = args.pop();
var hash = args[0].FETCH();
var keys = args[1].FETCH();
if(keys.length == 0) PIL2JS.die("No keys given to &postcircumfix:<{ }>!");
var proxy_for = function (key) {
// Relay .FETCH and .STORE to hash.entries[key].
var ret = new PIL2JS.Box.Proxy(
function () {
var ret = hash.get_value(key);
return ret == undefined ? undefined : ret.FETCH();
},
function (n) {
if(!hash.exists(key)) {
hash.add_pair(new PIL2JS.Pair(
new PIL2JS.Box.ReadOnly(key),
new PIL2JS.Box(undefined)
));
}
hash.get_value(key).STORE(n);
return n;
}
);
ret.uid = hash.exists(key) ? hash.get_value(key).uid : undefined;
// %hash{$key} := $foo should autovivify %hash{$key} if necessary.
ret.BINDTO = function (other) {
if(!hash.exists(key))
hash.add_pair(new PIL2JS.Pair(
new PIL2JS.Box.ReadOnly(key),
new PIL2JS.Box(undefined)
));
return hash.get_value(key).BINDTO(other);
};
return ret;
};
if(keys.length == 1) {
cc(proxy_for(keys[0]));
} else {
var ret = [];
for(var i = 0; i < keys.length; i++) {
ret.push(proxy_for(keys[i]));
}
// Needed for %a = .
var proxy = new PIL2JS.Box.Proxy(
function () { return ret },
function (n) {
var arr = new PIL2JS.Box([]).STORE(n).FETCH();
for(var i = 0; i < arr.length; i++) {
if(ret[i]) ret[i].STORE(arr[i]);
}
return this;
}
);
proxy.BINDTO = function (other) {
var arr = other.FETCH();
if(!(arr instanceof Array)) {
PIL2JS.die("Can\'t bind hash slice to non-array object!");
}
var backup_arr = [];
for(var i = 0; i < arr.length; i++) {
backup_arr[i] = new PIL2JS.Box;
backup_arr[i].FETCH = arr[i].FETCH;
backup_arr[i].STORE = arr[i].STORE;
backup_arr[i].BINDTO = arr[i].BINDTO;
}
for(var i = 0; i < backup_arr.length; i++) {
ret[i].BINDTO(backup_arr[i]);
}
return this;
};
cc(proxy);
}
})')(%self, @keys);
}
# Hash autovification
# Needs PIL2 and MMD to be done without hacks
sub PIL2JS::Internals::Hacks::hash_postcircumfix_for_undefs (
$hash is rw, *@keys
) is primitive is rw {
if defined $hash {
die "\"$hash\" can't be autovivified to a hash!";
}
$hash = hash();
$hash{@keys};
}
sub PIL2JS::Internals::Hacks::init_undef_hash_postcircumfix_method () is primitive {
JS::inline('(function () {
PIL2JS.addmethod(
_3aMain_3a_3aItem,
"postcircumfix:{}",
_26PIL2JS_3a_3aInternals_3a_3aHacks_3a_3ahash_postcircumfix_for_undefs
);
})')();
}