diff --git a/src/expr.rs b/src/expr.rs index 06da22a..6816fa1 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -30,8 +30,9 @@ pub fn infix_bp(op: &BinaryOp) -> (u8, u8) { #[derive(Debug, Clone)] pub enum Expr { Number(i64), + Bool(bool), Ident(String), - EOL, + StringLit(String), Binary { op: BinaryOp, @@ -42,6 +43,8 @@ pub enum Expr { Unary { op: UnaryOp, right: Box - } + }, + + EOL } diff --git a/src/main.rs b/src/main.rs index 608fb86..4ed9847 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,13 +2,14 @@ use std::{fs::File, io::Read}; mod token; mod expr; +mod stmt; mod lexer; mod error; use lexer::Lexer; mod parser; use parser::Parser; -mod eval; -use eval::Evaluator; +// mod eval; +// use eval::Evaluator; fn main() -> std::io::Result<()> { let args = std::env::args().collect::>(); @@ -30,17 +31,23 @@ fn main() -> std::io::Result<()> { println!("\n"); let mut parser = Parser::new(tokens); - loop { - let parsed = parser.parse().unwrap_or(expr::Expr::EOL); - match parsed { - expr::Expr::EOL => break, - _ => { - println!("AST: {:?}", parsed); - let eval = Evaluator::new(parsed); - println!("Eval: {:?}", eval.eval()); - } - } + let parsed = parser.parse(); + match parsed { + Ok(parsed) => println!("AST: {:?}", parsed), + Err(e) => eprintln!("{e}") } + + // loop { + // let parsed = parser.parse().unwrap_or(Vec::new()); + // match parsed { + // expr::Expr::EOL => break, + // _ => { + // println!("AST: {:?}", parsed); + // // let eval = Evaluator::new(parsed); + // // println!("Eval: {:?}", eval.eval()); + // } + // } + // } Ok(()) } diff --git a/src/parser.rs b/src/parser.rs index 181b4fa..09e5d36 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,6 @@ use crate::token::Token; use crate::expr::{Expr, UnaryOp, BinaryOp, infix_bp, prefix_bp}; +use crate::stmt::{CondOp, Condition, Stmt}; use crate::error::ParseError; type ParseResult = Result; @@ -40,9 +41,19 @@ impl Parser { } } + fn expect_ident(&mut self) -> ParseResult { + match self.next() { + Some(Token::Ident(ident)) => Ok(ident), + other => Err(ParseError::new(format!( + "expected identifier, got {other:?}" + ))) + } + } + fn parse_atom(&mut self) -> ParseResult { match self.next() { Some(Token::Number(n)) => Ok(Expr::Number(n)), + Some(Token::StringLit(s)) => Ok(Expr::StringLit(s)), Some(Token::Ident(id)) => Ok(Expr::Ident(id)), Some(Token::LParen) => { let expr = self.parse_expr(0)?; @@ -102,8 +113,164 @@ impl Parser { Ok(lhs) } - pub fn parse(&mut self) -> ParseResult { - if self.peek().is_none() {return Ok(Expr::EOL)} - self.parse_expr(0) + fn parse_block(&mut self) -> ParseResult> { + self.expect(&Token::LBrace)?; + let mut stmts = Vec::new(); + while !matches!(self.peek(), Some(Token::RBrace) | None) { + stmts.push(self.parse_stmt()?); + } + self.expect(&Token::RBrace)?; + Ok(stmts) + } + + fn parse_condition(&mut self) -> ParseResult { + let op = match self.next() { + Some(Token::Eq) => CondOp::Eq, + Some(Token::Neq) => CondOp::Neq, + Some(Token::Lt) => CondOp::Lt, + Some(Token::Gt) => CondOp::Gt, + Some(Token::Lte) => CondOp::Lte, + Some(Token::Gte) => CondOp::Gte, + tok => return Err(ParseError::new(format!( + "expected condition operator, got {tok:?}" + ))) + }; + + let left = self.parse_expr(0)?; + self.expect(&Token::Comma)?; + let right = self.parse_expr(0)?; + + Ok(Condition { op, left, right }) + } + + fn parse_mov(&mut self) -> ParseResult { + self.expect(&Token::Mov)?; + let src = self.parse_expr(0)?; + self.expect(&Token::Comma)?; + let dst = self.expect_ident()?; + self.expect(&Token::Semicolon)?; + Ok(Stmt::Mov { src, dst }) + } + + fn parse_ifelse(&mut self) -> ParseResult { + self.expect(&Token::If)?; + let condition = self.parse_condition()?; + let then = if matches!(self.peek(), Some(Token::LBrace)) { + self.parse_block()? + } else { + self.expect(&Token::Comma)?; + vec![self.parse_stmt()?] + }; + + let else_ = if matches!(self.peek(), Some(Token::Else)) { + self.advance(); + Some(if matches!(self.peek(), Some(Token::LBrace)) { + self.parse_block()? + } else { + vec![self.parse_stmt()?] + }) + } else { + None + }; + + Ok(Stmt::IfElse { condition, then, else_ }) + } + + fn parse_loop(&mut self) -> ParseResult { + self.expect(&Token::Loop)?; + let body = self.parse_block()?; + Ok(Stmt::Loop { body }) + } + + fn parse_while(&mut self) -> ParseResult { + self.expect(&Token::While)?; + let condition = self.parse_condition()?; + let body = self.parse_block()?; + Ok(Stmt::While { condition, body }) + } + + fn parse_for(&mut self) -> ParseResult { + self.expect(&Token::For)?; + let var = self.expect_ident()?; + + match self.peek() { + Some(Token::In) => { + self.advance(); + let list = self.parse_expr(0)?; + let body = self.parse_block()?; + Ok(Stmt::ForIn { var, list, body }) + }, + Some(Token::Comma) => { + self.advance(); + let start = self.parse_expr(0)?; + self.expect(&Token::DotDot)?; + let end = self.parse_expr(0)?; + let step = if matches!(self.peek(), Some(Token::Comma)) { + self.advance(); + Some(self.parse_expr(0)?) + } else { + None + }; + let body = self.parse_block()?; + Ok(Stmt::ForRange { var, start, end, step, body }) + }, + tok => Err(ParseError::new(format!( + "expected 'in' or ',' after for variable, got {tok:?}" + ))) + } + } + + fn parse_call(&mut self) -> ParseResult { + self.expect(&Token::Call)?; + let name = self.expect_ident()?; + let mut args = Vec::new(); + while matches!(self.peek(), Some(Token::Comma)) { + self.advance(); + args.push(self.parse_expr(0)?); + } + self.expect(&Token::Semicolon)?; + Ok(Stmt::Call { name, args }) + } + + fn parse_func_def(&mut self) -> ParseResult { + self.expect(&Token::Fun)?; + let name = self.expect_ident()?; + let mut params = Vec::new(); + while matches!(self.peek(), Some(Token::Comma)) { + self.advance(); + params.push(self.expect_ident()?); + } + let body = self.parse_block()?; + Ok(Stmt::FuncDef { name, params, body }) + } + + fn parse_stmt(&mut self) -> ParseResult { + match self.peek() { + Some(Token::Mov) => self.parse_mov(), + Some(Token::If) => self.parse_ifelse(), + Some(Token::Loop) => self.parse_loop(), + Some(Token::While) => self.parse_while(), + Some(Token::For) => self.parse_for(), + Some(Token::Call) => self.parse_call(), + Some(Token::Fun) => self.parse_func_def(), + Some(Token::Break) => { self.advance(); self.expect(&Token::Semicolon)?; Ok(Stmt::Break) }, + Some(Token::Continue) => { self.advance(); self.expect(&Token::Semicolon)?; Ok(Stmt::Continue) }, + tok => Err(ParseError::new(format!( + "expected start of statement, got {tok:?}" + ))) + } + } + + pub fn parse(&mut self) -> ParseResult> { + let mut stmts = Vec::new(); + + while self.peek().is_some() { + match self.parse_stmt() { + Ok(stmt) => stmts.push(stmt), + Err(e) => return Err(e) + } + } + + Ok(stmts) } } \ No newline at end of file diff --git a/src/stmt.rs b/src/stmt.rs new file mode 100644 index 0000000..2affe49 --- /dev/null +++ b/src/stmt.rs @@ -0,0 +1,32 @@ +use crate::expr::Expr; + +#[derive(Debug)] +pub enum CondOp { + Eq, + Neq, + Lt, + Gt, + Lte, + Gte +} + +#[derive(Debug)] +pub struct Condition { + pub op: CondOp, + pub left: Expr, + pub right: Expr +} + +#[derive(Debug)] +pub enum Stmt { + Mov { src: Expr, dst: String }, + IfElse { condition: Condition, then: Vec, else_: Option> }, + Loop { body: Vec }, + While { condition: Condition, body: Vec }, + ForRange { var: String, start: Expr, end: Expr, step: Option, body: Vec }, + ForIn { var: String, list: Expr, body: Vec }, + Call { name: String, args: Vec }, + FuncDef { name: String, params: Vec, body: Vec }, + Break, + Continue +} \ No newline at end of file