1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
|
use lang:bs;
use lang:bs:macro;
use core:lang;
use core:asm;
class MapExpr extends Block {
private Expr src;
private Expr? transform;
private LocalVar boundVar;
init(SrcPos pos, Block parent, Expr src, SStr varName) {
init(pos, parent) {
src = expectCastTo(src, named{Array<Int>}, parent.scope);
boundVar = LocalVar(varName.v, named{Int}, varName.pos, false);
}
add(boundVar);
}
void setTransform(Expr expr) {
transform = expectCastTo(expr, named{Int}, scope);
}
ExprResult result() : override {
ExprResult(Value(named{Array<Int>}));
}
void blockCode(CodeGen gen, CodeResult res) : override {
unless (transform)
throw InternalError("No transform set for a MapBlock!");
// Create the array. Put it in the result variable:
var resultVar = res.location(gen);
allocObject(gen, named{Array<Int>:__init<Array<Int>>}, [], resultVar);
res.created(gen);
// Get the original array:
CodeResult originalArrayRes(named{Array<Int>}, gen.block);
src.code(gen, originalArrayRes);
var originalArray = originalArrayRes.location(gen);
// Extract the count of the original array.
Function countFn = named{Array<Int>:count<Array<Int>>};
CodeResult originalCountRes(named{Nat}, gen.block);
countFn.autoCall(gen, [originalArray], originalCountRes);
var originalCount = originalCountRes.location(gen);
// Create a loop counter:
var loopCounter = gen.createVar(named{Nat}).v;
gen.l << mov(loopCounter, natConst(0));
// Start the loop:
Label loopStart = gen.l.label();
gen.l << loopStart;
// Check if we are done.
Label loopEnd = gen.l.label();
gen.l << cmp(loopCounter, originalCount);
gen.l << jmp(loopEnd, CondFlag:ifAboveEqual);
// Get an element. Returns a reference to the element.
Function accessFunction = named{Array<Int>:"[]"<Array<Int>, Nat>};
CodeResult elemPtr(accessFunction.result, gen.block);
accessFunction.autoCall(gen, [originalArray, loopCounter], elemPtr);
// Evaluate the expression to get the value to insert. First set our variable:
gen.l << mov(ptrA, elemPtr.location(gen));
gen.l << mov(boundVar.var.v, intRel(ptrA));
CodeResult transformed(named{Int}, gen.block);
transform.code(gen, transformed);
// Push it into the array.
Function pushFn = named{Array<Int>:push<Array<Int>, Int>};
gen.l << lea(ptrA, transformed.location(gen));
pushFn.autoCall(gen, [resultVar, ptrA], CodeResult());
// Increment the loop counter and restart the loop.
gen.l << add(loopCounter, natConst(1));
gen.l << jmp(loopStart);
// End of the loop.
gen.l << loopEnd;
}
}
|