Skip to main content

ratex_parser/functions/
phantom.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    define_function_full(
9        map,
10        &["\\phantom"],
11        "phantom",
12        1,
13        0,
14        None,
15        true,
16        true,
17        true,
18        false,
19        false,
20        handle_phantom,
21    );
22
23    define_function_full(
24        map,
25        &["\\vphantom"],
26        "vphantom",
27        1,
28        0,
29        None,
30        true,
31        true,
32        true,
33        false,
34        false,
35        handle_vphantom,
36    );
37
38    // \hphantom is defined as a macro: \smash{\phantom{#1}}
39    // (registered in macro_expander builtins)
40
41    define_function_full(
42        map,
43        &["\\smash"],
44        "smash",
45        1,
46        1,
47        None,
48        true,
49        true,
50        true,
51        false,
52        false,
53        handle_smash,
54    );
55}
56
57fn handle_phantom(
58    ctx: &mut FunctionContext,
59    args: Vec<ParseNode>,
60    _opt_args: Vec<Option<ParseNode>>,
61) -> ParseResult<ParseNode> {
62    let body = ParseNode::ord_argument(args.into_iter().next().unwrap());
63    Ok(ParseNode::Phantom {
64        mode: ctx.parser.mode,
65        body,
66        loc: None,
67    })
68}
69
70fn handle_vphantom(
71    ctx: &mut FunctionContext,
72    args: Vec<ParseNode>,
73    _opt_args: Vec<Option<ParseNode>>,
74) -> ParseResult<ParseNode> {
75    Ok(ParseNode::VPhantom {
76        mode: ctx.parser.mode,
77        body: Box::new(args.into_iter().next().unwrap()),
78        loc: None,
79    })
80}
81
82fn handle_smash(
83    ctx: &mut FunctionContext,
84    args: Vec<ParseNode>,
85    opt_args: Vec<Option<ParseNode>>,
86) -> ParseResult<ParseNode> {
87    let mut smash_height = false;
88    let mut smash_depth = false;
89
90    if let Some(Some(ParseNode::OrdGroup { body, .. })) = opt_args.first() {
91        for node in body {
92            let text = node.symbol_text().unwrap_or("");
93            match text {
94                "t" => smash_height = true,
95                "b" => smash_depth = true,
96                _ => {
97                    smash_height = false;
98                    smash_depth = false;
99                    break;
100                }
101            }
102        }
103    } else {
104        smash_height = true;
105        smash_depth = true;
106    }
107
108    Ok(ParseNode::Smash {
109        mode: ctx.parser.mode,
110        body: Box::new(args.into_iter().next().unwrap()),
111        smash_height,
112        smash_depth,
113        loc: None,
114    })
115}