diff options
Diffstat (limited to 'src/model')
| -rw-r--r-- | src/model/eval.rs | 74 | ||||
| -rw-r--r-- | src/model/library.rs | 5 |
2 files changed, 70 insertions, 9 deletions
diff --git a/src/model/eval.rs b/src/model/eval.rs index b037a1bd..91112949 100644 --- a/src/model/eval.rs +++ b/src/model/eval.rs @@ -280,6 +280,7 @@ impl Eval for ast::Expr { Self::Enum(v) => v.eval(vm).map(Value::Content), Self::Term(v) => v.eval(vm).map(Value::Content), Self::Atom(v) => v.eval(vm).map(Value::Content), + Self::Delimited(v) => v.eval(vm).map(Value::Content), Self::Script(v) => v.eval(vm).map(Value::Content), Self::Frac(v) => v.eval(vm).map(Value::Content), Self::AlignPoint(v) => v.eval(vm).map(Value::Content), @@ -325,10 +326,19 @@ impl ast::Expr { Self::Shorthand(v) => v.eval_in_math(vm)?, Self::Symbol(v) => v.eval_in_math(vm)?, Self::Ident(v) => v.eval_in_math(vm)?, + Self::FuncCall(v) => v.eval_in_math(vm)?, _ => self.eval(vm)?.display_in_math(), } .spanned(self.span())) } + + fn eval_without_parens(&self, vm: &mut Vm) -> SourceResult<Content> { + Ok(match self { + Self::Delimited(v) => v.eval_without_parens(vm)?, + _ => self.eval_in_math(vm)?, + } + .spanned(self.span())) + } } impl Eval for ast::Text { @@ -401,7 +411,7 @@ impl Eval for ast::Symbol { impl ast::Symbol { fn eval_in_math(&self, vm: &mut Vm) -> SourceResult<Content> { - Ok((vm.items.symbol)(EcoString::from(self.get()) + ":op".into())) + Ok((vm.items.symbol)(EcoString::from(self.get()) + ":op:square".into())) } } @@ -511,7 +521,7 @@ impl Eval for ast::Math { .map(|expr| expr.eval_in_math(vm)) .collect::<SourceResult<_>>()?; let block = self.block(); - Ok((vm.items.math)(seq, block)) + Ok((vm.items.math)(Content::sequence(seq), block)) } } @@ -523,13 +533,44 @@ impl Eval for ast::Atom { } } +impl Eval for ast::Delimited { + type Output = Content; + + fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { + let seq = self + .exprs() + .map(|expr| expr.eval_in_math(vm)) + .collect::<SourceResult<_>>()?; + Ok((vm.items.math_delimited)(Content::sequence(seq))) + } +} + +impl ast::Delimited { + fn eval_without_parens(&self, vm: &mut Vm) -> SourceResult<Content> { + let exprs: Vec<_> = self.exprs().collect(); + let mut slice = exprs.as_slice(); + if let (Some(ast::Expr::Atom(first)), Some(ast::Expr::Atom(last))) = + (exprs.first(), exprs.last()) + { + if first.get() == "(" && last.get() == ")" { + slice = &exprs[1..exprs.len() - 1]; + } + } + let seq = slice + .iter() + .map(|expr| expr.eval_in_math(vm)) + .collect::<SourceResult<_>>()?; + Ok((vm.items.math_delimited)(Content::sequence(seq))) + } +} + impl Eval for ast::Script { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { let base = self.base().eval_in_math(vm)?; - let sub = self.sub().map(|expr| expr.eval_in_math(vm)).transpose()?; - let sup = self.sup().map(|expr| expr.eval_in_math(vm)).transpose()?; + let sub = self.sub().map(|expr| expr.eval_without_parens(vm)).transpose()?; + let sup = self.sup().map(|expr| expr.eval_without_parens(vm)).transpose()?; Ok((vm.items.math_script)(base, sub, sup)) } } @@ -538,8 +579,8 @@ impl Eval for ast::Frac { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { - let num = self.num().eval_in_math(vm)?; - let denom = self.denom().eval_in_math(vm)?; + let num = self.num().eval_without_parens(vm)?; + let denom = self.denom().eval_without_parens(vm)?; Ok((vm.items.math_frac)(num, denom)) } } @@ -878,12 +919,29 @@ impl Eval for ast::FuncCall { type Output = Value; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { + let callee = self.callee(); + let callee = callee.eval(vm)?.cast::<Func>().at(callee.span())?; + self.eval_with_callee(vm, callee) + } +} + +impl ast::FuncCall { + fn eval_in_math(&self, vm: &mut Vm) -> SourceResult<Content> { + let callee = self.callee().eval(vm)?; + if let Value::Func(callee) = callee { + Ok(self.eval_with_callee(vm, callee)?.display_in_math()) + } else { + Ok(callee.display_in_math() + + (vm.items.math_atom)("(".into()) + + (vm.items.math_atom)(")".into())) + } + } + + fn eval_with_callee(&self, vm: &mut Vm, callee: Func) -> SourceResult<Value> { if vm.depth >= MAX_CALL_DEPTH { bail!(self.span(), "maximum function call depth exceeded"); } - let callee = self.callee(); - let callee = callee.eval(vm)?.cast::<Func>().at(callee.span())?; let args = self.args().eval(vm)?; let point = || Tracepoint::Call(callee.name().map(Into::into)); callee.call(vm, args).trace(vm.world, point, self.span()) diff --git a/src/model/library.rs b/src/model/library.rs index 96218bb1..54eeeb5b 100644 --- a/src/model/library.rs +++ b/src/model/library.rs @@ -66,7 +66,10 @@ pub struct LangItems { /// An item in a term list: `/ Term: Details`. pub term_item: fn(term: Content, description: Content) -> Content, /// A mathematical formula: `$x$`, `$ x^2 $`. - pub math: fn(children: Vec<Content>, block: bool) -> Content, + pub math: fn(body: Content, block: bool) -> Content, + /// A subsection in a math formula that is surrounded by matched delimiters: + /// `[x + y]`. + pub math_delimited: fn(body: Content) -> Content, /// An atom in a formula: `x`, `+`, `12`. pub math_atom: fn(atom: EcoString) -> Content, /// A base with optional sub- and superscripts in a formula: `a_1^2`. |
