devalang_core/core/parser/handler/
at.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};
10pub fn parse_at_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
11    parser.advance(); // consume '@'
12
13    let Some(token) = parser.peek_clone() else {
14        return Statement::unknown();
15    };
16
17    let keyword = token.lexeme.as_str();
18
19    match keyword {
20        "use" => {
21            parser.advance(); // consume 'use'
22            let Some(use_token) = parser.previous_clone() else {
23                return Statement::unknown();
24            };
25
26            // Expect plugin author
27            let Some(author_token) = parser.peek_clone() else {
28                return Statement::error(use_token, "Expected plugin author".to_string());
29            };
30            if author_token.kind != TokenKind::Identifier {
31                return Statement::error(
32                    author_token,
33                    "Expected identifier for plugin author".to_string(),
34                );
35            }
36            parser.advance(); // consume author
37
38            // Expect '.'
39            if !parser.match_token(TokenKind::Dot) {
40                return Statement::error(
41                    author_token,
42                    "Expected '.' after plugin author".to_string(),
43                );
44            }
45
46            // Expect plugin name
47            let Some(plugin_token) = parser.peek_clone() else {
48                return Statement::error(author_token, "Expected plugin name".to_string());
49            };
50
51            let name = match plugin_token.kind {
52                TokenKind::Identifier | TokenKind::Number => {
53                    parser.advance();
54                    format!("{}.{}", author_token.lexeme, plugin_token.lexeme)
55                }
56                _ => {
57                    return Statement::error(
58                        plugin_token,
59                        "Expected identifier or number for plugin name".to_string(),
60                    );
61                }
62            };
63
64            // Optional alias
65            let alias = if parser.match_token(TokenKind::As) {
66                let Some(alias_token) = parser.peek_clone() else {
67                    return Statement::error(
68                        use_token,
69                        "Expected identifier after 'as'".to_string(),
70                    );
71                };
72                if alias_token.kind != TokenKind::Identifier {
73                    return Statement::error(
74                        alias_token,
75                        "Expected identifier after 'as'".to_string(),
76                    );
77                }
78                parser.advance();
79                Some(alias_token.lexeme.clone())
80            } else {
81                None
82            };
83
84            Statement {
85                kind: StatementKind::Use {
86                    name: name.clone(),
87                    alias,
88                },
89                value: Value::Null,
90                indent: use_token.indent,
91                line: use_token.line,
92                column: use_token.column,
93            }
94        }
95
96        "import" => {
97            parser.advance(); // consume 'import'
98
99            if !parser.match_token(TokenKind::LBrace) {
100                return Statement::error(token, "Expected '{{' after 'import'".to_string());
101            }
102
103            let mut names = Vec::new();
104            while let Some(token) = parser.peek() {
105                match &token.kind {
106                    TokenKind::Identifier => {
107                        names.push(token.lexeme.clone());
108                        parser.advance();
109                    }
110                    TokenKind::Comma => {
111                        parser.advance();
112                    }
113                    TokenKind::RBrace => {
114                        parser.advance();
115                        break;
116                    }
117                    _ => {
118                        let message =
119                            format!("Unexpected token in import list: {:?}", token.kind.clone());
120                        return Statement::error(token.clone(), message);
121                    }
122                }
123            }
124
125            let Some(from_token) = parser.peek_clone() else {
126                return Statement::error(token, "Expected 'from' after import list".to_string());
127            };
128
129            if from_token.lexeme != "from" {
130                return Statement::error(token, "Expected keyword 'from'".to_string());
131            }
132
133            parser.advance(); // consume 'from'
134
135            let Some(source_token) = parser.peek() else {
136                return Statement::error(token, "Expected string after 'from'".to_string());
137            };
138
139            if source_token.kind != TokenKind::String {
140                return Statement::error(token, "Expected string after 'from'".to_string());
141            }
142
143            let source = source_token.lexeme.clone();
144            parser.advance(); // consume string
145
146            Statement {
147                kind: StatementKind::Import { names, source },
148                value: Value::Null,
149                indent: token.indent,
150                line: token.line,
151                column: token.column,
152            }
153        }
154
155        "export" => {
156            parser.advance(); // consume 'export'
157
158            parser.advance(); // consume '{'
159
160            let names_tokens = parser.collect_until(|t| TokenKind::RBrace == t.kind);
161            let mut names: Vec<String> = Vec::new();
162
163            for token in names_tokens {
164                if token.kind == TokenKind::Identifier {
165                    names.push(token.lexeme.clone());
166                } else if token.kind == TokenKind::Comma {
167                    continue; // Ignore commas
168                } else if token.kind == TokenKind::RBrace {
169                    break; // Stop at the closing brace
170                } else {
171                    return Statement::error(token, "Unexpected token in export list".to_string());
172                }
173            }
174
175            Statement {
176                kind: StatementKind::Export {
177                    names: names.clone(),
178                    source: parser.current_module.clone(),
179                },
180                value: Value::Null,
181                indent: token.indent,
182                line: token.line,
183                column: token.column,
184            }
185        }
186
187        "load" => {
188            parser.advance(); // consume 'load'
189
190            // Example: @load "preset.mydeva"
191            let Some(path_token) = parser.peek() else {
192                return Statement::error(token, "Expected string after 'load'".to_string());
193            };
194
195            if path_token.kind != TokenKind::String {
196                return Statement::error(token, "Expected string after 'load'".to_string());
197            }
198
199            let path = path_token.lexeme.clone();
200
201            parser.advance(); // consume string
202
203            if !parser.match_token(TokenKind::As) {
204                return Statement::error(
205                    token,
206                    "Expected 'as' after path in load statement".to_string(),
207                );
208            }
209
210            let Some(alias_token) = parser.peek_clone() else {
211                return Statement::error(
212                    token,
213                    "Expected identifier after 'as' in load statement".to_string(),
214                );
215            };
216
217            if alias_token.kind != TokenKind::Identifier {
218                return Statement::error(
219                    token,
220                    "Expected identifier after 'as' in load statement".to_string(),
221                );
222            }
223
224            let alias = alias_token.lexeme.clone();
225
226            parser.advance(); // consume identifier
227
228            Statement {
229                kind: StatementKind::Load {
230                    source: path,
231                    alias,
232                },
233                value: Value::Null,
234                indent: token.indent,
235                line: token.line,
236                column: token.column,
237            }
238        }
239
240        _ => {
241            let message = format!("Unknown keyword after '@' : {}", keyword);
242            Statement::error(token, message)
243        }
244    }
245}