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