mod builder;
mod completion;
mod constants;
mod nodes;
pub use self::builder::{Command, CommandTree, Parameter};
pub use self::constants::ParameterKind;
pub use self::constants::{PRIORITY_DEFAULT, PRIORITY_MINIMUM, PRIORITY_PARAMETER};
pub use self::completion::{Completion, CompletionOption};
pub use self::nodes::{Node, NodeOps, TreeNode};
pub use self::nodes::{CommandNode, ParameterNameNode, ParameterNode, RootNode};
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use tokenizer::{Token, TokenType};
pub struct Parser<'text> {
current_node: Rc<Node>,
pub nodes: Vec<Rc<Node>>,
pub tokens: Vec<Token<'text>>,
commands: Vec<Rc<Node>>,
parameters: HashMap<String, String>,
}
impl<'text> Parser<'text> {
pub fn new(initial_node: Rc<Node>) -> Parser<'text> {
Parser {
current_node: initial_node,
nodes: vec![],
tokens: vec![],
commands: vec![],
parameters: HashMap::new(),
}
}
pub fn complete(&self, token: Option<Token<'text>>) -> Vec<Completion> {
self.current_node
.successors()
.iter()
.filter(|n| {
!n.node().hidden && n.acceptable(self, n) &&
if let Some(t) = token {
n.matches(self, t)
} else {
true
}
})
.map(|n| n.complete(token))
.collect::<Vec<_>>()
}
pub fn parse(&mut self, tokens: Vec<Token<'text>>) -> Result<(), ParseError<'text>> {
for token in tokens {
match token.token_type {
TokenType::Whitespace => {}
TokenType::Word => try!(self.advance(token)),
}
}
Ok(())
}
pub fn advance(&mut self, token: Token<'text>) -> Result<(), ParseError<'text>> {
let matches = self.current_node
.successors()
.iter()
.filter(|n| n.acceptable(self, n) && n.matches(self, token))
.cloned()
.collect::<Vec<_>>();
match matches.len() {
1 => {
let matching_node = &matches[0];
matching_node.accept(self, token, matching_node);
self.current_node = matching_node.clone();
self.nodes.push(matching_node.clone());
self.tokens.push(token);
Ok(())
}
0 => {
Err(ParseError::NoMatches(token,
self.current_node
.successors()
.iter()
.filter(|n| n.acceptable(self, n))
.cloned()
.collect::<Vec<_>>()))
}
_ => Err(ParseError::AmbiguousMatch(token, matches)),
}
}
pub fn execute(&self) {
if !self.commands.is_empty() {
unimplemented!();
}
}
pub fn verify(&self) -> Result<(), VerifyError> {
if let Some(&Node::Command(ref command)) = self.commands.first().map(|n| &**n) {
for expected in &command.parameters {
if let Node::Parameter(ref param) = **expected {
let name = ¶m.node.name;
if param.required && !self.parameters.contains_key(name) {
return Err(VerifyError::MissingParameter(name.clone()));
}
} else {
unreachable!();
}
}
Ok(())
} else {
Err(VerifyError::NoCommandAccepted)
}
}
}
#[derive(Clone)]
pub enum ParseError<'text> {
NoMatches(Token<'text>, Vec<Rc<Node>>),
AmbiguousMatch(Token<'text>, Vec<Rc<Node>>),
}
impl<'text> fmt::Debug for ParseError<'text> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ParseError::NoMatches(token, _) => write!(f, "NoMatches({:?}, ...)", token),
ParseError::AmbiguousMatch(token, _) => write!(f, "AmbiguousMatch({:?}, ...)", token),
}
}
}
impl<'text> Error for ParseError<'text> {
fn description(&self) -> &str {
match *self {
ParseError::NoMatches(_, _) => "No match.",
ParseError::AmbiguousMatch(_, _) => "Ambiguous match.",
}
}
}
impl<'text> fmt::Display for ParseError<'text> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.description().fmt(f)
}
}
#[derive(Clone,Debug)]
pub enum VerifyError {
NoCommandAccepted,
MissingParameter(String),
}
impl Error for VerifyError {
fn description(&self) -> &str {
match *self {
VerifyError::NoCommandAccepted => "No command has been accepted by the parser.",
VerifyError::MissingParameter(_) => "A required parameter is missing.",
}
}
}
impl fmt::Display for VerifyError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.description().fmt(f)
}
}
#[cfg(test)]
mod test {
use super::*;
use tokenizer::tokenize;
#[test]
#[should_panic]
fn verify_signals_no_command() {
let root = CommandTree::new().finalize();
let parser = Parser::new(root);
match parser.verify() {
Err(VerifyError::NoCommandAccepted) => panic!(),
_ => {}
}
}
#[test]
#[should_panic]
fn parse_signals_no_matches() {
let mut tree = CommandTree::new();
tree.command(Command::new("show"));
let mut parser = Parser::new(tree.finalize());
if let Ok(tokens) = tokenize("h") {
match parser.parse(tokens) {
Err(ParseError::NoMatches(_, _)) => panic!(),
_ => {}
}
}
}
#[test]
#[should_panic]
fn parse_signals_ambiguous_match() {
let mut tree = CommandTree::new();
tree.command(Command::new("show"));
tree.command(Command::new("set"));
let mut parser = Parser::new(tree.finalize());
if let Ok(tokens) = tokenize("s") {
match parser.parse(tokens) {
Err(ParseError::AmbiguousMatch(_, _)) => panic!(),
_ => {}
}
}
}
}