katex-parser 0.1.0

A port of the KaTeX parser: lexing and parsing LaTeX math expressions with macro expansion into a typed AST, plus a Unicode rendering backend
Documentation
use crate::ast::ParseNode;
use crate::error::ParseError;
use crate::function_registry::{FunctionContext, FunctionParser, FunctionSpec};

use super::require_function_arg;

pub(crate) fn smash_spec() -> FunctionSpec {
    FunctionSpec {
        names: vec!["\\smash".to_string()],
        num_args: 1,
        num_optional_args: 1,
        allowed_in_text: true,
        handler: Some(smash_handler),
        ..Default::default()
    }
}

fn smash_flags(arg: Option<&ParseNode>) -> Result<(bool, bool), ParseError> {
    let Some(ParseNode::OrdGroup { body, .. }) = arg else {
        return Ok((true, true));
    };
    let mut smash_height = false;
    let mut smash_depth = false;
    for node in body {
        let text = match node {
            ParseNode::MathOrd { text, .. }
            | ParseNode::TextOrd { text, .. }
            | ParseNode::Atom { text, .. } => text,
            _ => {
                return Err(ParseError::InternalInvariant {
                    message: "Expected symbol in \\smash option".to_string(),
                })
            }
        };
        if text == "t" {
            smash_height = true;
        } else if text == "b" {
            smash_depth = true;
        } else {
            return Ok((false, false));
        }
    }
    Ok((smash_height, smash_depth))
}

fn smash_handler(
    _parser: &mut dyn FunctionParser,
    context: &FunctionContext,
    args: &[ParseNode],
    opt_args: &[Option<ParseNode>],
) -> Result<ParseNode, ParseError> {
    let (smash_height, smash_depth) = smash_flags(opt_args.first().and_then(|o| o.as_ref()))?;
    Ok(ParseNode::Smash {
        mode: context.mode,
        body: Box::new(require_function_arg(args, 0, &context.func_name)?),
        smash_height,
        smash_depth,
    })
}