Skip to main content

ternlang_core/
parser.rs

1use crate::lexer::Token;
2use crate::ast::*;
3use logos::{Logos, Lexer};
4
5pub struct Parser<'a> {
6    lex: Lexer<'a, Token>,
7}
8
9#[derive(Debug)]
10pub enum ParseError {
11    UnexpectedToken(String),
12    ExpectedToken(String, String),
13    InvalidTrit(String),
14    NonExhaustiveMatch(String),
15}
16
17impl std::fmt::Display for ParseError {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        match self {
20            Self::UnexpectedToken(tok) =>
21                write!(f, "[PARSE-001] Unexpected token '{tok}' — the lexer hit something it didn't expect. Binary habit? Check 'fn' vs 'func', trit vs bool.\n            → details: stdlib/errors/PARSE-001.tern  |  ternlang errors PARSE-001"),
22            Self::ExpectedToken(expected, found) =>
23                write!(f, "[PARSE-002] Expected {expected} but found '{found}'. Missing type annotation, brace, or semicolon?\n            → details: stdlib/errors/PARSE-002.tern  |  ternlang errors PARSE-002"),
24            Self::InvalidTrit(val) =>
25                write!(f, "[PARSE-003] '{val}' is not a valid trit. Trits are -1, 0, or +1 — the universe has exactly three states.\n            → details: stdlib/errors/PARSE-003.tern  |  ternlang errors PARSE-003"),
26            Self::NonExhaustiveMatch(msg) =>
27                write!(f, "[PARSE-004] Non-exhaustive match: {msg}. Ternary has three states — cover -1, 0, and +1 or the compiler won't let you through.\n            → details: stdlib/errors/PARSE-004.tern  |  ternlang errors PARSE-004"),
28        }
29    }
30}
31
32impl<'a> Parser<'a> {
33    pub fn new(input: &'a str) -> Self {
34        Self { lex: Token::lexer(input) }
35    }
36
37    pub fn parse_program(&mut self) -> Result<Program, ParseError> {
38        let mut imports = Vec::new();
39        let mut import_specs = Vec::new();
40        let mut structs = Vec::new();
41        let mut agents = Vec::new();
42        let mut functions = Vec::new();
43        let mut toplevel_stmts: Vec<Stmt> = Vec::new();
44
45        while self.peek_token().is_ok() {
46            match self.peek_token()? {
47                Token::Use => {
48                    if let Stmt::Use { path } = self.parse_stmt()? {
49                        imports.push(path);
50                    }
51                }
52                Token::From => {
53                    if let Stmt::FromImport { spec } = self.parse_stmt()? {
54                        import_specs.push(spec);
55                    }
56                }
57                Token::Struct => structs.push(self.parse_struct_def()?),
58                Token::Agent  => agents.push(self.parse_agent_def()?),
59                Token::Fn | Token::At => functions.push(self.parse_function()?),
60                // Top-level statements (scripts / snippets without explicit fn main)
61                _ => toplevel_stmts.push(self.parse_stmt()?),
62            }
63        }
64
65        // Wrap any top-level statements in a synthetic fn main() -> trit { ... }
66        // only when no explicit main function is defined.
67        if !toplevel_stmts.is_empty() && !functions.iter().any(|f| f.name == "main") {
68            functions.push(Function {
69                name: "main".to_string(),
70                params: vec![],
71                return_type: Type::Trit,
72                body: toplevel_stmts,
73                directive: None,
74            });
75        }
76
77        Ok(Program { imports, import_specs, structs, agents, functions })
78    }
79
80    fn parse_agent_def(&mut self) -> Result<AgentDef, ParseError> {
81        self.expect(Token::Agent)?;
82        let name = match self.next_token()? {
83            Token::Ident(n) => n,
84            t => return Err(ParseError::ExpectedToken("agent name".into(), format!("{:?}", t))),
85        };
86        self.expect(Token::LBrace)?;
87        let mut methods = Vec::new();
88        while self.peek_token()? != Token::RBrace {
89            methods.push(self.parse_function()?);
90        }
91        self.expect(Token::RBrace)?;
92        Ok(AgentDef { name, methods })
93    }
94
95    fn parse_struct_def(&mut self) -> Result<StructDef, ParseError> {
96        self.expect(Token::Struct)?;
97        let name = match self.next_token()? {
98            Token::Ident(n) => n,
99            t => return Err(ParseError::ExpectedToken("struct name".into(), format!("{:?}", t))),
100        };
101        self.expect(Token::LBrace)?;
102        let mut fields = Vec::new();
103        while self.peek_token()? != Token::RBrace {
104            let field_name = match self.next_token()? {
105                Token::Ident(n) => n,
106                t => return Err(ParseError::ExpectedToken("field name".into(), format!("{:?}", t))),
107            };
108            self.expect(Token::Colon)?;
109            let field_type = self.parse_type()?;
110            fields.push((field_name, field_type));
111            if let Ok(Token::Comma) = self.peek_token() { self.next_token()?; }
112        }
113        self.expect(Token::RBrace)?;
114        Ok(StructDef { name, fields })
115    }
116
117    pub fn parse_function(&mut self) -> Result<Function, ParseError> {
118        let directive = if let Ok(Token::At) = self.peek_token() {
119            self.next_token()?;
120            let dir = match self.next_token()? {
121                Token::SparseSkip  => "sparseskip".to_string(),
122                Token::Ident(n)    => n,
123                t => return Err(ParseError::ExpectedToken("directive".into(), format!("{:?}", t))),
124            };
125            Some(dir)
126        } else {
127            None
128        };
129
130        self.expect(Token::Fn)?;
131        let name = match self.next_token()? {
132            Token::Ident(n) => n,
133            t => return Err(ParseError::ExpectedToken("function name".into(), format!("{:?}", t))),
134        };
135
136        self.expect(Token::LParen)?;
137        let mut params = Vec::new();
138        if self.peek_token()? != Token::RParen {
139            loop {
140                let p_name = match self.next_token()? {
141                    Token::Ident(n) => n,
142                    t => return Err(ParseError::ExpectedToken("parameter name".into(), format!("{:?}", t))),
143                };
144                self.expect(Token::Colon)?;
145                let p_type = self.parse_type()?;
146                params.push((p_name, p_type));
147                if self.peek_token()? == Token::Comma { self.next_token()?; } else { break; }
148            }
149        }
150        self.expect(Token::RParen)?;
151        self.expect(Token::Arrow)?;
152        let return_type = self.parse_type()?;
153        let body = match self.parse_block()? {
154            Stmt::Block(stmts) => stmts,
155            _ => unreachable!(),
156        };
157        Ok(Function { name, params, return_type, body, directive })
158    }
159
160    fn next_token(&mut self) -> Result<Token, ParseError> {
161        self.lex.next()
162            .map(|res| res.map_err(|_| ParseError::UnexpectedToken("Invalid token".into())))
163            .transpose()?
164            .ok_or(ParseError::UnexpectedToken("EOF".into()))
165    }
166
167    fn peek_token(&mut self) -> Result<Token, ParseError> {
168        let mut cloned = self.lex.clone();
169        cloned.next()
170            .map(|res| res.map_err(|_| ParseError::UnexpectedToken("Invalid token".into())))
171            .transpose()?
172            .ok_or(ParseError::UnexpectedToken("EOF".into()))
173    }
174
175    pub fn parse_expr(&mut self) -> Result<Expr, ParseError> {
176        self.parse_binary_expr(0)
177    }
178
179    fn parse_binary_expr(&mut self, min_prec: i8) -> Result<Expr, ParseError> {
180        let mut lhs = self.parse_unary_expr()?;
181        loop {
182            let Ok(op_token) = self.peek_token() else { break };
183            if op_token == Token::RBrace || op_token == Token::Comma || op_token == Token::RParen || op_token == Token::Semicolon || op_token == Token::Return { break; }
184            let prec = self.get_precedence(&op_token);
185            if prec < min_prec { break; }
186            self.next_token()?;
187            let rhs = self.parse_binary_expr(prec + 1)?;
188            lhs = Expr::BinaryOp {
189                op: self.token_to_binop(op_token),
190                lhs: Box::new(lhs),
191                rhs: Box::new(rhs),
192            };
193        }
194        Ok(lhs)
195    }
196
197    fn get_precedence(&self, token: &Token) -> i8 {
198        match token {
199            Token::Or                      => 0,
200            Token::And                     => 1,
201            Token::Equal | Token::NotEqual => 2,
202            Token::LAngle | Token::RAngle  => 2, // Comparisons
203            Token::LessEqual | Token::GreaterEqual => 2,
204            Token::Plus  | Token::Minus    => 3,
205            Token::Star | Token::Slash | Token::Percent => 4,
206            _ => -1,
207        }
208    }
209
210    fn token_to_binop(&self, token: Token) -> BinOp {
211        match token {
212            Token::Plus     => BinOp::Add,
213            Token::Minus    => BinOp::Sub,
214            Token::Star     => BinOp::Mul,
215            Token::Slash    => BinOp::Div,
216            Token::Percent  => BinOp::Mod,
217            Token::Equal    => BinOp::Equal,
218            Token::NotEqual => BinOp::NotEqual,
219            Token::And      => BinOp::And,
220            Token::Or       => BinOp::Or,
221            Token::LAngle   => BinOp::Less,
222            Token::RAngle   => BinOp::Greater,
223            Token::LessEqual => BinOp::LessEqual,
224            Token::GreaterEqual => BinOp::GreaterEqual,
225            _ => unreachable!(),
226        }
227    }
228
229    /// Parse unary prefix expressions, then wrap with postfix (field access, indexing, `?`).
230    fn parse_unary_expr(&mut self) -> Result<Expr, ParseError> {
231        let mut expr = self.parse_primary_expr()?;
232        loop {
233            match self.peek_token()? {
234                Token::Dot => {
235                    self.next_token()?; // consume `.`
236                    let field = match self.next_token()? {
237                        Token::Ident(n) => n,
238                        t => return Err(ParseError::ExpectedToken("field name".into(), format!("{:?}", t))),
239                    };
240                    expr = Expr::FieldAccess { object: Box::new(expr), field };
241                }
242                Token::LBracket => {
243                    self.next_token()?; // consume `[`
244                    let row = self.parse_expr()?;
245                    if let Ok(Token::Comma) = self.peek_token() {
246                        self.next_token()?; // consume `,`
247                        let col = self.parse_expr()?;
248                        self.expect(Token::RBracket)?;
249                        expr = Expr::Index { object: Box::new(expr), row: Box::new(row), col: Box::new(col) };
250                    } else {
251                        self.expect(Token::RBracket)?;
252                        // Use row as the single index, 0 as column (for 1D logic in VM)
253                        expr = Expr::Index { object: Box::new(expr), row: Box::new(row), col: Box::new(Expr::IntLiteral(0)) };
254                    }
255                }
256                Token::UncertainBranch => {
257                    // Postfix `?` — ternary error propagation.
258                    // Disambiguate from `if cond ? { }`: if the token after `?` is `{`, this
259                    // `?` belongs to the enclosing if/while statement — don't consume it.
260                    let mut lookahead = self.lex.clone();
261                    lookahead.next(); // skip `?`
262                    let after_q = lookahead.next();
263                    let is_uncertain_branch = matches!(after_q, Some(Ok(Token::LBrace)));
264                    if !is_uncertain_branch {
265                        self.next_token()?; // consume `?`
266                        expr = Expr::Propagate { expr: Box::new(expr) };
267                    } else {
268                        break;
269                    }
270                }
271                _ => break,
272            }
273        }
274        Ok(expr)
275    }
276
277    fn parse_primary_expr(&mut self) -> Result<Expr, ParseError> {
278        let token = self.next_token()?;
279        match token {
280            // spawn AgentName           — local agent
281            // spawn remote "addr" Name  — remote agent (Phase 5.1)
282            Token::Spawn => {
283                let node_addr = if let Ok(Token::Remote) = self.peek_token() {
284                    self.next_token()?; // consume `remote`
285                    match self.next_token()? {
286                        Token::StringLit(addr) => Some(addr),
287                        t => return Err(ParseError::ExpectedToken("node address string".into(), format!("{:?}", t))),
288                    }
289                } else {
290                    None
291                };
292                let agent_name = match self.next_token()? {
293                    Token::Ident(n) => n,
294                    t => return Err(ParseError::ExpectedToken("agent name".into(), format!("{:?}", t))),
295                };
296                Ok(Expr::Spawn { agent_name, node_addr })
297            }
298            // await <agentref_expr> — receive from agent mailbox
299            Token::Await => {
300                let target = self.parse_unary_expr()?;
301                Ok(Expr::Await { target: Box::new(target) })
302            }
303            Token::NodeId => Ok(Expr::NodeId),
304            Token::Minus => {
305                let expr = self.parse_unary_expr()?;
306                Ok(Expr::UnaryOp { op: UnOp::Neg, expr: Box::new(expr) })
307            }
308            Token::LBracket => {
309                let mut vals = Vec::new();
310                loop {
311                    match self.next_token()? {
312                        Token::TritLiteral => {
313                            let s = self.lex.slice();
314                            let v = s.parse::<i8>().unwrap_or(0);
315                            vals.push(v);
316                        }
317                        Token::Int(v) => vals.push(v as i8),
318                        Token::Minus => {
319                            match self.next_token()? {
320                                Token::Int(v) => vals.push(-(v as i8)),
321                                t => return Err(ParseError::UnexpectedToken(format!("tensor literal element after '-': {:?}", t))),
322                            }
323                        }
324                        Token::Affirm => vals.push(1),
325                        Token::Tend => vals.push(0),
326                        Token::Reject => vals.push(-1),
327                        t => return Err(ParseError::UnexpectedToken(format!("tensor literal element: {:?}", t))),
328                    }
329                    if self.peek_token()? == Token::Comma {
330                        self.next_token()?;
331                    } else {
332                        break;
333                    }
334                }
335                self.expect(Token::RBracket)?;
336                Ok(Expr::TritTensorLiteral(vals))
337            }
338            Token::TritLiteral => {
339                let slice = self.lex.slice();
340                let val = slice.parse::<i8>()
341                    .map_err(|_| ParseError::InvalidTrit(slice.to_string()))?;
342                Ok(Expr::TritLiteral(val))
343            }
344            // Semantic trit keywords: affirm=+1, tend=0, reject=-1
345            Token::Affirm => Ok(Expr::TritLiteral(1)),
346            Token::Tend   => Ok(Expr::TritLiteral(0)),
347            Token::Reject => Ok(Expr::TritLiteral(-1)),
348            Token::Int(val) => Ok(Expr::IntLiteral(val)),
349            Token::Float(val) => Ok(Expr::FloatLiteral(val)),
350            Token::StringLit(s) => Ok(Expr::StringLiteral(s)),
351            Token::Ident(name) => {
352                // cast(expr) built-in: returns Cast node
353                if name == "cast" {
354                    if let Ok(Token::LParen) = self.peek_token() {
355                        self.next_token()?;
356                        let inner = self.parse_expr()?;
357                        self.expect(Token::RParen)?;
358                        // Type is resolved by context (the let binding ty)
359                        // Emit with placeholder Trit — semantic pass refines this
360                        return Ok(Expr::Cast { expr: Box::new(inner), ty: Type::Trit });
361                    }
362                }
363
364                if let Ok(Token::LParen) = self.peek_token() {
365                    // Function call
366                    self.next_token()?;
367                    let mut args = Vec::new();
368                    if self.peek_token()? != Token::RParen {
369                        loop {
370                            args.push(self.parse_expr()?);
371                            if self.peek_token()? == Token::Comma {
372                                self.next_token()?;
373                            } else {
374                                break;
375                            }
376                        }
377                    }
378                    self.expect(Token::RParen)?;
379                    Ok(Expr::Call { callee: name, args })
380                } else if let Ok(Token::LBrace) = self.peek_token() {
381                    // Struct literal: Name { field: val, ... }
382                    // Disambiguate from: if x { ... } or match x { ... }
383                    // Peek ahead: after '{', is it an 'ident :'?
384                    let mut lookahead = self.lex.clone();
385                    let _ = lookahead.next(); // consume '{'
386                    let maybe_ident = lookahead.next();
387                    let maybe_colon = lookahead.next();
388
389                    let is_struct_literal = matches!(maybe_ident, Some(Ok(Token::Ident(_)))) &&
390                                            matches!(maybe_colon, Some(Ok(Token::Colon)));
391
392                    if is_struct_literal {
393                        self.next_token()?; // consume `{`
394                        let mut fields = Vec::new();
395                        while self.peek_token()? != Token::RBrace {
396                            let f_name = match self.next_token()? {
397                                Token::Ident(n) => n,
398                                t => return Err(ParseError::ExpectedToken("field name".into(), format!("{:?}", t))),
399                            };
400                            self.expect(Token::Colon)?;
401                            let f_val = self.parse_expr()?;
402                            fields.push((f_name, f_val));
403                            if let Ok(Token::Comma) = self.peek_token() {
404                                self.next_token()?;
405                            } else {
406                                break;
407                            }
408                        }
409                        self.expect(Token::RBrace)?;
410                        Ok(Expr::StructLiteral { name, fields })
411                    } else {
412                        Ok(Expr::Ident(name))
413                    }
414                } else {
415                    Ok(Expr::Ident(name))
416                }
417            }
418            Token::LParen => {
419                let expr = self.parse_expr()?;
420                self.expect(Token::RParen)?;
421                Ok(expr)
422            }
423            _ => Err(ParseError::UnexpectedToken(format!("{:?}", token))),
424        }
425    }
426
427    pub fn parse_stmt(&mut self) -> Result<Stmt, ParseError> {
428        let token = self.peek_token()?;
429        match token {
430            Token::At => {
431                self.next_token()?;
432                let dir = match self.next_token()? {
433                    Token::SparseSkip  => "sparseskip".to_string(),
434                    Token::Ident(n)    => n,
435                    t => return Err(ParseError::ExpectedToken("directive".into(), format!("{:?}", t))),
436                };
437                let stmt = self.parse_stmt()?;
438                Ok(Stmt::Decorated { directive: dir, stmt: Box::new(stmt) })
439            }
440
441            Token::Use => {
442                self.next_token()?;
443                let mut path = Vec::new();
444                loop {
445                    // Accept both identifiers and reserved type keywords as path segments
446                    let segment = match self.next_token()? {
447                        Token::Ident(n)   => n,
448                        Token::TritType   => "trit".to_string(),
449                        Token::TritTensor => "trittensor".to_string(),
450                        t => return Err(ParseError::ExpectedToken("module path segment".into(), format!("{:?}", t))),
451                    };
452                    path.push(segment);
453                    if let Ok(Token::DoubleColon) = self.peek_token() {
454                        self.next_token()?;
455                    } else {
456                        break;
457                    }
458                }
459                self.expect(Token::Semicolon)?;
460                Ok(Stmt::Use { path })
461            }
462
463            // from <module::path | "file.tern"> import <name, name2 | *>;
464            Token::From => {
465                self.next_token()?;
466                // Determine source: string literal = file path, else module path
467                let source = match self.peek_token()? {
468                    Token::StringLit(_) => {
469                        if let Token::StringLit(s) = self.next_token()? {
470                            ImportSource::File(s)
471                        } else { unreachable!() }
472                    }
473                    _ => {
474                        let mut path = Vec::new();
475                        loop {
476                            let segment = match self.next_token()? {
477                                Token::Ident(n)   => n,
478                                Token::TritType   => "trit".to_string(),
479                                Token::TritTensor => "trittensor".to_string(),
480                                t => return Err(ParseError::ExpectedToken("module path segment".into(), format!("{:?}", t))),
481                            };
482                            path.push(segment);
483                            if let Ok(Token::DoubleColon) = self.peek_token() {
484                                self.next_token()?;
485                            } else {
486                                break;
487                            }
488                        }
489                        ImportSource::Module(path)
490                    }
491                };
492                self.expect(Token::Import)?;
493                // Parse names: `*` or comma-separated identifiers
494                let names = if let Ok(Token::Star) = self.peek_token() {
495                    self.next_token()?;
496                    ImportNames::Wildcard
497                } else {
498                    let mut named = Vec::new();
499                    loop {
500                        match self.next_token()? {
501                            Token::Ident(n) => named.push(n),
502                            t => return Err(ParseError::ExpectedToken("import name".into(), format!("{:?}", t))),
503                        }
504                        if let Ok(Token::Comma) = self.peek_token() {
505                            self.next_token()?;
506                        } else {
507                            break;
508                        }
509                    }
510                    ImportNames::Named(named)
511                };
512                self.expect(Token::Semicolon)?;
513                Ok(Stmt::FromImport { spec: ImportSpec { source, names } })
514            }
515
516            Token::Let => {
517                self.next_token()?;
518                // optional mut
519                let _mutable = if let Ok(Token::Mut) = self.peek_token() {
520                    self.next_token()?; true
521                } else { false };
522
523                let name = match self.next_token()? {
524                    Token::Ident(n) => n,
525                    t => return Err(ParseError::ExpectedToken("identifier".into(), format!("{:?}", t))),
526                };
527                self.expect(Token::Colon)?;
528                let ty = self.parse_type()?;
529                let value = if let Ok(Token::Assign) = self.peek_token() {
530                    self.next_token()?;
531                    self.parse_expr()?
532                } else {
533                    Expr::TritLiteral(0)
534                };
535                self.expect(Token::Semicolon)?;
536                Ok(Stmt::Let { name, ty, value })
537            }
538
539            Token::If => {
540                self.next_token()?;
541                let condition = self.parse_expr()?;
542                if let Ok(Token::UncertainBranch) = self.peek_token() {
543                    self.next_token()?;
544                    let on_pos  = Box::new(self.parse_block()?);
545                    self.expect(Token::Else)?;
546                    let on_zero = Box::new(self.parse_block()?);
547                    self.expect(Token::Else)?;
548                    let on_neg  = Box::new(self.parse_block()?);
549                    Ok(Stmt::IfTernary { condition, on_pos, on_zero, on_neg })
550                } else {
551                    // Binary if: if cond { A } else { B }
552                    // Maps to IfTernary(cond, A, B, B)
553                    let then_branch = Box::new(self.parse_block()?);
554                    let else_branch = if let Ok(Token::Else) = self.peek_token() {
555                        self.next_token()?;
556                        Box::new(self.parse_block()?)
557                    } else {
558                        Box::new(Stmt::Block(vec![]))
559                    };
560                    Ok(Stmt::IfTernary {
561                        condition,
562                        on_pos: then_branch,
563                        on_zero: else_branch.clone(),
564                        on_neg: else_branch,
565                    })
566                }
567            }
568
569            Token::Match => {
570                self.next_token()?;
571                let condition = self.parse_expr()?;
572                self.expect(Token::LBrace)?;
573                let mut arms = Vec::new();
574                while self.peek_token()? != Token::RBrace {
575                    let val = match self.next_token()? {
576                        Token::TritLiteral => {
577                            let slice = self.lex.slice();
578                            slice.parse::<i64>().map_err(|_| ParseError::InvalidTrit(slice.to_string()))?
579                        }
580                        Token::Int(v) => v,
581                        Token::Minus => {
582                            match self.next_token()? {
583                                Token::Int(v) => -v,
584                                t => return Err(ParseError::ExpectedToken("integer literal after '-'".into(), format!("{:?}", t))),
585                            }
586                        }
587                        Token::Affirm => 1,
588                        Token::Tend   => 0,
589                        Token::Reject => -1,
590                        t => return Err(ParseError::ExpectedToken("pattern (int or trit)".into(), format!("{:?}", t))),
591                    };
592                    self.expect(Token::FatArrow)?;
593                    let stmt = self.parse_stmt()?;
594                    arms.push((val, stmt));
595                }
596                self.expect(Token::RBrace)?;
597
598                Ok(Stmt::Match { condition, arms })
599            }
600
601            // for <var> in <expr> { body }
602            Token::For => {
603                self.next_token()?;
604                let var = match self.next_token()? {
605                    Token::Ident(n) => n,
606                    t => return Err(ParseError::ExpectedToken("loop variable".into(), format!("{:?}", t))),
607                };
608                self.expect(Token::In)?;
609                let iter = self.parse_expr()?;
610                let body = Box::new(self.parse_block()?);
611                Ok(Stmt::ForIn { var, iter, body })
612            }
613
614            // while <condition> [?] { on_pos } [else { on_zero } else { on_neg }]
615            Token::While => {
616                self.next_token()?;
617                let condition = self.parse_expr()?;
618                if let Ok(Token::UncertainBranch) = self.peek_token() {
619                    self.next_token()?;
620                    let on_pos  = Box::new(self.parse_block()?);
621                    self.expect(Token::Else)?;
622                    let on_zero = Box::new(self.parse_block()?);
623                    self.expect(Token::Else)?;
624                    let on_neg  = Box::new(self.parse_block()?);
625                    Ok(Stmt::WhileTernary { condition, on_pos, on_zero, on_neg })
626                } else {
627                    // Binary while: while cond { body }
628                    // Maps to WhileTernary(cond, body, Break, Break)
629                    let body = Box::new(self.parse_block()?);
630                    Ok(Stmt::WhileTernary {
631                        condition,
632                        on_pos: body,
633                        on_zero: Box::new(Stmt::Break),
634                        on_neg: Box::new(Stmt::Break),
635                    })
636                }
637            }
638
639            // loop { body }
640            Token::Loop => {
641                self.next_token()?;
642                let body = Box::new(self.parse_block()?);
643                Ok(Stmt::Loop { body })
644            }
645
646            // send <target_expr> <message_expr>;
647            Token::Send => {
648                self.next_token()?;
649                let target = self.parse_expr()?;
650                let message = self.parse_expr()?;
651                self.expect(Token::Semicolon)?;
652                Ok(Stmt::Send { target, message })
653            }
654
655            Token::Break => {
656                self.next_token()?;
657                self.expect(Token::Semicolon)?;
658                Ok(Stmt::Break)
659            }
660
661            Token::Continue => {
662                self.next_token()?;
663                self.expect(Token::Semicolon)?;
664                Ok(Stmt::Continue)
665            }
666
667            Token::Return => {
668                self.next_token()?;
669                let expr = self.parse_expr()?;
670                self.expect(Token::Semicolon)?;
671                Ok(Stmt::Return(expr))
672            }
673
674            Token::LBrace => self.parse_block(),
675
676            // BUG-L02 fix: 'fn' at statement level — do NOT consume the token.
677            // peek_token() was used above so the lexer is still positioned at 'fn'.
678            // Returning this error lets the fallback in main.rs detect it and call
679            // parse_function() directly, which expects 'fn' as its first token.
680            Token::Fn => Err(ParseError::UnexpectedToken("Fn".into())),
681
682            _ => {
683                // Could be: expr; OR assignment: ident.field = value; OR ident[row, col] = value;
684                let expr = self.parse_expr()?;
685
686                // Check for assignment
687                if let Ok(Token::Assign) = self.peek_token() {
688                    match expr {
689                        Expr::FieldAccess { object, field } => {
690                            if let Expr::Ident(obj_name) = *object {
691                                self.next_token()?; // consume `=`
692                                let value = self.parse_expr()?;
693                                self.expect(Token::Semicolon)?;
694                                return Ok(Stmt::FieldSet { object: obj_name, field, value });
695                            }
696                        }
697                        Expr::Index { object, row, col } => {
698                            if let Expr::Ident(obj_name) = *object {
699                                self.next_token()?; // consume `=`
700                                let value = self.parse_expr()?;
701                                self.expect(Token::Semicolon)?;
702                                return Ok(Stmt::IndexSet { object: obj_name, row: *row, col: *col, value });
703                            }
704                        }
705                        Expr::Ident(name) => {
706                            self.next_token()?; // consume `=`
707                            let value = self.parse_expr()?;
708                            self.expect(Token::Semicolon)?;
709                            return Ok(Stmt::Set { name, value });
710                        }
711                        _ => {}
712                    }
713                    return Err(ParseError::UnexpectedToken("invalid assignment target".into()));
714                }
715
716                self.expect(Token::Semicolon)?;
717                Ok(Stmt::Expr(expr))
718            }
719        }
720    }
721
722    fn parse_block(&mut self) -> Result<Stmt, ParseError> {
723        self.expect(Token::LBrace)?;
724        let mut stmts = Vec::new();
725        while self.peek_token()? != Token::RBrace {
726            stmts.push(self.parse_stmt()?);
727        }
728        self.expect(Token::RBrace)?;
729        Ok(Stmt::Block(stmts))
730    }
731
732    fn parse_type(&mut self) -> Result<Type, ParseError> {
733        let token = self.next_token()?;
734        match token {
735            Token::TritType   => {
736                if let Ok(Token::LBracket) = self.peek_token() {
737                    self.next_token()?;
738                    self.expect(Token::RBracket)?;
739                    Ok(Type::TritTensor { dims: vec![0] })
740                } else {
741                    Ok(Type::Trit)
742                }
743            }
744            Token::AgentRef   => Ok(Type::AgentRef),
745            Token::TritTensor => {
746                self.expect(Token::LAngle)?;
747                let mut dims = Vec::new();
748                loop {
749                    let d = match self.next_token()? {
750                        Token::Int(v) => v as usize,
751                        // TritLiteral matches "0" and "1" — accept them as dims
752                        Token::TritLiteral => {
753                            let s = self.lex.slice();
754                            s.parse::<i8>().unwrap_or(0).max(0) as usize
755                        }
756                        t => return Err(ParseError::ExpectedToken("dimension".into(), format!("{:?}", t))),
757                    };
758                    dims.push(d);
759                    if self.peek_token()? == Token::Ident("x".to_string()) {
760                        self.next_token()?;
761                    } else {
762                        break;
763                    }
764                }
765                self.expect(Token::RAngle)?;
766                Ok(Type::TritTensor { dims })
767            }
768            Token::Ident(ref name) => match name.as_str() {
769                "int"    => Ok(Type::Int),
770                "float"  => Ok(Type::Float),
771                "bool"   => Ok(Type::Bool),
772                "string" => Ok(Type::String),
773                // Named struct type
774                _        => Ok(Type::Named(name.clone())),
775            },
776            _ => Err(ParseError::UnexpectedToken(format!("{:?}", token))),
777        }
778    }
779
780    fn expect(&mut self, expected: Token) -> Result<(), ParseError> {
781        let token = self.next_token()?;
782        if token == expected {
783            Ok(())
784        } else {
785            Err(ParseError::ExpectedToken(format!("{:?}", expected), format!("{:?}", token)))
786        }
787    }
788}
789
790#[cfg(test)]
791mod tests {
792    use super::*;
793
794    #[test]
795    fn test_parse_function() {
796        let input = "fn invert(signal: trit) -> trit { return -signal; }";
797        let mut parser = Parser::new(input);
798        let func = parser.parse_function().unwrap();
799        assert_eq!(func.name, "invert");
800        assert_eq!(func.params[0].1, Type::Trit);
801        assert_eq!(func.return_type, Type::Trit);
802    }
803
804    #[test]
805    fn test_parse_match() {
806        let input = "match x { 1 => return 1; 0 => return 0; -1 => return -1; }";
807        let mut parser = Parser::new(input);
808        let stmt = parser.parse_stmt().unwrap();
809        if let Stmt::Match { arms, .. } = stmt {
810            assert_eq!(arms.len(), 3);
811            assert_eq!(arms[0].0, 1);
812            assert_eq!(arms[1].0, 0);
813            assert_eq!(arms[2].0, -1);
814        } else {
815            panic!("Expected Match");
816        }
817    }
818
819    #[test]
820    fn test_match_parses_non_exhaustive() {
821        // Missing hold (0) arm — now parses (exhaustiveness moved to semantic)
822        let input = "match x { 1 => return 1; -1 => return -1; }";
823        let mut parser = Parser::new(input);
824        let result = parser.parse_stmt();
825        assert!(result.is_ok(), "should parse successfully even if non-exhaustive");
826    }
827
828    #[test]
829    fn test_parse_for_loop() {
830        let input = "for item in weights { return item; }";
831        let mut parser = Parser::new(input);
832        let stmt = parser.parse_stmt().unwrap();
833        assert!(matches!(stmt, Stmt::ForIn { .. }));
834    }
835
836    #[test]
837    fn test_parse_loop_break() {
838        let input = "loop { break; }";
839        let mut parser = Parser::new(input);
840        let stmt = parser.parse_stmt().unwrap();
841        assert!(matches!(stmt, Stmt::Loop { .. }));
842    }
843
844    #[test]
845    fn test_parse_use() {
846        let input = "use std::trit;";
847        let mut parser = Parser::new(input);
848        let stmt = parser.parse_stmt().unwrap();
849        if let Stmt::Use { path } = stmt {
850            assert_eq!(path, vec!["std", "trit"]);
851        } else {
852            panic!("Expected Use");
853        }
854    }
855
856    #[test]
857    fn test_parse_mut_let() {
858        let input = "let mut signal: trit = 1;";
859        let mut parser = Parser::new(input);
860        let stmt = parser.parse_stmt().unwrap();
861        assert!(matches!(stmt, Stmt::Let { .. }));
862    }
863
864    #[test]
865    fn test_parse_struct_def() {
866        let input = "struct Signal { value: trit, weight: trit }";
867        let mut parser = Parser::new(input);
868        let s = parser.parse_struct_def().unwrap();
869        assert_eq!(s.name, "Signal");
870        assert_eq!(s.fields.len(), 2);
871        assert_eq!(s.fields[0], ("value".to_string(), Type::Trit));
872        assert_eq!(s.fields[1], ("weight".to_string(), Type::Trit));
873    }
874
875    #[test]
876    fn test_parse_field_access() {
877        let input = "let v: trit = sig.value;";
878        let mut parser = Parser::new(input);
879        let stmt = parser.parse_stmt().unwrap();
880        if let Stmt::Let { value: Expr::FieldAccess { field, .. }, .. } = stmt {
881            assert_eq!(field, "value");
882        } else {
883            panic!("Expected FieldAccess in let binding");
884        }
885    }
886
887    #[test]
888    fn test_parse_field_set() {
889        let input = "sig.value = 1;";
890        let mut parser = Parser::new(input);
891        let stmt = parser.parse_stmt().unwrap();
892        assert!(matches!(stmt, Stmt::FieldSet { .. }));
893    }
894
895    #[test]
896    fn test_parse_cast() {
897        let input = "let t: trit = cast(flag);";
898        let mut parser = Parser::new(input);
899        let stmt = parser.parse_stmt().unwrap();
900        if let Stmt::Let { value: Expr::Cast { .. }, .. } = stmt {
901            // ok
902        } else {
903            panic!("Expected Cast in let binding");
904        }
905    }
906
907    #[test]
908    fn test_parse_named_type() {
909        let input = "let s: Signal;";
910        let mut parser = Parser::new(input);
911        let stmt = parser.parse_stmt().unwrap();
912        if let Stmt::Let { ty: Type::Named(name), .. } = stmt {
913            assert_eq!(name, "Signal");
914        } else {
915            panic!("Expected Named type");
916        }
917    }
918
919    #[test]
920    fn test_parse_agent_def() {
921        let input = r#"
922            agent Voter {
923                fn handle(msg: trit) -> trit {
924                    match msg {
925                         1 => { return  1; }
926                         0 => { return  0; }
927                        -1 => { return -1; }
928                    }
929                }
930            }
931        "#;
932        let mut parser = Parser::new(input);
933        let agent = parser.parse_agent_def().unwrap();
934        assert_eq!(agent.name, "Voter");
935        assert_eq!(agent.methods.len(), 1);
936        assert_eq!(agent.methods[0].name, "handle");
937    }
938
939    #[test]
940    fn test_parse_spawn() {
941        let input = "let v: agentref = spawn Voter;";
942        let mut parser = Parser::new(input);
943        let stmt = parser.parse_stmt().unwrap();
944        if let Stmt::Let { ty: Type::AgentRef, value: Expr::Spawn { agent_name, node_addr }, .. } = stmt {
945            assert_eq!(agent_name, "Voter");
946            assert_eq!(node_addr, None);
947        } else {
948            panic!("Expected spawn in let binding");
949        }
950    }
951
952    #[test]
953    fn test_parse_spawn_remote() {
954        let input = r#"let v: agentref = spawn remote "10.0.0.1:7373" Voter;"#;
955        let mut parser = Parser::new(input);
956        let stmt = parser.parse_stmt().unwrap();
957        if let Stmt::Let { ty: Type::AgentRef, value: Expr::Spawn { agent_name, node_addr }, .. } = stmt {
958            assert_eq!(agent_name, "Voter");
959            assert_eq!(node_addr, Some("10.0.0.1:7373".to_string()));
960        } else {
961            panic!("Expected remote spawn in let binding");
962        }
963    }
964
965    #[test]
966    fn test_parse_send() {
967        let input = "send v 1;";
968        let mut parser = Parser::new(input);
969        let stmt = parser.parse_stmt().unwrap();
970        assert!(matches!(stmt, Stmt::Send { .. }));
971    }
972
973    #[test]
974    fn test_parse_await() {
975        let input = "let reply: trit = await v;";
976        let mut parser = Parser::new(input);
977        let stmt = parser.parse_stmt().unwrap();
978        if let Stmt::Let { value: Expr::Await { .. }, .. } = stmt {
979            // ok
980        } else {
981            panic!("Expected await in let binding");
982        }
983    }
984}