diff --git a/src/syn/ast.rs b/src/syn/ast.rs index 9ad1fdb..23ddcb3 100644 --- a/src/syn/ast.rs +++ b/src/syn/ast.rs @@ -95,6 +95,7 @@ pub enum BaseExprKind { List(Vec), Object(Vec<(Expr, Expr)>), Tuple(Vec), + Block(Vec), } #[derive(Derivative, Clone, PartialEq, Eq)] diff --git a/src/syn/parser.rs b/src/syn/parser.rs index 803a776..22b2b69 100644 --- a/src/syn/parser.rs +++ b/src/syn/parser.rs @@ -1,18 +1,28 @@ use crate::syn::{ast::*, error::*, lexer::Lexer, op::*, span::*, token::*}; +use lazy_static::lazy_static; use std::{convert::TryFrom, mem}; -const BASE_EXPR_START: &[TokenKind] = &[ - TokenKind::Ident, - TokenKind::Num, - TokenKind::Str, - TokenKind::Sym, - TokenKind::LParen, - TokenKind::LBracket, - TokenKind::LBrace, - TokenKind::ObjBrace, -]; +lazy_static! { + static ref BASE_EXPR_START: Vec = vec![ + TokenKind::Ident, + TokenKind::Num, + TokenKind::Str, + TokenKind::Sym, + TokenKind::LParen, + TokenKind::LBracket, + TokenKind::LBrace, + TokenKind::ObjBrace, + ]; + static ref UN_EXPR_START: Vec = + vec![TokenKind::Plus, TokenKind::Minus, TokenKind::Bang]; + static ref EXPR_START: Vec = { + let mut start = BASE_EXPR_START.clone(); + start.extend(UN_EXPR_START.iter()); + start + }; -const UN_EXPR_START: &[TokenKind] = &[TokenKind::Plus, TokenKind::Minus, TokenKind::Bang]; + static ref EOL: Vec = vec![TokenKind::Eol, TokenKind::Newline]; +} pub struct Parser<'t> { lexer: Lexer<'t>, @@ -66,9 +76,54 @@ impl<'t> Parser<'t> { // Statement parsing //////////////////////////////////////////////////////////////////////////////// impl<'t> Parser<'t> { - pub fn next_stmt(&mut self) -> Result { + pub fn next_stmt(&mut self) -> Result> { + // skip any leading EOL tokens + while self.match_any_token_kind(&EOL)?.is_some() {} + + if self.is_eof() { + return Ok(None); + } + + if self.is_any_token_kind(&EXPR_START) { + let expr = self.next_expr()?; + if self.match_token_kind(TokenKind::Eq)?.is_some() { + let rhs = self.next_expr()?; + self.expect_eol_or_eof("end-of-line after assignment")?; + let span = expr.span().union(rhs.span()); + Ok(Some(Stmt::Assign(AssignStmt { lhs: expr, rhs, span, }))) + } else { + // TODO catch EOF + self.expect_eol_or_eof("end-of-line after expression")?; + Ok(Some(Stmt::Expr(expr))) + } + } else { + Ok(None) + } + } + + /// Parses a brace-enclosed list of statements. + pub fn next_block(&mut self) -> Result> { todo!() } + + /// Parses a list of statements. + pub fn next_body(&mut self) -> Result> { + let mut body = Vec::new(); + + if self.is_token_kind(TokenKind::RBrace) { + // end of body token + return Ok(body); + } + + while let Some(stmt) = self.next_stmt()? { + body.push(stmt); + if self.is_token_kind(TokenKind::RBrace) { + // end of body token + break; + } + } + Ok(body) + } } //////////////////////////////////////////////////////////////////////////////// @@ -79,7 +134,7 @@ macro_rules! bin_expr { ($name:ident, $op_tokens:expr, $next:ident) => { fn $name(&mut self) -> Result { let lhs = self.$next()?; - if let Some(token) = self.match_token_where(|t| $op_tokens.contains(&t.kind()))? { + if let Some(token) = self.match_any_token_kind($op_tokens)? { let op = BinOp::from(token); let rhs = self.$name()?; let span = lhs.span().union(rhs.span()); @@ -122,7 +177,7 @@ impl<'t> Parser<'t> { ); fn next_un_expr(&mut self) -> Result { - if let Some(un_op) = self.match_token_where(|t| UN_EXPR_START.contains(&t.kind()))? { + if let Some(un_op) = self.match_any_token_kind(&UN_EXPR_START)? { let start = un_op.span(); let expr = self.next_un_expr()?; let end = expr.span(); @@ -140,7 +195,7 @@ impl<'t> Parser<'t> { fn next_base_expr(&mut self) -> Result { let token = - self.expect_token_where(|t| BASE_EXPR_START.contains(&t.kind()), "base expression")?; + self.expect_any_token_kind(&BASE_EXPR_START, "base expression")?; let expr: Expr = match token.kind() { TokenKind::Ident => BaseExpr { kind: BaseExprKind::Ident, @@ -179,6 +234,7 @@ impl<'t> Parser<'t> { TokenKind::ObjBrace => { let prev_skip = self.set_skip_newlines(true)?; let object = self.next_obj_list()?; + self.set_skip_newlines(prev_skip)?; let end_token = self.expect_token_kind(TokenKind::RBrace, "end of object (right curly brace)")?; let span = token.span().union(end_token.span()); @@ -303,6 +359,14 @@ impl<'t> Parser<'t> { } } + fn match_any_token_kind(&mut self, kinds: &[TokenKind]) -> Result> { + if self.is_any_token_kind(kinds) { + self.adv_token() + } else { + Ok(None) + } + } + fn is_token_match

(&self, pred: P) -> bool where P: Fn(Token) -> bool, @@ -317,6 +381,10 @@ impl<'t> Parser<'t> { self.is_token_match(|t| t.kind() == kind) } + fn is_any_token_kind(&self, kinds: &[TokenKind]) -> bool { + self.is_token_match(|t| kinds.contains(&t.kind())) + } + fn expect_token_where

(&mut self, pred: P, expected: impl ToString) -> Result where P: Fn(Token) -> bool, @@ -335,6 +403,18 @@ impl<'t> Parser<'t> { fn expect_token_kind(&mut self, kind: TokenKind, expected: impl ToString) -> Result { self.expect_token_where(|t| t.kind() == kind, expected) } + + fn expect_any_token_kind(&mut self, kinds: &[TokenKind], expected: impl ToString) -> Result { + self.expect_token_where(|t| kinds.contains(&t.kind()), expected) + } + + fn expect_eol_or_eof(&mut self, expected: impl ToString) -> Result> { + if self.curr_token.is_none() { + Ok(None) + } else { + self.expect_any_token_kind(&EOL, expected).map(Some) + } + } } impl<'t> Spanned for Parser<'t> { @@ -446,6 +526,10 @@ mod test { }; } + //////////////////////////////////////////////////////////////////////////////// + // Expr testing + //////////////////////////////////////////////////////////////////////////////// + fn bin_expr(lhs: Expr, op: BinOp, rhs: Expr) -> Expr { Expr::Bin( BinExpr { @@ -779,4 +863,94 @@ mod test { )])) ); } + + //////////////////////////////////////////////////////////////////////////////// + // Stmt testing + //////////////////////////////////////////////////////////////////////////////// + + fn assign_stmt(lhs: Expr, rhs: Expr) -> Stmt { + Stmt::Assign( + AssignStmt { + lhs, + rhs, + span: Default::default(), + } + ) + } + + #[test] + fn test_assign_stmt() { + test_parser!( + Parser::try_from( + r" + a = 1 + + b = :sym + " + ).unwrap(), + next_stmt, + Some(assign_stmt( + base_expr(BaseExprKind::Ident), + base_expr(BaseExprKind::Num), + )), + next_stmt, + Some(assign_stmt( + base_expr(BaseExprKind::Ident), + base_expr(BaseExprKind::Sym), + )) + ); + } + + #[test] + fn test_expr_stmt() { + test_parser!( + Parser::try_from( + r" + a + 'b' + :sym + 1 + " + ).unwrap(), + next_stmt, + Some(Stmt::Expr ( + base_expr(BaseExprKind::Ident), + )), + next_stmt, + Some(Stmt::Expr ( + base_expr(BaseExprKind::Str), + )), + next_stmt, + Some(Stmt::Expr ( + base_expr(BaseExprKind::Sym), + )), + next_stmt, + Some(Stmt::Expr ( + base_expr(BaseExprKind::Num), + )) + ); + + test_parser!( + Parser::try_from( + r" + (a + + + 1 + * + 3)" + ).unwrap(), + next_stmt, + Some(Stmt::Expr( + bin_expr( + base_expr(BaseExprKind::Ident), + BinOp::Plus, + bin_expr( + base_expr(BaseExprKind::Num), + BinOp::Times, + base_expr(BaseExprKind::Num) + ) + ) + )) + ); + } }