devalang_core/core/parser/handler/
loop_.rs

1use crate::core::{
2    lexer::{ token::TokenKind },
3    parser::{ statement::{ Statement, StatementKind }, driver::Parser },
4    shared::value::Value,
5    store::global::GlobalStore,
6};
7
8pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
9    parser.advance(); // consume 'loop' or 'for' (aliased in lexer)
10    let Some(loop_token) = parser.previous_clone() else {
11        return Statement::unknown();
12    };
13
14    // Support two forms:
15    // 1) loop <count>:
16    // 2) for <ident> in [a,b,c]:
17
18    // Peek next to decide
19    let Some(next_token) = parser.peek_clone() else {
20        return Statement::error(loop_token, "Expected iterator after loop/for".to_string());
21    };
22
23    // Try to detect 'for <ident> in [array]:' form
24    let mut foreach_ident: Option<String> = None;
25    if let TokenKind::Identifier = next_token.kind {
26        // Could be either count identifier (old form) or foreach variable
27        // Look ahead for 'in'
28        let name = next_token.lexeme.clone();
29        // don't consume yet; we'll branch
30        if let Some(t2) = parser.peek_nth(1) {
31            if t2.kind == TokenKind::Identifier && t2.lexeme == "in" {
32                // foreach form
33                foreach_ident = Some(name);
34                // consume ident and 'in'
35                parser.advance();
36                parser.advance();
37            }
38        }
39    }
40
41    if let Some(var_name) = foreach_ident {
42        // Expect array literal
43        let array_val = if let Some(v) = parser.parse_array_value() { v } else {
44            return Statement::error(loop_token, "Expected array literal after 'in'".to_string());
45        };
46
47        // Expect ':'
48        if !parser.match_token(TokenKind::Colon) {
49            return Statement::error(loop_token, "Expected ':' after foreach header".to_string());
50        }
51
52        let tokens = parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
53        let loop_body = parser.parse_block(tokens.clone(), global_store);
54        if let Some(token) = parser.peek() { if token.kind == TokenKind::Dedent { parser.advance(); } }
55
56        let mut value_map = std::collections::HashMap::new();
57        value_map.insert("foreach".to_string(), Value::Identifier(var_name));
58        value_map.insert("array".to_string(), array_val);
59        value_map.insert("body".to_string(), Value::Block(loop_body.clone()));
60
61        return Statement { kind: StatementKind::Loop, value: Value::Map(value_map), indent: loop_token.indent, line: loop_token.line, column: loop_token.column };
62    }
63
64    // Fallback to legacy: loop <count>:
65    let Some(iterator_token) = parser.peek_clone() else {
66        return Statement::error(loop_token, "Expected number or identifier after 'loop'".to_string());
67    };
68
69    let iterator_value = match iterator_token.kind {
70        TokenKind::Number => { let val = iterator_token.lexeme.parse::<f32>().unwrap_or(1.0); parser.advance(); Value::Number(val) }
71        TokenKind::Identifier => { let val = iterator_token.lexeme.clone(); parser.advance(); Value::Identifier(val) }
72        _ => { return Statement::error(iterator_token.clone(), "Expected a number or identifier as loop count".to_string()); }
73    };
74
75    if !parser.match_token(TokenKind::Colon) {
76        let message = format!("Expected ':' after loop count, got {:?}", parser.peek_kind());
77        return Statement::error(loop_token.clone(), message);
78    }
79
80    let tokens = parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
81    let loop_body = parser.parse_block(tokens.clone(), global_store);
82    if let Some(token) = parser.peek() { if token.kind == TokenKind::Dedent { parser.advance(); } }
83
84    let mut value_map = std::collections::HashMap::new();
85    value_map.insert("iterator".to_string(), iterator_value);
86    value_map.insert("body".to_string(), Value::Block(loop_body.clone()));
87
88    Statement { kind: StatementKind::Loop, value: Value::Map(value_map), indent: loop_token.indent, line: loop_token.line, column: loop_token.column }
89}