From 48cb1f72782b773b7d91aac87284722e44c8d11b Mon Sep 17 00:00:00 2001 From: annieversary Date: Sun, 26 Sep 2021 18:49:46 +0200 Subject: [PATCH] added statements, but this isn't working --- src/ast.rs | 3 +- src/main.rs | 10 +-- src/parser.rs | 184 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 178 insertions(+), 19 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 7416045..3cf73da 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -24,9 +24,10 @@ pub enum BinOp { GreaterThan, } +#[derive(Debug, PartialEq, Clone)] pub enum Stmt { Expr(Expr), - Var(Identifier, Expr), + Let(Identifier, Expr), Assign(Identifier, Expr), If(Expr, Vec), While(Expr, Vec), diff --git a/src/main.rs b/src/main.rs index c40c57c..06281da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,10 +2,12 @@ mod ast; mod parser; fn main() { - let a = r#"1 + a < 9 - <- chan"#; - let (rest, res) = parser::expr(a).unwrap(); + let a = r#" + if (n < 2) { + return n; + } + "#; + let (rest, res) = parser::stmt(a).unwrap(); dbg!(res); dbg!(rest); - - println!("Hello, world!"); } diff --git a/src/parser.rs b/src/parser.rs index adc1082..7ba70f6 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,7 +2,7 @@ use nom::{ branch::alt, bytes::complete::{escaped, is_not, tag, take_until}, character::complete::{alpha1, alphanumeric1, char, multispace0, one_of, space0}, - combinator::{cut, map, recognize, value}, + combinator::{cut, map, opt, recognize, value}, error::ParseError, multi::{fold_many0, many0, separated_list0}, number::complete::double, @@ -18,7 +18,6 @@ where { alt((value((), multispace0), pinline_comment, peol_comment))(i) } - fn pinline_comment<'a, E>(i: &'a str) -> IResult<&'a str, (), E> where E: ParseError<&'a str>, @@ -30,32 +29,33 @@ fn peol_comment<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, (), value((), pair(char('/'), is_not("\n\r")))(i) } +fn semi(i: &str) -> IResult<&str, &str> { + preceded(sc, tag(";"))(i) +} + fn braces<'a, P, O, E>(a: P) -> impl FnMut(&'a str) -> IResult<&'a str, O, E> where P: Parser<&'a str, O, E>, E: ParseError<&'a str>, { - delimited(char('{'), a, char('}')) + map(tuple((tag("{"), sc, a, sc, tag("}"))), |(_, _, a, _, _)| a) } - fn parens<'a, P, O, E>(a: P) -> impl FnMut(&'a str) -> IResult<&'a str, O, E> where P: Parser<&'a str, O, E>, E: ParseError<&'a str>, { - delimited( - tuple((tag("("), recognize(sc))), - a, - tuple((recognize(sc), tag(")"))), - ) + map(tuple((tag("("), sc, a, sc, tag(")"))), |(_, _, a, _, _)| a) } - fn identifier(i: &str) -> IResult<&str, &str> { println!("identifier: {}", i); - recognize(pair( - alt((alpha1, tag("_"))), - many0(alt((alphanumeric1, tag("_")))), - ))(i) + preceded( + sc, + recognize(pair( + alt((alpha1, tag("_"))), + many0(alt((alphanumeric1, tag("_")))), + )), + )(i) } fn variable(i: &str) -> IResult<&str, Expr> { @@ -193,6 +193,113 @@ pub fn expr<'a>(i: &'a str) -> IResult<&'a str, Expr> { binary(i) } +fn if_stmt(i: &str) -> IResult<&str, Stmt> { + println!("if: {}", i); + map( + tuple((tag("if"), sc, parens(expr), sc, braces(many0(stmt)))), + |(_, _, expr, _, stmts)| Stmt::If(expr, stmts), + )(i) +} +fn while_stmt(i: &str) -> IResult<&str, Stmt> { + println!("while: {}", i); + map( + tuple((tag("while"), sc, parens(expr), sc, braces(many0(stmt)))), + |(_, _, expr, _, stmts)| Stmt::While(expr, stmts), + )(i) +} +fn let_stmt(i: &str) -> IResult<&str, Stmt> { + println!("let: {}", i); + map( + tuple(( + tag("let"), + sc, + identifier, + tuple((sc, tag("="), sc)), + expr, + semi, + )), + |(_, _, id, _, expr, _)| Stmt::Let(id.to_string(), expr), + )(i) +} +fn yield_stmt(i: &str) -> IResult<&str, Stmt> { + println!("yield: {}", i); + map(tuple((tag("yield"), semi)), |_| Stmt::Yield)(i) +} +fn spawn_stmt(i: &str) -> IResult<&str, Stmt> { + println!("spawn: {}", i); + map(tuple((tag("spawn"), sc, expr, semi)), |(_, _, expr, _)| { + Stmt::Spawn(expr) + })(i) +} +fn return_stmt(i: &str) -> IResult<&str, Stmt> { + println!("return: {}", i); + map( + tuple((tag("return"), sc, opt(expr), semi)), + |(_, _, expr, _)| Stmt::Return(expr), + )(i) +} +fn func_stmt(i: &str) -> IResult<&str, Stmt> { + println!("func: {}", i); + map( + tuple(( + tag("fn"), + sc, + identifier, + sc, + alt(( + value(vec![], tuple((char('('), sc, char(')')))), + delimited( + char('('), + separated_list0( + tuple((sc, tag(","), sc)), + map(identifier, |a| a.to_string()), + ), + char(')'), + ), + )), + sc, + braces(many0(stmt)), + )), + |(_, _, id, _, params, _, stmts)| Stmt::Func(id.to_string(), params, stmts), + )(i) +} +fn assign_stmt(i: &str) -> IResult<&str, Stmt> { + println!("assign: {}", i); + map( + tuple((identifier, tuple((sc, tag("="), sc)), expr, semi)), + |(id, _, expr, _)| Stmt::Assign(id.to_string(), expr), + )(i) +} +fn send_stmt(i: &str) -> IResult<&str, Stmt> { + println!("send: {}", i); + map( + tuple((expr, tuple((sc, tag("->"), sc)), identifier, semi)), + |(expr, _, id, _)| Stmt::Send(expr, id.to_string()), + )(i) +} +fn expr_stmt(i: &str) -> IResult<&str, Stmt> { + println!("expr: {}", i); + map(tuple((expr, semi)), |(expr, _)| Stmt::Expr(expr))(i) +} + +pub fn stmt(i: &str) -> IResult<&str, Stmt> { + preceded( + sc, + alt(( + if_stmt, + while_stmt, + let_stmt, + yield_stmt, + spawn_stmt, + return_stmt, + func_stmt, + assign_stmt, + send_stmt, + expr_stmt, + )), + )(i) +} + #[cfg(test)] mod tests { use super::*; @@ -396,4 +503,53 @@ mod tests { ); assert_eq!(rest, ""); } + + #[test] + fn can_parse_let_stmt() { + let a = r#"let a = 0;"#; + let (rest, res) = stmt(a).unwrap(); + + assert_eq!(res, Stmt::Let("a".to_string(), Expr::LNum(0.0))); + assert_eq!(rest, ""); + } + + #[test] + fn can_parse_if_stmt() { + let a = r#" + if (n < 2) { + return n; + } +"#; + let (rest, res) = stmt(a).unwrap(); + + assert_eq!( + res, + Stmt::If( + Expr::Binary( + BinOp::LessThan, + Box::new(Expr::Var("n".to_string())), + Box::new(Expr::LNum(2.0)), + ), + vec![Stmt::Return(Some(Expr::Var("n".to_string())))] + ) + ); + assert_eq!(rest, ""); + } + + #[test] + fn can_parse_func() { + let a = r#" +fn fib(n) { + if (n < 2) { + return n; + } + return fib(n - 2) + + fib(n - 1); +} +"#; + let (rest, res) = stmt(a).unwrap(); + + assert_eq!(res, Stmt::Let("a".to_string(), Expr::LNum(0.0))); + assert_eq!(rest, ""); + } }