fix(hir_lower): generic monomorphization for cross-module generic calls
The old findGenericCalls second-pass only looked in non-generic functions and generated unresolved instances like Array_Get_T when generic funcs called other generic funcs. Removed it entirely. lowerExpr for ekCall now invokes generateMethodInstance directly for both explicit (ekGenericCall) and inferred generic calls. This ensures concrete instantiations are generated on-demand with correct typeSubst. Also added guard in resolveTypeExpr/substituteType to skip emitting C struct definitions for unresolved type parameters (e.g. Array<T> inside a generic function body before monomorphization). feat(std): add Std::Iter module - Array_Iter, Iter_Next, Iter_HasNext, Iter_Peek, Iter_Reset - Iter_Pos, Iter_Len, Iter_Count, Iter_Skip, Iter_Take docs: document Std::Iter in Stdlib.md examples: add iter.bux example tests: add _test_array regression test
This commit is contained in:
@@ -3,7 +3,7 @@ SRC := compiler/bootstrap/main.nim
|
|||||||
OUT := buxc
|
OUT := buxc
|
||||||
BUILD_DIR := build
|
BUILD_DIR := build
|
||||||
|
|
||||||
EXAMPLES := hello fibonacci factorial structs enums methods algebraic_enums generics generics_struct generic_infer generic_infer2 extend_generic pattern_matching strings strings2 map result_option try_operator ownership ctfe async concurrency os_time process json
|
EXAMPLES := hello fibonacci factorial structs enums methods algebraic_enums generics generics_struct generic_infer generic_infer2 extend_generic pattern_matching strings strings2 map result_option try_operator ownership ctfe async concurrency os_time process json iter
|
||||||
|
|
||||||
.PHONY: all build dev test clean test-examples
|
.PHONY: all build dev test clean test-examples
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
name = "test_array"
|
||||||
|
version = "0.1.0"
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
module Main {
|
||||||
|
import Std::Array::Array;
|
||||||
|
import Std::Iter::Iter;
|
||||||
|
import Std::Test::Test;
|
||||||
|
import Std::Io::Io;
|
||||||
|
|
||||||
|
func Main() -> int {
|
||||||
|
var arr: Array<int> = Array_New<int>(4);
|
||||||
|
Array_Push<int>(&arr, 10);
|
||||||
|
Array_Push<int>(&arr, 20);
|
||||||
|
Array_Push<int>(&arr, 30);
|
||||||
|
|
||||||
|
Test_AssertEqInt(Array_Len<int>(&arr) as int, 3);
|
||||||
|
Test_AssertEqInt(Array_Get<int>(&arr, 0), 10);
|
||||||
|
Test_AssertEqInt(Array_Get<int>(&arr, 1), 20);
|
||||||
|
Test_AssertEqInt(Array_Get<int>(&arr, 2), 30);
|
||||||
|
|
||||||
|
var it: Iter<int> = Array_Iter<int>(&arr);
|
||||||
|
Test_AssertTrue(Iter_HasNext<int>(&it));
|
||||||
|
Test_AssertEqInt(Iter_Next<int>(&it), 10);
|
||||||
|
Test_AssertEqInt(Iter_Next<int>(&it), 20);
|
||||||
|
Test_AssertEqInt(Iter_Next<int>(&it), 30);
|
||||||
|
Test_AssertFalse(Iter_HasNext<int>(&it));
|
||||||
|
|
||||||
|
var it2: Iter<int> = Array_Iter<int>(&arr);
|
||||||
|
let count: uint = Iter_Count<int>(&it2);
|
||||||
|
Test_AssertEqInt(count as int, 3);
|
||||||
|
|
||||||
|
Print("All array+iter tests passed!");
|
||||||
|
Array_Free<int>(&arr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -152,16 +152,26 @@ proc substituteType(ctx: var LowerCtx, te: TypeExpr, subst: Table[string, Type])
|
|||||||
let mangledName = te.typeName & "_" & suffix
|
let mangledName = te.typeName & "_" & suffix
|
||||||
if not ctx.generatedStructInsts.hasKey(mangledName):
|
if not ctx.generatedStructInsts.hasKey(mangledName):
|
||||||
let genericDecl = ctx.genericStructs[te.typeName]
|
let genericDecl = ctx.genericStructs[te.typeName]
|
||||||
var fields: seq[tuple[name: string, typ: Type]] = @[]
|
# Skip if any type arg is still an unresolved type parameter
|
||||||
var concreteArgs: seq[Type] = @[]
|
var hasUnresolved = false
|
||||||
for f in genericDecl.declStructFields:
|
|
||||||
let resolvedType = substituteType(ctx, f.ftype, subst)
|
|
||||||
fields.add((f.name, resolvedType))
|
|
||||||
for arg in te.typeArgs:
|
for arg in te.typeArgs:
|
||||||
concreteArgs.add(substituteType(ctx, arg, subst))
|
let argType = substituteType(ctx, arg, subst)
|
||||||
ctx.extraStructs.add((mangledName, fields))
|
for tp in genericDecl.declStructTypeParams:
|
||||||
ctx.generatedStructInsts[mangledName] = true
|
if argType.kind == tkNamed and argType.name == tp.name:
|
||||||
ctx.structInstMap[mangledName] = (te.typeName, concreteArgs)
|
hasUnresolved = true
|
||||||
|
break
|
||||||
|
if hasUnresolved: break
|
||||||
|
if not hasUnresolved:
|
||||||
|
var fields: seq[tuple[name: string, typ: Type]] = @[]
|
||||||
|
var concreteArgs: seq[Type] = @[]
|
||||||
|
for f in genericDecl.declStructFields:
|
||||||
|
let resolvedType = substituteType(ctx, f.ftype, subst)
|
||||||
|
fields.add((f.name, resolvedType))
|
||||||
|
for arg in te.typeArgs:
|
||||||
|
concreteArgs.add(substituteType(ctx, arg, subst))
|
||||||
|
ctx.extraStructs.add((mangledName, fields))
|
||||||
|
ctx.generatedStructInsts[mangledName] = true
|
||||||
|
ctx.structInstMap[mangledName] = (te.typeName, concreteArgs)
|
||||||
return makeNamed(mangledName)
|
return makeNamed(mangledName)
|
||||||
return ctx.resolveTypeExpr(te)
|
return ctx.resolveTypeExpr(te)
|
||||||
of tekOwn:
|
of tekOwn:
|
||||||
@@ -197,20 +207,30 @@ proc resolveTypeExpr(ctx: var LowerCtx, te: TypeExpr): Type =
|
|||||||
let mangledName = te.typeName & "_" & suffix
|
let mangledName = te.typeName & "_" & suffix
|
||||||
if not ctx.generatedStructInsts.hasKey(mangledName):
|
if not ctx.generatedStructInsts.hasKey(mangledName):
|
||||||
let genericDecl = ctx.genericStructs[te.typeName]
|
let genericDecl = ctx.genericStructs[te.typeName]
|
||||||
var fields: seq[tuple[name: string, typ: Type]] = @[]
|
# Skip if any type arg is still an unresolved type parameter
|
||||||
var subst = initTable[string, Type]()
|
var hasUnresolved = false
|
||||||
var concreteArgs: seq[Type] = @[]
|
|
||||||
for j, tp in genericDecl.declStructTypeParams:
|
|
||||||
if j < te.typeArgs.len:
|
|
||||||
subst[tp.name] = ctx.resolveTypeExpr(te.typeArgs[j])
|
|
||||||
for arg in te.typeArgs:
|
for arg in te.typeArgs:
|
||||||
concreteArgs.add(ctx.resolveTypeExpr(arg))
|
let argType = ctx.resolveTypeExpr(arg)
|
||||||
for f in genericDecl.declStructFields:
|
for tp in genericDecl.declStructTypeParams:
|
||||||
let resolvedType = substituteType(ctx, f.ftype, subst)
|
if argType.kind == tkNamed and argType.name == tp.name:
|
||||||
fields.add((f.name, resolvedType))
|
hasUnresolved = true
|
||||||
ctx.extraStructs.add((mangledName, fields))
|
break
|
||||||
ctx.generatedStructInsts[mangledName] = true
|
if hasUnresolved: break
|
||||||
ctx.structInstMap[mangledName] = (te.typeName, concreteArgs)
|
if not hasUnresolved:
|
||||||
|
var fields: seq[tuple[name: string, typ: Type]] = @[]
|
||||||
|
var subst = initTable[string, Type]()
|
||||||
|
var concreteArgs: seq[Type] = @[]
|
||||||
|
for j, tp in genericDecl.declStructTypeParams:
|
||||||
|
if j < te.typeArgs.len:
|
||||||
|
subst[tp.name] = ctx.resolveTypeExpr(te.typeArgs[j])
|
||||||
|
for arg in te.typeArgs:
|
||||||
|
concreteArgs.add(ctx.resolveTypeExpr(arg))
|
||||||
|
for f in genericDecl.declStructFields:
|
||||||
|
let resolvedType = substituteType(ctx, f.ftype, subst)
|
||||||
|
fields.add((f.name, resolvedType))
|
||||||
|
ctx.extraStructs.add((mangledName, fields))
|
||||||
|
ctx.generatedStructInsts[mangledName] = true
|
||||||
|
ctx.structInstMap[mangledName] = (te.typeName, concreteArgs)
|
||||||
return makeNamed(mangledName)
|
return makeNamed(mangledName)
|
||||||
case te.typeName
|
case te.typeName
|
||||||
of "void": return makeVoid()
|
of "void": return makeVoid()
|
||||||
@@ -539,15 +559,7 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode =
|
|||||||
# Generic function call: Max<int>(10, 20) → Max_int(10, 20)
|
# Generic function call: Max<int>(10, 20) → Max_int(10, 20)
|
||||||
if expr.exprCallCallee.kind == ekGenericCall:
|
if expr.exprCallCallee.kind == ekGenericCall:
|
||||||
let baseName = expr.exprCallCallee.exprGenericCallee
|
let baseName = expr.exprCallCallee.exprGenericCallee
|
||||||
var typeSuffix = ""
|
let mangledName = ctx.generateMethodInstance(baseName, expr.exprCallCallee.exprGenericTypeArgs)
|
||||||
for i, targ in expr.exprCallCallee.exprGenericTypeArgs:
|
|
||||||
if i > 0:
|
|
||||||
typeSuffix.add("_")
|
|
||||||
if targ.kind == tekNamed:
|
|
||||||
typeSuffix.add(targ.typeName)
|
|
||||||
else:
|
|
||||||
typeSuffix.add("unknown")
|
|
||||||
let mangledName = baseName & "_" & typeSuffix
|
|
||||||
let args = ctx.lowerCallArgs(expr.exprCallCallee, expr.exprCallArgs)
|
let args = ctx.lowerCallArgs(expr.exprCallCallee, expr.exprCallArgs)
|
||||||
return hirCall(mangledName, args, typ, loc)
|
return hirCall(mangledName, args, typ, loc)
|
||||||
|
|
||||||
@@ -563,32 +575,7 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode =
|
|||||||
calleeName = expr.exprCallCallee.exprPath.join("_")
|
calleeName = expr.exprCallCallee.exprPath.join("_")
|
||||||
else: discard
|
else: discard
|
||||||
if calleeName != "":
|
if calleeName != "":
|
||||||
var typeSuffix = ""
|
let mangledName = ctx.generateMethodInstance(calleeName, expr.exprCallInferredTypeArgs)
|
||||||
var typeArgIdx = 0
|
|
||||||
if ctx.genericFuncs.hasKey(calleeName):
|
|
||||||
let genericDecl = ctx.genericFuncs[calleeName]
|
|
||||||
for j, tp in genericDecl.declFuncTypeParams:
|
|
||||||
if tp.isLifetime: continue
|
|
||||||
if typeArgIdx > 0:
|
|
||||||
typeSuffix.add("_")
|
|
||||||
if j < expr.exprCallInferredTypeArgs.len:
|
|
||||||
let targ = expr.exprCallInferredTypeArgs[j]
|
|
||||||
if targ.kind == tekNamed:
|
|
||||||
typeSuffix.add(targ.typeName)
|
|
||||||
else:
|
|
||||||
typeSuffix.add("unknown")
|
|
||||||
else:
|
|
||||||
typeSuffix.add("unknown")
|
|
||||||
inc(typeArgIdx)
|
|
||||||
else:
|
|
||||||
for i, targ in expr.exprCallInferredTypeArgs:
|
|
||||||
if i > 0:
|
|
||||||
typeSuffix.add("_")
|
|
||||||
if targ.kind == tekNamed:
|
|
||||||
typeSuffix.add(targ.typeName)
|
|
||||||
else:
|
|
||||||
typeSuffix.add("unknown")
|
|
||||||
let mangledName = calleeName & "_" & typeSuffix
|
|
||||||
let args = ctx.lowerCallArgs(expr.exprCallCallee, expr.exprCallArgs)
|
let args = ctx.lowerCallArgs(expr.exprCallCallee, expr.exprCallArgs)
|
||||||
return hirCall(mangledName, args, typ, loc)
|
return hirCall(mangledName, args, typ, loc)
|
||||||
|
|
||||||
@@ -1184,131 +1171,7 @@ proc lowerModule*(module: Module, sema: Sema): HirModule =
|
|||||||
let mangledName = typeName & "_" & methodDecl.declFuncName
|
let mangledName = typeName & "_" & methodDecl.declFuncName
|
||||||
ctx.genericFuncs[mangledName] = methodDecl
|
ctx.genericFuncs[mangledName] = methodDecl
|
||||||
|
|
||||||
# Second pass: find all generic calls and monomorphize
|
# Second pass: lower all non-generic functions
|
||||||
proc findGenericCalls(expr: Expr): seq[tuple[name: string, typeArgs: seq[TypeExpr]]] =
|
|
||||||
if expr == nil: return @[]
|
|
||||||
result = @[]
|
|
||||||
case expr.kind
|
|
||||||
of ekCall:
|
|
||||||
if expr.exprCallCallee.kind == ekGenericCall:
|
|
||||||
result.add((expr.exprCallCallee.exprGenericCallee, expr.exprCallCallee.exprGenericTypeArgs))
|
|
||||||
elif expr.exprCallInferredTypeArgs.len > 0:
|
|
||||||
var calleeName = ""
|
|
||||||
case expr.exprCallCallee.kind
|
|
||||||
of ekIdent: calleeName = expr.exprCallCallee.exprIdent
|
|
||||||
of ekPath: calleeName = expr.exprCallCallee.exprPath.join("::")
|
|
||||||
else: discard
|
|
||||||
if calleeName != "":
|
|
||||||
result.add((calleeName, expr.exprCallInferredTypeArgs))
|
|
||||||
result.add(findGenericCalls(expr.exprCallCallee))
|
|
||||||
for arg in expr.exprCallArgs:
|
|
||||||
result.add(findGenericCalls(arg))
|
|
||||||
of ekGenericCall:
|
|
||||||
result.add((expr.exprGenericCallee, expr.exprGenericTypeArgs))
|
|
||||||
of ekBinary:
|
|
||||||
result.add(findGenericCalls(expr.exprBinaryLeft))
|
|
||||||
result.add(findGenericCalls(expr.exprBinaryRight))
|
|
||||||
of ekUnary:
|
|
||||||
result.add(findGenericCalls(expr.exprUnaryOperand))
|
|
||||||
of ekTry:
|
|
||||||
result.add(findGenericCalls(expr.exprTryOperand))
|
|
||||||
of ekUnwrap:
|
|
||||||
result.add(findGenericCalls(expr.exprUnwrapOperand))
|
|
||||||
of ekAssign:
|
|
||||||
result.add(findGenericCalls(expr.exprAssignTarget))
|
|
||||||
result.add(findGenericCalls(expr.exprAssignValue))
|
|
||||||
of ekBlock:
|
|
||||||
if expr.exprBlock != nil:
|
|
||||||
for stmt in expr.exprBlock.stmts:
|
|
||||||
case stmt.kind
|
|
||||||
of skLet: result.add(findGenericCalls(stmt.stmtLetInit))
|
|
||||||
of skReturn: result.add(findGenericCalls(stmt.stmtReturnValue))
|
|
||||||
of skExpr: result.add(findGenericCalls(stmt.stmtExpr))
|
|
||||||
of skIf:
|
|
||||||
result.add(findGenericCalls(stmt.stmtIfCond))
|
|
||||||
of skWhile:
|
|
||||||
result.add(findGenericCalls(stmt.stmtWhileCond))
|
|
||||||
else: discard
|
|
||||||
else: discard
|
|
||||||
|
|
||||||
# Collect all generic instantiations
|
|
||||||
var instantiations: seq[tuple[name: string, typeArgs: seq[TypeExpr]]] = @[]
|
|
||||||
for decl in module.items:
|
|
||||||
if decl.kind == dkFunc and decl.declFuncBody != nil:
|
|
||||||
for stmt in decl.declFuncBody.stmts:
|
|
||||||
case stmt.kind
|
|
||||||
of skLet:
|
|
||||||
instantiations.add(findGenericCalls(stmt.stmtLetInit))
|
|
||||||
of skReturn:
|
|
||||||
instantiations.add(findGenericCalls(stmt.stmtReturnValue))
|
|
||||||
of skExpr:
|
|
||||||
instantiations.add(findGenericCalls(stmt.stmtExpr))
|
|
||||||
of skIf:
|
|
||||||
instantiations.add(findGenericCalls(stmt.stmtIfCond))
|
|
||||||
of skWhile:
|
|
||||||
instantiations.add(findGenericCalls(stmt.stmtWhileCond))
|
|
||||||
else: discard
|
|
||||||
|
|
||||||
# Generate monomorphized functions
|
|
||||||
var generated = initTable[string, bool]()
|
|
||||||
for inst in instantiations:
|
|
||||||
let baseName = inst.name
|
|
||||||
if ctx.genericFuncs.hasKey(baseName):
|
|
||||||
let genericDecl = ctx.genericFuncs[baseName]
|
|
||||||
var typeSuffix = ""
|
|
||||||
var nonLifetimeIdx = 0
|
|
||||||
for j, tp in genericDecl.declFuncTypeParams:
|
|
||||||
if tp.isLifetime: continue
|
|
||||||
if nonLifetimeIdx > 0: typeSuffix.add("_")
|
|
||||||
if j < inst.typeArgs.len:
|
|
||||||
let targ = inst.typeArgs[j]
|
|
||||||
if targ.kind == tekNamed:
|
|
||||||
typeSuffix.add(targ.typeName)
|
|
||||||
else:
|
|
||||||
typeSuffix.add("unknown")
|
|
||||||
else:
|
|
||||||
typeSuffix.add("unknown")
|
|
||||||
inc(nonLifetimeIdx)
|
|
||||||
let mangledName = baseName & "_" & typeSuffix
|
|
||||||
if not generated.hasKey(mangledName):
|
|
||||||
# Generate specialized version
|
|
||||||
|
|
||||||
# Build type substitution table
|
|
||||||
var subst = initTable[string, Type]()
|
|
||||||
for j, tp in genericDecl.declFuncTypeParams:
|
|
||||||
if tp.isLifetime: continue
|
|
||||||
if j < inst.typeArgs.len:
|
|
||||||
let targ = inst.typeArgs[j]
|
|
||||||
if targ.kind == tekNamed:
|
|
||||||
case targ.typeName
|
|
||||||
of "int", "int32": subst[tp.name] = makeInt()
|
|
||||||
of "int64": subst[tp.name] = makeInt64()
|
|
||||||
of "float64": subst[tp.name] = makeFloat64()
|
|
||||||
of "float32": subst[tp.name] = makeFloat32()
|
|
||||||
of "bool": subst[tp.name] = makeBool()
|
|
||||||
else: subst[tp.name] = makeNamed(targ.typeName)
|
|
||||||
|
|
||||||
# Create specialized declaration
|
|
||||||
var specDecl = Decl(
|
|
||||||
kind: dkFunc,
|
|
||||||
loc: genericDecl.loc,
|
|
||||||
isPublic: genericDecl.isPublic,
|
|
||||||
declFuncAsm: genericDecl.declFuncAsm,
|
|
||||||
declFuncCallConv: genericDecl.declFuncCallConv,
|
|
||||||
declFuncName: mangledName,
|
|
||||||
declFuncTypeParams: @[],
|
|
||||||
declFuncParams: genericDecl.declFuncParams,
|
|
||||||
declFuncReturnType: genericDecl.declFuncReturnType,
|
|
||||||
declFuncBody: genericDecl.declFuncBody
|
|
||||||
)
|
|
||||||
|
|
||||||
# Set substitution and lower
|
|
||||||
ctx.typeSubst = subst
|
|
||||||
funcs.add(ctx.lowerFunc(specDecl))
|
|
||||||
ctx.typeSubst = initTable[string, Type]() # Clear substitution
|
|
||||||
generated[mangledName] = true
|
|
||||||
|
|
||||||
# Third pass: lower all non-generic functions
|
|
||||||
for decl in module.items:
|
for decl in module.items:
|
||||||
case decl.kind
|
case decl.kind
|
||||||
of dkFunc:
|
of dkFunc:
|
||||||
|
|||||||
+54
-1
@@ -101,6 +101,59 @@ func Main() -> int {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Std::Iter
|
||||||
|
|
||||||
|
Lightweight iterator over `Array<T>` (index-based, no allocation).
|
||||||
|
|
||||||
|
### Types
|
||||||
|
```bux
|
||||||
|
struct Iter<T> {
|
||||||
|
data: *T,
|
||||||
|
len: uint,
|
||||||
|
pos: uint,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Functions
|
||||||
|
|
||||||
|
| Function | Signature | Description |
|
||||||
|
|----------|-----------|-------------|
|
||||||
|
| `Array_Iter<T>` | `func Array_Iter<T>(arr: *Array<T>) -> Iter<T>` | Create iterator from array |
|
||||||
|
| `Iter_HasNext<T>` | `func Iter_HasNext<T>(it: *Iter<T>) -> bool` | Check if more elements remain |
|
||||||
|
| `Iter_Next<T>` | `func Iter_Next<T>(it: *Iter<T>) -> T` | Get next element and advance |
|
||||||
|
| `Iter_Peek<T>` | `func Iter_Peek<T>(it: *Iter<T>) -> T` | Peek current element without advancing |
|
||||||
|
| `Iter_Reset<T>` | `func Iter_Reset<T>(it: *Iter<T>)` | Reset to start |
|
||||||
|
| `Iter_Pos<T>` | `func Iter_Pos<T>(it: *Iter<T>) -> uint` | Current position |
|
||||||
|
| `Iter_Len<T>` | `func Iter_Len<T>(it: *Iter<T>) -> uint` | Total length |
|
||||||
|
| `Iter_Count<T>` | `func Iter_Count<T>(it: *Iter<T>) -> uint` | Count remaining elements |
|
||||||
|
| `Iter_Skip<T>` | `func Iter_Skip<T>(it: *Iter<T>, n: uint)` | Skip N elements |
|
||||||
|
| `Iter_Take<T>` | `func Iter_Take<T>(it: *Iter<T>, n: uint) -> Iter<T>` | Take first N elements as new iterator |
|
||||||
|
|
||||||
|
### Example
|
||||||
|
```bux
|
||||||
|
import Std::Array::*;
|
||||||
|
import Std::Iter::*;
|
||||||
|
import Std::Io::{PrintInt, PrintLine};
|
||||||
|
|
||||||
|
func Main() -> int {
|
||||||
|
let arr: Array<int> = Array_New<int>(4);
|
||||||
|
Array_Push<int>(&arr, 10);
|
||||||
|
Array_Push<int>(&arr, 20);
|
||||||
|
Array_Push<int>(&arr, 30);
|
||||||
|
|
||||||
|
let it: Iter<int> = Array_Iter<int>(&arr);
|
||||||
|
while Iter_HasNext<int>(&it) {
|
||||||
|
PrintInt(Iter_Next<int>(&it));
|
||||||
|
PrintLine("");
|
||||||
|
}
|
||||||
|
|
||||||
|
Array_Free<int>(&arr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Std::String
|
## Std::String
|
||||||
|
|
||||||
String manipulation utilities.
|
String manipulation utilities.
|
||||||
@@ -848,7 +901,7 @@ func Main() -> int {
|
|||||||
- `Std::Time` — `NowMs`, `NowUs`, `SleepMs` ✅
|
- `Std::Time` — `NowMs`, `NowUs`, `SleepMs` ✅
|
||||||
- `Std::Process` — `Run`, `Output` ✅
|
- `Std::Process` — `Run`, `Output` ✅
|
||||||
- `Std::Fmt` — String formatting with interpolation ✅
|
- `Std::Fmt` — String formatting with interpolation ✅
|
||||||
- `Std::Iter` — Iterator trait and combinators ⏳
|
- `Std::Iter` — Iterator over `Array<T>` ✅
|
||||||
- `Std::Task` / `Std::Channel` — Lightweight concurrency (pthread-based threads) ✅
|
- `Std::Task` / `Std::Channel` — Lightweight concurrency (pthread-based threads) ✅
|
||||||
- `Std::Net` — TCP sockets ✅
|
- `Std::Net` — TCP sockets ✅
|
||||||
- `Std::Json` — JSON parser/serializer ✅
|
- `Std::Json` — JSON parser/serializer ✅
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import Std::Io::{PrintLine, PrintInt};
|
||||||
|
import Std::Array::*;
|
||||||
|
import Std::Iter::*;
|
||||||
|
|
||||||
|
func Main() -> int {
|
||||||
|
let arr: Array<int> = Array_New<int>(8);
|
||||||
|
Array_Push<int>(&arr, 10);
|
||||||
|
Array_Push<int>(&arr, 20);
|
||||||
|
Array_Push<int>(&arr, 30);
|
||||||
|
|
||||||
|
let it: Iter<int> = Array_Iter<int>(&arr);
|
||||||
|
while Iter_HasNext<int>(&it) {
|
||||||
|
PrintInt(Iter_Next<int>(&it));
|
||||||
|
PrintLine("");
|
||||||
|
}
|
||||||
|
|
||||||
|
Array_Free<int>(&arr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
module Std::Iter {
|
||||||
|
|
||||||
|
import Std::Array::*;
|
||||||
|
|
||||||
|
struct Iter<T> {
|
||||||
|
data: *T,
|
||||||
|
len: uint,
|
||||||
|
pos: uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create an iterator from an Array */
|
||||||
|
func Array_Iter<T>(arr: *Array<T>) -> Iter<T> {
|
||||||
|
return Iter<T> { data: arr.data, len: arr.len, pos: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if there are more elements */
|
||||||
|
func Iter_HasNext<T>(it: *Iter<T>) -> bool {
|
||||||
|
return it.pos < it.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the next element and advance (undefined if HasNext is false) */
|
||||||
|
func Iter_Next<T>(it: *Iter<T>) -> T {
|
||||||
|
let val: T = it.data[it.pos];
|
||||||
|
it.pos = it.pos + 1;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Peek current element without advancing (undefined if HasNext is false) */
|
||||||
|
func Iter_Peek<T>(it: *Iter<T>) -> T {
|
||||||
|
return it.data[it.pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset iterator to the beginning */
|
||||||
|
func Iter_Reset<T>(it: *Iter<T>) {
|
||||||
|
it.pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Current position */
|
||||||
|
func Iter_Pos<T>(it: *Iter<T>) -> uint {
|
||||||
|
return it.pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remaining length */
|
||||||
|
func Iter_Len<T>(it: *Iter<T>) -> uint {
|
||||||
|
return it.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Count remaining elements */
|
||||||
|
func Iter_Count<T>(it: *Iter<T>) -> uint {
|
||||||
|
return it.len - it.pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip N elements */
|
||||||
|
func Iter_Skip<T>(it: *Iter<T>, n: uint) {
|
||||||
|
it.pos = it.pos + n;
|
||||||
|
if it.pos > it.len {
|
||||||
|
it.pos = it.len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Take first N elements (by limiting len) */
|
||||||
|
func Iter_Take<T>(it: *Iter<T>, n: uint) -> Iter<T> {
|
||||||
|
var endPos: uint = it.pos + n;
|
||||||
|
if endPos > it.len {
|
||||||
|
endPos = it.len;
|
||||||
|
}
|
||||||
|
return Iter<T> { data: it.data, len: endPos, pos: it.pos };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user