feat(stdlib): generic Iter_Map/Filter/Fold with func monomorphization
Add Iter_Map<T,U>, Filter, Fold, Any, All, ForEach over fat function pointers; keep Iter_MapInt and friends as thin aliases. Compiler fixes required for non-int returns and capturing closures: - bootstrap: resolve fat-func call return type under mono typeSubst - bootstrap: type-check args of Foo<T>(...) so closures capture correctly - selfhost: substitute type params inside tekFunc (BuxFn_U_T → concrete) - selfhost: emit cstr fat typedefs with #ifndef redefinition guards Example: examples/iter_generic.bux (int↔String map, fold, closures). Selfhost-loop remains binary-identical.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
// Generic Iter_Map / Filter / Fold / Any / All (not just int)
|
||||
import Std::Io::{PrintLine, PrintInt};
|
||||
import Std::Array::{
|
||||
Array, Array_New, Array_Push, Array_Get, Array_Len, Array_Free
|
||||
};
|
||||
import Std::String::{String_FromInt, String_Len, String_Eq};
|
||||
import Std::Iter::{
|
||||
Array_Iter, Iter,
|
||||
Iter_Map, Iter_Filter, Iter_Fold, Iter_Any, Iter_All,
|
||||
Iter_MapInt, Iter_SumInt
|
||||
};
|
||||
import Std::Test::{
|
||||
Test_AssertEqInt, Test_AssertTrue, Test_AssertFalse, Test_AssertEqString, Test_Pass
|
||||
};
|
||||
|
||||
func Double(x: int) -> int {
|
||||
return x * 2;
|
||||
}
|
||||
|
||||
func IsEven(x: int) -> bool {
|
||||
return (x % 2) == 0;
|
||||
}
|
||||
|
||||
func IntToString(x: int) -> String {
|
||||
return String_FromInt(x);
|
||||
}
|
||||
|
||||
func StringLenAsInt(s: String) -> int {
|
||||
return String_Len(s) as int;
|
||||
}
|
||||
|
||||
func AddLens(acc: int, s: String) -> int {
|
||||
return acc + (String_Len(s) as int);
|
||||
}
|
||||
|
||||
func IsNonEmpty(s: String) -> bool {
|
||||
return String_Len(s) > 0;
|
||||
}
|
||||
|
||||
func Main() -> int {
|
||||
var nums: Array<int> = Array_New<int>(8);
|
||||
Array_Push<int>(&nums, 1);
|
||||
Array_Push<int>(&nums, 2);
|
||||
Array_Push<int>(&nums, 3);
|
||||
Array_Push<int>(&nums, 4);
|
||||
Array_Push<int>(&nums, 5);
|
||||
|
||||
// Generic Map int → int
|
||||
let itA: Iter<int> = Array_Iter<int>(&nums);
|
||||
var doubled: Array<int> = Iter_Map<int, int>(&itA, Double);
|
||||
Test_AssertEqInt(Array_Get<int>(&doubled, 0), 2);
|
||||
Test_AssertEqInt(Array_Get<int>(&doubled, 4), 10);
|
||||
|
||||
// Generic Map int → String
|
||||
let itB: Iter<int> = Array_Iter<int>(&nums);
|
||||
var asStr: Array<String> = Iter_Map<int, String>(&itB, IntToString);
|
||||
Test_AssertEqInt(Array_Len<String>(&asStr) as int, 5);
|
||||
Test_AssertEqString(Array_Get<String>(&asStr, 0), "1");
|
||||
Test_AssertEqString(Array_Get<String>(&asStr, 4), "5");
|
||||
|
||||
// Map String → int (lengths)
|
||||
let itC: Iter<String> = Array_Iter<String>(&asStr);
|
||||
var lens: Array<int> = Iter_Map<String, int>(&itC, StringLenAsInt);
|
||||
Test_AssertEqInt(Array_Get<int>(&lens, 0), 1);
|
||||
Test_AssertEqInt(Array_Get<int>(&lens, 4), 1);
|
||||
|
||||
// Filter generic
|
||||
let itD: Iter<int> = Array_Iter<int>(&nums);
|
||||
var evens: Array<int> = Iter_Filter<int>(&itD, IsEven);
|
||||
Test_AssertEqInt(Array_Len<int>(&evens) as int, 2);
|
||||
Test_AssertEqInt(Array_Get<int>(&evens, 0), 2);
|
||||
Test_AssertEqInt(Array_Get<int>(&evens, 1), 4);
|
||||
|
||||
// Fold String lengths
|
||||
let itE: Iter<String> = Array_Iter<String>(&asStr);
|
||||
let totalChars: int = Iter_Fold<String, int>(&itE, 0, AddLens);
|
||||
Test_AssertEqInt(totalChars, 5); // "1"+"2"+"3"+"4"+"5"
|
||||
|
||||
// Any / All on String
|
||||
let itF: Iter<String> = Array_Iter<String>(&asStr);
|
||||
Test_AssertTrue(Iter_Any<String>(&itF, IsNonEmpty));
|
||||
let itG: Iter<String> = Array_Iter<String>(&asStr);
|
||||
Test_AssertTrue(Iter_All<String>(&itG, IsNonEmpty));
|
||||
|
||||
// Closures with generic Map
|
||||
let scale: int = 100;
|
||||
let itH: Iter<int> = Array_Iter<int>(&nums);
|
||||
var scaled: Array<int> = Iter_Map<int, int>(&itH, |x: int| -> int {
|
||||
return x * scale;
|
||||
});
|
||||
Test_AssertEqInt(Array_Get<int>(&scaled, 0), 100);
|
||||
Test_AssertEqInt(Array_Get<int>(&scaled, 2), 300);
|
||||
|
||||
// Int aliases still work
|
||||
let itI: Iter<int> = Array_Iter<int>(&nums);
|
||||
var d2: Array<int> = Iter_MapInt(&itI, Double);
|
||||
Test_AssertEqInt(Array_Get<int>(&d2, 1), 4);
|
||||
let itJ: Iter<int> = Array_Iter<int>(&nums);
|
||||
Test_AssertEqInt(Iter_SumInt(&itJ), 15);
|
||||
|
||||
PrintInt(totalChars);
|
||||
PrintLine("");
|
||||
Test_Pass("iter_generic");
|
||||
|
||||
Array_Free<int>(&nums);
|
||||
Array_Free<int>(&doubled);
|
||||
Array_Free<String>(&asStr);
|
||||
Array_Free<int>(&lens);
|
||||
Array_Free<int>(&evens);
|
||||
Array_Free<int>(&scaled);
|
||||
Array_Free<int>(&d2);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user