devalang_core/core/parser/handler/
arrow_call.rs

1use crate::core::{
2    lexer::token::TokenKind,
3    parser::{
4        driver::Parser,
5        statement::{Statement, StatementKind},
6    },
7    store::global::GlobalStore,
8};
9use devalang_types::Value;
10
11fn parse_map_literal(parser: &mut Parser) -> Value {
12    // Assumes '{' has already been consumed by caller
13    let mut map = std::collections::HashMap::new();
14    loop {
15        let Some(inner_token) = parser.peek_clone() else {
16            break;
17        };
18
19        match inner_token.kind {
20            TokenKind::RBrace => {
21                parser.advance(); // consume '}'
22                break;
23            }
24            TokenKind::Newline | TokenKind::Comma => {
25                parser.advance();
26                continue;
27            }
28            _ => {}
29        }
30
31        // Key
32        parser.advance();
33        let key = inner_token.lexeme.clone();
34
35        // Expect ':'
36        if let Some(colon_token) = parser.peek_clone() {
37            if colon_token.kind == TokenKind::Colon {
38                parser.advance(); // consume ':'
39
40                // Value
41                if let Some(value_token) = parser.peek_clone() {
42                    match value_token.kind {
43                        TokenKind::LBrace => {
44                            parser.advance(); // consume '{'
45                            let nested = parse_map_literal(parser);
46                            map.insert(key, nested);
47                        }
48                        TokenKind::Identifier => {
49                            parser.advance();
50                            let v = if value_token.lexeme == "true" {
51                                Value::Boolean(true)
52                            } else if value_token.lexeme == "false" {
53                                Value::Boolean(false)
54                            } else {
55                                Value::Identifier(value_token.lexeme.clone())
56                            };
57                            map.insert(key, v);
58                        }
59                        TokenKind::String => {
60                            parser.advance();
61                            map.insert(key, Value::String(value_token.lexeme.clone()));
62                        }
63                        TokenKind::Number => {
64                            parser.advance();
65                            // Beat fraction support: NUMBER '/' NUMBER
66                            if let Some(TokenKind::Slash) = parser.peek_kind() {
67                                parser.advance(); // '/'
68                                if let Some(den) = parser.peek_clone() {
69                                    if den.kind == TokenKind::Number {
70                                        parser.advance();
71                                        let beat = format!("{}/{}", value_token.lexeme, den.lexeme);
72                                        map.insert(key, Value::Beat(beat));
73                                        continue;
74                                    }
75                                }
76                            }
77                            // Decimal support NUMBER '.' NUMBER
78                            if let Some(next) = parser.peek_clone() {
79                                if next.kind == TokenKind::Dot {
80                                    parser.advance(); // '.'
81                                    if let Some(after) = parser.peek_clone() {
82                                        if after.kind == TokenKind::Number {
83                                            parser.advance();
84                                            let combined =
85                                                format!("{}.{}", value_token.lexeme, after.lexeme);
86                                            map.insert(
87                                                key,
88                                                Value::Number(
89                                                    combined.parse::<f32>().unwrap_or(0.0),
90                                                ),
91                                            );
92                                            continue;
93                                        }
94                                    }
95                                }
96                            }
97                            map.insert(
98                                key,
99                                Value::Number(value_token.lexeme.parse::<f32>().unwrap_or(0.0)),
100                            );
101                        }
102                        TokenKind::Boolean => {
103                            parser.advance();
104                            map.insert(
105                                key,
106                                Value::Boolean(value_token.lexeme.parse::<bool>().unwrap_or(false)),
107                            );
108                        }
109                        _ => {
110                            // Unknown value type, consume and store Unknown
111                            parser.advance();
112                            map.insert(key, Value::Unknown);
113                        }
114                    }
115                }
116            }
117        }
118    }
119    Value::Map(map)
120}
121
122pub fn parse_arrow_call(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
123    let Some(target_token) = parser.peek_clone() else {
124        return Statement::unknown();
125    };
126
127    if target_token.kind != TokenKind::Identifier {
128        parser.advance(); // consume target token
129        return Statement::unknown_with_pos(
130            target_token.indent,
131            target_token.line,
132            target_token.column,
133        );
134    }
135
136    let Some(arrow_token) = parser.peek_nth(1).cloned() else {
137        parser.advance(); // consume arrow token
138        return Statement::unknown_with_pos(
139            target_token.indent,
140            target_token.line,
141            target_token.column,
142        );
143    };
144
145    if arrow_token.kind != TokenKind::Arrow {
146        parser.advance(); // consume method token
147        return Statement::unknown_with_pos(
148            target_token.indent,
149            target_token.line,
150            target_token.column,
151        );
152    }
153
154    // We have a valid arrow call, so we consume the arrow token
155    let Some(method_token) = parser.peek_nth(2).cloned() else {
156        parser.advance();
157        return Statement::unknown_with_pos(
158            target_token.indent,
159            target_token.line,
160            target_token.column,
161        );
162    };
163
164    if method_token.kind != TokenKind::Identifier {
165        parser.advance();
166        return Statement::unknown_with_pos(
167            method_token.indent,
168            method_token.line,
169            method_token.column,
170        );
171    }
172
173    // Consume the tokens for target, arrow, and method
174    parser.advance(); // target
175    parser.advance(); // ->
176    parser.advance(); // method
177
178    let mut args = Vec::new();
179    let mut paren_depth = 0;
180    let mut map_depth = 0;
181
182    while let Some(token) = parser.peek_clone() {
183        if token.kind == TokenKind::Newline || token.kind == TokenKind::EOF {
184            break;
185        }
186        if token.kind == TokenKind::LParen {
187            paren_depth += 1;
188        }
189        if token.kind == TokenKind::RParen {
190            if paren_depth > 0 {
191                paren_depth -= 1;
192                parser.advance();
193                if paren_depth == 0 {
194                    break;
195                }
196                continue;
197            } else {
198                break;
199            }
200        }
201        if token.kind == TokenKind::LBrace {
202            map_depth += 1;
203        }
204        if token.kind == TokenKind::RBrace {
205            if map_depth > 0 {
206                map_depth -= 1;
207                parser.advance();
208                if map_depth == 0 {
209                    continue;
210                }
211                continue;
212            } else {
213                break;
214            }
215        }
216
217        parser.advance();
218
219        let value = match token.kind {
220            TokenKind::Identifier => Value::Identifier(token.lexeme.clone()),
221            TokenKind::String => Value::String(token.lexeme.clone()),
222            TokenKind::Number => Value::Number(token.lexeme.parse::<f32>().unwrap_or(0.0)),
223            TokenKind::LBrace => {
224                // Handle map literal (supports nested maps)
225
226                // We consumed the matching '}', so outer map_depth should be decremented
227                // if the caller tracks it.
228                parse_map_literal(parser)
229            }
230            _ => Value::Unknown,
231        };
232
233        args.push(value);
234
235        // Stop if we reach the end of the statement
236        if paren_depth == 0 && (token.kind == TokenKind::RParen || token.kind == TokenKind::RBrace)
237        {
238            break;
239        }
240    }
241
242    Statement {
243        kind: StatementKind::ArrowCall {
244            target: target_token.lexeme.clone(),
245            method: method_token.lexeme.clone(),
246            args,
247        },
248        value: Value::Null,
249        indent: target_token.indent,
250        line: target_token.line,
251        column: target_token.column,
252    }
253}