commands/parser/
nodes.rs

1// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6
7// Parser nodes represent the grammar that is defined
8// by the currently permissible set of commands and their
9// parameters.
10
11use std::rc::Rc;
12
13use super::{Completion, Parser};
14use super::constants::*;
15use tokenizer::Token;
16
17/// Enumeration of node types used to have vectors of `Node` and so on.
18pub enum Node {
19    /// `Node` variant wrapping a `CommandNode`.
20    Command(CommandNode),
21    /// `Node` variant wrapping a `ParameterNode`.
22    Parameter(ParameterNode),
23    /// `Node` variant wrapping a `ParameterNameNode`.
24    ParameterName(ParameterNameNode),
25    /// `Node` variant wrapping a `RootNode`.
26    Root(RootNode),
27}
28
29/// The operations that every node must implement.
30pub trait NodeOps {
31    /// Accept this node with the given `token` as data.
32    ///
33    /// By default, nothing needs to happen for `accept`.
34    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token, node_ref: &Rc<Node>);
35
36    /// Can this node be accepted in the current parser state?
37    /// By default, a node can be accepted when it hasn't been seen yet.
38    ///
39    /// The `node_ref` is provided so that implementations have access to
40    /// the `Rc<Node>` value for the node rather than having to rely upon
41    /// `self` which won't be a [`Node`], but the underlying [`CommandNode`]
42    /// or similar.
43    ///
44    /// [`Node`]: enum.Node.html
45    /// [`CommandNode`]: struct.CommandNode.html
46    fn acceptable(&self, parser: &Parser, node_ref: &Rc<Node>) -> bool;
47
48    /// Given a node and an optional token, provide the completion options.
49    ///
50    /// By default, completion should complete for the name of the given
51    /// node.
52    ///
53    /// This is the expected behavior for [`CommandNode`],
54    /// [`ParameterNameNode`], as well as [`ParameterNode`] where the
55    /// [`ParameterKind`] is `Flag`.
56    ///
57    /// [`CommandNode`]: struct.CommandNode.html
58    /// [`ParameterKind`]: enum.ParameterKind.html
59    /// [`ParameterNameNode`]: struct.ParameterNameNode.html
60    /// [`ParameterNode`]: struct.ParameterNode.html
61    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text>;
62
63    /// By default, a node matches a `token` when the name of the
64    /// node starts with the `token`.
65    ///
66    /// This is the expected behavior for [`CommandNode`],
67    /// [`ParameterNameNode`], as well as [`ParameterNode`] where the
68    /// [`ParameterKind`] is `Flag`.
69    ///
70    /// [`CommandNode`]: struct.CommandNode.html
71    /// [`ParameterKind`]: enum.ParameterKind.html
72    /// [`ParameterNameNode`]: struct.ParameterNameNode.html
73    /// [`ParameterNode`]: struct.ParameterNode.html
74    fn matches(&self, parser: &Parser, token: Token) -> bool;
75}
76
77/// A parse tree node.
78pub struct TreeNode {
79    /// The name of this node.
80    pub name: String,
81    /// The text used to identify this node in help text.
82    /// This is typically the node name, either in plain
83    /// form or decorated for parameters.
84    pub help_symbol: String,
85    /// Help text describing this node.
86    pub help_text: String,
87    /// Hidden nodes are not completed. This doesn't modify matching.
88    pub hidden: bool,
89    /// Match and complete priority.
90    pub priority: i32,
91    /// Whether or not this node can be repeated. A repeated
92    /// node can be `accept`ed multiple times.
93    pub repeatable: bool,
94    /// If present, this node will no longer be `acceptable`.
95    pub repeat_marker: Option<Rc<Node>>,
96    /// Possible successor nodes. Collected while building.
97    pub successors: Vec<Rc<Node>>,
98}
99
100/// The root of a command tree.
101pub struct RootNode {
102    /// [`TreeNode`] data.
103    ///
104    /// [`TreeNode`]: struct.TreeNode.html
105    pub node: TreeNode,
106}
107
108/// A node representing a command. Constructed via [`Command`] and [`CommandTree`].
109///
110/// If `wrapped_root` is set then this node wraps another command.
111/// This is used for the help command so that it can complete
112/// normal commands. The `successors` will be those of the wrapped node.
113///
114/// [`Command`]: struct.Command.html
115/// [`CommandTree`]: struct.CommandTree.html
116pub struct CommandNode {
117    /// [`TreeNode`] data.
118    ///
119    /// [`TreeNode`]: struct.TreeNode.html
120    pub node: TreeNode,
121    /// The handler which is executed once this node has been accepted.
122    pub handler: Option<fn(node: &Node) -> ()>,
123    /// Parameter nodes for this command
124    pub parameters: Vec<Rc<Node>>,
125    /// If present, the command wrapped by this node.
126    pub wrapped_root: Option<Rc<Node>>,
127}
128
129/// A node that represented the name portion of a named
130/// parameter.
131pub struct ParameterNameNode {
132    /// [`TreeNode`] data.
133    ///
134    /// [`TreeNode`]: struct.TreeNode.html
135    pub node: TreeNode,
136    /// The `parameter` named by this node.
137    pub parameter: Rc<Node>,
138}
139
140/// A node representing a parameter for a command.
141pub struct ParameterNode {
142    /// [`TreeNode`] data.
143    ///
144    /// [`TreeNode`]: struct.TreeNode.html
145    pub node: TreeNode,
146    /// A `required` parameter must be supplied for the
147    /// command line being parsed to be valid.
148    pub required: bool,
149    /// What type of `ParameterKind` this is.
150    pub kind: ParameterKind,
151}
152
153impl PartialEq for Node {
154    /// Nodes are equal based on pointer equality.
155    fn eq(&self, other: &Self) -> bool {
156        self as *const _ == other as *const _
157    }
158}
159
160/// The node in the tree of commands and parameters used in the
161/// parser.
162///
163/// This trait defines the core operations which a node must
164/// support.
165impl Node {
166    /// Get the [`TreeNode`] data for a given `Node`.
167    ///
168    /// [`TreeNode`]: struct.TreeNode.html
169    pub fn node(&self) -> &TreeNode {
170        match *self {
171            Node::Command(ref command) => &command.node,
172            Node::Parameter(ref parameter) => &parameter.node,
173            Node::ParameterName(ref name) => &name.node,
174            Node::Root(ref root) => &root.node,
175        }
176    }
177
178    /// Get or calculate successors of this node.
179    pub fn successors(&self) -> &Vec<Rc<Node>> {
180        match *self {
181            Node::Root(ref root) => &root.node.successors,
182            _ => &self.node().successors,
183        }
184    }
185}
186
187impl NodeOps for Node {
188    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token, node_ref: &Rc<Node>) {
189        match *self {
190            Node::Command(ref command) => command.accept(parser, token, node_ref),
191            Node::Parameter(ref parameter) => parameter.accept(parser, token, node_ref),
192            Node::ParameterName(ref name) => name.accept(parser, token, node_ref),
193            Node::Root(ref root) => root.accept(parser, token, node_ref),
194        }
195    }
196
197    fn acceptable(&self, parser: &Parser, node_ref: &Rc<Node>) -> bool {
198        match *self {
199            Node::Command(ref command) => command.acceptable(parser, node_ref),
200            Node::Parameter(ref parameter) => parameter.acceptable(parser, node_ref),
201            Node::ParameterName(ref name) => name.acceptable(parser, node_ref),
202            Node::Root(ref root) => root.acceptable(parser, node_ref),
203        }
204    }
205
206    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
207        match *self {
208            Node::Command(ref command) => command.complete(token),
209            Node::Parameter(ref parameter) => parameter.complete(token),
210            Node::ParameterName(ref name) => name.complete(token),
211            Node::Root(ref root) => root.complete(token),
212        }
213    }
214
215    fn matches(&self, parser: &Parser, token: Token) -> bool {
216        match *self {
217            Node::Command(ref command) => command.matches(parser, token),
218            Node::Parameter(ref parameter) => parameter.matches(parser, token),
219            Node::ParameterName(ref name) => name.matches(parser, token),
220            Node::Root(ref root) => root.matches(parser, token),
221        }
222    }
223}
224
225impl RootNode {
226    /// Create a new `RootNode`
227    pub fn new(successors: Vec<Rc<Node>>) -> Self {
228        RootNode {
229            node: TreeNode {
230                name: "__root__".to_string(),
231                help_symbol: "".to_string(),
232                help_text: "".to_string(),
233                hidden: false,
234                priority: PRIORITY_DEFAULT,
235                repeat_marker: None,
236                repeatable: false,
237                successors: successors,
238            },
239        }
240    }
241}
242
243/// `RootNode` does not want to perform any actual `NodeOps` as these
244/// operations should only be invoked by the `Parser` on successor nodes.
245impl NodeOps for RootNode {
246    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token, _node_ref: &Rc<Node>) {}
247
248    fn acceptable(&self, _parser: &Parser, _node_ref: &Rc<Node>) -> bool {
249        false
250    }
251
252    /// A `RootNode` can not be completed.
253    fn complete<'text>(&self, _token: Option<Token<'text>>) -> Completion<'text> {
254        panic!("BUG: Can not complete a root node.");
255    }
256
257    /// A `RootNode` can not be matched.
258    fn matches(&self, _parser: &Parser, _token: Token) -> bool {
259        panic!("BUG: Can not match a root node.");
260    }
261}
262
263impl CommandNode {
264    /// Construct a new `CommandNode`.
265    pub fn new(name: &str,
266               help_text: Option<&str>,
267               hidden: bool,
268               priority: i32,
269               successors: Vec<Rc<Node>>,
270               handler: Option<fn(node: &Node) -> ()>,
271               parameters: Vec<Rc<Node>>)
272               -> Self {
273        CommandNode {
274            node: TreeNode {
275                name: name.to_string(),
276                help_symbol: name.to_string(),
277                help_text: help_text.unwrap_or("Command").to_string(),
278                hidden: hidden,
279                priority: priority,
280                repeat_marker: None,
281                repeatable: false,
282                successors: successors,
283            },
284            handler: handler,
285            parameters: parameters,
286            wrapped_root: None,
287        }
288    }
289}
290
291impl NodeOps for CommandNode {
292    /// Record this command.
293    fn accept<'text>(&self, parser: &mut Parser<'text>, _token: Token, node_ref: &Rc<Node>) {
294        if self.handler.is_some() {
295            parser.commands.push(node_ref.clone())
296        }
297    }
298
299    fn acceptable(&self, parser: &Parser, node_ref: &Rc<Node>) -> bool {
300        !parser.nodes.contains(node_ref)
301    }
302
303    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
304        Completion::new(self.node.help_symbol.clone(),
305                        self.node.help_text.clone(),
306                        token,
307                        true,
308                        vec![&self.node.name],
309                        vec![])
310    }
311
312    fn matches(&self, _parser: &Parser, token: Token) -> bool {
313        self.node.name.starts_with(token.text)
314    }
315}
316
317impl ParameterNameNode {
318    /// Construct a new `ParameterNameNode`.
319    pub fn new(name: &str,
320               hidden: bool,
321               priority: i32,
322               successors: Vec<Rc<Node>>,
323               repeatable: bool,
324               repeat_marker: Option<Rc<Node>>,
325               parameter: Rc<Node>)
326               -> Self {
327        let param_node = &parameter.node();
328        let help_text = param_node.help_text.clone();
329        let help_symbol = name.to_string() + " " + param_node.help_symbol.as_str();
330        ParameterNameNode {
331            node: TreeNode {
332                name: name.to_string(),
333                help_symbol: help_symbol,
334                help_text: help_text,
335                hidden: hidden,
336                priority: priority,
337                repeat_marker: repeat_marker,
338                repeatable: repeatable,
339                successors: successors,
340            },
341            parameter: parameter.clone(),
342        }
343    }
344}
345
346impl NodeOps for ParameterNameNode {
347    /// Record this command.
348    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token, _node_ref: &Rc<Node>) {}
349
350    fn acceptable(&self, parser: &Parser, node_ref: &Rc<Node>) -> bool {
351        if self.node.repeatable {
352            return true;
353        }
354        !parser.nodes.contains(node_ref) &&
355        match self.node.repeat_marker {
356            None => true,
357            Some(ref n) => !parser.nodes.contains(n),
358        }
359    }
360
361    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
362        Completion::new(self.node.help_symbol.clone(),
363                        self.node.help_text.clone(),
364                        token,
365                        true,
366                        vec![&self.node.name],
367                        vec![])
368    }
369
370    fn matches(&self, _parser: &Parser, token: Token) -> bool {
371        self.node.name.starts_with(token.text)
372    }
373}
374
375impl ParameterNode {
376    /// Construct a new `ParameterNode`.
377    pub fn new(name: &str,
378               help_text: Option<&str>,
379               hidden: bool,
380               priority: i32,
381               successors: Vec<Rc<Node>>,
382               repeatable: bool,
383               repeat_marker: Option<Rc<Node>>,
384               kind: ParameterKind,
385               required: bool)
386               -> Self {
387        let help_symbol = if repeatable {
388            String::from("<") + name + ">..."
389        } else {
390            String::from("<") + name + ">"
391        };
392        let default_help_text = match kind {
393            ParameterKind::Flag => "Flag",
394            ParameterKind::Named | ParameterKind::Simple => "Parameter",
395        };
396        let help_text = help_text.unwrap_or(default_help_text).to_string();
397        ParameterNode {
398            node: TreeNode {
399                name: name.to_string(),
400                help_symbol: help_symbol,
401                help_text: help_text,
402                hidden: hidden,
403                priority: priority,
404                repeat_marker: repeat_marker,
405                repeatable: repeatable,
406                successors: successors,
407            },
408            kind: kind,
409            required: required,
410        }
411    }
412}
413
414impl NodeOps for ParameterNode {
415    /// Record this parameter value.
416    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token, _node_ref: &Rc<Node>) {
417        if self.node.repeatable {
418            unimplemented!();
419        } else {
420            parser.parameters.insert(self.node.name.clone(), token.text.to_string());
421        }
422    }
423
424    fn acceptable(&self, parser: &Parser, node_ref: &Rc<Node>) -> bool {
425        if self.node.repeatable {
426            return true;
427        }
428        !parser.nodes.contains(node_ref) &&
429        match self.node.repeat_marker {
430            None => true,
431            Some(ref n) => !parser.nodes.contains(n),
432        }
433    }
434
435    /// By default named and simple parameters complete only to the token
436    /// being input while flag parameters complete to the name of the flag.
437    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
438        match self.kind {
439            ParameterKind::Named | ParameterKind::Simple => {
440                Completion::new(self.node.help_symbol.clone(),
441                                self.node.help_text.clone(),
442                                token,
443                                true,
444                                vec![],
445                                vec![])
446            }
447            ParameterKind::Flag => {
448                Completion::new(self.node.help_symbol.clone(),
449                                self.node.help_text.clone(),
450                                token,
451                                true,
452                                vec![&self.node.name],
453                                vec![])
454            }
455        }
456    }
457
458    fn matches(&self, _parser: &Parser, token: Token) -> bool {
459        match self.kind {
460            ParameterKind::Named | ParameterKind::Simple => true,
461            ParameterKind::Flag => self.node.name.starts_with(token.text),
462        }
463    }
464}