treeflection/
node_runner.rs

1use crate::node_token::NodeToken;
2use std::slice::Iter;
3
4#[derive(Clone)]
5pub struct NodeRunner {
6    pub tokens: Vec<NodeToken>,
7}
8
9impl NodeRunner {
10    pub fn new(command: &str) -> Result<NodeRunner, String> {
11        let mut tokens: Vec<NodeToken> = vec!();
12
13        if command.len() == 0 {
14            return Err(String::from("Empty command"));
15        }
16
17        let chars: Vec<char> = {
18            let mut chars = vec!();
19            if !command.starts_with('.') && !command.starts_with('[') && !command.starts_with(':') {
20                chars.push('.');
21            }
22            chars.extend(command.chars());
23            chars
24        };
25
26        // repeat:
27        // *         if '.' then property, consume until before '.' or '[' or '>'
28        // *    else if '[?]' then context, consume it.
29        // *    else if '[*]' then all, consume it.
30        // *    else if '["' then index, consume until '"]'
31        // *    else if '[' then key, consume until ']'
32        // *    else if '>' then action, consume arguments seperated by ' ' until end of string
33        let mut i = 0;
34        loop {
35            if chars[i] == '.' {
36                let mut prop_string = String::new();
37                if i + 1 >= chars.len() {
38                    return Err(String::from("Missing action"));
39                }
40
41                let mut next = chars[i+1];
42                while next != '.' && next != '[' && next != ':' {
43                    i += 1;
44                    prop_string.push(chars[i]);
45                    if i + 1 >= chars.len() {
46                        return Err(String::from("Missing action"));
47                    }
48                    next = chars[i+1];
49                }
50
51                if i + 1 >= chars.len() {
52                    return Err(String::from("Missing action"));
53                }
54                i += 1;
55
56                if prop_string.len() == 0 {
57                    return Err(String::from("Empty property"));
58                }
59                tokens.push(NodeToken::ChainProperty (prop_string));
60            }
61            else if i + 2 < chars.len() && chars[i] == '[' && chars[i+1] == '?' && chars[i+2] == ']' {
62                if i + 3 >= chars.len() {
63                    return Err(String::from("Missing action"));
64                }
65                i += 3;
66                tokens.push(NodeToken::ChainContext);
67            }
68            else if i + 2 < chars.len() && chars[i] == '[' && chars[i+1] == '*' && chars[i+2] == ']' {
69                if i + 3 >= chars.len() {
70                    return Err(String::from("Missing action"));
71                }
72                i += 3;
73                tokens.push(NodeToken::ChainAll);
74            }
75            else if i + 1 < chars.len() && chars[i] == '[' && chars[i+1] == '"' {
76                let mut key_string = String::new();
77                i += 1;
78                if i + 4 >= chars.len() {
79                    return Err(String::from("Missing action"));
80                }
81                let mut next1 = chars[i+1];
82                let mut next2 = chars[i+2];
83                while next1 != '"' || next2 != ']' {
84                    i += 1;
85                    key_string.push(chars[i]);
86                    if i + 2 >= chars.len() {
87                        return Err(String::from("Missing \"]"));
88                    }
89                    next1 = chars[i+1];
90                    next2 = chars[i+2];
91                }
92
93                if i + 3 >= chars.len() {
94                    return Err(String::from("Missing action"));
95                }
96                i += 3;
97
98                tokens.push(NodeToken::ChainKey(key_string));
99            }
100            else if chars[i] == '[' {
101                let mut index_string = String::new();
102                if i + 1 >= chars.len() {
103                    return Err(String::from("Missing action"));
104                }
105
106                let mut next = chars[i+1];
107                while next != ']' {
108                    i += 1;
109                    index_string.push(chars[i]);
110                    if i + 1 >= chars.len() {
111                        return Err(String::from("Missing ]"));
112                    }
113                    next = chars[i+1];
114                }
115
116                if i + 2 >= chars.len() {
117                    return Err(String::from("Missing action"));
118                }
119                i += 2;
120
121                if index_string.len() == 0 {
122                    return Err(String::from("Missing index"));
123                }
124
125                match index_string.parse() {
126                    Ok (index) => tokens.push(NodeToken::ChainIndex (index)),
127                    Err (_)    => return Err (format!("Invalid index: {}", index_string)),
128                }
129            }
130            else if chars[i] == ':' {
131                let tokenized = NodeRunner::tokenize_action(&chars[i+1..])?;
132                tokens.push(NodeRunner::get_action(tokenized.iter())?);
133
134                tokens.reverse();
135
136                return Ok(NodeRunner {
137                    tokens: tokens
138                });
139            }
140            else {
141                // This happens after a ] followed by a character that doesnt start a new property, key or index
142                // So just assume the user forgot the dot on a property
143                return Err(String::from("Missing ."));
144            }
145        }
146    }
147
148    // Split string into tokens by whitespace.
149    // characters sorounded by quotes are considered one token regardless of whitespace
150    fn tokenize_action(string: &[char]) -> Result<Vec<String>, String> {
151        let mut tokens: Vec<String> = vec!();
152        let mut current = String::new();
153        let mut quoted = false;
154        let mut escaped = false;
155        for c in string {
156            if escaped {
157                match *c {
158                    '"'  => { current.push('"') }
159                    't'  => { current.push('\t') }
160                    'n'  => { current.push('\n') }
161                    ' '  => { current.push(' ') }
162                    '\\' => { current.push('\\') }
163                    _    => { }
164                }
165                escaped = false;
166            }
167            else if *c == '\\' {
168                escaped = true;
169            }
170            else if !quoted && c.is_whitespace() {
171                if current.len() > 0 {
172                    tokens.push(current);
173                    current = String::new();
174                }
175            }
176            else if *c == '"' {
177                if quoted {
178                    tokens.push(current);
179                    current = String::new();
180                }
181                quoted = !quoted;
182            }
183            else {
184                current.push(*c);
185            }
186        }
187
188        if current.len() > 0 {
189            tokens.push(current);
190        }
191
192        if quoted {
193            Err(String::from("Unterminated string"))
194        } else {
195            Ok(tokens)
196        }
197    }
198
199    fn get_action(mut action: Iter<String>) -> Result<NodeToken, String> {
200        match action.next().map(|x| x.as_ref()) {
201            Some("help")    => Ok(NodeToken::Help),
202            Some("reset")   => Ok(NodeToken::SetDefault),
203            Some("edit")    => Ok(NodeToken::Edit),
204            Some("copy")    => Ok(NodeToken::CopyFrom),
205            Some("paste")   => Ok(NodeToken::PasteTo),
206            Some("getkeys") => Ok(NodeToken::GetKeys),
207            Some("get")     => Ok(NodeToken::Get),
208            Some("set") => {
209                let mut set_value: Vec<&str> = vec!();
210                for token in action {
211                    set_value.push(token);
212                }
213                Ok(NodeToken::Set(set_value.join(" ")))
214            }
215            Some("insert") => {
216                match action.next() {
217                    Some(arg0) => {
218                        match action.next() {
219                            Some(arg1) => {
220                                match arg0.parse() {
221                                    Ok(index) => {
222                                        Ok(NodeToken::InsertIndexKey (index, arg1.to_string()))
223                                    }
224                                    Err(_) => Err(String::from("When two arguments are used, first must be a valid index."))
225                                }
226                            }
227                            None => {
228                                match arg0.parse() {
229                                    Ok(index) => Ok(NodeToken::InsertIndex (index)),
230                                    Err(_)    => Ok(NodeToken::InsertKey (arg0.to_string())),
231                                }
232                            }
233                        }
234                    }
235                    None => {
236                        Ok(NodeToken::Insert)
237                    }
238                }
239            }
240            Some("remove") => {
241                match action.next() {
242                    Some(arg) => {
243                        match arg.parse() {
244                            Ok(index) => Ok(NodeToken::RemoveIndex (index)),
245                            Err(_)    => Ok(NodeToken::RemoveKey (arg.to_string())),
246                        }
247                    }
248                    None => {
249                        Ok(NodeToken::Remove)
250                    }
251                }
252            }
253            Some("variant") => {
254                Ok(NodeToken::SetVariant (
255                    match action.next() {
256                        Some(value) => value.to_string(),
257                        None        => String::new()
258                    }
259                ))
260            }
261            Some(action_name) => {
262               let args: Vec<String> = action.cloned().collect();
263               Ok(NodeToken::Custom(action_name.to_string(), args))
264            }
265            None     => Err (String::from("Missing action"))
266        }
267    }
268
269    pub fn step(&mut self) -> NodeToken {
270        self.tokens.pop().unwrap()
271    }
272}