This commit is contained in:
minish 2025-07-11 03:02:03 -04:00
parent 29b8d9644f
commit 21616e2723
Signed by: min
SSH Key Fingerprint: SHA256:h4k7JNrfe1dzv1WE3oGVeAY9DPSZXIu3/j89+6DtHWE
3 changed files with 29 additions and 3 deletions

View File

@ -47,6 +47,8 @@ pub enum Token {
Comma, Comma,
Eol, Eol,
If,
Else,
Return, Return,
Not, Not,
@ -68,6 +70,7 @@ pub enum Token {
pub enum Precedence { pub enum Precedence {
Min, Min,
Return, Return,
If,
Assign, Assign,
Logical, Logical,
Equality, Equality,
@ -86,6 +89,7 @@ impl Token {
pub fn prefix_precedence(&self) -> Option<Precedence> { pub fn prefix_precedence(&self) -> Option<Precedence> {
Some(match self { Some(match self {
Token::Return => Precedence::Return, Token::Return => Precedence::Return,
Token::If => Precedence::If,
Token::Minus | Token::Not => Precedence::NegateNot, Token::Minus | Token::Not => Precedence::NegateNot,
_ => return None, _ => return None,
}) })
@ -192,6 +196,8 @@ where
match word.as_str() { match word.as_str() {
"return" => Token::Return, "return" => Token::Return,
"if" => Token::If,
"else" => Token::Else,
"true" => Token::Literal(Literal::Boolean(true)), "true" => Token::Literal(Literal::Boolean(true)),
"false" => Token::Literal(Literal::Boolean(false)), "false" => Token::Literal(Literal::Boolean(false)),
"nil" => Token::Literal(Literal::Nil), "nil" => Token::Literal(Literal::Nil),

View File

@ -12,6 +12,7 @@ pub enum Expr {
// Runtime datatypes // Runtime datatypes
Block(Block), Block(Block),
// Control flow // Control flow
If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
Return(Box<Expr>), Return(Box<Expr>),
Call(Box<Expr>, Vec<Expr>), Call(Box<Expr>, Vec<Expr>),
// Unary operations // Unary operations
@ -137,6 +138,19 @@ where
Token::Minus => Expr::Negate(rhs), Token::Minus => Expr::Negate(rhs),
Token::Not => Expr::Not(rhs), Token::Not => Expr::Not(rhs),
Token::Return => Expr::Return(rhs), Token::Return => Expr::Return(rhs),
Token::If => {
// parse the true case
let true_case = self.parse_expr(Precedence::Min, false)?;
// and maybe a false case
let false_case = matches!(self.try_peek(), Ok(Token::Else))
.then(|| {
self.eat();
self.parse_expr(Precedence::Min, false)
})
.transpose()?;
// pack
Expr::If(rhs, true_case, false_case)
}
_ => unreachable!(), _ => unreachable!(),
}) })
} }
@ -238,15 +252,14 @@ where
match self.try_peek() { match self.try_peek() {
// end (block) // end (block)
Ok(Token::CurlyClose) if in_block => break, Ok(Token::CurlyClose) if in_block => break,
// end (stream) lpwkey idk if this is a good way to check for error // end (stream)
// need to add error nodes anyway so whatever
Err(ParseError::UnexpectedEnd) if !in_block => break, Err(ParseError::UnexpectedEnd) if !in_block => break,
// try to parse expr // try to parse expr
Ok(_) => exprs.push(*self.parse_expr(Precedence::Min, false)?), Ok(_) => exprs.push(*self.parse_expr(Precedence::Min, false)?),
// invalid // invalid
Err(err) => return Err(err), Err(_) => unreachable!(),
} }
} }
Ok(Block { exprs }) Ok(Block { exprs })

View File

@ -31,6 +31,13 @@ fn fmt_expr(e: Expr, depth: usize) -> String {
result.push(')'); result.push(')');
result result
} }
Expr::If(c, t, f) => {
let mut result = format!("if ({}) ({})", fmt_expr(*c, depth), fmt_expr(*t, depth));
if let Some(f) = f {
result.push_str(&format!(" else ({})", fmt_expr(*f, depth)));
}
result
}
Expr::Return(l) => format!("return {}", fmt_expr(*l, depth)), Expr::Return(l) => format!("return {}", fmt_expr(*l, depth)),
Expr::Block(b) => { Expr::Block(b) => {
let mut result = String::new(); let mut result = String::new();