Skip to main content

ratex_parser/functions/
op.rs

1use std::collections::HashMap;
2
3use crate::error::ParseResult;
4use crate::functions::{define_function_full, FunctionContext, FunctionSpec};
5use crate::parse_node::ParseNode;
6
7pub fn register(map: &mut HashMap<&'static str, FunctionSpec>) {
8    // Limits, symbols (big operators) — includes single-char Unicode equivalents
9    define_function_full(
10        map,
11        &[
12            "\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap",
13            "\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes",
14            "\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint",
15            "\u{220F}", "\u{2210}", "\u{2211}", "\u{22C0}", "\u{22C1}",
16            "\u{22C2}", "\u{22C3}", "\u{2A00}", "\u{2A01}", "\u{2A02}",
17            "\u{2A04}", "\u{2A06}",
18        ],
19        "op",
20        0, 0, None,
21        false, false, true, false, false,
22        handle_op_symbol_limits,
23    );
24
25    // No limits, not symbols (trig/log functions)
26    define_function_full(
27        map,
28        &[
29            "\\arcsin", "\\arccos", "\\arctan", "\\arctg", "\\arcctg",
30            "\\arg", "\\ch", "\\cos", "\\cosec", "\\cosh", "\\cot", "\\cotg",
31            "\\coth", "\\csc", "\\ctg", "\\cth", "\\deg", "\\dim", "\\exp",
32            "\\hom", "\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin",
33            "\\sinh", "\\sh", "\\tan", "\\tanh", "\\tg", "\\th",
34        ],
35        "op",
36        0, 0, None,
37        false, false, true, false, false,
38        handle_op_text_nolimits,
39    );
40
41    // Limits, not symbols (det, gcd, lim, etc.)
42    define_function_full(
43        map,
44        &[
45            "\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup",
46        ],
47        "op",
48        0, 0, None,
49        false, false, true, false, false,
50        handle_op_text_limits,
51    );
52
53    // No limits, symbols (integrals) — including single-char Unicode equivalents.
54    define_function_full(
55        map,
56        &[
57            "\\int", "\\iint", "\\iiint", "\\oint", "\\oiint", "\\oiiint",
58            "\u{222B}", "\u{222C}", "\u{222D}", "\u{222E}", "\u{222F}", "\u{2230}",
59        ],
60        "op",
61        0, 0, None,
62        true, // allowed_in_argument
63        false, true, false, false,
64        handle_op_symbol_nolimits,
65    );
66
67    // \mathop
68    define_function_full(
69        map,
70        &["\\mathop"],
71        "op",
72        1, 0, None,
73        false, false, true, false,
74        true, // primitive
75        handle_mathop,
76    );
77}
78
79fn single_char_big_op(c: &str) -> Option<&'static str> {
80    match c {
81        "\u{220F}" => Some("\\prod"),
82        "\u{2210}" => Some("\\coprod"),
83        "\u{2211}" => Some("\\sum"),
84        "\u{22C0}" => Some("\\bigwedge"),
85        "\u{22C1}" => Some("\\bigvee"),
86        "\u{22C2}" => Some("\\bigcap"),
87        "\u{22C3}" => Some("\\bigcup"),
88        "\u{2A00}" => Some("\\bigodot"),
89        "\u{2A01}" => Some("\\bigoplus"),
90        "\u{2A02}" => Some("\\bigotimes"),
91        "\u{2A04}" => Some("\\biguplus"),
92        "\u{2A06}" => Some("\\bigsqcup"),
93        _ => None,
94    }
95}
96
97fn single_char_integral(c: &str) -> Option<&'static str> {
98    match c {
99        "\u{222B}" => Some("\\int"),
100        "\u{222C}" => Some("\\iint"),
101        "\u{222D}" => Some("\\iiint"),
102        "\u{222E}" => Some("\\oint"),
103        "\u{222F}" => Some("\\oiint"),
104        "\u{2230}" => Some("\\oiiint"),
105        _ => None,
106    }
107}
108
109fn handle_op_symbol_limits(
110    ctx: &mut FunctionContext,
111    _args: Vec<ParseNode>,
112    _opt_args: Vec<Option<ParseNode>>,
113) -> ParseResult<ParseNode> {
114    let name = single_char_big_op(&ctx.func_name)
115        .map(|s| s.to_string())
116        .unwrap_or_else(|| ctx.func_name.clone());
117    Ok(ParseNode::Op {
118        mode: ctx.parser.mode,
119        limits: true,
120        always_handle_sup_sub: None,
121        suppress_base_shift: None,
122        parent_is_sup_sub: false,
123        symbol: true,
124        name: Some(name),
125        body: None,
126        loc: None,
127    })
128}
129
130fn handle_op_text_nolimits(
131    ctx: &mut FunctionContext,
132    _args: Vec<ParseNode>,
133    _opt_args: Vec<Option<ParseNode>>,
134) -> ParseResult<ParseNode> {
135    Ok(ParseNode::Op {
136        mode: ctx.parser.mode,
137        limits: false,
138        always_handle_sup_sub: None,
139        suppress_base_shift: None,
140        parent_is_sup_sub: false,
141        symbol: false,
142        name: Some(ctx.func_name.clone()),
143        body: None,
144        loc: None,
145    })
146}
147
148fn handle_op_text_limits(
149    ctx: &mut FunctionContext,
150    _args: Vec<ParseNode>,
151    _opt_args: Vec<Option<ParseNode>>,
152) -> ParseResult<ParseNode> {
153    Ok(ParseNode::Op {
154        mode: ctx.parser.mode,
155        limits: true,
156        always_handle_sup_sub: None,
157        suppress_base_shift: None,
158        parent_is_sup_sub: false,
159        symbol: false,
160        name: Some(ctx.func_name.clone()),
161        body: None,
162        loc: None,
163    })
164}
165
166fn handle_op_symbol_nolimits(
167    ctx: &mut FunctionContext,
168    _args: Vec<ParseNode>,
169    _opt_args: Vec<Option<ParseNode>>,
170) -> ParseResult<ParseNode> {
171    let name = single_char_integral(&ctx.func_name)
172        .map(|s| s.to_string())
173        .unwrap_or_else(|| ctx.func_name.clone());
174    Ok(ParseNode::Op {
175        mode: ctx.parser.mode,
176        limits: false,
177        always_handle_sup_sub: None,
178        suppress_base_shift: None,
179        parent_is_sup_sub: false,
180        symbol: true,
181        name: Some(name),
182        body: None,
183        loc: None,
184    })
185}
186
187fn handle_mathop(
188    ctx: &mut FunctionContext,
189    args: Vec<ParseNode>,
190    _opt_args: Vec<Option<ParseNode>>,
191) -> ParseResult<ParseNode> {
192    let body = ParseNode::ord_argument(args.into_iter().next().unwrap());
193    Ok(ParseNode::Op {
194        mode: ctx.parser.mode,
195        limits: false,
196        always_handle_sup_sub: None,
197        suppress_base_shift: None,
198        parent_is_sup_sub: false,
199        symbol: false,
200        name: None,
201        body: Some(body),
202        loc: None,
203    })
204}