diff options
Diffstat (limited to 'crates/rebel-parse/src/ast.rs')
-rw-r--r-- | crates/rebel-parse/src/ast.rs | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/crates/rebel-parse/src/ast.rs b/crates/rebel-parse/src/ast.rs new file mode 100644 index 0000000..d923f2a --- /dev/null +++ b/crates/rebel-parse/src/ast.rs @@ -0,0 +1,185 @@ +pub type Recipe<'a> = Vec<RecipeStmt<'a>>; + +#[derive(Debug, Clone)] +pub enum RecipeStmt<'a> { + BodyStmt(BodyStmt<'a>), + Fetch { + name: Ident<'a>, + body: Body<'a>, + }, + Task { + name: Ident<'a>, + args: Vec<ArgType<'a>>, + body: Body<'a>, + }, +} + +pub type Body<'a> = Vec<BodyStmt<'a>>; + +#[derive(Debug, Clone)] +pub enum BodyStmt<'a> { + Assign { + left: Box<TypedExpr<'a>>, + op: Option<OpBinary>, + right: Box<Expr<'a>>, + }, +} + +impl<'a> BodyStmt<'a> { + pub(crate) fn assign(left: TypedExpr<'a>, op: Option<OpBinary>, right: Expr<'a>) -> Self { + BodyStmt::Assign { + left: Box::new(left), + op, + right: Box::new(right), + } + } +} + +#[derive(Debug, Clone)] +pub enum Expr<'a> { + Binary { + left: Box<Expr<'a>>, + op: OpBinary, + right: Box<Expr<'a>>, + }, + Unary { + op: OpUnary, + expr: Box<Expr<'a>>, + }, + Apply { + expr: Box<Expr<'a>>, + args: Vec<Arg<'a>>, + }, + Index { + expr: Box<Expr<'a>>, + index: Box<Expr<'a>>, + }, + Field { + expr: Box<Expr<'a>>, + field: Ident<'a>, + }, + Paren(Box<Expr<'a>>), + Path(Path<'a>), + Literal(Literal<'a>), +} + +impl<'a> Expr<'a> { + pub(crate) fn binary(left: Expr<'a>, op: OpBinary, right: Expr<'a>) -> Self { + Expr::Binary { + left: Box::new(left), + op, + right: Box::new(right), + } + } + + pub(crate) fn unary(op: OpUnary, expr: Expr<'a>) -> Self { + Expr::Unary { + op, + expr: Box::new(expr), + } + } + + pub(crate) fn apply(expr: Expr<'a>, args: Args<'a>) -> Self { + Expr::Apply { + expr: Box::new(expr), + args, + } + } + + pub(crate) fn index(expr: Expr<'a>, index: Expr<'a>) -> Self { + Expr::Index { + expr: Box::new(expr), + index: Box::new(index), + } + } + + pub(crate) fn field(expr: Expr<'a>, field: Ident<'a>) -> Self { + Expr::Field { + expr: Box::new(expr), + field, + } + } + + pub(crate) fn paren(expr: Expr<'a>) -> Self { + Expr::Paren(Box::new(expr)) + } +} + +#[derive(Debug, Clone)] +pub struct TypedExpr<'a> { + pub expr: Expr<'a>, + pub typ: Option<Expr<'a>>, +} + +pub type Args<'a> = Vec<Arg<'a>>; + +#[derive(Debug, Clone)] +pub struct Arg<'a> { + pub expr: Expr<'a>, +} + +#[derive(Debug, Clone)] +pub struct ArgType<'a> { + pub name: Ident<'a>, + pub typ: Expr<'a>, +} + +#[derive(Debug, Clone)] +pub enum Literal<'a> { + Unit, + Boolean(bool), + Integer(u64), + String(&'a str), + RawString(&'a str), + ScriptString(&'a str), + Tuple(Vec<Expr<'a>>), + Array(Vec<Expr<'a>>), + Map(Vec<MapEntry<'a>>), +} + +impl<'a> Literal<'a> { + pub(crate) fn integer(s: &'a str, radix: u32) -> Result<Self, &'static str> { + let s = s.replace('_', ""); + let value = u64::from_str_radix(&s, radix).or(Err("Failed to parse number"))?; + Ok(Literal::Integer(value)) + } +} + +#[derive(Debug, Clone)] +pub struct MapEntry<'a> { + pub key: &'a str, + pub value: Expr<'a>, +} + +#[derive(Debug, Clone, Copy)] +pub enum OpUnary { + Not, + Neg, +} + +#[derive(Debug, Clone, Copy)] +pub enum OpBinary { + Add, + Sub, + Mul, + Div, + Rem, + And, + Or, + Eq, + Lt, + Le, + Ne, + Ge, + Gt, +} + +#[derive(Debug, Clone)] +pub struct Path<'a> { + pub components: Vec<Ident<'a>>, +} + +#[derive(Debug, Clone, Copy)] +pub struct Ident<'a> { + pub name: &'a str, +} |