diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-10-01 15:03:37 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-10-01 15:03:37 +0200 |
| commit | 7fcad452b87c8bd31a9b7dfba78c1b1a92d33dd9 (patch) | |
| tree | c1e82792456be54fd41e7b143be302dcd874e30b /src/syntax/expr.rs | |
| parent | aafd3c95cacd829b647cfab1533de5d4833b9a04 (diff) | |
Reorganize ast types 🏕
Diffstat (limited to 'src/syntax/expr.rs')
| -rw-r--r-- | src/syntax/expr.rs | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs new file mode 100644 index 00000000..817b3d6e --- /dev/null +++ b/src/syntax/expr.rs @@ -0,0 +1,124 @@ +//! Expressions. + +use super::span::{SpanWith, Spanned}; +use super::{Decoration, Ident, Lit, LitDict}; +use crate::compute::value::Value; +use crate::layout::LayoutContext; +use crate::Feedback; + +/// An expression. +#[derive(Debug, Clone, PartialEq)] +pub enum Expr { + /// A literal: `true`, `1cm`, `"hi"`, `{_Hey!_}`. + Lit(Lit), + /// A unary operation: `-x`. + Unary(ExprUnary), + /// A binary operation: `a + b`, `a / b`. + Binary(ExprBinary), + /// An invocation of a function: `[foo: ...]`, `foo(...)`. + Call(ExprCall), +} + +impl Expr { + /// Evaluate the expression to a value. + pub async fn eval(&self, ctx: &LayoutContext<'_>, f: &mut Feedback) -> Value { + match self { + Self::Lit(lit) => lit.eval(ctx, f).await, + Self::Unary(unary) => unary.eval(ctx, f).await, + Self::Binary(binary) => binary.eval(ctx, f).await, + Self::Call(call) => call.eval(ctx, f).await, + } + } +} + +/// A unary operation: `-x`. +#[derive(Debug, Clone, PartialEq)] +pub struct ExprUnary { + /// The operator: `-`. + pub op: Spanned<UnOp>, + /// The expression to operator on: `x`. + pub expr: Spanned<Box<Expr>>, +} + +impl ExprUnary { + /// Evaluate the expression to a value. + pub async fn eval(&self, _: &LayoutContext<'_>, _: &mut Feedback) -> Value { + match self.op.v { + UnOp::Neg => todo!("eval neg"), + } + } +} + +/// A unary operator. +#[derive(Debug, Clone, PartialEq)] +pub enum UnOp { + /// The negation operator: `-`. + Neg, +} + +/// A binary operation: `a + b`, `a / b`. +#[derive(Debug, Clone, PartialEq)] +pub struct ExprBinary { + /// The left-hand side of the operation: `a`. + pub lhs: Spanned<Box<Expr>>, + /// The operator: `+`. + pub op: Spanned<BinOp>, + /// The right-hand side of the operation: `b`. + pub rhs: Spanned<Box<Expr>>, +} + +impl ExprBinary { + /// Evaluate the expression to a value. + pub async fn eval(&self, _: &LayoutContext<'_>, _: &mut Feedback) -> Value { + match self.op.v { + BinOp::Add => todo!("eval add"), + BinOp::Sub => todo!("eval sub"), + BinOp::Mul => todo!("eval mul"), + BinOp::Div => todo!("eval div"), + } + } +} + +/// A binary operator. +#[derive(Debug, Clone, PartialEq)] +pub enum BinOp { + /// The addition operator: `+`. + Add, + /// The subtraction operator: `-`. + Sub, + /// The multiplication operator: `*`. + Mul, + /// The division operator: `/`. + Div, +} + +/// An invocation of a function: `[foo: ...]`, `foo(...)`. +#[derive(Debug, Clone, PartialEq)] +pub struct ExprCall { + /// The name of the function. + pub name: Spanned<Ident>, + /// The arguments to the function. + pub args: LitDict, +} + +impl ExprCall { + /// Evaluate the call expression to a value. + pub async fn eval(&self, ctx: &LayoutContext<'_>, f: &mut Feedback) -> Value { + let name = &self.name.v; + let span = self.name.span; + let args = self.args.eval(ctx, f).await; + + if let Some(func) = ctx.scope.func(name) { + let pass = func(span, args, ctx.clone()).await; + f.extend(pass.feedback); + f.decorations.push(Decoration::Resolved.span_with(span)); + pass.output + } else { + if !name.is_empty() { + error!(@f, span, "unknown function"); + f.decorations.push(Decoration::Unresolved.span_with(span)); + } + Value::Dict(args) + } + } +} |
