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