diff --git a/compiler/src/ast/mod.rs b/compiler/src/ast/mod.rs index 2a837cc..71907e1 100644 --- a/compiler/src/ast/mod.rs +++ b/compiler/src/ast/mod.rs @@ -76,7 +76,7 @@ pub struct FnDecl<'i> { pub name: Ident<'i>, pub params: Vec>, pub result_kind: Option>, - pub body: Vec>, + pub body: StatementList<'i>, pub span: Span<'i>, } @@ -125,11 +125,7 @@ impl<'i> Node<'i> for FnDecl<'i> { params = param_decls.into_iter().map(|p| p.into()).collect(); } - let body = body_pair - .into_inner() - .filter(|p| p.as_rule() != Rule::Semicolon) - .map(Statement::parse) - .collect::>()?; + let body = StatementList::parse(body_pair)?; Ok(Self { name, @@ -183,10 +179,13 @@ impl<'i> Node<'i> for ParameterList<'i> { }); } } - _ => { + invalid_rule => { return Err(BakugoParsingError::new( first.as_span(), - "Expected only types and identifiers in parameters".to_owned(), + format!( + "Expected only types and identifiers in parameters. Got {:?}", + invalid_rule + ), BakugoParsingErrorKind::InternalError, )) } @@ -237,7 +236,7 @@ impl<'i> From> for FnParameterDecl<'i> { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Kind<'i> { Simple { name: String, @@ -272,20 +271,26 @@ impl<'i> Node<'i> for Kind<'i> { kinds.push(Kind::parse(inner)?); } } - _ => { + invalid_rule => { return Err(BakugoParsingError::new( span, - "expected type but got something else".to_owned(), + format!( + "expected type but got something else. got: {:?}.", + invalid_rule + ), BakugoParsingErrorKind::InternalError, )) } } Ok(Self::Tuple { kinds, span }) } - _ => { + invalid_rule => { return Err(BakugoParsingError::new( inner.as_span(), - "expected type but got something else".to_owned(), + format!( + "expected type but got something else. got: {:?}.", + invalid_rule + ), BakugoParsingErrorKind::InternalError, )) } @@ -350,9 +355,9 @@ impl<'i> Node<'i> for Expr<'i> { span: pair.as_span(), }), Rule::FunctionCall => Ok(Self::parse_expr(pair.into_inner())?), - _ => Err(BakugoParsingError::new( + invalid_rule => Err(BakugoParsingError::new( pair.as_span(), - "got a non expression".to_owned(), + format!("expected an expression. got {:?}", invalid_rule), BakugoParsingErrorKind::InternalError, )), } @@ -397,9 +402,9 @@ impl<'i> Expr<'i> { .map_primary(|primary| match primary.as_rule() { // TODO: check if this match is needed Rule::IntLit | Rule::Ident | Rule::FunctionCall => Expr::parse(primary), - _ => Err(BakugoParsingError::new( + invalid_rule => Err(BakugoParsingError::new( primary.as_span(), - "got a non expression".to_owned(), + format!("expected an expresion. got {:?}", invalid_rule), BakugoParsingErrorKind::InternalError, )), }) @@ -415,9 +420,11 @@ impl<'i> Expr<'i> { _ => { return Err(BakugoParsingError::new( op.as_span(), + // TODO: use a general function to result this kinds of errors. + // also include the Rule that was found here in the error message. "got a non operator".to_owned(), BakugoParsingErrorKind::InternalError, - )) + )); } }; Ok(Expr::BinaryExpr { @@ -504,21 +511,159 @@ impl<'i> Expr<'i> { #[derive(Debug)] pub enum Statement<'i> { Return, // TODO: add expression list + Declaration(Decl<'i>), Expression(Expr<'i>), } -impl<'i> Node<'i> for Statement<'i> { +#[derive(Debug)] +pub struct StatementList<'i>(Vec>); + +#[derive(Debug)] +pub enum Decl<'i> { + Var(VarConstDecl<'i>), + Const(VarConstDecl<'i>), + Kind(KindDecl<'i>), +} + +#[derive(Debug)] +pub struct VarConstDecl<'i> { + pub name: Ident<'i>, + pub kind: Option>, + pub expr: Expr<'i>, +} + +#[derive(Debug)] +pub struct KindDecl<'i> { + pub name: Ident<'i>, + pub kind: Kind<'i>, +} + +impl<'i> StatementList<'i> { + fn parse_decl( + parsed_stmts: &mut Vec>, + pair: Pair<'i, Rule>, + ) -> Result<(), BakugoParsingError<'i>> { + match pair.as_rule() { + Rule::VarDecl | Rule::ConstDecl => { + let is_var = pair.as_rule() == Rule::VarDecl; + let var_specs = pair.into_inner().filter(|p| p.as_rule() != Rule::Semicolon); + + for var_spec in var_specs { + let var_spec_span = var_spec.as_span(); + + if !matches!(var_spec.as_rule(), Rule::VarSpec | Rule::ConstSpec) { + return Err(BakugoParsingError::new( + var_spec.as_span(), + format!( + "expected a var or const decl. got {:?}.", + var_spec.as_rule() + ), + BakugoParsingErrorKind::InternalError, + )); + } + + let mut var_spec_inner = var_spec.into_inner(); + let idents = var_spec_inner.next().unwrap(); + + let maybe_kind = var_spec_inner.next().unwrap(); + let exprs; + let kind = if maybe_kind.as_rule() == Rule::Type { + exprs = var_spec_inner.next().unwrap(); + Some(Kind::parse(maybe_kind)?) + } else { + exprs = maybe_kind; + None + }; + + let idents = idents + .into_inner() + .map(Ident::parse) + .collect::, _>>()?; + let exprs = exprs + .into_inner() + .filter(|p| p.as_rule() != Rule::Comma) + .map(Expr::parse) + .collect::, _>>()?; + + if idents.len() != exprs.len() { + return Err(BakugoParsingError::new( + var_spec_span, + format!( + "Number of expressions ({}) does not match number of identifers ({})", + exprs.len(), + idents.len() + ), + BakugoParsingErrorKind::SyntaxError, + )); + } + + for (ident, expr) in idents.into_iter().zip(exprs.into_iter()) { + let decl = VarConstDecl { + name: ident, + kind: kind.clone(), + expr, + }; + parsed_stmts.push(Statement::Declaration(if is_var { + Decl::Var(decl) + } else { + Decl::Const(decl) + })) + } + } + } + + Rule::TypeDecl => {} + + invalid_rule => { + return Err(BakugoParsingError::new( + pair.as_span(), + format!("expected a declaration. got {:?}", invalid_rule), + BakugoParsingErrorKind::InternalError, + )) + } + } + + Ok(()) + } +} + +impl<'i> Node<'i> for StatementList<'i> { fn parse(pair: Pair<'i, Rule>) -> Result { match pair.as_rule() { - Rule::ExpressionStmt => { - let expr = Expr::parse_expr(pair.into_inner())?; - Ok(Statement::Expression(expr)) + Rule::StatementList => { + let mut parsed_stmts = Vec::new(); + + for pair in pair.into_inner() { + match pair.as_rule() { + Rule::ExpressionStmt => { + let expr = Expr::parse_expr(pair.into_inner())?; + parsed_stmts.push(Statement::Expression(expr)) + } + + Rule::ReturnStmt => parsed_stmts.push(Statement::Return), + + Rule::Semicolon => {} + + Rule::Declaration => { + Self::parse_decl(&mut parsed_stmts, pair.into_inner().next().unwrap())? + } + + invalid_rule => { + return Err(BakugoParsingError::new( + pair.as_span(), + format!("expected a statement. got {:?}.", invalid_rule), + BakugoParsingErrorKind::InternalError, + )) + } + } + } + + Ok(Self(parsed_stmts)) } - Rule::ReturnStmt => Ok(Statement::Return), - _ => { + invalid_rule => { return Err(BakugoParsingError::new( pair.as_span(), - "got a statement".to_owned(), + format!("expected a statement list. got {:?}.", invalid_rule), BakugoParsingErrorKind::InternalError, )) } diff --git a/compiler/src/bakugo.pest b/compiler/src/bakugo.pest index 8ed4f21..ae66f13 100644 --- a/compiler/src/bakugo.pest +++ b/compiler/src/bakugo.pest @@ -108,7 +108,7 @@ TypeSpec = { TypeDef } TypeDef = { Ident ~ Type } // Variable declaration -VarDecl = { "var" ~ (VarSpec | "(" ~ (VarSpec ~ Semicolon)* ~ ")") } +VarDecl = { "var" ~ (VarSpec | "(" ~ (VarSpec ~ Semicolon)+ ~ ")") } VarSpec = { IdentifierList ~ ((Type ~ ("=" ~ ExpressionList)?) | ("=" ~ ExpressionList)) } // Function declaration diff --git a/compiler/tests/examples/06_var_decl.bakugo b/compiler/tests/examples/06_var_decl.bakugo new file mode 100644 index 0000000..9e48259 --- /dev/null +++ b/compiler/tests/examples/06_var_decl.bakugo @@ -0,0 +1,11 @@ +func abc() { + var a = 10; + var ( + b = 10; + c int = 20; + c, d, e int = 30, 40, 50; + // f, g, h = 40; + i, j, k = 50, 60, 70; + // i, j, k = 60, 70; + ); +};