summaryrefslogtreecommitdiffstats
path: root/crates/rebel-parse/src/ast.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/rebel-parse/src/ast.rs')
-rw-r--r--crates/rebel-parse/src/ast.rs185
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,
+}