<commit_before>extern crate tinyrsh;

use std::collections::HashMap;
use std::net::{TcpListener, TcpStream};
use std::io::{Read, Write};
use std::os::unix::io::{RawFd, AsRawFd};
use tinyrsh::select as select;
use tinyrsh::select::FdSet;
use tinyrsh::child::PersistentChild;

fn greet_client(mut stream: &TcpStream) {
    let remote = stream.peer_addr().unwrap();
    println!("connected: {}", remote);

    match stream.write(b"hello\n") {
        Err(e) => println!("{}", e),
        Ok(n) => println!("wrote {} bytes", n),
    };
}

fn read_child<T: Read>(readt: &mut T) {
    let mut buf = [0; 10];
    let n = readt.read(&mut buf).expect("read_child");
    println!("{:?} ({} bytes) `{}'", buf, n, String::from_utf8_lossy(&buf[..n]));
}

fn forward_to_remotes<T: Read, S>(child_out: &mut T, clients: &HashMap<S, TcpStream>) -> bool
    where S : std::cmp::Eq, S : std::hash::Hash
{
    let mut buf = [0; 10];
    let n = child_out.read(&mut buf).expect("read_child");
    let child_eof = (n == 0);
    if clients.is_empty() {
        println!("Warning: child output but no remote connected");
        println!("{:?} ({} bytes) `{}'", buf, n, String::from_utf8_lossy(&buf[..n]));
    }
    for mut remote in clients.values(){
        //println!("forwarding to {}", remote.peer_addr().unwrap());
        let written = remote.write(&buf[..n]).expect("remote write");
        assert_eq!(n, written);
    }
    child_eof
}

fn copy_to<T: Read, U: Write>(from: &mut T, to: &mut U) -> bool {
    let mut buf = [0; 10];
    let n = from.read(&mut buf).expect("copy_to read");
    //println!("copy_to read {:?} ({} bytes) `{}'", buf, n, String::from_utf8_lossy(&buf[..n]));
    let written = to.write(&buf[..n]).expect("copy_to write");
    to.flush();
    assert_eq!(n, written);

    n != 0
}

fn main() {
    println!("Hello, world!");

    let mut child = PersistentChild::new("../py-ptysh/ptysh.py");

    // TODO linebuffered? how is child output buffered at all?

    let listener = TcpListener::bind("127.0.0.1:6699").unwrap();

    let mut all_fdset = FdSet::new();
    let srv_fd = listener.as_raw_fd(); // not consumed

    //high fd for select() call
    let mut high_fd = 0;

    for fd in [srv_fd, child.child.stdout.as_ref().unwrap().as_raw_fd(), child.child.stderr.as_ref().unwrap().as_raw_fd()].iter() {
        println!("inserting fd {}", fd);
        all_fdset.insert(*fd);
        high_fd = std::cmp::max(high_fd, *fd);
    };

    let mut clients: HashMap<RawFd, TcpStream> = HashMap::new(); //could also use FromRawFd

    fn add_client(all_fdset: &mut FdSet, clients: &mut HashMap<RawFd, TcpStream>, stream: TcpStream) -> RawFd {
        let stream_fd: RawFd = stream.as_raw_fd(); //not consume
        println!("inserted fd {}", stream_fd);
        clients.insert(stream_fd, stream);
        all_fdset.insert(stream_fd);
        stream_fd
    };
    fn del_client(all_fdset: &mut FdSet, clients: &mut HashMap<RawFd, TcpStream>, stream_fd: RawFd) {
        assert!(clients.contains_key(&stream_fd));
        //let stream = clients.get(&stream_fd);
        println!("removing fd {}", stream_fd);
        assert!(all_fdset.contains(stream_fd));
        all_fdset.remove(stream_fd);
        assert!(clients.contains_key(&stream_fd));
        clients.remove(&stream_fd);
    };

   println!("select-looping");
   loop {
       //println!("all_fdset debug: {}", all_fdset.debug());
       //let mut fdset = all_fdset.clone();
       assert!(all_fdset.high_fd <= high_fd);
       //assert_eq!(high_fd, fdset.high_fd);
       let (num_active, fdset) = all_fdset.readfds_select();
       assert!(high_fd >= fdset.high_fd);
       assert!(num_active > 0);
       println!("selected returned {}", num_active);
        //TODO assertion fails because select, ...
       println!("fdset debug: {}", fdset.debug());

       let mut accept_new = false;

       let mut handled_fds = 0;
       for i in 0 .. high_fd + 1 {
           if fdset.contains(i) {
               if i == srv_fd {
                   println!("need to accept new connection");
                   accept_new = true;
                   //TODO move code?
               } else if child.is_stdout(i) {
                   println!("child fd {} (stdout) got active", i);
                   let child_eof = forward_to_remotes(child.stdout_as_mut(), &clients);
                   if child_eof {
                       println!("!!!!!!! child exited. pipe will break now");
                       //println!("exit code: {}", child.wait().expect("child unexpected state"));
                       //ahh, ownership!
                   }
                   assert!(!child_eof, "child exited, unhandled!");
               } else if child.is_stderr(i) {
                   println!("child fd {} (stderr) got active", i);
                   read_child(child.stderr_as_mut());
               } else {
                   assert!(clients.contains_key(&i));
                   let cont = {
                       //let ref stream = clients[&i];
                       let stream: &mut TcpStream= clients.get_mut(&i).unwrap();
                       //read_client(stream)
                       copy_to(stream, child.stdin_as_mut())
                   };
                   if !cont {
                       del_client(&mut all_fdset, &mut clients, i);
                   };
               }
               handled_fds += 1;
           }
       }
       assert_eq!(handled_fds, num_active);

       //accept new connection
       if accept_new {
           match listener.accept() {
               Err(e) => println!("couldn't get client: {:?}", e),
               Ok((mut stream, addr)) => {
                   println!("new client: {:?}", addr);
                   greet_client(&mut stream);
                   high_fd = std::cmp::max(high_fd, add_client(&mut all_fdset, &mut clients, stream));
                   println!("new high fd: {}", high_fd);
               }
           }
       }
    }
}
<commit_msg>removing highfd handling from main<commit_after>extern crate tinyrsh;

use std::collections::HashMap;
use std::net::{TcpListener, TcpStream};
use std::io::{Read, Write};
use std::os::unix::io::{RawFd, AsRawFd};
use tinyrsh::select as select;
use tinyrsh::select::FdSet;
use tinyrsh::child::PersistentChild;

fn greet_client(mut stream: &TcpStream) {
    let remote = stream.peer_addr().unwrap();
    println!("connected: {}", remote);

    match stream.write(b"hello\n") {
        Err(e) => println!("{}", e),
        Ok(n) => println!("wrote {} bytes", n),
    };
}

fn read_child<T: Read>(readt: &mut T) {
    let mut buf = [0; 10];
    let n = readt.read(&mut buf).expect("read_child");
    println!("{:?} ({} bytes) `{}'", buf, n, String::from_utf8_lossy(&buf[..n]));
}

fn forward_to_remotes<T: Read, S>(child_out: &mut T, clients: &HashMap<S, TcpStream>) -> bool
    where S : std::cmp::Eq, S : std::hash::Hash
{
    let mut buf = [0; 10];
    let n = child_out.read(&mut buf).expect("read_child");
    let child_eof = (n == 0);
    if clients.is_empty() {
        println!("Warning: child output but no remote connected");
        println!("{:?} ({} bytes) `{}'", buf, n, String::from_utf8_lossy(&buf[..n]));
    }
    for mut remote in clients.values(){
        //println!("forwarding to {}", remote.peer_addr().unwrap());
        let written = remote.write(&buf[..n]).expect("remote write");
        assert_eq!(n, written);
    }
    child_eof
}

fn copy_to<T: Read, U: Write>(from: &mut T, to: &mut U) -> bool {
    let mut buf = [0; 10];
    let n = from.read(&mut buf).expect("copy_to read");
    //println!("copy_to read {:?} ({} bytes) `{}'", buf, n, String::from_utf8_lossy(&buf[..n]));
    let written = to.write(&buf[..n]).expect("copy_to write");
    to.flush();
    assert_eq!(n, written);

    n != 0
}

fn main() {
    println!("Hello, world!");

    let mut child = PersistentChild::new("../py-ptysh/ptysh.py");

    // TODO linebuffered? how is child output buffered at all?

    let listener = TcpListener::bind("127.0.0.1:6699").unwrap();

    let mut all_fdset = FdSet::new();
    let srv_fd = listener.as_raw_fd(); // not consumed

    for fd in [srv_fd, child.child.stdout.as_ref().unwrap().as_raw_fd(), child.child.stderr.as_ref().unwrap().as_raw_fd()].iter() {
        println!("inserting fd {}", fd);
        all_fdset.insert(*fd);
    };

    let mut clients: HashMap<RawFd, TcpStream> = HashMap::new(); //could also use FromRawFd

    fn add_client(all_fdset: &mut FdSet, clients: &mut HashMap<RawFd, TcpStream>, stream: TcpStream) -> RawFd {
        let stream_fd: RawFd = stream.as_raw_fd(); //not consume
        println!("inserted fd {}", stream_fd);
        clients.insert(stream_fd, stream);
        all_fdset.insert(stream_fd);
        stream_fd
    };
    fn del_client(all_fdset: &mut FdSet, clients: &mut HashMap<RawFd, TcpStream>, stream_fd: RawFd) {
        assert!(clients.contains_key(&stream_fd));
        //let stream = clients.get(&stream_fd);
        println!("removing fd {}", stream_fd);
        assert!(all_fdset.contains(stream_fd));
        all_fdset.remove(stream_fd);
        assert!(clients.contains_key(&stream_fd));
        clients.remove(&stream_fd);
    };

   println!("select-looping");
   loop {
       let (num_active, fdset) = all_fdset.readfds_select();
       assert!(num_active > 0);
       println!("selected returned {}", num_active);
       println!("fdset debug: {}", fdset.debug());

       let mut accept_new = false;

       let mut handled_fds = 0;
       for i in 0 .. fdset.high_fd + 1 {
           if fdset.contains(i) {
               if i == srv_fd {
                   println!("need to accept new connection");
                   accept_new = true;
                   //TODO move code?
               } else if child.is_stdout(i) {
                   println!("child fd {} (stdout) got active", i);
                   let child_eof = forward_to_remotes(child.stdout_as_mut(), &clients);
                   if child_eof {
                       println!("!!!!!!! child exited. pipe will break now");
                       //println!("exit code: {}", child.wait().expect("child unexpected state"));
                       //ahh, ownership!
                   }
                   assert!(!child_eof, "child exited, unhandled!");
               } else if child.is_stderr(i) {
                   println!("child fd {} (stderr) got active", i);
                   read_child(child.stderr_as_mut());
               } else {
                   assert!(clients.contains_key(&i));
                   let cont = {
                       //let ref stream = clients[&i];
                       let stream: &mut TcpStream= clients.get_mut(&i).unwrap();
                       //read_client(stream)
                       copy_to(stream, child.stdin_as_mut())
                   };
                   if !cont {
                       del_client(&mut all_fdset, &mut clients, i);
                   };
               }
               handled_fds += 1;
           }
       }
       assert_eq!(handled_fds, num_active);

       //accept new connection
       if accept_new {
           match listener.accept() {
               Err(e) => println!("couldn't get client: {:?}", e),
               Ok((mut stream, addr)) => {
                   println!("new client: {:?}", addr);
                   greet_client(&mut stream);
                   add_client(&mut all_fdset, &mut clients, stream);
               }
           }
       }
    }
}
<|endoftext|>


<commit_before><commit_msg>Added another swap fix<commit_after><|endoftext|>


<commit_before>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! RESTful API server to easily expose services as RESTful JSON/HTTP endpoints.
//! Fairly constrained on what the service API must look like by design.
//!
//! To use it, just have your service(s) implement the ApiEndpoint trait and
//! register them on a ApiServer.

use std::error::Error;
use std::fmt::{self, Display, Debug, Formatter};
use std::io::Read;
use std::net::ToSocketAddrs;
use std::ops::Index;
use std::string::ToString;
use std::str::FromStr;

use iron::{Iron, Request, Response, IronResult, IronError, status, headers};
use iron::method::Method;
use iron::modifiers::Header;
use iron::middleware::Handler;
use router::Router;
use serde::{Serialize, Deserialize};
use serde_json;

/// Errors that can be returned by an ApiEndpoint implementation.
#[derive(Debug)]
pub enum ApiError {
	Internal(String),
	Argument(String),
}

impl Display for ApiError {
	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
		match *self {
			ApiError::Argument(ref s) => write!(f, "Bad arguments: {}", s),
			ApiError::Internal(ref s) => write!(f, "Internal error: {}", s),
		}
	}
}

impl Error for ApiError {
	fn description(&self) -> &str {
		match *self {
			ApiError::Argument(_) => "Bad arguments.",
			ApiError::Internal(_) => "Internal error.",
		}
	}
}

impl From<ApiError> for IronError {
	fn from(e: ApiError) -> IronError {
		match e {
			ApiError::Argument(_) => IronError::new(e, status::Status::BadRequest),
			ApiError::Internal(_) => IronError::new(e, status::Status::InternalServerError),
		}
	}
}

pub type ApiResult<T> = ::std::result::Result<T, ApiError>;

/// Trait to implement to expose a service as a RESTful HTTP endpoint. Each
/// method corresponds to a specific relative URL and HTTP method following
/// basic REST principles:
///
/// * create: POST /
/// * get:    GET /:id
/// * update: PUT /:id
/// * delete: DELETE /:id
///
/// The methods method defines which operation the endpoint implements, they're
/// all optional by default. It also allows the framework to automatically
/// define the OPTIONS HTTP method.
///
/// The type accepted by create and update, and returned by get, must implement
/// the serde Serialize and Deserialize traits. The identifier type returned by
/// create and accepted by all other methods must have a string representation.
pub trait ApiEndpoint: Clone + Send + Sync + 'static {
	type ID: ToString + FromStr;
	type T: Serialize + Deserialize;

	fn methods(&self) -> Vec<Method>;

	#[allow(unused_variables)]
	fn create(&self, o: Self::T) -> ApiResult<Self::ID> {
		unimplemented!()
	}

	#[allow(unused_variables)]
	fn delete(&self, id: Self::ID) -> ApiResult<()> {
		unimplemented!()
	}

	#[allow(unused_variables)]
	fn update(&self, id: Self::ID, o: Self::T) -> ApiResult<()> {
		unimplemented!()
	}

	#[allow(unused_variables)]
	fn get(&self, id: Self::ID) -> ApiResult<Self::T> {
		unimplemented!()
	}
}

// Wrapper required to define the implementation below, Rust doesn't let us
// define the parametric implementation for trait from another crate.
struct ApiWrapper<E>(E);

impl<E> Handler for ApiWrapper<E>
	where E: ApiEndpoint,
	      <<E as ApiEndpoint>::ID as FromStr>::Err: Debug + Send + Error
{
	fn handle(&self, req: &mut Request) -> IronResult<Response> {
		match req.method {
			Method::Get => {
				let res = self.0.get(extract_param(req, "id")?)?;
				let res_json = serde_json::to_string(&res)
          .map_err(|e| IronError::new(e, status::InternalServerError))?;
				Ok(Response::with((status::Ok, res_json)))
			}
			Method::Put => {
				let id = extract_param(req, "id")?;
				let t: E::T = serde_json::from_reader(req.body.by_ref())
          .map_err(|e| IronError::new(e, status::BadRequest))?;
				self.0.update(id, t)?;
				Ok(Response::with(status::NoContent))
			}
			Method::Delete => {
				let id = extract_param(req, "id")?;
				self.0.delete(id)?;
				Ok(Response::with(status::NoContent))
			}
			Method::Post => {
				let t: E::T = serde_json::from_reader(req.body.by_ref())
          .map_err(|e| IronError::new(e, status::BadRequest))?;
				let id = self.0.create(t)?;
				Ok(Response::with((status::Created, id.to_string())))
			}
			_ => Ok(Response::with(status::MethodNotAllowed)),
		}
	}
}

fn extract_param<ID>(req: &mut Request, param: &'static str) -> IronResult<ID>
	where ID: ToString + FromStr,
	      <ID as FromStr>::Err: Debug + Send + Error + 'static
{

	let id = req.extensions.get::<Router>().unwrap().find(param).unwrap_or("");
	id.parse::<ID>().map_err(|e| IronError::new(e, status::BadRequest))
}

/// HTTP server allowing the registration of ApiEndpoint implementations.
pub struct ApiServer {
	root: String,
	router: Router,
}

impl ApiServer {
	/// Creates a new ApiServer that will serve ApiEndpoint implementations
	/// under the root URL.
	pub fn new(root: String) -> ApiServer {
		ApiServer {
			root: root,
			router: Router::new(),
		}
	}

	/// Starts the ApiServer at the provided address.
	pub fn start<A: ToSocketAddrs>(self, addr: A) -> Result<(), String> {
		Iron::new(self.router).http(addr).map(|_| ()).map_err(|e| e.to_string())
	}

	/// Register a new API endpoint, providing a relative URL for the new
	/// endpoint.
	pub fn register_endpoint<E>(&mut self, subpath: String, endpoint: E)
		where E: ApiEndpoint,
		      <<E as ApiEndpoint>::ID as FromStr>::Err: Debug + Send + Error
	{

		assert_eq!(subpath.chars().nth(0).unwrap(), '/');

		// declare a route for each method actually implemented by the endpoint
		let route_postfix = &subpath[1..];
		let root = self.root.clone() + &subpath;
		for m in endpoint.methods() {
			let full_path = match m {
				Method::Get => root.clone() + "/:id",
				Method::Put => root.clone() + "/:id",
				Method::Delete => root.clone() + "/:id",
				Method::Post => root.clone(),
				_ => panic!(format!("Unsupported method: {}.", m)),
			};
			self.router.route(m.clone(),
			                  full_path,
			                  ApiWrapper(endpoint.clone()),
			                  m.to_string() + "_" + route_postfix);
		}

		// support for the HTTP Options method by differentiating what's on the
		// root resource vs the id resource
		let (root_opts, sub_opts) = endpoint.methods().iter().fold((vec![], vec![]),
		                                                           |mut acc, m| {
			if *m == Method::Post {
				acc.0.push(m.clone());
			} else {
				acc.1.push(m.clone());
			}
			acc
		});
		self.router.options(root.clone(),
		                    move |_: &mut Request| {
			                    Ok(Response::with((status::Ok,
			                                       Header(headers::Allow(root_opts.clone())))))
			                   },
		                    "option_".to_string() + route_postfix);
		self.router.options(root.clone() + "/:id",
		                    move |_: &mut Request| {
			                    Ok(Response::with((status::Ok,
			                                       Header(headers::Allow(sub_opts.clone())))))
			                   },
		                    "option_id_".to_string() + route_postfix);
	}
}

#[cfg(test)]
mod test {
	use super::*;
	use rest::*;

	#[derive(Serialize, Deserialize)]
	pub struct Animal {
		name: String,
		legs: u32,
		lethal: bool,
	}

	#[derive(Clone)]
	pub struct TestApi;

	impl ApiEndpoint for TestApi {
		type ID = String;
		type T = Animal;

		fn methods(&self) -> Vec<Method> {
			vec![Method::Get]
		}

		fn get(&self, name: String) -> Result<Animal> {
			Ok(Animal {
				name: name,
				legs: 4,
				lethal: false,
			})
		}
	}

	#[test]
	fn req_chain_json() {
		let mut apis = ApiServer::new("/v1".to_string());
		apis.register_endpoint("/animal".to_string(), TestApi);
	}
}
<commit_msg>Fix error[E0243]: wrong number of type arguments (#41)<commit_after>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! RESTful API server to easily expose services as RESTful JSON/HTTP endpoints.
//! Fairly constrained on what the service API must look like by design.
//!
//! To use it, just have your service(s) implement the ApiEndpoint trait and
//! register them on a ApiServer.

use std::error::Error;
use std::fmt::{self, Display, Debug, Formatter};
use std::io::Read;
use std::net::ToSocketAddrs;
use std::ops::Index;
use std::string::ToString;
use std::str::FromStr;

use iron::{Iron, Request, Response, IronResult, IronError, status, headers};
use iron::method::Method;
use iron::modifiers::Header;
use iron::middleware::Handler;
use router::Router;
use serde::{Serialize, Deserialize};
use serde_json;

/// Errors that can be returned by an ApiEndpoint implementation.
#[derive(Debug)]
pub enum ApiError {
	Internal(String),
	Argument(String),
}

impl Display for ApiError {
	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
		match *self {
			ApiError::Argument(ref s) => write!(f, "Bad arguments: {}", s),
			ApiError::Internal(ref s) => write!(f, "Internal error: {}", s),
		}
	}
}

impl Error for ApiError {
	fn description(&self) -> &str {
		match *self {
			ApiError::Argument(_) => "Bad arguments.",
			ApiError::Internal(_) => "Internal error.",
		}
	}
}

impl From<ApiError> for IronError {
	fn from(e: ApiError) -> IronError {
		match e {
			ApiError::Argument(_) => IronError::new(e, status::Status::BadRequest),
			ApiError::Internal(_) => IronError::new(e, status::Status::InternalServerError),
		}
	}
}

pub type ApiResult<T> = ::std::result::Result<T, ApiError>;

/// Trait to implement to expose a service as a RESTful HTTP endpoint. Each
/// method corresponds to a specific relative URL and HTTP method following
/// basic REST principles:
///
/// * create: POST /
/// * get:    GET /:id
/// * update: PUT /:id
/// * delete: DELETE /:id
///
/// The methods method defines which operation the endpoint implements, they're
/// all optional by default. It also allows the framework to automatically
/// define the OPTIONS HTTP method.
///
/// The type accepted by create and update, and returned by get, must implement
/// the serde Serialize and Deserialize traits. The identifier type returned by
/// create and accepted by all other methods must have a string representation.
pub trait ApiEndpoint: Clone + Send + Sync + 'static {
	type ID: ToString + FromStr;
	type T: Serialize + Deserialize;

	fn methods(&self) -> Vec<Method>;

	#[allow(unused_variables)]
	fn create(&self, o: Self::T) -> ApiResult<Self::ID> {
		unimplemented!()
	}

	#[allow(unused_variables)]
	fn delete(&self, id: Self::ID) -> ApiResult<()> {
		unimplemented!()
	}

	#[allow(unused_variables)]
	fn update(&self, id: Self::ID, o: Self::T) -> ApiResult<()> {
		unimplemented!()
	}

	#[allow(unused_variables)]
	fn get(&self, id: Self::ID) -> ApiResult<Self::T> {
		unimplemented!()
	}
}

// Wrapper required to define the implementation below, Rust doesn't let us
// define the parametric implementation for trait from another crate.
struct ApiWrapper<E>(E);

impl<E> Handler for ApiWrapper<E>
	where E: ApiEndpoint,
	      <<E as ApiEndpoint>::ID as FromStr>::Err: Debug + Send + Error
{
	fn handle(&self, req: &mut Request) -> IronResult<Response> {
		match req.method {
			Method::Get => {
				let res = self.0.get(extract_param(req, "id")?)?;
				let res_json = serde_json::to_string(&res)
          .map_err(|e| IronError::new(e, status::InternalServerError))?;
				Ok(Response::with((status::Ok, res_json)))
			}
			Method::Put => {
				let id = extract_param(req, "id")?;
				let t: E::T = serde_json::from_reader(req.body.by_ref())
          .map_err(|e| IronError::new(e, status::BadRequest))?;
				self.0.update(id, t)?;
				Ok(Response::with(status::NoContent))
			}
			Method::Delete => {
				let id = extract_param(req, "id")?;
				self.0.delete(id)?;
				Ok(Response::with(status::NoContent))
			}
			Method::Post => {
				let t: E::T = serde_json::from_reader(req.body.by_ref())
          .map_err(|e| IronError::new(e, status::BadRequest))?;
				let id = self.0.create(t)?;
				Ok(Response::with((status::Created, id.to_string())))
			}
			_ => Ok(Response::with(status::MethodNotAllowed)),
		}
	}
}

fn extract_param<ID>(req: &mut Request, param: &'static str) -> IronResult<ID>
	where ID: ToString + FromStr,
	      <ID as FromStr>::Err: Debug + Send + Error + 'static
{

	let id = req.extensions.get::<Router>().unwrap().find(param).unwrap_or("");
	id.parse::<ID>().map_err(|e| IronError::new(e, status::BadRequest))
}

/// HTTP server allowing the registration of ApiEndpoint implementations.
pub struct ApiServer {
	root: String,
	router: Router,
}

impl ApiServer {
	/// Creates a new ApiServer that will serve ApiEndpoint implementations
	/// under the root URL.
	pub fn new(root: String) -> ApiServer {
		ApiServer {
			root: root,
			router: Router::new(),
		}
	}

	/// Starts the ApiServer at the provided address.
	pub fn start<A: ToSocketAddrs>(self, addr: A) -> Result<(), String> {
		Iron::new(self.router).http(addr).map(|_| ()).map_err(|e| e.to_string())
	}

	/// Register a new API endpoint, providing a relative URL for the new
	/// endpoint.
	pub fn register_endpoint<E>(&mut self, subpath: String, endpoint: E)
		where E: ApiEndpoint,
		      <<E as ApiEndpoint>::ID as FromStr>::Err: Debug + Send + Error
	{

		assert_eq!(subpath.chars().nth(0).unwrap(), '/');

		// declare a route for each method actually implemented by the endpoint
		let route_postfix = &subpath[1..];
		let root = self.root.clone() + &subpath;
		for m in endpoint.methods() {
			let full_path = match m {
				Method::Get => root.clone() + "/:id",
				Method::Put => root.clone() + "/:id",
				Method::Delete => root.clone() + "/:id",
				Method::Post => root.clone(),
				_ => panic!(format!("Unsupported method: {}.", m)),
			};
			self.router.route(m.clone(),
			                  full_path,
			                  ApiWrapper(endpoint.clone()),
			                  m.to_string() + "_" + route_postfix);
		}

		// support for the HTTP Options method by differentiating what's on the
		// root resource vs the id resource
		let (root_opts, sub_opts) = endpoint.methods().iter().fold((vec![], vec![]),
		                                                           |mut acc, m| {
			if *m == Method::Post {
				acc.0.push(m.clone());
			} else {
				acc.1.push(m.clone());
			}
			acc
		});
		self.router.options(root.clone(),
		                    move |_: &mut Request| {
			                    Ok(Response::with((status::Ok,
			                                       Header(headers::Allow(root_opts.clone())))))
			                   },
		                    "option_".to_string() + route_postfix);
		self.router.options(root.clone() + "/:id",
		                    move |_: &mut Request| {
			                    Ok(Response::with((status::Ok,
			                                       Header(headers::Allow(sub_opts.clone())))))
			                   },
		                    "option_id_".to_string() + route_postfix);
	}
}

#[cfg(test)]
mod test {
	use super::*;
	use rest::*;

	#[derive(Serialize, Deserialize)]
	pub struct Animal {
		name: String,
		legs: u32,
		lethal: bool,
	}

	#[derive(Clone)]
	pub struct TestApi;

	impl ApiEndpoint for TestApi {
		type ID = String;
		type T = Animal;

		fn methods(&self) -> Vec<Method> {
			vec![Method::Get]
		}

		fn get(&self, name: String) -> ApiResult<Animal> {
			Ok(Animal {
				name: name,
				legs: 4,
				lethal: false,
			})
		}
	}

	#[test]
	fn req_chain_json() {
		let mut apis = ApiServer::new("/v1".to_string());
		apis.register_endpoint("/animal".to_string(), TestApi);
	}
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the `commands::tokenizer` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The command parser consists of two important things:
//!
//! * A tree that represents the available commands and their arguments.
//!   This tree consists of instances of `Nodes` from the
//!   `commands::parser::nodes` module. Construction of this tree
//!   is done with the help of the `commands::parser::builder` module.
//! * A `Parser` that handles input and matches it against the command
//!   tree. This parser is intended to be short-lived and to just live
//!   for the duration of parsing and evaluating a single command line
//!   input.

pub mod nodes;
pub mod completion;
pub mod builder;

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'p` refers to the lifetime of the
/// parser itself, the root node of the command tree that was
/// used to create this parser, as well as the tokens passed
/// into the parser.
///
/// ```
/// use commands::parser::nodes::RootNode;
/// use commands::parser::Parser;
///
/// let root = RootNode::new(vec![]);
/// let mut parser = Parser::new(root);
/// ```
///
/// The parser is constructed as a `mut`able object as most of
/// the methods on it will modify its state.
pub struct Parser<'p> {
    current_node: Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<Token<'p>>,
    commands: Vec<Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'p> Parser<'p> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: Rc<RootNode>) -> Parser<'p> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    ///
    /// Possible completions are successors of the current node which
    /// are not `hidden`, are `acceptable`, and which match the token,
    /// if one has been provided.
    ///
    /// Nodes may customize the `Complete` trait to customize the
    /// `Completion` and `CompletionOption`s which are generated
    /// for that node.
    ///
    /// Each valid successor node will have one `Completion` in the
    /// result vector. Each `Completion` will have one or more
    /// `CompletionOption` for each valid way that the value may be
    /// entered.
    ///
    /// ```
    /// use commands::parser::builder::{Command, CommandTree};
    /// use commands::parser::Parser;
    /// use commands::tokenizer::{Token, tokenize};
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show").finalize());
    /// tree.command(Command::new("set").finalize());
    /// tree.command(Command::new("help").finalize());
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// // Completing now should have 3 options, 1 for each command.
    /// let comps = parser.complete(None);
    /// assert_eq!(comps.len(), 3);
    ///
    /// // But completing with a token for 'h' should have 1 option.
    /// if let Ok(tokens) = tokenize("h") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 1);
    ///   assert_eq!(comps[0].options.len(), 1);
    ///   assert_eq!(comps[0].options[0].option_string, "help");
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    ///
    /// // And completing for 's' should have 2 options.
    /// if let Ok(tokens) = tokenize("s") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 2);
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    /// ```
    pub fn complete(&self, token: Option<Token<'p>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.hidden() && n.acceptable(self) &&
                if let Some(t) = token {
                    n.matches(self, t)
                } else {
                    true
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    ///
    /// ```
    /// use commands::parser::nodes::RootNode;
    /// use commands::parser::Parser;
    /// use commands::tokenizer::tokenize;
    ///
    /// let root = RootNode::new(vec![]);
    /// let mut parser = Parser::new(root);
    ///
    /// if let Ok(tokens) = tokenize("show interface") {
    ///     parser.parse(tokens);
    /// }
    /// ```
    pub fn parse(&mut self, tokens: Vec<Token<'p>>) -> Result<(), ParseError<'p>> {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => try!(self.advance(token)),
            }
        }
        Ok(())
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: Token<'p>) -> Result<(), ParseError<'p>> {
        // We clone the current node so that it doesn't stay borrowed
        // and break things when we try to modify it below.
        let cn = self.current_node.clone();
        let matches = cn.successors()
                        .into_iter()
                        .filter(|n| n.acceptable(self) && n.matches(self, token))
                        .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node.clone());
                self.tokens.push(token);
                Ok(())
            }
            0 => Err(ParseError::NoMatches(token)),
            _ => Err(ParseError::AmbiguousMatch(token)),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    pub fn verify(&self) -> Result<(), VerifyError> {
        if self.commands.is_empty() {
            return Err(VerifyError::NoCommandAccepted);
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() && !self.parameters.contains_key(expected.name()) {
                    return Err(VerifyError::MissingParameter(expected.name().clone()));
                }
            }
        }
        Ok(())
    }
}

/// Errors that calling `parse` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum ParseError<'t> {
    /// The parser is in an invalid state.
    InvalidState,
    /// There were no matches for the token.
    NoMatches(Token<'t>),
    /// There was more than 1 possible match for the token.
    AmbiguousMatch(Token<'t>), // XXX: One day, add: Vec<&'p Rc<Node>>),
}

impl<'t> Error for ParseError<'t> {
    fn description(&self) -> &str {
        match *self {
            ParseError::InvalidState => "Invalid state.",
            ParseError::NoMatches(_) => "No match.",
            ParseError::AmbiguousMatch(_) => "Ambiguous match.",
        }
    }
}

impl<'t> fmt::Display for ParseError<'t> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// Errors that calling `verify` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum VerifyError {
    /// No command has been accepted by the parser.
    NoCommandAccepted,
    /// A required parameter is missing.
    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)
    }
}

/// Can this node be accepted in the current parser state?
pub trait Acceptable {
    /// Can this node be accepted in the current parser state?
    fn acceptable(&self, parser: &Parser) -> bool;
}

impl Acceptable for Rc<Node> {
    /// By default, a node can be accepted when it hasn't been seen yet.
    fn acceptable(&self, parser: &Parser) -> bool {
        !parser.nodes.contains(self)
    }
}

impl Acceptable for RepeatableNode {
    /// A repeatable node can be accepted.
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.repeatable() {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }
}

/// Define whether or not a node matches a token.
pub trait Matches {
    /// Does this node match the specified `token`?
    fn matches(&self, parser: &Parser, token: Token) -> bool;
}

impl Matches for Node {
    /// By default, a node matches a `token` when the name of the
    /// node starts with the `token`.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

impl Matches for ParameterNode {
    /// Parameters can match any token by default.
    fn matches(&self, _parser: &Parser, _token: Token) -> bool {
        true
    }
}

impl Matches for FlagParameterNode {
    /// A flag parameter is just looking for the token matching
    /// its name.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

/// Define the behavior of a node when it is accepted by the parser.
pub trait Accept {
    /// Accept this node with the given `token` as data.
    ///
    /// This is where parameters are stored, commands added.
    fn accept<'p>(&self, parser: &mut Parser<'p>, token: Token);
}

impl Accept for Node {
    /// By default, nothing needs to happen for `accept`.
    fn accept<'p>(&self, _parser: &mut Parser<'p>, _token: Token) {}
}

impl Accept for Rc<CommandNode> {
    /// Record this command.
    fn accept<'p>(&self, parser: &mut Parser<'p>, _token: Token) {
        if let Some(_) = self.handler() {
            parser.commands.push(self.clone())
        }
    }
}

impl Accept for ParameterNode {
    /// Record this parameter value.
    fn accept<'p>(&self, parser: &mut Parser<'p>, token: Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}

#[cfg(test)]
mod test {
    use super::nodes::*;
    use super::*;

    #[test]
    #[should_panic]
    fn verify_signals_no_command() {
        let root = RootNode::new(vec![]);
        let parser = Parser::new(root);
        match parser.verify() {
            Err(VerifyError::NoCommandAccepted) => panic!(),
            _ => {}
        }
    }
}
<commit_msg>Parser doctests shouldn't manually create RootNode.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the `commands::tokenizer` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The command parser consists of two important things:
//!
//! * A tree that represents the available commands and their arguments.
//!   This tree consists of instances of `Nodes` from the
//!   `commands::parser::nodes` module. Construction of this tree
//!   is done with the help of the `commands::parser::builder` module.
//! * A `Parser` that handles input and matches it against the command
//!   tree. This parser is intended to be short-lived and to just live
//!   for the duration of parsing and evaluating a single command line
//!   input.

pub mod nodes;
pub mod completion;
pub mod builder;

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'p` refers to the lifetime of the
/// parser itself, the root node of the command tree that was
/// used to create this parser, as well as the tokens passed
/// into the parser.
///
/// When creating a `Parser`, you must give it an `Rc<RootNode>`.
/// The easiest and best way to get a root node is to use the
/// `commands::parser::builder` module.
///
/// ```
/// use commands::parser::builder::{Command, CommandTree};
/// use commands::parser::Parser;
///
/// let mut tree = CommandTree::new();
/// tree.command(Command::new("show").finalize());
/// tree.command(Command::new("set").finalize());
/// tree.command(Command::new("help").finalize());
///
/// let mut parser = Parser::new(tree.finalize());
/// ```
///
/// The parser is constructed as a `mut`able object as most of
/// the methods on it will modify its state.
pub struct Parser<'p> {
    current_node: Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<Token<'p>>,
    commands: Vec<Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'p> Parser<'p> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: Rc<RootNode>) -> Parser<'p> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    ///
    /// Possible completions are successors of the current node which
    /// are not `hidden`, are `acceptable`, and which match the token,
    /// if one has been provided.
    ///
    /// Nodes may customize the `Complete` trait to customize the
    /// `Completion` and `CompletionOption`s which are generated
    /// for that node.
    ///
    /// Each valid successor node will have one `Completion` in the
    /// result vector. Each `Completion` will have one or more
    /// `CompletionOption` for each valid way that the value may be
    /// entered.
    ///
    /// ```
    /// use commands::parser::builder::{Command, CommandTree};
    /// use commands::parser::Parser;
    /// use commands::tokenizer::{Token, tokenize};
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show").finalize());
    /// tree.command(Command::new("set").finalize());
    /// tree.command(Command::new("help").finalize());
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// // Completing now should have 3 options, 1 for each command.
    /// let comps = parser.complete(None);
    /// assert_eq!(comps.len(), 3);
    ///
    /// // But completing with a token for 'h' should have 1 option.
    /// if let Ok(tokens) = tokenize("h") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 1);
    ///   assert_eq!(comps[0].options.len(), 1);
    ///   assert_eq!(comps[0].options[0].option_string, "help");
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    ///
    /// // And completing for 's' should have 2 options.
    /// if let Ok(tokens) = tokenize("s") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 2);
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    /// ```
    pub fn complete(&self, token: Option<Token<'p>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.hidden() && n.acceptable(self) &&
                if let Some(t) = token {
                    n.matches(self, t)
                } else {
                    true
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    ///
    /// ```
    /// use commands::parser::builder::{Command, CommandTree};
    /// use commands::parser::Parser;
    /// use commands::tokenizer::tokenize;
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show interface").finalize());
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// if let Ok(tokens) = tokenize("show interface") {
    ///     parser.parse(tokens);
    /// }
    /// ```
    pub fn parse(&mut self, tokens: Vec<Token<'p>>) -> Result<(), ParseError<'p>> {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => try!(self.advance(token)),
            }
        }
        Ok(())
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: Token<'p>) -> Result<(), ParseError<'p>> {
        // We clone the current node so that it doesn't stay borrowed
        // and break things when we try to modify it below.
        let cn = self.current_node.clone();
        let matches = cn.successors()
                        .into_iter()
                        .filter(|n| n.acceptable(self) && n.matches(self, token))
                        .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node.clone());
                self.tokens.push(token);
                Ok(())
            }
            0 => Err(ParseError::NoMatches(token)),
            _ => Err(ParseError::AmbiguousMatch(token)),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    pub fn verify(&self) -> Result<(), VerifyError> {
        if self.commands.is_empty() {
            return Err(VerifyError::NoCommandAccepted);
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() && !self.parameters.contains_key(expected.name()) {
                    return Err(VerifyError::MissingParameter(expected.name().clone()));
                }
            }
        }
        Ok(())
    }
}

/// Errors that calling `parse` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum ParseError<'t> {
    /// The parser is in an invalid state.
    InvalidState,
    /// There were no matches for the token.
    NoMatches(Token<'t>),
    /// There was more than 1 possible match for the token.
    AmbiguousMatch(Token<'t>), // XXX: One day, add: Vec<&'p Rc<Node>>),
}

impl<'t> Error for ParseError<'t> {
    fn description(&self) -> &str {
        match *self {
            ParseError::InvalidState => "Invalid state.",
            ParseError::NoMatches(_) => "No match.",
            ParseError::AmbiguousMatch(_) => "Ambiguous match.",
        }
    }
}

impl<'t> fmt::Display for ParseError<'t> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// Errors that calling `verify` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum VerifyError {
    /// No command has been accepted by the parser.
    NoCommandAccepted,
    /// A required parameter is missing.
    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)
    }
}

/// Can this node be accepted in the current parser state?
pub trait Acceptable {
    /// Can this node be accepted in the current parser state?
    fn acceptable(&self, parser: &Parser) -> bool;
}

impl Acceptable for Rc<Node> {
    /// By default, a node can be accepted when it hasn't been seen yet.
    fn acceptable(&self, parser: &Parser) -> bool {
        !parser.nodes.contains(self)
    }
}

impl Acceptable for RepeatableNode {
    /// A repeatable node can be accepted.
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.repeatable() {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }
}

/// Define whether or not a node matches a token.
pub trait Matches {
    /// Does this node match the specified `token`?
    fn matches(&self, parser: &Parser, token: Token) -> bool;
}

impl Matches for Node {
    /// By default, a node matches a `token` when the name of the
    /// node starts with the `token`.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

impl Matches for ParameterNode {
    /// Parameters can match any token by default.
    fn matches(&self, _parser: &Parser, _token: Token) -> bool {
        true
    }
}

impl Matches for FlagParameterNode {
    /// A flag parameter is just looking for the token matching
    /// its name.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

/// Define the behavior of a node when it is accepted by the parser.
pub trait Accept {
    /// Accept this node with the given `token` as data.
    ///
    /// This is where parameters are stored, commands added.
    fn accept<'p>(&self, parser: &mut Parser<'p>, token: Token);
}

impl Accept for Node {
    /// By default, nothing needs to happen for `accept`.
    fn accept<'p>(&self, _parser: &mut Parser<'p>, _token: Token) {}
}

impl Accept for Rc<CommandNode> {
    /// Record this command.
    fn accept<'p>(&self, parser: &mut Parser<'p>, _token: Token) {
        if let Some(_) = self.handler() {
            parser.commands.push(self.clone())
        }
    }
}

impl Accept for ParameterNode {
    /// Record this parameter value.
    fn accept<'p>(&self, parser: &mut Parser<'p>, token: Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}

#[cfg(test)]
mod test {
    use super::nodes::*;
    use super::*;

    #[test]
    #[should_panic]
    fn verify_signals_no_command() {
        let root = RootNode::new(vec![]);
        let parser = Parser::new(root);
        match parser.verify() {
            Err(VerifyError::NoCommandAccepted) => panic!(),
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the `commands::tokenizer` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The command parser consists of two important things:
//!
//! * A tree that represents the available commands and their arguments.
//!   This tree consists of instances of `Nodes` from the
//!   `commands::parser::nodes` module. Construction of this tree
//!   is done with the help of the `commands::parser::builder` module.
//! * A `Parser` that handles input and matches it against the command
//!   tree. This parser is intended to be short-lived and to just live
//!   for the duration of parsing and evaluating a single command line
//!   input.

pub mod nodes;
pub mod completion;
pub mod builder;

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'text` refers to the lifetime of the
/// tokens passed into the parser. This is the same as the lifetime
/// of the text used to create the tokens.
///
/// When creating a `Parser`, you must give it an `Rc<RootNode>`.
/// The easiest and best way to get a root node is to use the
/// `commands::parser::builder` module.
///
/// ```
/// use commands::parser::builder::{Command, CommandTree};
/// use commands::parser::Parser;
///
/// let mut tree = CommandTree::new();
/// tree.command(Command::new("show").finalize());
/// tree.command(Command::new("set").finalize());
/// tree.command(Command::new("help").finalize());
///
/// let mut parser = Parser::new(tree.finalize());
/// ```
///
/// The parser is constructed as a `mut`able object as most of
/// the methods on it will modify its state.
pub struct Parser<'text> {
    current_node: Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<Token<'text>>,
    commands: Vec<Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'text> Parser<'text> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: Rc<RootNode>) -> Parser<'text> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    ///
    /// Possible completions are successors of the current node which
    /// are not `hidden`, are `acceptable`, and which match the token,
    /// if one has been provided.
    ///
    /// Nodes may customize the `Complete` trait to customize the
    /// `Completion` and `CompletionOption`s which are generated
    /// for that node.
    ///
    /// Each valid successor node will have one `Completion` in the
    /// result vector. Each `Completion` will have one or more
    /// `CompletionOption` for each valid way that the value may be
    /// entered.
    ///
    /// ```
    /// use commands::parser::builder::{Command, CommandTree};
    /// use commands::parser::Parser;
    /// use commands::tokenizer::{Token, tokenize};
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show").finalize());
    /// tree.command(Command::new("set").finalize());
    /// tree.command(Command::new("help").finalize());
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// // Completing now should have 3 options, 1 for each command.
    /// let comps = parser.complete(None);
    /// assert_eq!(comps.len(), 3);
    ///
    /// // But completing with a token for 'h' should have 1 option.
    /// if let Ok(tokens) = tokenize("h") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 1);
    ///   assert_eq!(comps[0].options.len(), 1);
    ///   assert_eq!(comps[0].options[0].option_string, "help");
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    ///
    /// // And completing for 's' should have 2 options.
    /// if let Ok(tokens) = tokenize("s") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 2);
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    /// ```
    pub fn complete(&self, token: Option<Token<'text>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.hidden() && n.acceptable(self) &&
                if let Some(t) = token {
                    n.matches(self, t)
                } else {
                    true
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    ///
    /// ```
    /// use commands::parser::builder::{Command, CommandTree};
    /// use commands::parser::Parser;
    /// use commands::tokenizer::tokenize;
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show interface").finalize());
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// if let Ok(tokens) = tokenize("show interface") {
    ///     parser.parse(tokens);
    /// }
    /// ```
    pub fn parse(&mut self, tokens: Vec<Token<'text>>) -> Result<(), ParseError<'text>> {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => try!(self.advance(token)),
            }
        }
        Ok(())
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: Token<'text>) -> Result<(), ParseError<'text>> {
        // We clone the current node so that it doesn't stay borrowed
        // and break things when we try to modify it below.
        let cn = self.current_node.clone();
        let matches = cn.successors()
                        .into_iter()
                        .filter(|n| n.acceptable(self) && n.matches(self, token))
                        .map(|n| n.clone())
                        .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let ref matching_node = matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node.clone());
                self.tokens.push(token);
                Ok(())
            }
            0 => Err(ParseError::NoMatches(token)),
            _ => Err(ParseError::AmbiguousMatch(token, matches)),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    pub fn verify(&self) -> Result<(), VerifyError> {
        if self.commands.is_empty() {
            return Err(VerifyError::NoCommandAccepted);
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() && !self.parameters.contains_key(expected.name()) {
                    return Err(VerifyError::MissingParameter(expected.name().clone()));
                }
            }
        }
        Ok(())
    }
}

/// Errors that calling `parse` on the `Parser` can raise.
#[derive(Clone)]
pub enum ParseError<'text> {
    /// The parser is in an invalid state.
    InvalidState,
    /// There were no matches for the token.
    NoMatches(Token<'text>),
    /// There was more than 1 possible match for the token.
    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::InvalidState => write!(f, "InvalidState"),
            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::InvalidState => "Invalid state.",
            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)
    }
}

/// Errors that calling `verify` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum VerifyError {
    /// No command has been accepted by the parser.
    NoCommandAccepted,
    /// A required parameter is missing.
    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)
    }
}

/// Can this node be accepted in the current parser state?
pub trait Acceptable {
    /// Can this node be accepted in the current parser state?
    fn acceptable(&self, parser: &Parser) -> bool;
}

impl Acceptable for Rc<Node> {
    /// By default, a node can be accepted when it hasn't been seen yet.
    fn acceptable(&self, parser: &Parser) -> bool {
        !parser.nodes.contains(self)
    }
}

impl Acceptable for RepeatableNode {
    /// A repeatable node can be accepted.
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.repeatable() {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }
}

/// Define whether or not a node matches a token.
pub trait Matches {
    /// Does this node match the specified `token`?
    fn matches(&self, parser: &Parser, token: Token) -> bool;
}

impl Matches for Node {
    /// By default, a node matches a `token` when the name of the
    /// node starts with the `token`.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

impl Matches for ParameterNode {
    /// Parameters can match any token by default.
    fn matches(&self, _parser: &Parser, _token: Token) -> bool {
        true
    }
}

impl Matches for FlagParameterNode {
    /// A flag parameter is just looking for the token matching
    /// its name.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

/// Define the behavior of a node when it is accepted by the parser.
pub trait Accept {
    /// Accept this node with the given `token` as data.
    ///
    /// This is where parameters are stored, commands added.
    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token);
}

impl Accept for Node {
    /// By default, nothing needs to happen for `accept`.
    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token) {}
}

impl Accept for Rc<CommandNode> {
    /// Record this command.
    fn accept<'text>(&self, parser: &mut Parser<'text>, _token: Token) {
        if let Some(_) = self.handler() {
            parser.commands.push(self.clone())
        }
    }
}

impl Accept for ParameterNode {
    /// Record this parameter value.
    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}

#[cfg(test)]
mod test {
    use super::nodes::*;
    use super::*;

    #[test]
    #[should_panic]
    fn verify_signals_no_command() {
        let root = RootNode::new(vec![]);
        let parser = Parser::new(root);
        match parser.verify() {
            Err(VerifyError::NoCommandAccepted) => panic!(),
            _ => {}
        }
    }
}
<commit_msg>Parser: Add tests for failing parses.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the `commands::tokenizer` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The command parser consists of two important things:
//!
//! * A tree that represents the available commands and their arguments.
//!   This tree consists of instances of `Nodes` from the
//!   `commands::parser::nodes` module. Construction of this tree
//!   is done with the help of the `commands::parser::builder` module.
//! * A `Parser` that handles input and matches it against the command
//!   tree. This parser is intended to be short-lived and to just live
//!   for the duration of parsing and evaluating a single command line
//!   input.

pub mod nodes;
pub mod completion;
pub mod builder;

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'text` refers to the lifetime of the
/// tokens passed into the parser. This is the same as the lifetime
/// of the text used to create the tokens.
///
/// When creating a `Parser`, you must give it an `Rc<RootNode>`.
/// The easiest and best way to get a root node is to use the
/// `commands::parser::builder` module.
///
/// ```
/// use commands::parser::builder::{Command, CommandTree};
/// use commands::parser::Parser;
///
/// let mut tree = CommandTree::new();
/// tree.command(Command::new("show").finalize());
/// tree.command(Command::new("set").finalize());
/// tree.command(Command::new("help").finalize());
///
/// let mut parser = Parser::new(tree.finalize());
/// ```
///
/// The parser is constructed as a `mut`able object as most of
/// the methods on it will modify its state.
pub struct Parser<'text> {
    current_node: Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<Token<'text>>,
    commands: Vec<Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'text> Parser<'text> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: Rc<RootNode>) -> Parser<'text> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    ///
    /// Possible completions are successors of the current node which
    /// are not `hidden`, are `acceptable`, and which match the token,
    /// if one has been provided.
    ///
    /// Nodes may customize the `Complete` trait to customize the
    /// `Completion` and `CompletionOption`s which are generated
    /// for that node.
    ///
    /// Each valid successor node will have one `Completion` in the
    /// result vector. Each `Completion` will have one or more
    /// `CompletionOption` for each valid way that the value may be
    /// entered.
    ///
    /// ```
    /// use commands::parser::builder::{Command, CommandTree};
    /// use commands::parser::Parser;
    /// use commands::tokenizer::{Token, tokenize};
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show").finalize());
    /// tree.command(Command::new("set").finalize());
    /// tree.command(Command::new("help").finalize());
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// // Completing now should have 3 options, 1 for each command.
    /// let comps = parser.complete(None);
    /// assert_eq!(comps.len(), 3);
    ///
    /// // But completing with a token for 'h' should have 1 option.
    /// if let Ok(tokens) = tokenize("h") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 1);
    ///   assert_eq!(comps[0].options.len(), 1);
    ///   assert_eq!(comps[0].options[0].option_string, "help");
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    ///
    /// // And completing for 's' should have 2 options.
    /// if let Ok(tokens) = tokenize("s") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 2);
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    /// ```
    pub fn complete(&self, token: Option<Token<'text>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.hidden() && n.acceptable(self) &&
                if let Some(t) = token {
                    n.matches(self, t)
                } else {
                    true
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    ///
    /// ```
    /// use commands::parser::builder::{Command, CommandTree};
    /// use commands::parser::Parser;
    /// use commands::tokenizer::tokenize;
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show interface").finalize());
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// if let Ok(tokens) = tokenize("show interface") {
    ///     parser.parse(tokens);
    /// }
    /// ```
    pub fn parse(&mut self, tokens: Vec<Token<'text>>) -> Result<(), ParseError<'text>> {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => try!(self.advance(token)),
            }
        }
        Ok(())
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: Token<'text>) -> Result<(), ParseError<'text>> {
        // We clone the current node so that it doesn't stay borrowed
        // and break things when we try to modify it below.
        let cn = self.current_node.clone();
        let matches = cn.successors()
                        .into_iter()
                        .filter(|n| n.acceptable(self) && n.matches(self, token))
                        .map(|n| n.clone())
                        .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let ref matching_node = matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node.clone());
                self.tokens.push(token);
                Ok(())
            }
            0 => Err(ParseError::NoMatches(token)),
            _ => Err(ParseError::AmbiguousMatch(token, matches)),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    pub fn verify(&self) -> Result<(), VerifyError> {
        if self.commands.is_empty() {
            return Err(VerifyError::NoCommandAccepted);
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() && !self.parameters.contains_key(expected.name()) {
                    return Err(VerifyError::MissingParameter(expected.name().clone()));
                }
            }
        }
        Ok(())
    }
}

/// Errors that calling `parse` on the `Parser` can raise.
#[derive(Clone)]
pub enum ParseError<'text> {
    /// The parser is in an invalid state.
    InvalidState,
    /// There were no matches for the token.
    NoMatches(Token<'text>),
    /// There was more than 1 possible match for the token.
    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::InvalidState => write!(f, "InvalidState"),
            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::InvalidState => "Invalid state.",
            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)
    }
}

/// Errors that calling `verify` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum VerifyError {
    /// No command has been accepted by the parser.
    NoCommandAccepted,
    /// A required parameter is missing.
    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)
    }
}

/// Can this node be accepted in the current parser state?
pub trait Acceptable {
    /// Can this node be accepted in the current parser state?
    fn acceptable(&self, parser: &Parser) -> bool;
}

impl Acceptable for Rc<Node> {
    /// By default, a node can be accepted when it hasn't been seen yet.
    fn acceptable(&self, parser: &Parser) -> bool {
        !parser.nodes.contains(self)
    }
}

impl Acceptable for RepeatableNode {
    /// A repeatable node can be accepted.
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.repeatable() {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }
}

/// Define whether or not a node matches a token.
pub trait Matches {
    /// Does this node match the specified `token`?
    fn matches(&self, parser: &Parser, token: Token) -> bool;
}

impl Matches for Node {
    /// By default, a node matches a `token` when the name of the
    /// node starts with the `token`.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

impl Matches for ParameterNode {
    /// Parameters can match any token by default.
    fn matches(&self, _parser: &Parser, _token: Token) -> bool {
        true
    }
}

impl Matches for FlagParameterNode {
    /// A flag parameter is just looking for the token matching
    /// its name.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

/// Define the behavior of a node when it is accepted by the parser.
pub trait Accept {
    /// Accept this node with the given `token` as data.
    ///
    /// This is where parameters are stored, commands added.
    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token);
}

impl Accept for Node {
    /// By default, nothing needs to happen for `accept`.
    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token) {}
}

impl Accept for Rc<CommandNode> {
    /// Record this command.
    fn accept<'text>(&self, parser: &mut Parser<'text>, _token: Token) {
        if let Some(_) = self.handler() {
            parser.commands.push(self.clone())
        }
    }
}

impl Accept for ParameterNode {
    /// Record this parameter value.
    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}

#[cfg(test)]
mod test {
    use super::nodes::*;
    use super::builder::{Command, CommandTree};
    use super::*;
    use tokenizer::tokenize;

    #[test]
    #[should_panic]
    fn verify_signals_no_command() {
        let root = RootNode::new(vec![]);
        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").finalize());
        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").finalize());
        tree.command(Command::new("set").finalize());
        let mut parser = Parser::new(tree.finalize());
        if let Ok(tokens) = tokenize("s") {
            match parser.parse(tokens) {
                Err(ParseError::AmbiguousMatch(_, _)) => panic!(),
                _ => {}
            }
        }
    }
}
<|endoftext|>


<commit_before>macro_rules! push {
    ($s:ident, $t:expr) => {{
        // println!("parser push: {:?}", $t);
        Ok($s.vm.borrow_mut().alloc($t))
    }}
}

mod error;

use std::rc::Rc;
use std::cell::RefCell;
use core::*;
use lexer::*;
use self::error::Error;

pub struct Parser<'a> {
    lexer: Lexer<'a, 'a>,
    vm: Rc<RefCell<Heliqs>>,
    // state: State,
    current_token: RefCell<CurrentToken>,
    // aexp_tokens: Vec<Vec<Tokn>>,
}

#[derive(Eq, PartialEq, Clone, Debug)]
enum CurrentToken {
    SOT, // Start Of Tokens
    Has(Tokn),
    EOT, // End Of Tokens
}

impl<'a> Parser<'a> {
    pub fn new(lexer: Lexer<'a, 'a>, vm: Rc<RefCell<Heliqs>>) -> Self {
        Parser {
            lexer: lexer,
            vm: vm,
            // state: State::Aexp,
            current_token: RefCell::new(/*None*/CurrentToken::SOT),
            // aexp_tokens: vec![vec![]],
        }
    }

    fn add_prim(&mut self, name: &str) {
        let prim = self.vm.borrow_mut().alloc(Epiq::Prim(name.to_string()));
        self.vm.borrow_mut().define(name, prim);
    }

    pub fn parse(&mut self) {
        self.add_prim("decr");
        self.add_prim("ltoreq");
        self.add_prim("eq");
        self.add_prim("plus");
        self.add_prim("minus");

        self.consume_token();

        let _ = self.parse_aexp();
    }

    fn consume_token(&mut self) {
        let res = self.lexer.tokenize();
        match res {
            TokenizeResult::Ok(t) => {
                let mut token = self.current_token.borrow_mut();
                *token = CurrentToken::Has(t);
            },
            TokenizeResult::Err(_e) => {},
            TokenizeResult::EOF => {
                let mut token = self.current_token.borrow_mut();
                *token = CurrentToken::EOT;
            },
        }
    }

    fn parse_aexp(&mut self) -> Result<usize, Error> {
        let res = self.current_token.borrow().clone();

        match res {
            CurrentToken::Has(Tokn::Pipe) => {
                self.consume_token();
                self.parse_otag(Tokn::Pipe)
            },
            CurrentToken::Has(Tokn::Crrt) => {
                self.consume_token();
                self.parse_otag(Tokn::Crrt)
            },
            CurrentToken::Has(Tokn::Smcl) => {
                self.consume_token();
                push!(self, Epiq::Unit)
            }
            CurrentToken::Has(Tokn::Lbkt) => {
                self.consume_token();
                self.parse_list()
            }
            _ => self.parse_literal(),
        }
    }

    // Pipe QTag Pval QVal
    fn parse_otag(&mut self, tokn: Tokn) -> Result<usize, Error> {
        let current_token = self.current_token.borrow().clone();
        match current_token {
            CurrentToken::Has(Tokn::Otag(ref otag)) => {
                self.consume_token();

                match tokn {
                    Tokn::Pipe => {
                        let pidx = (self.parse_aexp())?;
                        let qidx = (self.parse_aexp())?;
                        match otag.as_ref() {
                            ">" => push!(self, Epiq::Eval(pidx, qidx)),
                            ":" => push!(self, Epiq::Lpiq(pidx, qidx)),
                            "!" => push!(self, Epiq::Appl(pidx, qidx)),
                            "@" => push!(self, Epiq::Rslv(pidx, qidx)),
                            "?" => push!(self, Epiq::Cond(pidx, qidx)),
                            "%" => push!(self, Epiq::Envn(pidx, qidx)),
                            "#" => push!(self, Epiq::Bind(pidx, qidx)),
                            "." => push!(self, Epiq::Accs(pidx, qidx)),
                            r"\" => push!(self, Epiq::Lmbd(pidx, qidx)),

                            _ => {
                                push!(self, Epiq::Tpiq{o: otag.clone(), p: pidx, q: qidx})
                            },
                        }
                    },
                    Tokn::Crrt => {
                        match otag.as_ref() {
                            // ^Tと^Fは特別扱い
                            "T" => push!(self, Epiq::Tval),
                            "F" => push!(self, Epiq::Fval),
                            _ =>  {
                                // 現在は^Tか^Fしか認めていないが、将来のため
                                let pidx = (self.parse_aexp())?;
                                let qidx = (self.parse_aexp())?;
                                push!(self, Epiq::Mpiq{o: otag.clone(), p: pidx, q: qidx})
                            },
                        }
                    },
                    _ => Err(Error::UnknownError(255)),
                }
            },

            CurrentToken::Has(ref t) => Err(Error::TokenError(t.clone())),
            _ => Err(Error::UnknownError(1)),
        }
    }

    fn parse_list(&mut self) -> Result<usize, Error> {
        let current_token = self.current_token.borrow().clone();
        // 閉じbracketが出るまで再帰呼出
        match current_token {
            CurrentToken::Has(Tokn::Rbkt) => {
                self.consume_token();
                push!(self, Epiq::Unit)
            },
            _ => {
                let pidx = (self.parse_aexp())?;
                let qidx = (self.parse_list())?;
                push!(self, Epiq::Lpiq(pidx, qidx))
            }
        }
    }

    fn parse_literal(&mut self) -> Result<usize, Error> {
        let current_token = self.current_token.borrow().clone();
        match current_token {
            CurrentToken::Has(Tokn::Chvc(ref s)) => {
                self.consume_token();
                push!(self, Epiq::Name(s.clone()))
            },
            CurrentToken::Has(Tokn::Nmbr(ref s)) => {
                self.consume_token();
                push!(self, Epiq::Uit8(s.parse::<i64>().unwrap()))
            },
            _ => Err(Error::UnknownError(10)),
        }
    }
}
<commit_msg>delete old code2<commit_after>macro_rules! push {
    ($s:ident, $t:expr) => {{
        // println!("parser push: {:?}", $t);
        Ok($s.vm.borrow_mut().alloc($t))
    }}
}

mod error;

use std::rc::Rc;
use std::cell::RefCell;
use core::*;
use lexer::*;
use self::error::Error;

pub struct Parser<'a> {
    lexer: Lexer<'a, 'a>,
    vm: Rc<RefCell<Heliqs>>,
    // state: State,
    current_token: RefCell<CurrentToken>,
    // aexp_tokens: Vec<Vec<Tokn>>,
}

#[derive(Eq, PartialEq, Clone, Debug)]
enum CurrentToken {
    SOT, // Start Of Tokens
    Has(Tokn),
    EOT, // End Of Tokens
}

impl<'a> Parser<'a> {
    pub fn new(lexer: Lexer<'a, 'a>, vm: Rc<RefCell<Heliqs>>) -> Self {
        Parser {
            lexer: lexer,
            vm: vm,
            // state: State::Aexp,
            current_token: RefCell::new(CurrentToken::SOT),
            // aexp_tokens: vec![vec![]],
        }
    }

    fn add_prim(&mut self, name: &str) {
        let prim = self.vm.borrow_mut().alloc(Epiq::Prim(name.to_string()));
        self.vm.borrow_mut().define(name, prim);
    }

    pub fn parse(&mut self) {
        self.add_prim("decr");
        self.add_prim("ltoreq");
        self.add_prim("eq");
        self.add_prim("plus");
        self.add_prim("minus");

        self.consume_token();

        let _ = self.parse_aexp();
    }

    fn consume_token(&mut self) {
        let res = self.lexer.tokenize();
        match res {
            TokenizeResult::Ok(t) => {
                let mut token = self.current_token.borrow_mut();
                *token = CurrentToken::Has(t);
            },
            TokenizeResult::Err(_e) => {},
            TokenizeResult::EOF => {
                let mut token = self.current_token.borrow_mut();
                *token = CurrentToken::EOT;
            },
        }
    }

    fn parse_aexp(&mut self) -> Result<usize, Error> {
        let res = self.current_token.borrow().clone();

        match res {
            CurrentToken::Has(Tokn::Pipe) => {
                self.consume_token();
                self.parse_otag(Tokn::Pipe)
            },
            CurrentToken::Has(Tokn::Crrt) => {
                self.consume_token();
                self.parse_otag(Tokn::Crrt)
            },
            CurrentToken::Has(Tokn::Smcl) => {
                self.consume_token();
                push!(self, Epiq::Unit)
            }
            CurrentToken::Has(Tokn::Lbkt) => {
                self.consume_token();
                self.parse_list()
            }
            _ => self.parse_literal(),
        }
    }

    // Pipe QTag Pval QVal
    fn parse_otag(&mut self, tokn: Tokn) -> Result<usize, Error> {
        let current_token = self.current_token.borrow().clone();
        match current_token {
            CurrentToken::Has(Tokn::Otag(ref otag)) => {
                self.consume_token();

                match tokn {
                    Tokn::Pipe => {
                        let pidx = (self.parse_aexp())?;
                        let qidx = (self.parse_aexp())?;
                        match otag.as_ref() {
                            ">" => push!(self, Epiq::Eval(pidx, qidx)),
                            ":" => push!(self, Epiq::Lpiq(pidx, qidx)),
                            "!" => push!(self, Epiq::Appl(pidx, qidx)),
                            "@" => push!(self, Epiq::Rslv(pidx, qidx)),
                            "?" => push!(self, Epiq::Cond(pidx, qidx)),
                            "%" => push!(self, Epiq::Envn(pidx, qidx)),
                            "#" => push!(self, Epiq::Bind(pidx, qidx)),
                            "." => push!(self, Epiq::Accs(pidx, qidx)),
                            r"\" => push!(self, Epiq::Lmbd(pidx, qidx)),

                            _ => {
                                push!(self, Epiq::Tpiq{o: otag.clone(), p: pidx, q: qidx})
                            },
                        }
                    },
                    Tokn::Crrt => {
                        match otag.as_ref() {
                            // ^Tと^Fは特別扱い
                            "T" => push!(self, Epiq::Tval),
                            "F" => push!(self, Epiq::Fval),
                            _ =>  {
                                // 現在は^Tか^Fしか認めていないが、将来のため
                                let pidx = (self.parse_aexp())?;
                                let qidx = (self.parse_aexp())?;
                                push!(self, Epiq::Mpiq{o: otag.clone(), p: pidx, q: qidx})
                            },
                        }
                    },
                    _ => Err(Error::UnknownError(255)),
                }
            },

            CurrentToken::Has(ref t) => Err(Error::TokenError(t.clone())),
            _ => Err(Error::UnknownError(1)),
        }
    }

    fn parse_list(&mut self) -> Result<usize, Error> {
        let current_token = self.current_token.borrow().clone();
        // 閉じbracketが出るまで再帰呼出
        match current_token {
            CurrentToken::Has(Tokn::Rbkt) => {
                self.consume_token();
                push!(self, Epiq::Unit)
            },
            _ => {
                let pidx = (self.parse_aexp())?;
                let qidx = (self.parse_list())?;
                push!(self, Epiq::Lpiq(pidx, qidx))
            }
        }
    }

    fn parse_literal(&mut self) -> Result<usize, Error> {
        let current_token = self.current_token.borrow().clone();
        match current_token {
            CurrentToken::Has(Tokn::Chvc(ref s)) => {
                self.consume_token();
                push!(self, Epiq::Name(s.clone()))
            },
            CurrentToken::Has(Tokn::Nmbr(ref s)) => {
                self.consume_token();
                push!(self, Epiq::Uit8(s.parse::<i64>().unwrap()))
            },
            _ => Err(Error::UnknownError(10)),
        }
    }
}
<|endoftext|>