add for-range loops to El (for i in 0..n)
Adds `for i in start..end` (exclusive) and `for i in start..=end` (inclusive) range loop syntax. Existing `for item in list` iteration is preserved; the parser branches on DotDot/DotDotEq presence after the start expression. Lexer adds DotDot and DotDotEq tokens with longer-match-first priority. Codegen emits a C `for` loop with the loop variable scoped to the statement; inclusive uses `<=`, exclusive `<`.
This commit is contained in:
@@ -1141,6 +1141,28 @@ fn cg_stmt(stmt: Map<String, Any>, indent: String, declared: [String]) -> [Strin
|
||||
return declared
|
||||
}
|
||||
|
||||
if kind == "ForRange" {
|
||||
let var_name: String = stmt["var"]
|
||||
let start_expr = stmt["start"]
|
||||
let end_expr = stmt["end"]
|
||||
let inclusive: Bool = stmt["inclusive"]
|
||||
let body = stmt["body"]
|
||||
let start_c: String = cg_expr(start_expr)
|
||||
let end_c: String = cg_expr(end_expr)
|
||||
// Loop variable introduced as a C local scoped to the for statement.
|
||||
// Body gets its own declared clone so let-bindings don't leak out.
|
||||
let body_decl = native_list_clone(declared)
|
||||
let body_decl = native_list_append(body_decl, var_name)
|
||||
if inclusive {
|
||||
emit_line(indent + "for (el_val_t " + var_name + " = " + start_c + "; " + var_name + " <= " + end_c + "; " + var_name + "++) {")
|
||||
} else {
|
||||
emit_line(indent + "for (el_val_t " + var_name + " = " + start_c + "; " + var_name + " < " + end_c + "; " + var_name + "++) {")
|
||||
}
|
||||
cg_stmts(body, indent + " ", body_decl)
|
||||
emit_line(indent + "}")
|
||||
return declared
|
||||
}
|
||||
|
||||
if kind == "FnDef" { return declared }
|
||||
if kind == "TypeDef" { return declared }
|
||||
if kind == "EnumDef" { return declared }
|
||||
|
||||
@@ -698,8 +698,24 @@ fn lex(source: String) -> [Map<String, Any>] {
|
||||
let i = i + 1
|
||||
} else {
|
||||
if ch == "." {
|
||||
let tokens = native_list_append(tokens, make_tok("Dot", "."))
|
||||
let i = i + 1
|
||||
// Check for ..= (inclusive range) before .. (exclusive range) before single .
|
||||
let peek2_i = i + 2
|
||||
let peek2_ch = ""
|
||||
if peek2_i < total {
|
||||
let peek2_ch: String = native_list_get(chars, peek2_i)
|
||||
}
|
||||
if peek_ch == "." {
|
||||
if peek2_ch == "=" {
|
||||
let tokens = native_list_append(tokens, make_tok("DotDotEq", "..="))
|
||||
let i = i + 3
|
||||
} else {
|
||||
let tokens = native_list_append(tokens, make_tok("DotDot", ".."))
|
||||
let i = i + 2
|
||||
}
|
||||
} else {
|
||||
let tokens = native_list_append(tokens, make_tok("Dot", "."))
|
||||
let i = i + 1
|
||||
}
|
||||
} else {
|
||||
if ch == ";" {
|
||||
let tokens = native_list_append(tokens, make_tok("Semicolon", ";"))
|
||||
|
||||
@@ -870,7 +870,7 @@ fn parse_stmt(tokens: [Map<String, Any>], pos: Int) -> Map<String, Any> {
|
||||
return make_result({ "stmt": "Continue" }, pos + 1)
|
||||
}
|
||||
|
||||
// for loop
|
||||
// for loop (range or list iteration)
|
||||
if k == "For" {
|
||||
let p = pos + 1
|
||||
let item_name = tok_value(tokens, p)
|
||||
@@ -880,8 +880,34 @@ fn parse_stmt(tokens: [Map<String, Any>], pos: Int) -> Map<String, Any> {
|
||||
state_set("__no_block_expr", "1")
|
||||
let r = parse_expr(tokens, p)
|
||||
state_set("__no_block_expr", prev_no_block)
|
||||
let list_expr = r["node"]
|
||||
let start_expr = r["node"]
|
||||
let p = r["pos"]
|
||||
// Check for range operator: .. (exclusive) or ..= (inclusive)
|
||||
let range_k = tok_kind(tokens, p)
|
||||
if range_k == "DotDot" {
|
||||
// exclusive range: for i in start..end
|
||||
let p = p + 1
|
||||
let r2 = parse_expr(tokens, p)
|
||||
let end_expr = r2["node"]
|
||||
let p = r2["pos"]
|
||||
let r3 = parse_block(tokens, p)
|
||||
let body = r3["stmts"]
|
||||
let p = r3["pos"]
|
||||
return make_result({ "stmt": "ForRange", "var": item_name, "start": start_expr, "end": end_expr, "inclusive": false, "body": body }, p)
|
||||
}
|
||||
if range_k == "DotDotEq" {
|
||||
// inclusive range: for i in start..=end
|
||||
let p = p + 1
|
||||
let r2 = parse_expr(tokens, p)
|
||||
let end_expr = r2["node"]
|
||||
let p = r2["pos"]
|
||||
let r3 = parse_block(tokens, p)
|
||||
let body = r3["stmts"]
|
||||
let p = r3["pos"]
|
||||
return make_result({ "stmt": "ForRange", "var": item_name, "start": start_expr, "end": end_expr, "inclusive": true, "body": body }, p)
|
||||
}
|
||||
// No range operator: regular for-in (list iteration)
|
||||
let list_expr = start_expr
|
||||
let r2 = parse_block(tokens, p)
|
||||
let body = r2["stmts"]
|
||||
let p = r2["pos"]
|
||||
|
||||
Reference in New Issue
Block a user