texform-transform 0.1.0

Profile-based AST transform engine for TeXForm (internal; use the texform crate)
Documentation
use texform_knowledge::builtin::base;
use texform_knowledge::builtin::physics;

use crate::ast::{ContentMode, Node, NodeId};
use crate::rewrite::helpers::{bare_command_node, mandatory_content_slot, prefix_command_node};
use crate::rewrite::rule_context::RuleContext;

pub(super) type DifferentialSymbol = fn(&mut RuleContext<'_>) -> NodeId;

pub(super) fn derivative_numerator(
    cx: &mut RuleContext<'_>,
    symbol: DifferentialSymbol,
    order: Option<NodeId>,
    expression: Option<NodeId>,
) -> NodeId {
    let differential = ordered_differential_symbol(cx, symbol, order);

    let mut children = vec![differential];
    if let Some(expression) = expression {
        cx.ast.append_cloned_math_content(&mut children, expression);
    }
    cx.ast.implicit_math_group(children)
}

pub(super) fn derivative_denominator(
    cx: &mut RuleContext<'_>,
    symbol: DifferentialSymbol,
    variable: NodeId,
    order: Option<NodeId>,
) -> NodeId {
    let variable = cx.ast.clone_subtree(variable);
    let variable = match order {
        Some(order) => {
            let order = cx.ast.clone_subtree(order);
            cx.ast.superscript(variable, order)
        }
        None => variable,
    };

    let differential = symbol(cx);
    let mut children = vec![differential];
    cx.ast.append_cloned_math_content(&mut children, variable);
    cx.ast.implicit_math_group(children)
}

pub(super) fn mixed_derivative_denominator(
    cx: &mut RuleContext<'_>,
    symbol: DifferentialSymbol,
    first_variable: NodeId,
    second_variable: NodeId,
) -> NodeId {
    let first_partial = symbol(cx);
    let mut children = vec![first_partial];
    cx.ast.append_cloned_math_content(&mut children, first_variable);
    let second_partial = symbol(cx);
    children.push(second_partial);
    cx.ast.append_cloned_math_content(&mut children, second_variable);
    cx.ast.implicit_math_group(children)
}

pub(super) fn derivative_fraction(starred: bool, numerator: NodeId, denominator: NodeId) -> Node {
    let record = if starred {
        &physics::cmd::FLATFRAC
    } else {
        &base::cmd::FRAC
    };
    prefix_command_node(
        record,
        vec![
            mandatory_content_slot(numerator, ContentMode::Math),
            mandatory_content_slot(denominator, ContentMode::Math),
        ],
    )
}

pub(super) fn differential_d(cx: &mut RuleContext<'_>) -> NodeId {
    let d = cx.ast.new_node(Node::Char('d'));
    cx.ast.new_node(prefix_command_node(
        &base::cmd::MATHRM,
        vec![mandatory_content_slot(d, ContentMode::Math)],
    ))
}

pub(super) fn delta_symbol(cx: &mut RuleContext<'_>) -> NodeId {
    named_symbol(cx, "delta")
}

pub(super) fn partial_symbol(cx: &mut RuleContext<'_>) -> NodeId {
    named_symbol(cx, "partial")
}

pub(super) fn order_two(cx: &mut RuleContext<'_>) -> NodeId {
    cx.ast.new_node(Node::Char('2'))
}

fn ordered_differential_symbol(
    cx: &mut RuleContext<'_>,
    symbol: DifferentialSymbol,
    order: Option<NodeId>,
) -> NodeId {
    match order {
        Some(order) => {
            let symbol = symbol(cx);
            let order = cx.ast.clone_subtree(order);
            cx.ast.superscript(symbol, order)
        }
        None => symbol(cx),
    }
}

fn named_symbol(cx: &mut RuleContext<'_>, name: &str) -> NodeId {
    cx.ast.new_node(bare_command_node(name))
}