summaryrefslogtreecommitdiffstats
path: root/crates/rebel-parse
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2024-04-28 23:50:46 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2024-04-28 23:50:46 +0200
commit54030e686915a07452a3d4bb5a23616eec30f4fa (patch)
treeb4bea5621abdaa64b06b39521c860bc96b1f2c05 /crates/rebel-parse
parentf8c5dc596ca58bb02d60f35984a78e6f962820c9 (diff)
downloadrebel-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.rs125
-rw-r--r--crates/rebel-parse/src/grammar/recipe.rs32
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>