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