1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
//! Expressions.
use super::span::{SpanWith, Spanned};
use super::{Decoration, Ident, Lit, LitDict};
use crate::eval::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)
}
}
}
|