Repository: typst/typst
File: crates/typst/src/eval/call.rs (Rust)

Code before:
                               field.as_str(),
                            ));
                        } else {
                            field_hint();
                        }
                    }
                    _ => field_hint(),
                }

                bail!(error);
            }
        } else {
            (callee.eval(vm)?, args.eval(vm)?.spanned(span))
        };

        // If the callee is a callable symbol, call its handler.
        let callee = match callee {
            Value::Symbol(sym) => {
                if let Some(handler) = sym.func() {
                    Value::Func(handler)
                } else {
                    Value::Symbol(sym)
                }
            }
            callee => callee,
        };

        // Handle math special cases for non-functions:
        // Combining accent symbols apply themselves while everything else
        // simply displays the arguments verbatim.
        if in_math && !matches!(callee, Value::Func(_)) {
            if let Value::Symbol(sym) = &callee {
                let c = sym.get();
                if let Some(accent) = Symbol::combining_accent(c) {
                    let base = args.expect("base")?;
                    let size = args.named("size")?;
                    args.finish()?;
                    let mut accent = AccentElem::new(base, Accent::new(accent));
                    if let Some(size) = size {
                        accent = accent.with_size(size);
                    }
                    return Ok(Value::Content(accent.pack()));
                }
            }
            let mut body = Content::empty();
            for (i, arg) in args.all::<Content>()?.into_iter().enumerate() {
                if i > 0 {
                    body += TextElem::packed(',');
                }
                body += arg;
            }

Review comment (refactor):
Seeing this file changed, I'd like to note that I think the `Eval<FuncCall>::eval` function is really ugly in general, and deserves an overhaul. I'd be interested in discussing this if @laurmaedje agrees. I think splitting out the massive `let (...) = if { /* huge mess of 80+ lines */ } else {/* one single line */}` into a separate function would be a nice start, but there are a few early returns in the huge mess that make it complicated in the context of the overall function. (This is also somewhat relevant for the new VM refactor, since it completely redoes the func call system)

Code after:
                            ));
                        } else {
                            field_hint();
                        }
                    }
                    _ => field_hint(),
                }

                bail!(error);
            }
        } else {
            (callee.eval(vm)?, args.eval(vm)?.spanned(span))
        };

        let func_result = callee.clone().cast::<Func>().at(callee_span);
        if in_math && func_result.is_err() {
            // For non-functions in math, we wrap the arguments in parentheses.
            let mut body = Content::empty();
            for (i, arg) in args.all::<Content>()?.into_iter().enumerate() {
                if i > 0 {
                    body += TextElem::packed(',');
                }
                body += arg;
            }
            if trailing_comma {
                body += TextElem::packed(',');
            }
            return Ok(Value::Content(
                callee.display().spanned(callee_span)
                    + LrElem::new(TextElem::packed('(') + body + TextElem::packed(')'))
                        .pack(),
            ));
        }

        let func = func_result?;
        let point = || Tracepoint::Call(func.name().map(Into::into));
        let f = || {
            func.call(&mut vm.engine, vm.context, args)
                .trace(vm.world(), point, span)
        };

        // Stacker is broken on WASM.
        #[cfg(target_arch = "wasm32")]
        return f();

        #[cfg(not(target_arch = "wasm32"))]
        stacker::maybe_grow(32 * 1024, 2 * 1024 * 1024, f)
    }
}

impl Eval for ast::Args<'_> {