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