devalang_core/core/parser/handler/identifier/
on.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
11// Syntax:
12// on <identifier>:
13//   <indented block>
14pub fn parse_on_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
15    // consume 'on'
16    let on_tok = match parser.peek_clone() {
17        Some(tok) => tok,
18        None => return Statement::unknown(),
19    };
20    parser.advance();
21
22    // Expect event name identifier
23    let event_tok = match parser.peek_clone() {
24        Some(tok) if tok.kind == TokenKind::Identifier => tok,
25        Some(other) => {
26            return Statement::error(other, "Expected event name after 'on'".to_string());
27        }
28        None => return Statement::error(on_tok, "Expected event name after 'on'".to_string()),
29    };
30    let event_name = event_tok.lexeme.clone();
31    parser.advance();
32
33    // Optional parenthesized args on same line
34    let mut args: Option<Vec<Value>> = None;
35    if parser.peek_kind() == Some(TokenKind::LParen) {
36        parser.advance(); // '('
37        let mut collected: Vec<Value> = Vec::new();
38        // Collect tokens until ')', supporting numbers and identifiers separated by comma
39        while let Some(tok) = parser.peek_clone() {
40            match tok.kind {
41                TokenKind::RParen => {
42                    parser.advance();
43                    break;
44                }
45                TokenKind::Number => {
46                    parser.advance();
47                    collected.push(Value::Number(tok.lexeme.parse().unwrap_or(0.0)));
48                }
49                TokenKind::Identifier => {
50                    parser.advance();
51                    collected.push(Value::Identifier(tok.lexeme));
52                }
53                TokenKind::Comma => {
54                    parser.advance();
55                }
56                TokenKind::Whitespace | TokenKind::Newline => {
57                    parser.advance();
58                }
59                _ => {
60                    break;
61                }
62            }
63        }
64        if !collected.is_empty() {
65            args = Some(collected);
66        }
67    }
68
69    // Expect ':' then block
70    if parser.peek_kind() != Some(TokenKind::Colon) {
71        return Statement::error(event_tok, "Expected ':' after event name".to_string());
72    }
73    parser.advance(); // consume ':'
74
75    let base_indent = on_tok.indent;
76    let block_tokens = parser.collect_block_tokens(base_indent);
77    // Parse body within current store context
78    let body = parser.parse_block(block_tokens, _global_store);
79
80    let stmt = Statement {
81        kind: StatementKind::On {
82            event: event_name,
83            args,
84            body,
85        },
86        value: Value::Null,
87        indent: on_tok.indent,
88        line: on_tok.line,
89        column: on_tok.column,
90    };
91
92    // Register in global store for later emission
93    if let StatementKind::On { event, .. } = &stmt.kind {
94        _global_store.register_event_handler(event, stmt.clone());
95    }
96
97    stmt
98}