Skip to main content

ratex_parser/functions/
mod.rs

1pub mod genfrac;
2pub mod sqrt;
3pub mod op;
4pub mod accent;
5pub mod font;
6pub mod color;
7pub mod sizing;
8pub mod delimsizing;
9pub mod left_right;
10pub mod spacing;
11pub mod styling;
12pub mod overline;
13pub mod kern;
14pub mod phantom;
15pub mod text;
16pub mod cr;
17pub mod relax;
18pub mod verb;
19pub mod symbols_cmd;
20pub mod environment;
21pub mod mclass;
22pub mod operatorname;
23pub mod horiz_brace;
24pub mod arrow;
25pub mod enclose;
26pub mod rule;
27pub mod href;
28pub mod hbox;
29pub mod lap;
30pub mod raisebox;
31pub mod vcenter;
32pub mod pmb;
33pub mod mathchoice;
34pub mod def;
35pub mod htmlmathml;
36pub mod char_cmd;
37pub mod math;
38
39use std::collections::HashMap;
40use crate::error::ParseResult;
41use crate::parse_node::{Mode, ParseNode};
42
43use ratex_lexer::token::Token;
44
45/// Context passed to function handlers.
46pub struct FunctionContext<'a, 'b> {
47    pub func_name: String,
48    pub parser: &'a mut crate::parser::Parser<'b>,
49    pub token: Option<Token>,
50    pub break_on_token_text: Option<String>,
51}
52
53/// Handler function signature.
54pub type FunctionHandler =
55    fn(ctx: &mut FunctionContext, args: Vec<ParseNode>, opt_args: Vec<Option<ParseNode>>) -> ParseResult<ParseNode>;
56
57/// Argument types for function parameters.
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub enum ArgType {
60    Color,
61    Size,
62    Url,
63    Math,
64    Text,
65    HBox,
66    Raw,
67    Primitive,
68    Original,
69}
70
71/// Specification for a registered function.
72pub struct FunctionSpec {
73    pub node_type: &'static str,
74    pub num_args: usize,
75    pub num_optional_args: usize,
76    pub arg_types: Option<Vec<ArgType>>,
77    pub allowed_in_argument: bool,
78    pub allowed_in_text: bool,
79    pub allowed_in_math: bool,
80    pub infix: bool,
81    pub primitive: bool,
82    pub handler: FunctionHandler,
83}
84
85/// Get the global function registry.
86pub static FUNCTIONS: std::sync::LazyLock<HashMap<&'static str, FunctionSpec>> =
87    std::sync::LazyLock::new(|| {
88        let mut map = HashMap::new();
89        genfrac::register(&mut map);
90        sqrt::register(&mut map);
91        op::register(&mut map);
92        accent::register(&mut map);
93        font::register(&mut map);
94        color::register(&mut map);
95        sizing::register(&mut map);
96        delimsizing::register(&mut map);
97        left_right::register(&mut map);
98        spacing::register(&mut map);
99        styling::register(&mut map);
100        overline::register(&mut map);
101        kern::register(&mut map);
102        phantom::register(&mut map);
103        text::register(&mut map);
104        cr::register(&mut map);
105        relax::register(&mut map);
106        verb::register(&mut map);
107        symbols_cmd::register(&mut map);
108        environment::register(&mut map);
109        mclass::register(&mut map);
110        operatorname::register(&mut map);
111        horiz_brace::register(&mut map);
112        arrow::register(&mut map);
113        enclose::register(&mut map);
114        rule::register(&mut map);
115        href::register(&mut map);
116        hbox::register(&mut map);
117        lap::register(&mut map);
118        raisebox::register(&mut map);
119        vcenter::register(&mut map);
120        pmb::register(&mut map);
121        mathchoice::register(&mut map);
122        def::register(&mut map);
123        htmlmathml::register(&mut map);
124        char_cmd::register(&mut map);
125        math::register(&mut map);
126        map
127    });
128
129/// Helper to define a function with common defaults.
130pub fn define_function(
131    map: &mut HashMap<&'static str, FunctionSpec>,
132    names: &[&'static str],
133    node_type: &'static str,
134    num_args: usize,
135    handler: FunctionHandler,
136) {
137    define_function_full(
138        map, names, node_type, num_args, 0, None, false, false, true, false, false, handler,
139    );
140}
141
142#[allow(clippy::too_many_arguments)]
143pub fn define_function_full(
144    map: &mut HashMap<&'static str, FunctionSpec>,
145    names: &[&'static str],
146    node_type: &'static str,
147    num_args: usize,
148    num_optional_args: usize,
149    arg_types: Option<Vec<ArgType>>,
150    allowed_in_argument: bool,
151    allowed_in_text: bool,
152    allowed_in_math: bool,
153    infix: bool,
154    primitive: bool,
155    handler: FunctionHandler,
156) {
157    for &name in names {
158        map.insert(
159            name,
160            FunctionSpec {
161                node_type,
162                num_args,
163                num_optional_args,
164                arg_types: arg_types.clone(),
165                allowed_in_argument,
166                allowed_in_text,
167                allowed_in_math,
168                infix,
169                primitive,
170                handler,
171            },
172        );
173    }
174}
175
176/// Check if a mode is compatible with a function spec.
177pub fn check_mode_compatibility(
178    func: &FunctionSpec,
179    mode: Mode,
180    func_name: &str,
181    token: Option<&Token>,
182) -> ParseResult<()> {
183    if mode == Mode::Text && !func.allowed_in_text {
184        return Err(crate::error::ParseError::new(
185            format!("Can't use function '{}' in text mode", func_name),
186            token,
187        ));
188    }
189    if mode == Mode::Math && !func.allowed_in_math {
190        return Err(crate::error::ParseError::new(
191            format!("Can't use function '{}' in math mode", func_name),
192            token,
193        ));
194    }
195    Ok(())
196}