Skip to main content

neutron_engine/iris/
parser.rs

1/// Iris Parser - Converts tokens into AST
2
3use super::lexer::Token;
4use super::token::TokenType;
5
6
7
8
9#[derive(Debug, Clone, PartialEq)]
10pub enum Expr {
11    Null,
12    Bool(bool),
13    Number(f64),
14    String(String),
15    Identifier(String),
16    Array(Vec<Expr>),
17    Object(Vec<(String, Expr)>),
18    Binary {
19        left: Box<Expr>,
20        op: BinaryOp,
21        right: Box<Expr>,
22    },
23    Unary {
24        op: UnaryOp,
25        expr: Box<Expr>,
26    },
27    Call {
28        callee: Box<Expr>,
29        args: Vec<Expr>,
30    },
31    Index {
32        object: Box<Expr>,
33        index: Box<Expr>,
34    },
35    Member {
36        object: Box<Expr>,
37        property: String,
38    },
39    Assign {
40        target: Box<Expr>,
41        value: Box<Expr>,
42    },
43    Lambda {
44        params: Vec<String>,
45        body: Vec<Stmt>,
46    },
47}
48
49#[derive(Debug, Clone, PartialEq)]
50pub enum BinaryOp {
51    Add, Sub, Mul, Div, Mod,
52    Eq, Neq, Lt, Gt, Lte, Gte,
53    And, Or,
54}
55
56#[derive(Debug, Clone, PartialEq)]
57pub enum UnaryOp {
58    Neg, Not,
59}
60
61#[derive(Debug, Clone, PartialEq)]
62pub enum Stmt {
63    Expr(Expr),
64
65    // system iris:"..." directive
66    // stores compile-time/runtime traits requested by the user
67    SystemIris {
68        traits: Vec<String>,
69    },
70
71    Let {
72        name: String,
73        value: Expr,
74    },
75    Const {
76        name: String,
77        value: Expr,
78    },
79    Fn {
80        name: String,
81        params: Vec<String>,
82        body: Vec<Stmt>,
83    },
84    Block(Vec<Stmt>),
85    If {
86        condition: Expr,
87        then_branch: Vec<Stmt>,
88        else_branch: Option<Vec<Stmt>>,
89    },
90    While {
91        condition: Expr,
92        body: Vec<Stmt>,
93    },
94    For {
95        var: String,
96        iterable: Expr,
97        body: Vec<Stmt>,
98    },
99    Return(Option<Expr>),
100    Break,
101    Continue,
102    Import {
103        path: String,
104    },
105}
106
107pub struct Parser {
108    tokens: Vec<Token>,
109    current: usize,
110}
111
112impl Parser {
113    pub fn new(tokens: Vec<Token>) -> Self {
114        Parser { tokens, current: 0 }
115    }
116
117    pub fn parse(&mut self) -> Result<Vec<Stmt>, String> {
118        let mut stmts = Vec::new();
119        while !self.is_at_end() {
120            if self.match_token(&[TokenType::Newline]) || self.match_token(&[TokenType::Comment(String::new())]) {
121                continue;
122            }
123            stmts.push(self.statement()?);
124        }
125        Ok(stmts)
126    }
127
128    fn statement(&mut self) -> Result<Stmt, String> {
129        if self.match_token(&[TokenType::Import]) {
130            self.import_statement()
131        } else if self.match_token(&[TokenType::System]) {
132            self.system_iris_statement()
133        } else if self.match_token(&[TokenType::Let]) {
134            self.let_statement()
135        } else if self.match_token(&[TokenType::Const]) {
136            self.const_statement()
137        } else if self.match_token(&[TokenType::Fn]) {
138            self.fn_statement()
139        } else if self.match_token(&[TokenType::If]) {
140            self.if_statement()
141        } else if self.match_token(&[TokenType::Elif]) {
142            Err("Iris does not use 'elif'. Use nested if logic: else { if condition { ... } }".to_string())
143        } else if self.match_token(&[TokenType::While]) {
144            self.while_statement()
145        } else if self.match_token(&[TokenType::For]) {
146            self.for_statement()
147        } else if self.match_token(&[TokenType::Return]) {
148            self.return_statement()
149        } else if self.match_token(&[TokenType::Break]) {
150            Ok(Stmt::Break)
151        } else if self.match_token(&[TokenType::Continue]) {
152            Ok(Stmt::Continue)
153        } else if self.check(&TokenType::LBrace) {
154            self.block()
155        } else {
156            let expr = self.expression()?;
157            self.consume_semicolon();
158            Ok(Stmt::Expr(expr))
159        }
160    }
161
162    fn system_iris_statement(&mut self) -> Result<Stmt, String> {
163        // Syntax supported:
164        // system iris:"borrow checker"
165        // system iris:"borrow checker","ownership"
166        // system iris:"borrow checker", "ownership"
167
168        // Expect identifier `iris`
169        let namespace = self.consume_identifier("Expected identifier after 'system' (expected 'iris')")?;
170        if namespace != "iris" {
171            return Err(format!("Expected 'iris' after 'system' but got '{}'", namespace));
172        }
173
174        self.consume(&TokenType::Colon, "Expected ':' after 'iris'")?;
175
176        let mut traits = Vec::new();
177        loop {
178            match self.peek_token_type() {
179                Some(TokenType::String(s)) => {
180                    traits.extend(
181                        s.split(',')
182                            .map(str::trim)
183                            .filter(|trait_name| !trait_name.is_empty())
184                            .map(str::to_string),
185                    );
186                    self.advance();
187                }
188                _ => {
189                    return Err(format!("Expected string trait after 'system iris:' at line {}", self.peek().line));
190                }
191            }
192
193            if self.match_token(&[TokenType::Comma]) {
194                continue;
195            } else {
196                break;
197            }
198        }
199
200        self.consume_semicolon();
201        Ok(Stmt::SystemIris { traits })
202    }
203
204    fn import_statement(&mut self) -> Result<Stmt, String> {
205        let path = match self.peek_token_type() {
206            Some(TokenType::String(s)) => {
207                let s = s.clone();
208                self.advance();
209                s
210            }
211            _ => return Err(format!("Expected string path after 'import' at line {}", self.peek().line)),
212        };
213        self.consume_semicolon();
214        Ok(Stmt::Import { path })
215    }
216
217    fn let_statement(&mut self) -> Result<Stmt, String> {
218        let name = self.consume_identifier("Expected variable name after 'let'")?;
219        self.consume(&TokenType::Assign, "Expected '=' after variable name")?;
220        let value = self.expression()?;
221        self.consume_semicolon();
222        Ok(Stmt::Let { name, value })
223    }
224
225    fn const_statement(&mut self) -> Result<Stmt, String> {
226        let name = self.consume_identifier("Expected constant name after 'const'")?;
227        self.consume(&TokenType::Assign, "Expected '=' after constant name")?;
228        let value = self.expression()?;
229        self.consume_semicolon();
230        Ok(Stmt::Const { name, value })
231    }
232
233    fn fn_statement(&mut self) -> Result<Stmt, String> {
234        let name = self.consume_identifier("Expected function name after 'fn'")?;
235        self.consume(&TokenType::LParen, "Expected '(' after function name")?;
236        let mut params = Vec::new();
237        if !self.check(&TokenType::RParen) {
238            loop {
239                params.push(self.consume_identifier("Expected parameter name")?);
240                if !self.match_token(&[TokenType::Comma]) {
241                    break;
242                }
243            }
244        }
245        self.consume(&TokenType::RParen, "Expected ')' after parameters")?;
246        let body = self.block()?;
247        let body = match body {
248            Stmt::Block(stmts) => stmts,
249            _ => vec![body],
250        };
251        Ok(Stmt::Fn { name, params, body })
252    }
253
254    fn if_statement(&mut self) -> Result<Stmt, String> {
255        let condition = self.expression()?;
256        let then_branch = match self.block()? {
257            Stmt::Block(stmts) => stmts,
258            s => vec![s],
259        };
260        let else_branch = if self.match_token(&[TokenType::Else]) {
261            if self.check(&TokenType::If) {
262                return Err("Iris does not use 'else if'. Use nested if logic: else { if condition { ... } }".to_string());
263            }
264            Some(match self.block()? {
265                Stmt::Block(stmts) => stmts,
266                s => vec![s],
267            })
268        } else {
269            None
270        };
271        Ok(Stmt::If { condition, then_branch, else_branch })
272    }
273
274    fn while_statement(&mut self) -> Result<Stmt, String> {
275        let condition = self.expression()?;
276        let body = match self.block()? {
277            Stmt::Block(stmts) => stmts,
278            s => vec![s],
279        };
280        Ok(Stmt::While { condition, body })
281    }
282
283    fn for_statement(&mut self) -> Result<Stmt, String> {
284        let var = self.consume_identifier("Expected variable name after 'for'")?;
285        self.consume(&TokenType::In, "Expected 'in' after for variable")?;
286        let iterable = self.expression()?;
287        let body = match self.block()? {
288            Stmt::Block(stmts) => stmts,
289            s => vec![s],
290        };
291        Ok(Stmt::For { var, iterable, body })
292    }
293
294    fn return_statement(&mut self) -> Result<Stmt, String> {
295        let value = if self.check(&TokenType::Semicolon) || self.check(&TokenType::Newline) || self.check(&TokenType::RBrace) || self.is_at_end() {
296            None
297        } else {
298            Some(self.expression()?)
299        };
300        self.consume_semicolon();
301        Ok(Stmt::Return(value))
302    }
303
304    fn block(&mut self) -> Result<Stmt, String> {
305        self.consume(&TokenType::LBrace, "Expected '{'")?;
306        let mut stmts = Vec::new();
307        while !self.check(&TokenType::RBrace) && !self.is_at_end() {
308            if self.match_token(&[TokenType::Newline]) || self.match_token(&[TokenType::Comment(String::new())]) {
309                continue;
310            }
311            stmts.push(self.statement()?);
312        }
313        self.consume(&TokenType::RBrace, "Expected '}' after block")?;
314        Ok(Stmt::Block(stmts))
315    }
316
317    fn expression(&mut self) -> Result<Expr, String> {
318        self.assignment()
319    }
320
321    fn assignment(&mut self) -> Result<Expr, String> {
322        let expr = self.or()?;
323        if self.match_token(&[TokenType::Assign, TokenType::PlusAssign, TokenType::MinusAssign, TokenType::StarAssign, TokenType::SlashAssign]) {
324            let op = self.previous().token_type.clone();
325            let value = self.assignment()?;
326            match expr {
327                Expr::Identifier(name) => {
328                    let value = match op {
329                        TokenType::PlusAssign => Expr::Binary { left: Box::new(Expr::Identifier(name.clone())), op: BinaryOp::Add, right: Box::new(value) },
330                        TokenType::MinusAssign => Expr::Binary { left: Box::new(Expr::Identifier(name.clone())), op: BinaryOp::Sub, right: Box::new(value) },
331                        TokenType::StarAssign => Expr::Binary { left: Box::new(Expr::Identifier(name.clone())), op: BinaryOp::Mul, right: Box::new(value) },
332                        TokenType::SlashAssign => Expr::Binary { left: Box::new(Expr::Identifier(name.clone())), op: BinaryOp::Div, right: Box::new(value) },
333                        _ => value,
334                    };
335                    Ok(Expr::Assign { target: Box::new(Expr::Identifier(name)), value: Box::new(value) })
336                }
337                Expr::Member { object, property } => {
338                    Ok(Expr::Assign { target: Box::new(Expr::Member { object, property }), value: Box::new(value) })
339                }
340                Expr::Index { object, index } => {
341                    Ok(Expr::Assign { target: Box::new(Expr::Index { object, index }), value: Box::new(value) })
342                }
343                _ => Err("Invalid assignment target".to_string()),
344            }
345        } else {
346            Ok(expr)
347        }
348    }
349
350    fn or(&mut self) -> Result<Expr, String> {
351        let mut expr = self.and()?;
352        while self.match_token(&[TokenType::Or]) {
353            let right = self.and()?;
354            expr = Expr::Binary { left: Box::new(expr), op: BinaryOp::Or, right: Box::new(right) };
355        }
356        Ok(expr)
357    }
358
359    fn and(&mut self) -> Result<Expr, String> {
360        let mut expr = self.equality()?;
361        while self.match_token(&[TokenType::And]) {
362            let right = self.equality()?;
363            expr = Expr::Binary { left: Box::new(expr), op: BinaryOp::And, right: Box::new(right) };
364        }
365        Ok(expr)
366    }
367
368    fn equality(&mut self) -> Result<Expr, String> {
369        let mut expr = self.comparison()?;
370        while self.match_token(&[TokenType::Eq, TokenType::Neq]) {
371            let op = match self.previous().token_type {
372                TokenType::Eq => BinaryOp::Eq,
373                TokenType::Neq => BinaryOp::Neq,
374                _ => unreachable!(),
375            };
376            let right = self.comparison()?;
377            expr = Expr::Binary { left: Box::new(expr), op, right: Box::new(right) };
378        }
379        Ok(expr)
380    }
381
382    fn comparison(&mut self) -> Result<Expr, String> {
383        let mut expr = self.term()?;
384        while self.match_token(&[TokenType::Lt, TokenType::Gt, TokenType::Lte, TokenType::Gte]) {
385            let op = match self.previous().token_type {
386                TokenType::Lt => BinaryOp::Lt,
387                TokenType::Gt => BinaryOp::Gt,
388                TokenType::Lte => BinaryOp::Lte,
389                TokenType::Gte => BinaryOp::Gte,
390                _ => unreachable!(),
391            };
392            let right = self.term()?;
393            expr = Expr::Binary { left: Box::new(expr), op, right: Box::new(right) };
394        }
395        Ok(expr)
396    }
397
398    fn term(&mut self) -> Result<Expr, String> {
399        let mut expr = self.factor()?;
400        while self.match_token(&[TokenType::Plus, TokenType::Minus]) {
401            let op = match self.previous().token_type {
402                TokenType::Plus => BinaryOp::Add,
403                TokenType::Minus => BinaryOp::Sub,
404                _ => unreachable!(),
405            };
406            let right = self.factor()?;
407            expr = Expr::Binary { left: Box::new(expr), op, right: Box::new(right) };
408        }
409        Ok(expr)
410    }
411
412    fn factor(&mut self) -> Result<Expr, String> {
413        let mut expr = self.unary()?;
414        while self.match_token(&[TokenType::Star, TokenType::Slash, TokenType::Percent]) {
415            let op = match self.previous().token_type {
416                TokenType::Star => BinaryOp::Mul,
417                TokenType::Slash => BinaryOp::Div,
418                TokenType::Percent => BinaryOp::Mod,
419                _ => unreachable!(),
420            };
421            let right = self.unary()?;
422            expr = Expr::Binary { left: Box::new(expr), op, right: Box::new(right) };
423        }
424        Ok(expr)
425    }
426
427fn unary(&mut self) -> Result<Expr, String> {
428    if self.match_token(&[TokenType::Minus, TokenType::Not, TokenType::Bang]) {
429        let op = match self.previous().token_type {
430            TokenType::Minus => UnaryOp::Neg,
431            TokenType::Not => UnaryOp::Not,
432            TokenType::Bang => UnaryOp::Not, // ! as logical not or macro prefix
433            _ => unreachable!(),
434        };
435        let expr = self.unary()?;
436        Ok(Expr::Unary { op, expr: Box::new(expr) })
437    } else {
438        self.call()
439    }
440}
441
442    fn call(&mut self) -> Result<Expr, String> {
443        let mut expr = self.primary()?;
444        loop {
445            if self.match_token(&[TokenType::LParen]) {
446                let mut args = Vec::new();
447                if !self.check(&TokenType::RParen) {
448                    loop {
449                        args.push(self.expression()?);
450                        if !self.match_token(&[TokenType::Comma]) {
451                            break;
452                        }
453                    }
454                }
455                self.consume(&TokenType::RParen, "Expected ')' after arguments")?;
456                expr = Expr::Call { callee: Box::new(expr), args };
457            } else if self.match_token(&[TokenType::Dot, TokenType::Scope]) {
458                let property = self.consume_identifier("Expected property name after namespace access")?;
459                expr = Expr::Member { object: Box::new(expr), property };
460            } else if self.match_token(&[TokenType::LBracket]) {
461                let index = self.expression()?;
462                self.consume(&TokenType::RBracket, "Expected ']' after index")?;
463                expr = Expr::Index { object: Box::new(expr), index: Box::new(index) };
464            } else {
465                break;
466            }
467        }
468        Ok(expr)
469    }
470
471    fn primary(&mut self) -> Result<Expr, String> {
472        if self.match_token(&[TokenType::Null]) {
473            Ok(Expr::Null)
474        } else if self.match_token(&[TokenType::Bool(true)]) {
475            Ok(Expr::Bool(true))
476        } else if self.match_token(&[TokenType::Bool(false)]) {
477            Ok(Expr::Bool(false))
478        } else if let Some(TokenType::Number(n)) = self.peek_token_type() {
479            let n = *n;
480            self.advance();
481            Ok(Expr::Number(n))
482        } else if let Some(TokenType::String(s)) = self.peek_token_type() {
483            let s = s.clone();
484            self.advance();
485            Ok(Expr::String(s))
486        } else if self.match_token(&[TokenType::LBracket]) {
487            let mut elements = Vec::new();
488            if !self.check(&TokenType::RBracket) {
489                loop {
490                    elements.push(self.expression()?);
491                    if !self.match_token(&[TokenType::Comma]) {
492                        break;
493                    }
494                }
495            }
496            self.consume(&TokenType::RBracket, "Expected ']' after array elements")?;
497            Ok(Expr::Array(elements))
498        } else if self.match_token(&[TokenType::LBrace]) {
499            let mut pairs = Vec::new();
500            if !self.check(&TokenType::RBrace) {
501                loop {
502                    let key = self.consume_identifier("Expected object key")?;
503                    self.consume(&TokenType::Colon, "Expected ':' after object key")?;
504                    let value = self.expression()?;
505                    pairs.push((key, value));
506                    if !self.match_token(&[TokenType::Comma]) {
507                        break;
508                    }
509                }
510            }
511            self.consume(&TokenType::RBrace, "Expected '}' after object pairs")?;
512            Ok(Expr::Object(pairs))
513        } else if self.match_token(&[TokenType::Fn]) {
514            self.consume(&TokenType::LParen, "Expected '(' after 'fn'")?;
515            let mut params = Vec::new();
516            if !self.check(&TokenType::RParen) {
517                loop {
518                    params.push(self.consume_identifier("Expected parameter name")?);
519                    if !self.match_token(&[TokenType::Comma]) {
520                        break;
521                    }
522                }
523            }
524            self.consume(&TokenType::RParen, "Expected ')' after parameters")?;
525            let body = match self.block()? {
526                Stmt::Block(stmts) => stmts,
527                s => vec![s],
528            };
529            Ok(Expr::Lambda { params, body })
530        } else if let Some(TokenType::Identifier(name)) = self.peek_token_type() {
531            let name = name.clone();
532            self.advance();
533            Ok(Expr::Identifier(name))
534        } else {
535            Err(format!("Unexpected token: {:?}", self.peek()))
536        }
537    }
538
539    // Helper methods
540    fn match_token(&mut self, types: &[TokenType]) -> bool {
541        for t in types {
542            if self.check(t) {
543                self.advance();
544                return true;
545            }
546        }
547        false
548    }
549
550    fn check(&self, token_type: &TokenType) -> bool {
551        if self.is_at_end() {
552            return false;
553        }
554        token_matches(&self.peek().token_type, token_type)
555    }
556
557    fn advance(&mut self) -> &Token {
558        if !self.is_at_end() {
559            self.current += 1;
560        }
561        self.previous()
562    }
563
564    fn is_at_end(&self) -> bool {
565        matches!(self.peek().token_type, TokenType::Eof)
566    }
567
568    fn peek(&self) -> &Token {
569        &self.tokens[self.current]
570    }
571
572    fn peek_token_type(&self) -> Option<&TokenType> {
573        if self.is_at_end() {
574            None
575        } else {
576            Some(&self.peek().token_type)
577        }
578    }
579
580    fn previous(&self) -> &Token {
581        &self.tokens[self.current - 1]
582    }
583
584    fn consume(&mut self, token_type: &TokenType, message: &str) -> Result<(), String> {
585        if self.check(token_type) {
586            self.advance();
587            Ok(())
588        } else {
589            Err(format!("{} at line {}, column {} (got {:?})", 
590                message, self.peek().line, self.peek().column, self.peek().token_type))
591        }
592    }
593
594    fn consume_identifier(&mut self, message: &str) -> Result<String, String> {
595        if let Some(TokenType::Identifier(name)) = self.peek_token_type() {
596            let name = name.clone();
597            self.advance();
598            Ok(name)
599        } else {
600            Err(format!("{} at line {}, column {} (got {:?})", 
601                message, self.peek().line, self.peek().column, self.peek().token_type))
602        }
603    }
604
605    fn consume_semicolon(&mut self) {
606        self.match_token(&[TokenType::Semicolon]);
607    }
608}
609
610fn token_matches(actual: &TokenType, expected: &TokenType) -> bool {
611    match (actual, expected) {
612        (TokenType::Comment(_), TokenType::Comment(_)) => true,
613        (TokenType::LParen, TokenType::LeftParen) | (TokenType::LeftParen, TokenType::LParen) => true,
614        (TokenType::RParen, TokenType::RightParen) | (TokenType::RightParen, TokenType::RParen) => true,
615        (TokenType::LBrace, TokenType::LeftBrace) | (TokenType::LeftBrace, TokenType::LBrace) => true,
616        (TokenType::RBrace, TokenType::RightBrace) | (TokenType::RightBrace, TokenType::RBrace) => true,
617        (a, b) => std::mem::discriminant(a) == std::mem::discriminant(b),
618    }
619}
620
621pub fn parse(tokens: &[Token]) -> Result<Vec<Stmt>, String> {
622    let mut parser = Parser::new(tokens.to_vec());
623    parser.parse()
624}
625