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
48pub 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
56pub type FunctionHandler = fn(
58 ctx: &mut FunctionContext,
59 args: Vec<ParseNode>,
60 opt_args: Vec<Option<ParseNode>>,
61) -> ParseResult<ParseNode>;
62
63#[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
77pub 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
91pub 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
138pub 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
185pub 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}