devalang_core/core/parser/handler/
loop_.rs1use crate::core::{
2 lexer::token::TokenKind,
3 parser::{
4 driver::Parser,
5 statement::{Statement, StatementKind},
6 },
7 shared::value::Value,
8 store::global::GlobalStore,
9};
10
11pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
12 parser.advance(); let Some(loop_token) = parser.previous_clone() else {
14 return Statement::unknown();
15 };
16
17 let Some(next_token) = parser.peek_clone() else {
23 return Statement::error(loop_token, "Expected iterator after loop/for".to_string());
24 };
25
26 let mut foreach_ident: Option<String> = None;
28 if let TokenKind::Identifier = next_token.kind {
29 let name = next_token.lexeme.clone();
32 if let Some(t2) = parser.peek_nth(1) {
34 if t2.kind == TokenKind::Identifier && t2.lexeme == "in" {
35 foreach_ident = Some(name);
37 parser.advance();
39 parser.advance();
40 }
41 }
42 }
43
44 if let Some(var_name) = foreach_ident {
45 let array_val = if let Some(tok) = parser.peek_clone() {
47 match tok.kind {
48 TokenKind::LBracket => {
49 if let Some(v) = parser.parse_array_value() {
50 v
51 } else {
52 Value::Array(vec![])
53 }
54 }
55 TokenKind::Number => {
56 parser.advance();
57 let n = tok.lexeme.parse::<f32>().unwrap_or(0.0);
58 Value::Number(n)
59 }
60 TokenKind::String => {
61 parser.advance();
62 Value::String(tok.lexeme.clone())
63 }
64 TokenKind::Identifier => {
65 parser.advance();
66 Value::Identifier(tok.lexeme.clone())
67 }
68 _ => {
69 return Statement::error(
70 loop_token,
71 "Expected array, number, string or identifier after 'in'".to_string(),
72 );
73 }
74 }
75 } else {
76 return Statement::error(
77 loop_token,
78 "Expected array, number, string or identifier after 'in'".to_string(),
79 );
80 };
81
82 if !parser.match_token(TokenKind::Colon) {
84 return Statement::error(loop_token, "Expected ':' after foreach header".to_string());
85 }
86
87 let tokens =
88 parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
89 let loop_body = parser.parse_block(tokens.clone(), global_store);
90 if let Some(token) = parser.peek() {
91 if token.kind == TokenKind::Dedent {
92 parser.advance();
93 }
94 }
95
96 let mut value_map = std::collections::HashMap::new();
97 value_map.insert("foreach".to_string(), Value::Identifier(var_name));
98 value_map.insert("array".to_string(), array_val);
99 value_map.insert("body".to_string(), Value::Block(loop_body.clone()));
100
101 return Statement {
102 kind: StatementKind::Loop,
103 value: Value::Map(value_map),
104 indent: loop_token.indent,
105 line: loop_token.line,
106 column: loop_token.column,
107 };
108 }
109
110 let Some(iterator_token) = parser.peek_clone() else {
112 return Statement::error(
113 loop_token,
114 "Expected number or identifier after 'loop'".to_string(),
115 );
116 };
117
118 let iterator_value = match iterator_token.kind {
119 TokenKind::Number => {
120 let val = iterator_token.lexeme.parse::<f32>().unwrap_or(1.0);
121 parser.advance();
122 Value::Number(val)
123 }
124 TokenKind::Identifier => {
125 let val = iterator_token.lexeme.clone();
126 parser.advance();
127 Value::Identifier(val)
128 }
129 TokenKind::String => {
130 let s = iterator_token.lexeme.clone();
132 parser.advance();
133 Value::String(s)
134 }
135 _ => {
136 return Statement::error(
137 iterator_token.clone(),
138 "Expected a number, string or identifier as loop count".to_string(),
139 );
140 }
141 };
142
143 if !parser.match_token(TokenKind::Colon) {
144 let message = format!(
145 "Expected ':' after loop count, got {:?}",
146 parser.peek_kind()
147 );
148 return Statement::error(loop_token.clone(), message);
149 }
150
151 let tokens = parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
152 let loop_body = parser.parse_block(tokens.clone(), global_store);
153 if let Some(token) = parser.peek() {
154 if token.kind == TokenKind::Dedent {
155 parser.advance();
156 }
157 }
158
159 let mut value_map = std::collections::HashMap::new();
160 value_map.insert("iterator".to_string(), iterator_value);
161 value_map.insert("body".to_string(), Value::Block(loop_body.clone()));
162
163 Statement {
164 kind: StatementKind::Loop,
165 value: Value::Map(value_map),
166 indent: loop_token.indent,
167 line: loop_token.line,
168 column: loop_token.column,
169 }
170}