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)
54    define_function_full(
55        map,
56        &[
57            "\\int", "\\iint", "\\iiint", "\\oint", "\\oiint", "\\oiiint",
58        ],
59        "op",
60        0, 0, None,
61        true, // allowed_in_argument
62        false, true, false, false,
63        handle_op_symbol_nolimits,
64    );
65
66    // \mathop
67    define_function_full(
68        map,
69        &["\\mathop"],
70        "op",
71        1, 0, None,
72        false, false, true, false,
73        true, // primitive
74        handle_mathop,
75    );
76}
77
78fn single_char_big_op(c: &str) -> Option<&'static str> {
79    match c {
80        "\u{220F}" => Some("\\prod"),
81        "\u{2210}" => Some("\\coprod"),
82        "\u{2211}" => Some("\\sum"),
83        "\u{22C0}" => Some("\\bigwedge"),
84        "\u{22C1}" => Some("\\bigvee"),
85        "\u{22C2}" => Some("\\bigcap"),
86        "\u{22C3}" => Some("\\bigcup"),
87        "\u{2A00}" => Some("\\bigodot"),
88        "\u{2A01}" => Some("\\bigoplus"),
89        "\u{2A02}" => Some("\\bigotimes"),
90        "\u{2A04}" => Some("\\biguplus"),
91        "\u{2A06}" => Some("\\bigsqcup"),
92        _ => None,
93    }
94}
95
96fn handle_op_symbol_limits(
97    ctx: &mut FunctionContext,
98    _args: Vec<ParseNode>,
99    _opt_args: Vec<Option<ParseNode>>,
100) -> ParseResult<ParseNode> {
101    let name = single_char_big_op(&ctx.func_name)
102        .map(|s| s.to_string())
103        .unwrap_or_else(|| ctx.func_name.clone());
104    Ok(ParseNode::Op {
105        mode: ctx.parser.mode,
106        limits: true,
107        always_handle_sup_sub: None,
108        suppress_base_shift: None,
109        parent_is_sup_sub: false,
110        symbol: true,
111        name: Some(name),
112        body: None,
113        loc: None,
114    })
115}
116
117fn handle_op_text_nolimits(
118    ctx: &mut FunctionContext,
119    _args: Vec<ParseNode>,
120    _opt_args: Vec<Option<ParseNode>>,
121) -> ParseResult<ParseNode> {
122    Ok(ParseNode::Op {
123        mode: ctx.parser.mode,
124        limits: false,
125        always_handle_sup_sub: None,
126        suppress_base_shift: None,
127        parent_is_sup_sub: false,
128        symbol: false,
129        name: Some(ctx.func_name.clone()),
130        body: None,
131        loc: None,
132    })
133}
134
135fn handle_op_text_limits(
136    ctx: &mut FunctionContext,
137    _args: Vec<ParseNode>,
138    _opt_args: Vec<Option<ParseNode>>,
139) -> ParseResult<ParseNode> {
140    Ok(ParseNode::Op {
141        mode: ctx.parser.mode,
142        limits: true,
143        always_handle_sup_sub: None,
144        suppress_base_shift: None,
145        parent_is_sup_sub: false,
146        symbol: false,
147        name: Some(ctx.func_name.clone()),
148        body: None,
149        loc: None,
150    })
151}
152
153fn handle_op_symbol_nolimits(
154    ctx: &mut FunctionContext,
155    _args: Vec<ParseNode>,
156    _opt_args: Vec<Option<ParseNode>>,
157) -> ParseResult<ParseNode> {
158    Ok(ParseNode::Op {
159        mode: ctx.parser.mode,
160        limits: false,
161        always_handle_sup_sub: None,
162        suppress_base_shift: None,
163        parent_is_sup_sub: false,
164        symbol: true,
165        name: Some(ctx.func_name.clone()),
166        body: None,
167        loc: None,
168    })
169}
170
171fn handle_mathop(
172    ctx: &mut FunctionContext,
173    args: Vec<ParseNode>,
174    _opt_args: Vec<Option<ParseNode>>,
175) -> ParseResult<ParseNode> {
176    let body = ParseNode::ord_argument(args.into_iter().next().unwrap());
177    Ok(ParseNode::Op {
178        mode: ctx.parser.mode,
179        limits: false,
180        always_handle_sup_sub: None,
181        suppress_base_shift: None,
182        parent_is_sup_sub: false,
183        symbol: false,
184        name: None,
185        body: Some(body),
186        loc: None,
187    })
188}