// Legend:
// $variable - internal variable
// %Func - runtime function
// @value - compile-time macro/value
// `output` - output code, literal code
// Note that the stubs implicitly create blocks, and their arguments are
// implicitly evaluated.
// This is just a helper.
function %CloneArray(array) {
const ret = []
const len = TO_LENGTH(array.length)
for (let i = 0; i < len; i++) {
if (HAS_INDEX(array, i, true)) {
DefineIndexedProperty(ret, i, array[i])
}
}
return ret
}
stub @initPipeline(@init) {
// The initial copy should be considered the master copy.
`let $ret = {got: true, value: @init}`
// This is a lazy value that, when initialized, does the equivalent of the
// following code:
// if (!$ret.got) {
// $ret.got = true
// $ret.value = %CloneArray($ret.value)
// }
`let $ref = %Ref($ret)`
`let $len = @init.length`
}
// Return the actual result
stub @assignResult(@dest) {
`if ($ret.got) {`
`@dest = $ret.value`
`} else {
`
`@dest = %CloneArray($ret.value)`
`}`
}
// Assign the result of the last part
stub @assignValue(@dest) {
`@dest = $ret.value`
}
// This is just a helper.
stub @iterate(@passed, @receiver, stub @missing, stub @exists) {
if (@passed) `if (IS_UNDEFINED(@receiver)) {`
`for (let $i = 0; $i < $len; $i++) {`
`if (HAS_INDEX($ret.value, $i, true)) {`
@missing(`$i`, `$ret.value[$i]`) `}` `}`
if (@passed) {
`} else {`
`for (let $i = 0; $i < $len; $i++) {`
`if (HAS_INDEX($ret.value, $i, true)) {`
@exists(`$i`, `$ret.value[$i]`, `$receiver`) `}` `}`
`}`
}
}
stub @runMap(@f, @passed, @receiver) {
`let $f = @f`
if (@passed) `let $receiver = @receiver`
@iterate(@passed, @receiver, (@i, @entry) => {
`@entry = $f(@entry, @i, $ref)`
}, (@i, @entry, $receiver) => {
`@entry = %Call($f, $receiver, @entry, @i, $ref)`
})
}
stub @runFilter(@f, @passed, @receiver) {
`let $new = []`
`let $newLen = 0`
`let $f = @f`
if (@passed) `let $receiver = @receiver`
@iterate(@passed, @receiver, (@i, @entry) => {
`let $entry = @entry`
`if ($f($entry, @i, $ref)) {`
`$new[$newLen++] = $entry`
`}`
}, (@i, @entry, $receiver) => {
`let $entry = @entry`
`if (%Call(@f, $receiver, $entry, $i, $ref)) {`
`$new[$newLen++] = $entry`
`}`
})
`$ret.value = $new`
`$ret.got = false`
`$len = $newLen`
}