use super::{Expectable, Parser, Position, SyntaxError}; type Ident = String; #[derive(Debug, Clone)] pub struct ParsedReid(pub Expression); #[derive(Debug, Clone)] pub enum Statement { LetStatement(Position, Ident, Box), ExprStatement(Position, Expression), } impl Statement { pub fn parse(parser: &mut Parser) -> Result { let pos = parser.pos(); if parser.expect_static("let").get().is_some() { let ident = parser .expect_ident() .get_or(SyntaxError::ExpectedIdent(pos))?; parser .expect_static("=") .get_or(SyntaxError::ExpectedToken(pos, '='))?; match Expression::parse(parser, true) { Ok(expr) => { parser .expect_static(";") .get_or(SyntaxError::ExpectedToken(pos, ';'))?; Ok(Statement::LetStatement(pos, ident, Box::new(expr))) } Err(err) => Err(SyntaxError::ExpectedExpression(pos, Some(Box::new(err)))), } } else { match Expression::parse(parser, true) { Ok(expr) => { let statement = Statement::ExprStatement(pos, expr); parser .expect_static(";") .get_or(SyntaxError::ExpectedToken(pos, ';'))?; Ok(statement) } Err(err) => Err(SyntaxError::ExpectedStatement(pos, Some(Box::new(err)))), } } } } #[derive(Debug, Clone)] pub enum Expression { BlockExpr(Position, Vec), FunctionCall(Position, Ident, Vec), ArithmeticExpression(Position, Box), ValueRef(Position, Pattern), } impl Expression { pub fn parse(parser: &mut Parser, allow_arithmetic: bool) -> Result { let begin_pos = parser.pos(); let first = if parser.expect_static("{").get().is_some() { let mut statement_list = Vec::new(); while { match Statement::parse(parser) { Ok(exp) => { statement_list.push(exp); true } Err(_) => false, } } {} if parser.expect_static("}").get().is_some() { Ok(Expression::BlockExpr(begin_pos, statement_list)) } else { Err(SyntaxError::ExpectedToken(parser.pos(), '}')) } } else if let Some(texts) = parser.expect_ident().and(Expectable::Static("(")).get() { let pos = parser.pos(); let name = texts.get(0).unwrap(); let mut arg_list = Vec::new(); while { match Expression::parse(parser, true) { Ok(exp) => { arg_list.push(exp); parser.expect_static(",").get().is_some() } Err(err) => { if arg_list.is_empty() { false } else { return Err(err); } } } } {} parser .expect_static(")") .get_or(SyntaxError::ExpectedToken(pos, ')'))?; Ok(Expression::FunctionCall(pos, name.clone(), arg_list)) } else if let Ok(pattern) = Pattern::parse(parser) { Ok(Expression::ValueRef(begin_pos, pattern)) } else { Err(SyntaxError::ExpectedExpression(begin_pos, None)) }?; if allow_arithmetic { if let Ok(exp) = ArithmeticExpression::parse(first.clone(), parser) { Ok(Expression::ArithmeticExpression(begin_pos, Box::new(exp))) } else { Ok(first) } } else { Ok(first) } } } #[derive(Debug, Clone)] pub enum ArithmeticExpression { Add(Expression, Expression), Subtract(Expression, Expression), Mult(Expression, Expression), Div(Expression, Expression), Pow(Expression, Expression), } impl ArithmeticExpression { fn parse( first_exp: Expression, parser: &mut Parser, ) -> Result { let mut list = Vec::new(); let mut exp = first_exp; while { let sign = parser .expect_static("+") .get() .or_else(|| parser.expect_static("-").get()) .or_else(|| parser.expect_static("**").get()) .or_else(|| parser.expect_static("/").get()) .or_else(|| parser.expect_static("*").get()); if sign.is_some() { list.push((exp, sign.clone())); exp = Expression::parse(parser, false)?; } sign.is_some() } {} list.push((exp, None)); if list.len() == 1 { return Err(SyntaxError::Fatal); } // Replace all (expr, "*/**//"), (expr, any) => ((mult/pow/div_expr, any) let clone = list.clone(); let iter = clone.iter().enumerate().rev(); for (idx, (exp, sign)) in iter { if let Some(sign) = sign { if sign == "**" { if let Some((exp2, sign2)) = list.clone().get(idx + 1) { list.remove(idx + 1); list.remove(idx); let expr = Expression::ArithmeticExpression( parser.pos(), Box::new(ArithmeticExpression::Pow(exp.clone(), exp2.clone())), ); list.insert(idx, (expr, sign2.clone())); }; } if sign == "/" { if let Some((exp2, sign2)) = list.clone().get(idx + 1) { list.remove(idx + 1); list.remove(idx); let expr = Expression::ArithmeticExpression( parser.pos(), Box::new(ArithmeticExpression::Div(exp.clone(), exp2.clone())), ); list.insert(idx, (expr, sign2.clone())); }; } if sign == "*" { if let Some((exp2, sign2)) = list.clone().get(idx + 1) { list.remove(idx + 1); list.remove(idx); let expr = Expression::ArithmeticExpression( parser.pos(), Box::new(ArithmeticExpression::Mult(exp.clone(), exp2.clone())), ); list.insert(idx, (expr, sign2.clone())); }; } } } // Replace all (expr, "+/-"), (expr, any) => ((add/sub_expr, any)) let mut ret = Err(SyntaxError::Fatal); while list.len() > 1 { let (exp2, sign2) = list.remove(1); let (exp1, sign1) = list.remove(0); let expr = if let Some(sign1) = sign1 { match &*sign1 { "+" => Some(Box::new(ArithmeticExpression::Add(exp1, exp2))), "-" => Some(Box::new(ArithmeticExpression::Subtract(exp1, exp2))), _ => None, } } else { return Err(SyntaxError::ExpectedExpression(parser.pos(), None)); }; if let Some(expr) = expr { list.insert( 0, (Expression::ArithmeticExpression(parser.pos(), expr), sign2), ); } } if let Some(first) = list.get(0) { if let Expression::ArithmeticExpression(_, expr) = &first.0 { ret = Ok(*expr.clone()); } } ret } } #[derive(Debug, Clone)] pub enum Pattern { IdentPattern(Position, Ident), LiteralPattern(Position, LiteralPattern), } impl Pattern { fn parse(parser: &mut Parser) -> Result { let pos = parser.pos(); if let Some(string) = parser.expect_string_lit().get() { Ok(Pattern::LiteralPattern( pos, LiteralPattern::StringLit(string), )) } else if let Some(int) = parser.expect_numeral_lit().get() { Ok(Pattern::LiteralPattern( pos, LiteralPattern::Integer32Lit(int), )) } else if let Some(ident) = parser.expect_ident().get() { Ok(Pattern::IdentPattern(pos, ident)) } else { Err(SyntaxError::ExpectedPattern(pos)) } } } #[derive(Debug, Clone)] pub enum LiteralPattern { StringLit(String), Integer32Lit(String), }