diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2024-04-28 23:50:46 +0200 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2024-04-28 23:50:46 +0200 |
commit | 54030e686915a07452a3d4bb5a23616eec30f4fa (patch) | |
tree | b4bea5621abdaa64b06b39521c860bc96b1f2c05 /crates/rebel-parse | |
parent | f8c5dc596ca58bb02d60f35984a78e6f962820c9 (diff) | |
download | rebel-54030e686915a07452a3d4bb5a23616eec30f4fa.tar rebel-54030e686915a07452a3d4bb5a23616eec30f4fa.zip |
rebel-parse: split expr out of ast module
Diffstat (limited to 'crates/rebel-parse')
-rw-r--r-- | crates/rebel-parse/src/ast/expr.rs (renamed from crates/rebel-parse/src/ast.rs) | 125 | ||||
-rw-r--r-- | crates/rebel-parse/src/ast/mod.rs | 125 | ||||
-rw-r--r-- | crates/rebel-parse/src/grammar/recipe.rs | 32 |
3 files changed, 143 insertions, 139 deletions
diff --git a/crates/rebel-parse/src/ast.rs b/crates/rebel-parse/src/ast/expr.rs index 8be015b..6899903 100644 --- a/crates/rebel-parse/src/ast.rs +++ b/crates/rebel-parse/src/ast/expr.rs @@ -1,100 +1,9 @@ use std::collections::HashSet; +use super::{Ident, Path, ValidationError}; use crate::token; -pub type Recipe<'a> = Vec<RecipeStmt<'a>>; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum RecipeStmt<'a> { - BodyStmt(BodyStmt<'a>), - Fetch { - name: Ident<'a>, - body: Body<'a>, - }, - Task { - name: Ident<'a>, - params: Vec<FuncParam<'a>>, - body: Body<'a>, - }, -} - -impl<'a> RecipeStmt<'a> { - pub fn validate(&self) -> Result<(), ValidationError> { - match self { - RecipeStmt::BodyStmt(stmt) => stmt.validate(), - RecipeStmt::Fetch { name: _, body } => body.validate(), - RecipeStmt::Task { - name: _, - params: _, - body, - } => { - // TODO: Validate params? - body.validate() - } - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Body<'a>(pub Vec<BodyStmt<'a>>); - -impl<'a> Body<'a> { - pub fn validate(&self) -> Result<(), ValidationError> { - for stmt in &self.0 { - stmt.validate()?; - } - Ok(()) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum BodyStmt<'a> { - Assign { - dest: Box<TypedExpr<'a>>, - expr: Box<Expr<'a>>, - }, - Expr { - expr: Box<Expr<'a>>, - }, - Empty, -} - -impl<'a> BodyStmt<'a> { - pub(crate) fn assign( - dest: TypedExpr<'a>, - op: Option<OpBinary>, - swapped: bool, - expr: Expr<'a>, - ) -> Self { - let expr = match op { - Some(op) => { - let dest_expr = dest.expr.clone(); - if swapped { - Expr::binary(expr, op, dest_expr) - } else { - Expr::binary(dest_expr, op, expr) - } - } - None => expr, - }; - BodyStmt::Assign { - dest: Box::new(dest), - expr: Box::new(expr), - } - } - - pub fn validate(&self) -> Result<(), ValidationError> { - match self { - BodyStmt::Assign { dest, expr } => { - // TODO: Extend destination validation - dest.expr.validate()?; - expr.validate() - } - BodyStmt::Expr { expr } => expr.validate(), - BodyStmt::Empty => Ok(()), - } - } -} +pub use token::StrKind; #[derive(Debug, Clone, PartialEq, Eq)] pub enum Expr<'a> { @@ -234,20 +143,6 @@ impl<'a> Expr<'a> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct TypedExpr<'a> { - pub expr: Expr<'a>, - pub typ: Option<Expr<'a>>, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FuncParam<'a> { - pub name: Ident<'a>, - pub typ: Expr<'a>, -} - -pub use token::StrKind; - -#[derive(Debug, Clone, PartialEq, Eq)] pub enum Literal<'a> { Unit, Bool(bool), @@ -377,19 +272,3 @@ impl OpBinary { matches!(self, Eq | Lt | Le | Ne | Ge | Gt) } } - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Path<'a> { - pub components: Vec<Ident<'a>>, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct Ident<'a> { - pub name: &'a str, -} - -#[derive(Debug, Clone, Copy)] -pub enum ValidationError { - DuplicateKey, - NeedsParens, -} diff --git a/crates/rebel-parse/src/ast/mod.rs b/crates/rebel-parse/src/ast/mod.rs new file mode 100644 index 0000000..9db7630 --- /dev/null +++ b/crates/rebel-parse/src/ast/mod.rs @@ -0,0 +1,125 @@ +pub mod expr; + +use expr::*; + +pub type Recipe<'a> = Vec<RecipeStmt<'a>>; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum RecipeStmt<'a> { + BodyStmt(BodyStmt<'a>), + Fetch { + name: Ident<'a>, + body: Body<'a>, + }, + Task { + name: Ident<'a>, + params: Vec<FuncParam<'a>>, + body: Body<'a>, + }, +} + +impl<'a> RecipeStmt<'a> { + pub fn validate(&self) -> Result<(), ValidationError> { + match self { + RecipeStmt::BodyStmt(stmt) => stmt.validate(), + RecipeStmt::Fetch { name: _, body } => body.validate(), + RecipeStmt::Task { + name: _, + params: _, + body, + } => { + // TODO: Validate params? + body.validate() + } + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Body<'a>(pub Vec<BodyStmt<'a>>); + +impl<'a> Body<'a> { + pub fn validate(&self) -> Result<(), ValidationError> { + for stmt in &self.0 { + stmt.validate()?; + } + Ok(()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum BodyStmt<'a> { + Assign { + dest: Box<TypedExpr<'a>>, + expr: Box<Expr<'a>>, + }, + Expr { + expr: Box<Expr<'a>>, + }, + Empty, +} + +impl<'a> BodyStmt<'a> { + pub(crate) fn assign( + dest: TypedExpr<'a>, + op: Option<OpBinary>, + swapped: bool, + expr: Expr<'a>, + ) -> Self { + let expr = match op { + Some(op) => { + let dest_expr = dest.expr.clone(); + if swapped { + Expr::binary(expr, op, dest_expr) + } else { + Expr::binary(dest_expr, op, expr) + } + } + None => expr, + }; + BodyStmt::Assign { + dest: Box::new(dest), + expr: Box::new(expr), + } + } + + pub fn validate(&self) -> Result<(), ValidationError> { + match self { + BodyStmt::Assign { dest, expr } => { + // TODO: Extend destination validation + dest.expr.validate()?; + expr.validate() + } + BodyStmt::Expr { expr } => expr.validate(), + BodyStmt::Empty => Ok(()), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TypedExpr<'a> { + pub expr: Expr<'a>, + pub typ: Option<Expr<'a>>, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FuncParam<'a> { + pub name: Ident<'a>, + pub typ: Expr<'a>, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Path<'a> { + pub components: Vec<Ident<'a>>, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Ident<'a> { + pub name: &'a str, +} + +#[derive(Debug, Clone, Copy)] +pub enum ValidationError { + DuplicateKey, + NeedsParens, +} diff --git a/crates/rebel-parse/src/grammar/recipe.rs b/crates/rebel-parse/src/grammar/recipe.rs index 61688f5..64c7acd 100644 --- a/crates/rebel-parse/src/grammar/recipe.rs +++ b/crates/rebel-parse/src/grammar/recipe.rs @@ -1,12 +1,12 @@ -use crate::ast::{self, Expr}; +use crate::ast::{self, expr, expr::Expr}; use crate::token::*; pub use rules::*; peg::parser! { pub grammar rules<'a>() for TokenStream<'a> { - use ast::OpBinary::*; - use ast::OpUnary::*; + use expr::OpBinary::*; + use expr::OpUnary::*; pub rule recipe() -> ast::Recipe<'a> = recipe:recipe_stmt()* { recipe } @@ -38,7 +38,7 @@ peg::parser! { } / { ast::BodyStmt::Empty } - rule assign_op() -> Option<ast::OpBinary> + rule assign_op() -> Option<expr::OpBinary> = p('=') { None } / p2('+', '=') { Some(Add) } / p2('-', '=') { Some(Sub) } @@ -89,7 +89,7 @@ peg::parser! { = lit:literal() { Expr::Literal(lit) } / path:path() { Expr::Path(path) } - rule call_params() -> Vec<ast::Expr<'a>> + rule call_params() -> Vec<expr::Expr<'a>> = args:delimited(<expr()>, <p(',')>) { args } rule func_params() -> Vec<ast::FuncParam<'a>> @@ -98,33 +98,33 @@ peg::parser! { rule func_param() -> ast::FuncParam<'a> = name:ident() p(':') typ:expr() { ast::FuncParam { name, typ } } - rule literal() -> ast::Literal<'a> - = [Token::Keyword(Keyword::True)] { ast::Literal::Bool(true) } - / [Token::Keyword(Keyword::False)] { ast::Literal::Bool(false) } + rule literal() -> expr::Literal<'a> + = [Token::Keyword(Keyword::True)] { expr::Literal::Bool(true) } + / [Token::Keyword(Keyword::False)] { expr::Literal::Bool(false) } / [Token::Number(content)] { ? - ast::Literal::number(content) + expr::Literal::number(content) } / [Token::Str(Str { pieces, kind })] { ? let pieces = pieces .iter() .map(|piece| piece.try_into()) .collect::<Result<_, _>>()?; - Ok(ast::Literal::Str{ pieces, kind: *kind }) + Ok(expr::Literal::Str{ pieces, kind: *kind }) } - / p('(') p(')') { ast::Literal::Unit } + / p('(') p(')') { expr::Literal::Unit } / p('(') elements:(expr() ** p(',')) p(',')? p(')') { - ast::Literal::Tuple(elements) + expr::Literal::Tuple(elements) } / p('[') elements:delimited(<expr()>, <p(',')>) p(']') { - ast::Literal::Array(elements) + expr::Literal::Array(elements) } / p('{') entries:delimited(<struct_field()>, <p(',')>) p('}') { - ast::Literal::Struct(entries) + expr::Literal::Struct(entries) } - rule struct_field() -> ast::StructField<'a> + rule struct_field() -> expr::StructField<'a> = key:field() p('=') value:expr() { - ast::StructField { key: key.name, value } + expr::StructField { key: key.name, value } } rule path() -> ast::Path<'a> |