use std::rc::Rc;
use super::{Completion, Parser};
use super::constants::*;
use tokenizer::Token;
pub enum Node {
Command(CommandNode),
Parameter(ParameterNode),
ParameterName(ParameterNameNode),
Root(RootNode),
}
pub trait NodeOps {
fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token, node_ref: &Rc<Node>);
fn acceptable(&self, parser: &Parser, node_ref: &Rc<Node>) -> bool;
fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text>;
fn matches(&self, parser: &Parser, token: Token) -> bool;
}
pub struct TreeNode {
pub name: String,
pub help_symbol: String,
pub help_text: String,
pub hidden: bool,
pub priority: i32,
pub repeatable: bool,
pub repeat_marker: Option<Rc<Node>>,
pub successors: Vec<Rc<Node>>,
}
pub struct RootNode {
pub node: TreeNode,
}
pub struct CommandNode {
pub node: TreeNode,
pub handler: Option<fn(node: &Node) -> ()>,
pub parameters: Vec<Rc<Node>>,
pub wrapped_root: Option<Rc<Node>>,
}
pub struct ParameterNameNode {
pub node: TreeNode,
pub parameter: Rc<Node>,
}
pub struct ParameterNode {
pub node: TreeNode,
pub required: bool,
pub kind: ParameterKind,
}
impl PartialEq for Node {
fn eq(&self, other: &Self) -> bool {
self as *const _ == other as *const _
}
}
impl Node {
pub fn node(&self) -> &TreeNode {
match *self {
Node::Command(ref command) => &command.node,
Node::Parameter(ref parameter) => ¶meter.node,
Node::ParameterName(ref name) => &name.node,
Node::Root(ref root) => &root.node,
}
}
pub fn successors(&self) -> &Vec<Rc<Node>> {
match *self {
Node::Root(ref root) => &root.node.successors,
_ => &self.node().successors,
}
}
}
impl NodeOps for Node {
fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token, node_ref: &Rc<Node>) {
match *self {
Node::Command(ref command) => command.accept(parser, token, node_ref),
Node::Parameter(ref parameter) => parameter.accept(parser, token, node_ref),
Node::ParameterName(ref name) => name.accept(parser, token, node_ref),
Node::Root(ref root) => root.accept(parser, token, node_ref),
}
}
fn acceptable(&self, parser: &Parser, node_ref: &Rc<Node>) -> bool {
match *self {
Node::Command(ref command) => command.acceptable(parser, node_ref),
Node::Parameter(ref parameter) => parameter.acceptable(parser, node_ref),
Node::ParameterName(ref name) => name.acceptable(parser, node_ref),
Node::Root(ref root) => root.acceptable(parser, node_ref),
}
}
fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
match *self {
Node::Command(ref command) => command.complete(token),
Node::Parameter(ref parameter) => parameter.complete(token),
Node::ParameterName(ref name) => name.complete(token),
Node::Root(ref root) => root.complete(token),
}
}
fn matches(&self, parser: &Parser, token: Token) -> bool {
match *self {
Node::Command(ref command) => command.matches(parser, token),
Node::Parameter(ref parameter) => parameter.matches(parser, token),
Node::ParameterName(ref name) => name.matches(parser, token),
Node::Root(ref root) => root.matches(parser, token),
}
}
}
impl RootNode {
pub fn new(successors: Vec<Rc<Node>>) -> Self {
RootNode {
node: TreeNode {
name: "__root__".to_string(),
help_symbol: "".to_string(),
help_text: "".to_string(),
hidden: false,
priority: PRIORITY_DEFAULT,
repeat_marker: None,
repeatable: false,
successors: successors,
},
}
}
}
impl NodeOps for RootNode {
fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token, _node_ref: &Rc<Node>) {}
fn acceptable(&self, _parser: &Parser, _node_ref: &Rc<Node>) -> bool {
false
}
fn complete<'text>(&self, _token: Option<Token<'text>>) -> Completion<'text> {
panic!("BUG: Can not complete a root node.");
}
fn matches(&self, _parser: &Parser, _token: Token) -> bool {
panic!("BUG: Can not match a root node.");
}
}
impl CommandNode {
pub fn new(name: &str,
help_text: Option<&str>,
hidden: bool,
priority: i32,
successors: Vec<Rc<Node>>,
handler: Option<fn(node: &Node) -> ()>,
parameters: Vec<Rc<Node>>)
-> Self {
CommandNode {
node: TreeNode {
name: name.to_string(),
help_symbol: name.to_string(),
help_text: help_text.unwrap_or("Command").to_string(),
hidden: hidden,
priority: priority,
repeat_marker: None,
repeatable: false,
successors: successors,
},
handler: handler,
parameters: parameters,
wrapped_root: None,
}
}
}
impl NodeOps for CommandNode {
fn accept<'text>(&self, parser: &mut Parser<'text>, _token: Token, node_ref: &Rc<Node>) {
if self.handler.is_some() {
parser.commands.push(node_ref.clone())
}
}
fn acceptable(&self, parser: &Parser, node_ref: &Rc<Node>) -> bool {
!parser.nodes.contains(node_ref)
}
fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
Completion::new(self.node.help_symbol.clone(),
self.node.help_text.clone(),
token,
true,
vec![&self.node.name],
vec![])
}
fn matches(&self, _parser: &Parser, token: Token) -> bool {
self.node.name.starts_with(token.text)
}
}
impl ParameterNameNode {
pub fn new(name: &str,
hidden: bool,
priority: i32,
successors: Vec<Rc<Node>>,
repeatable: bool,
repeat_marker: Option<Rc<Node>>,
parameter: Rc<Node>)
-> Self {
let param_node = ¶meter.node();
let help_text = param_node.help_text.clone();
let help_symbol = name.to_string() + " " + param_node.help_symbol.as_str();
ParameterNameNode {
node: TreeNode {
name: name.to_string(),
help_symbol: help_symbol,
help_text: help_text,
hidden: hidden,
priority: priority,
repeat_marker: repeat_marker,
repeatable: repeatable,
successors: successors,
},
parameter: parameter.clone(),
}
}
}
impl NodeOps for ParameterNameNode {
fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token, _node_ref: &Rc<Node>) {}
fn acceptable(&self, parser: &Parser, node_ref: &Rc<Node>) -> bool {
if self.node.repeatable {
return true;
}
!parser.nodes.contains(node_ref) &&
match self.node.repeat_marker {
None => true,
Some(ref n) => !parser.nodes.contains(n),
}
}
fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
Completion::new(self.node.help_symbol.clone(),
self.node.help_text.clone(),
token,
true,
vec![&self.node.name],
vec![])
}
fn matches(&self, _parser: &Parser, token: Token) -> bool {
self.node.name.starts_with(token.text)
}
}
impl ParameterNode {
pub fn new(name: &str,
help_text: Option<&str>,
hidden: bool,
priority: i32,
successors: Vec<Rc<Node>>,
repeatable: bool,
repeat_marker: Option<Rc<Node>>,
kind: ParameterKind,
required: bool)
-> Self {
let help_symbol = if repeatable {
String::from("<") + name + ">..."
} else {
String::from("<") + name + ">"
};
let default_help_text = match kind {
ParameterKind::Flag => "Flag",
ParameterKind::Named | ParameterKind::Simple => "Parameter",
};
let help_text = help_text.unwrap_or(default_help_text).to_string();
ParameterNode {
node: TreeNode {
name: name.to_string(),
help_symbol: help_symbol,
help_text: help_text,
hidden: hidden,
priority: priority,
repeat_marker: repeat_marker,
repeatable: repeatable,
successors: successors,
},
kind: kind,
required: required,
}
}
}
impl NodeOps for ParameterNode {
fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token, _node_ref: &Rc<Node>) {
if self.node.repeatable {
unimplemented!();
} else {
parser.parameters.insert(self.node.name.clone(), token.text.to_string());
}
}
fn acceptable(&self, parser: &Parser, node_ref: &Rc<Node>) -> bool {
if self.node.repeatable {
return true;
}
!parser.nodes.contains(node_ref) &&
match self.node.repeat_marker {
None => true,
Some(ref n) => !parser.nodes.contains(n),
}
}
fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
match self.kind {
ParameterKind::Named | ParameterKind::Simple => {
Completion::new(self.node.help_symbol.clone(),
self.node.help_text.clone(),
token,
true,
vec![],
vec![])
}
ParameterKind::Flag => {
Completion::new(self.node.help_symbol.clone(),
self.node.help_text.clone(),
token,
true,
vec![&self.node.name],
vec![])
}
}
}
fn matches(&self, _parser: &Parser, token: Token) -> bool {
match self.kind {
ParameterKind::Named | ParameterKind::Simple => true,
ParameterKind::Flag => self.node.name.starts_with(token.text),
}
}
}