diff --git a/src/ast.rs b/src/ast.rs index a5fbae01..99868273 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -77,8 +77,8 @@ impl Stmt { /// like math and logical operations or values. #[derive(Debug)] pub struct Expr { - kind: ExprKind, - span: Span, + pub kind: ExprKind, + pub span: Span, } #[derive(Debug)] @@ -116,7 +116,6 @@ pub enum BinOpKind { impl BinOpKind { pub fn from_token(t: crate::lexer::Token) -> Result { use crate::lexer::Token; - use crate::error::*; match t { Token::Plus => Ok(Self::Add), @@ -129,7 +128,7 @@ impl BinOpKind { Token::NotEqual => Ok(Self::NotEqual), Token::And => Ok(Self::And), Token::Or => Ok(Self::Or), - t=> Err(ErrorKind::UnexpectedToken(t)), + t => Err(crate::error::ErrorKind::UnexpectedToken(t)), } } } diff --git a/src/lexer.rs b/src/lexer.rs index 2ac317e2..143aa6f3 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -76,11 +76,11 @@ pub enum Token { /// Brain fuck FFI #[token("bff")] - BfFunction, + Bff, /// Variable bro #[token("var")] - Variable, + Var, /// Prints the preceding things #[token("print")] @@ -187,7 +187,7 @@ mod tests { LeftParen, RightParen, LeftCurly, - Variable, + Var, Identifier("a".to_owned()), Equal, Integer(3), diff --git a/src/parser.rs b/src/parser.rs index c3c2f2ce..13f7ca36 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -48,6 +48,29 @@ impl<'source> Parser<'source> { self.functio_flow()?, start..self.lexer.span().end, )), + Token::Var => Ok(Stmt::new(self.var_flow()?, start..self.lexer.span().end)), + Token::Melo => Ok(Stmt::new(self.melo_flow()?, start..self.lexer.span().end)), + Token::Loop => Ok(Stmt::new(self.loop_flow()?, start..self.lexer.span().end)), + Token::Break => Ok(Stmt::new( + self.semi_terminated(StmtKind::Break)?, + start..self.lexer.span().end, + )), + Token::HopBack => Ok(Stmt::new( + self.semi_terminated(StmtKind::HopBack)?, + start..self.lexer.span().end, + )), + + Token::Identifier(_) + | Token::Char + | Token::String(_) + | Token::Integer(_) + | Token::Abool(_) + | Token::Bool(_) + | Token::LeftParen => Ok(Stmt::new( + self.value_flow(token)?, + start..self.lexer.span().end, + )), + t => Err(Error { kind: ErrorKind::UnexpectedToken(t), span: start..self.lexer.span().end, @@ -55,6 +78,14 @@ impl<'source> Parser<'source> { } } + /// Require statement to be semicolon terminated + /// + /// Utility function for short statements + fn semi_terminated(&mut self, stmt_kind: StmtKind) -> Result { + self.require(Token::Semicolon)?; + Ok(stmt_kind) + } + /// Require next item to be equal with expected one fn require(&mut self, expected: Token) -> Result<(), Error> { match self.lexer.next() { @@ -121,11 +152,8 @@ impl<'source> Parser<'source> { | Token::GreaterThan | Token::And | Token::Or => Ok(Expr::new( - self.op_flow( - match BinOpKind::from_token(token) { - Ok(op) => op, - Err(e) => return Err(Error::new(e, self.lexer.span())), - }, + self.binop_flow( + BinOpKind::from_token(token).map_err(|e| Error::new(e, self.lexer.span()))?, buf, )?, start..self.lexer.span().end, @@ -151,7 +179,7 @@ impl<'source> Parser<'source> { /// Generates operation from LHS buffer and next expression as RHS /// /// This is unaware of precedence, as AbleScript do not have it - fn op_flow(&mut self, kind: BinOpKind, lhs: &mut Option) -> Result { + fn binop_flow(&mut self, kind: BinOpKind, lhs: &mut Option) -> Result { Ok(ExprKind::BinOp { lhs: Box::new( lhs.take() @@ -177,7 +205,7 @@ impl<'source> Parser<'source> { } /// Parse a list of statements between curly braces - fn parse_block(&mut self) -> Result { + fn get_block(&mut self) -> Result { self.require(Token::LeftCurly)?; let mut block = vec![]; @@ -190,6 +218,31 @@ impl<'source> Parser<'source> { Ok(Block { block }) } + /// If Statement parser gets any kind of value (Identifier or Literal) + /// It cannot parse it as it do not parse expressions. Instead of it it + /// will parse it to function call or print statement. + fn value_flow(&mut self, init: Token) -> Result { + let mut buf = Some(self.parse_expr(init, &mut None)?); + let r = loop { + match self.lexer.next().ok_or(Error::unexpected_eof())? { + Token::Print => break StmtKind::Print(buf.take().unwrap()), + Token::LeftParen => { + if let Some(Expr { + kind: ExprKind::Variable(iden), + span, + }) = buf + { + break self.functio_call_flow(Iden::new(iden, span))?; + } + } + t => buf = Some(self.parse_expr(t, &mut buf)?), + } + }; + self.require(Token::Semicolon)?; + + Ok(r) + } + /// Parse If flow /// /// Consists of condition and block, there is no else @@ -198,7 +251,7 @@ impl<'source> Parser<'source> { let cond = self.expr_flow(Token::RightParen)?; - let body = self.parse_block()?; + let body = self.get_block()?; Ok(StmtKind::If { cond, body }) } @@ -233,8 +286,63 @@ impl<'source> Parser<'source> { } } - let body = self.parse_block()?; + let body = self.get_block()?; Ok(StmtKind::Functio { iden, args, body }) } + + /// Parse functio call flow + fn functio_call_flow(&mut self, iden: Iden) -> Result { + let mut args = vec![]; + let mut buf = None; + loop { + match self.lexer.next().ok_or(Error::unexpected_eof())? { + Token::RightParen => { + if let Some(expr) = buf.take() { + args.push(expr) + } + break; + } + Token::Comma => match buf.take() { + Some(expr) => args.push(expr), + None => { + return Err(Error::new( + ErrorKind::UnexpectedToken(Token::Comma), + self.lexer.span(), + )) + } + }, + t => buf = Some(self.parse_expr(t, &mut buf)?), + } + } + + Ok(StmtKind::Call { iden, args }) + } + + /// Parse variable declaration + fn var_flow(&mut self) -> Result { + let iden = self.get_iden()?; + let init = match self.lexer.next().ok_or(Error::unexpected_eof())? { + Token::Equal => Some(self.expr_flow(Token::Semicolon)?), + Token::Semicolon => None, + t => return Err(Error::new(ErrorKind::UnexpectedToken(t), self.lexer.span())), + }; + + Ok(StmtKind::Var { iden, init }) + } + + /// Parse Melo flow + fn melo_flow(&mut self) -> Result { + let iden = self.get_iden()?; + self.semi_terminated(StmtKind::Melo(iden)) + } + + /// Parse loop flow + /// + /// `loop` is an infinite loop, no condition, only body + fn loop_flow(&mut self) -> Result { + Ok(StmtKind::Loop { + body: self.get_block()?, + }) + } }