devalang_core/core/parser/handler/
at.rs

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