Skip to main content

ratex_parser/functions/
mod.rs

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