Skip to main content

ratex_parser/functions/
delimsizing.rs

1use std::collections::HashMap;
2
3use crate::error::{ParseError, ParseResult};
4use crate::functions::{define_function_full, ArgType, FunctionContext, FunctionSpec};
5use crate::parse_node::ParseNode;
6
7struct DelimInfo {
8    mclass: &'static str,
9    size: u8,
10}
11
12fn delim_info(name: &str) -> Option<DelimInfo> {
13    match name {
14        "\\bigl" => Some(DelimInfo { mclass: "mopen", size: 1 }),
15        "\\Bigl" => Some(DelimInfo { mclass: "mopen", size: 2 }),
16        "\\biggl" => Some(DelimInfo { mclass: "mopen", size: 3 }),
17        "\\Biggl" => Some(DelimInfo { mclass: "mopen", size: 4 }),
18        "\\bigr" => Some(DelimInfo { mclass: "mclose", size: 1 }),
19        "\\Bigr" => Some(DelimInfo { mclass: "mclose", size: 2 }),
20        "\\biggr" => Some(DelimInfo { mclass: "mclose", size: 3 }),
21        "\\Biggr" => Some(DelimInfo { mclass: "mclose", size: 4 }),
22        "\\bigm" => Some(DelimInfo { mclass: "mrel", size: 1 }),
23        "\\Bigm" => Some(DelimInfo { mclass: "mrel", size: 2 }),
24        "\\biggm" => Some(DelimInfo { mclass: "mrel", size: 3 }),
25        "\\Biggm" => Some(DelimInfo { mclass: "mrel", size: 4 }),
26        "\\big" => Some(DelimInfo { mclass: "mord", size: 1 }),
27        "\\Big" => Some(DelimInfo { mclass: "mord", size: 2 }),
28        "\\bigg" => Some(DelimInfo { mclass: "mord", size: 3 }),
29        "\\Bigg" => Some(DelimInfo { mclass: "mord", size: 4 }),
30        _ => None,
31    }
32}
33
34pub fn register(map: &mut HashMap<&'static str, FunctionSpec>) {
35    define_function_full(
36        map,
37        &[
38            "\\bigl", "\\Bigl", "\\biggl", "\\Biggl",
39            "\\bigr", "\\Bigr", "\\biggr", "\\Biggr",
40            "\\bigm", "\\Bigm", "\\biggm", "\\Biggm",
41            "\\big", "\\Big", "\\bigg", "\\Bigg",
42        ],
43        "delimsizing",
44        1, 0,
45        Some(vec![ArgType::Primitive]),
46        false, false, true, false, false,
47        handle_delimsizing,
48    );
49}
50
51fn handle_delimsizing(
52    ctx: &mut FunctionContext,
53    args: Vec<ParseNode>,
54    _opt_args: Vec<Option<ParseNode>>,
55) -> ParseResult<ParseNode> {
56    let delim = check_delimiter(&args[0], &ctx.func_name)?;
57    let info = delim_info(&ctx.func_name).unwrap();
58
59    Ok(ParseNode::DelimSizing {
60        mode: ctx.parser.mode,
61        size: info.size,
62        mclass: info.mclass.to_string(),
63        delim,
64        loc: None,
65    })
66}
67
68fn check_delimiter(node: &ParseNode, func_name: &str) -> ParseResult<String> {
69    if let Some(text) = node.symbol_text() {
70        if is_valid_delimiter(text) {
71            return Ok(text.to_string());
72        }
73        return Err(ParseError::msg(format!(
74            "Invalid delimiter '{}' after '{}'",
75            text, func_name
76        )));
77    }
78    Err(ParseError::msg(format!(
79        "Invalid delimiter type '{}' after '{}'",
80        node.type_name(),
81        func_name
82    )))
83}
84
85fn is_valid_delimiter(text: &str) -> bool {
86    matches!(
87        text,
88        "(" | "\\lparen" | ")" | "\\rparen"
89            | "[" | "\\lbrack" | "]" | "\\rbrack"
90            | "\\{" | "\\lbrace" | "\\}" | "\\rbrace"
91            | "\\lfloor" | "\\rfloor"
92            | "\\lceil" | "\\rceil"
93            | "<" | ">" | "\\langle" | "\\rangle" | "\\lt" | "\\gt"
94            | "\\lvert" | "\\rvert" | "\\lVert" | "\\rVert"
95            | "\\lgroup" | "\\rgroup"
96            | "\\lmoustache" | "\\rmoustache"
97            | "/" | "\\backslash"
98            | "|" | "\\vert" | "\\|" | "\\Vert"
99            | "\\uparrow" | "\\Uparrow"
100            | "\\downarrow" | "\\Downarrow"
101            | "\\updownarrow" | "\\Updownarrow"
102            | "."
103    )
104}