fix(compiler): allow integer coercion in range bounds; use for loops in boko-framework

- sema: range bounds now accept compatible integer types (e.g. int..uint)
  instead of requiring exact type equality.
- hir_lower: derive loop variable type from the common range type.
- boko-framework: replace manual while loops with for loops in Query_Parse,
  Request_Parse, Path_Match and App_Run.
This commit is contained in:
2026-06-17 12:08:36 +03:00
parent 9c632ce389
commit 94e6806dda
3 changed files with 24 additions and 16 deletions
+4 -12
View File
@@ -242,8 +242,7 @@ func Query_Parse(queryString: String) -> StringMap<String> {
} }
let pairCount: uint = String_SplitCount(queryString, "&"); let pairCount: uint = String_SplitCount(queryString, "&");
var i: uint = 0; for i in 0..pairCount {
while i < pairCount {
let pair: String = String_SplitPart(queryString, "&", i); let pair: String = String_SplitPart(queryString, "&", i);
let eqPos: String = String_Find(pair, "="); let eqPos: String = String_Find(pair, "=");
var key: String = pair; var key: String = pair;
@@ -258,7 +257,6 @@ func Query_Parse(queryString: String) -> StringMap<String> {
} }
} }
StringMap_Set<String>(&map, key, value); StringMap_Set<String>(&map, key, value);
i = i + 1;
} }
return map; return map;
} }
@@ -317,8 +315,7 @@ func Request_Parse(raw: String) -> Request {
} }
// Parse headers // Parse headers
var i: uint = 1; for i in 1..lineCount {
while i < lineCount {
let line: String = String_SplitPart(headerBlock, "\r\n", i); let line: String = String_SplitPart(headerBlock, "\r\n", i);
let colonPos: String = String_Find(line, ": "); let colonPos: String = String_Find(line, ": ");
if !String_IsNull(colonPos) { if !String_IsNull(colonPos) {
@@ -332,7 +329,6 @@ func Request_Parse(raw: String) -> Request {
} }
StringMap_Set<String>(&req.headers, key, value); StringMap_Set<String>(&req.headers, key, value);
} }
i = i + 1;
} }
return req; return req;
@@ -349,8 +345,7 @@ func Path_Match(pattern: String, path: String, req: *Request) -> bool {
req.pathParams = StringMap_New<String>(8); req.pathParams = StringMap_New<String>(8);
var i: uint = 0; for i in 0..patParts {
while i < patParts {
let patPart: String = String_SplitPart(pattern, "/", i); let patPart: String = String_SplitPart(pattern, "/", i);
let pathPart: String = String_SplitPart(path, "/", i); let pathPart: String = String_SplitPart(path, "/", i);
@@ -361,7 +356,6 @@ func Path_Match(pattern: String, path: String, req: *Request) -> bool {
} else { } else {
if !String_Eq(patPart, pathPart) { return false; } if !String_Eq(patPart, pathPart) { return false; }
} }
i = i + 1;
} }
return true; return true;
@@ -462,10 +456,8 @@ func App_Run(app: *App) {
PrintLine(""); PrintLine("");
// Spawn workers // Spawn workers
var i: int = 0; for i in 0..(app.threadCount - 1) {
while i < app.threadCount - 1 {
spawn App_Worker(fd); spawn App_Worker(fd);
i = i + 1;
} }
// Main thread is the last worker // Main thread is the last worker
+10 -1
View File
@@ -481,6 +481,14 @@ proc resolveExprType(ctx: var LowerCtx, expr: Expr): Type =
return makeSlice(makeUnknown()) return makeSlice(makeUnknown())
of ekRange: of ekRange:
let loType = ctx.resolveExprType(expr.exprRangeLo) let loType = ctx.resolveExprType(expr.exprRangeLo)
let hiType = ctx.resolveExprType(expr.exprRangeHi)
if loType == hiType:
return makeRange(loType)
elif loType.isAssignableTo(hiType):
return makeRange(hiType)
elif hiType.isAssignableTo(loType):
return makeRange(loType)
else:
return makeRange(loType) return makeRange(loType)
of ekTuple: of ekTuple:
var elems: seq[Type] = @[] var elems: seq[Type] = @[]
@@ -1377,7 +1385,8 @@ proc lowerStmt(ctx: var LowerCtx, stmt: Stmt): HirNode =
let inclusive = iterExpr.exprRangeInclusive let inclusive = iterExpr.exprRangeInclusive
# Determine loop variable type from range bounds # Determine loop variable type from range bounds
let varType = ctx.resolveExprType(iterExpr.exprRangeLo) let rangeType = ctx.resolveExprType(iterExpr)
let varType = if rangeType.inner.len > 0: rangeType.inner[0] else: ctx.resolveExprType(iterExpr.exprRangeLo)
# Create: var i = lo; while i < hi { body; i = i + 1; } # Create: var i = lo; while i < hi { body; i = i + 1; }
let initStmt = hirAlloca(varName, varType, loc) let initStmt = hirAlloca(varName, varType, loc)
+9 -2
View File
@@ -1007,9 +1007,16 @@ proc checkExpr(sema: var Sema, expr: Expr, scope: Scope): Type =
of ekRange: of ekRange:
let lo = sema.checkExpr(expr.exprRangeLo, scope) let lo = sema.checkExpr(expr.exprRangeLo, scope)
let hi = sema.checkExpr(expr.exprRangeHi, scope) let hi = sema.checkExpr(expr.exprRangeHi, scope)
if lo != hi: var rangeType: Type = lo
if lo == hi:
rangeType = lo
elif lo.isAssignableTo(hi):
rangeType = hi
elif hi.isAssignableTo(lo):
rangeType = lo
else:
sema.emitError(expr.loc, "range bounds must have same type") sema.emitError(expr.loc, "range bounds must have same type")
return makeRange(lo) return makeRange(rangeType)
of ekCall: of ekCall:
if expr.exprCallCallee == nil: if expr.exprCallCallee == nil:
sema.emitError(expr.loc, "internal error: nil callee in call expression") sema.emitError(expr.loc, "internal error: nil callee in call expression")