Add base statement parsing

Assign statements and standalone expression statements are added, plus
some tests.

Additionally, starting tokens are implemented using lazy_static!{} so
that they can be mixed and matched.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-05-06 16:57:28 -04:00
parent 7698e49baf
commit 66af3dcc53
2 changed files with 190 additions and 15 deletions

View File

@@ -95,6 +95,7 @@ pub enum BaseExprKind {
List(Vec<Expr>), List(Vec<Expr>),
Object(Vec<(Expr, Expr)>), Object(Vec<(Expr, Expr)>),
Tuple(Vec<Expr>), Tuple(Vec<Expr>),
Block(Vec<Stmt>),
} }
#[derive(Derivative, Clone, PartialEq, Eq)] #[derive(Derivative, Clone, PartialEq, Eq)]

View File

@@ -1,7 +1,9 @@
use crate::syn::{ast::*, error::*, lexer::Lexer, op::*, span::*, token::*}; use crate::syn::{ast::*, error::*, lexer::Lexer, op::*, span::*, token::*};
use lazy_static::lazy_static;
use std::{convert::TryFrom, mem}; use std::{convert::TryFrom, mem};
const BASE_EXPR_START: &[TokenKind] = &[ lazy_static! {
static ref BASE_EXPR_START: Vec<TokenKind> = vec![
TokenKind::Ident, TokenKind::Ident,
TokenKind::Num, TokenKind::Num,
TokenKind::Str, TokenKind::Str,
@@ -11,8 +13,16 @@ const BASE_EXPR_START: &[TokenKind] = &[
TokenKind::LBrace, TokenKind::LBrace,
TokenKind::ObjBrace, TokenKind::ObjBrace,
]; ];
static ref UN_EXPR_START: Vec<TokenKind> =
vec![TokenKind::Plus, TokenKind::Minus, TokenKind::Bang];
static ref EXPR_START: Vec<TokenKind> = {
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<TokenKind> = vec![TokenKind::Eol, TokenKind::Newline];
}
pub struct Parser<'t> { pub struct Parser<'t> {
lexer: Lexer<'t>, lexer: Lexer<'t>,
@@ -66,9 +76,54 @@ impl<'t> Parser<'t> {
// Statement parsing // Statement parsing
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
impl<'t> Parser<'t> { impl<'t> Parser<'t> {
pub fn next_stmt(&mut self) -> Result<Stmt> { pub fn next_stmt(&mut self) -> Result<Option<Stmt>> {
// 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<Vec<Stmt>> {
todo!() todo!()
} }
/// Parses a list of statements.
pub fn next_body(&mut self) -> Result<Vec<Stmt>> {
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) => { ($name:ident, $op_tokens:expr, $next:ident) => {
fn $name(&mut self) -> Result<Expr> { fn $name(&mut self) -> Result<Expr> {
let lhs = self.$next()?; 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 op = BinOp::from(token);
let rhs = self.$name()?; let rhs = self.$name()?;
let span = lhs.span().union(rhs.span()); let span = lhs.span().union(rhs.span());
@@ -122,7 +177,7 @@ impl<'t> Parser<'t> {
); );
fn next_un_expr(&mut self) -> Result<Expr> { fn next_un_expr(&mut self) -> Result<Expr> {
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 start = un_op.span();
let expr = self.next_un_expr()?; let expr = self.next_un_expr()?;
let end = expr.span(); let end = expr.span();
@@ -140,7 +195,7 @@ impl<'t> Parser<'t> {
fn next_base_expr(&mut self) -> Result<Expr> { fn next_base_expr(&mut self) -> Result<Expr> {
let token = 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() { let expr: Expr = match token.kind() {
TokenKind::Ident => BaseExpr { TokenKind::Ident => BaseExpr {
kind: BaseExprKind::Ident, kind: BaseExprKind::Ident,
@@ -179,6 +234,7 @@ impl<'t> Parser<'t> {
TokenKind::ObjBrace => { TokenKind::ObjBrace => {
let prev_skip = self.set_skip_newlines(true)?; let prev_skip = self.set_skip_newlines(true)?;
let object = self.next_obj_list()?; let object = self.next_obj_list()?;
self.set_skip_newlines(prev_skip)?;
let end_token = let end_token =
self.expect_token_kind(TokenKind::RBrace, "end of object (right curly brace)")?; self.expect_token_kind(TokenKind::RBrace, "end of object (right curly brace)")?;
let span = token.span().union(end_token.span()); 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<Option<Token>> {
if self.is_any_token_kind(kinds) {
self.adv_token()
} else {
Ok(None)
}
}
fn is_token_match<P>(&self, pred: P) -> bool fn is_token_match<P>(&self, pred: P) -> bool
where where
P: Fn(Token) -> bool, P: Fn(Token) -> bool,
@@ -317,6 +381,10 @@ impl<'t> Parser<'t> {
self.is_token_match(|t| t.kind() == kind) 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<P>(&mut self, pred: P, expected: impl ToString) -> Result<Token> fn expect_token_where<P>(&mut self, pred: P, expected: impl ToString) -> Result<Token>
where where
P: Fn(Token) -> bool, P: Fn(Token) -> bool,
@@ -335,6 +403,18 @@ impl<'t> Parser<'t> {
fn expect_token_kind(&mut self, kind: TokenKind, expected: impl ToString) -> Result<Token> { fn expect_token_kind(&mut self, kind: TokenKind, expected: impl ToString) -> Result<Token> {
self.expect_token_where(|t| t.kind() == kind, expected) self.expect_token_where(|t| t.kind() == kind, expected)
} }
fn expect_any_token_kind(&mut self, kinds: &[TokenKind], expected: impl ToString) -> Result<Token> {
self.expect_token_where(|t| kinds.contains(&t.kind()), expected)
}
fn expect_eol_or_eof(&mut self, expected: impl ToString) -> Result<Option<Token>> {
if self.curr_token.is_none() {
Ok(None)
} else {
self.expect_any_token_kind(&EOL, expected).map(Some)
}
}
} }
impl<'t> Spanned for Parser<'t> { impl<'t> Spanned for Parser<'t> {
@@ -446,6 +526,10 @@ mod test {
}; };
} }
////////////////////////////////////////////////////////////////////////////////
// Expr testing
////////////////////////////////////////////////////////////////////////////////
fn bin_expr(lhs: Expr, op: BinOp, rhs: Expr) -> Expr { fn bin_expr(lhs: Expr, op: BinOp, rhs: Expr) -> Expr {
Expr::Bin( Expr::Bin(
BinExpr { 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)
)
)
))
);
}
} }