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    shared::value::Value,
8    store::global::GlobalStore,
9};
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_from_token(&target_token);
130    }
131
132    let Some(arrow_token) = parser.peek_nth(1).cloned() else {
133        parser.advance(); // consume arrow token
134        return Statement::unknown_from_token(&target_token);
135    };
136
137    if arrow_token.kind != TokenKind::Arrow {
138        parser.advance(); // consume method token
139        return Statement::unknown_from_token(&target_token);
140    }
141
142    // We have a valid arrow call, so we consume the arrow token
143    let Some(method_token) = parser.peek_nth(2).cloned() else {
144        parser.advance();
145        return Statement::unknown_from_token(&target_token);
146    };
147
148    if method_token.kind != TokenKind::Identifier {
149        parser.advance();
150        return Statement::unknown_from_token(&method_token);
151    }
152
153    // Consume the tokens for target, arrow, and method
154    parser.advance(); // target
155    parser.advance(); // ->
156    parser.advance(); // method
157
158    let mut args = Vec::new();
159    let mut paren_depth = 0;
160    let mut map_depth = 0;
161
162    while let Some(token) = parser.peek_clone() {
163        if token.kind == TokenKind::Newline || token.kind == TokenKind::EOF {
164            break;
165        }
166        if token.kind == TokenKind::LParen {
167            paren_depth += 1;
168        }
169        if token.kind == TokenKind::RParen {
170            if paren_depth > 0 {
171                paren_depth -= 1;
172                parser.advance();
173                if paren_depth == 0 {
174                    break;
175                }
176                continue;
177            } else {
178                break;
179            }
180        }
181        if token.kind == TokenKind::LBrace {
182            map_depth += 1;
183        }
184        if token.kind == TokenKind::RBrace {
185            if map_depth > 0 {
186                map_depth -= 1;
187                parser.advance();
188                if map_depth == 0 {
189                    continue;
190                }
191                continue;
192            } else {
193                break;
194            }
195        }
196
197        parser.advance();
198
199        let value = match token.kind {
200            TokenKind::Identifier => Value::Identifier(token.lexeme.clone()),
201            TokenKind::String => Value::String(token.lexeme.clone()),
202            TokenKind::Number => Value::Number(token.lexeme.parse::<f32>().unwrap_or(0.0)),
203            TokenKind::LBrace => {
204                // Handle map literal (supports nested maps)
205                let map_val = parse_map_literal(parser);
206                // We consumed the matching '}', so outer map_depth should be decremented
207                // if the caller tracks it.
208                map_val
209            }
210            _ => Value::Unknown,
211        };
212
213        args.push(value);
214
215        // Stop if we reach the end of the statement
216        if paren_depth == 0 && (token.kind == TokenKind::RParen || token.kind == TokenKind::RBrace)
217        {
218            break;
219        }
220    }
221
222    Statement {
223        kind: StatementKind::ArrowCall {
224            target: target_token.lexeme.clone(),
225            method: method_token.lexeme.clone(),
226            args,
227        },
228        value: Value::Null,
229        indent: target_token.indent,
230        line: target_token.line,
231        column: target_token.column,
232    }
233}