caminos-lib 0.5.2

A modular interconnection network simulator.
Documentation

extern crate gramatica;

use std::cmp::Ordering;
use self::gramatica::{Associativity,EarleyKind,State,Parser,ParsingTablesTrait,ParsingError};


use std::rc::Rc;
use std::fmt::{Display,Formatter,Error};

#[derive(Clone,Debug,PartialEq,PartialOrd)]
//FIXME: we need support in `gramatica` for `pub`.
pub enum ConfigurationValue
{
	Literal(String),
	Number(f64),
	Object(String,Vec<(String,ConfigurationValue)>),
	Array(Vec<ConfigurationValue>),
	Experiments(Vec<ConfigurationValue>),
	NamedExperiments(String,Vec<ConfigurationValue>),
	True,
	False,
	Where(Rc<ConfigurationValue>,Expr),
	Expression(Expr),
	None,
}

impl Default for ConfigurationValue
{
	fn default() -> ConfigurationValue
	{
		ConfigurationValue::None
	}
}

impl ConfigurationValue
{
	fn write(&self, f: &mut Formatter, indent:usize) -> Result<(),Error>
	{
		let is=String::from("\t").repeat(indent);
		//FIXME: we need support in the `gramatica` crate for `write!()?`.
		write!(f,"{}",is)?;
		match self
		{
			&ConfigurationValue::Literal(ref s) => write!(f,"\"{}\"",s)?,
			&ConfigurationValue::Number(v) => write!(f,"{}",v)?,
			&ConfigurationValue::Object(ref name, ref list) =>
			{
				writeln!(f,"{}\n{}{{",name,is)?;
				for &(ref attr_name,ref attr_value) in list.iter()
				{
					writeln!(f,"{}\t{}:",is,attr_name)?;
					attr_value.write(f,indent+1)?;
					writeln!(f,",")?;
				}
				writeln!(f,"{}}}",is)?;
			},
			&ConfigurationValue::Array(ref list) =>
			{
				writeln!(f,"[")?;
				for elem in list.iter()
				{
					elem.write(f,indent+1)?;
					writeln!(f,",")?;
				}
				writeln!(f,"{}]",is)?;
			},
			&ConfigurationValue::Experiments(ref _list) => write!(f,"FIXME")?,
			&ConfigurationValue::NamedExperiments(ref _name, ref _list) => write!(f,"FIXME")?,
			&ConfigurationValue::True => write!(f,"true")?,
			&ConfigurationValue::False => write!(f,"false")?,
			&ConfigurationValue::Where(ref cv, ref _expr) => write!(f,"{} where FIXME",cv)?,
			&ConfigurationValue::Expression(ref e) => write!(f,"= {}",e)?,
			&ConfigurationValue::None => write!(f,"None")?,
		};
		Ok(())
	}
}

impl Display for ConfigurationValue
{
	fn fmt(&self, f: &mut Formatter) -> Result<(),Error>
	{
		self.write(f,0)
	}
}

#[derive(Clone,Debug,PartialEq,PartialOrd)]
pub enum Expr
{
	Equality(Rc<Expr>,Rc<Expr>),
	Literal(String),
	Number(f64),
	Ident(String),
	Member(Rc<Expr>,String),
	Parentheses(Rc<Expr>),
	///Gets the name of an object: @expr
	Name(Rc<Expr>),
	FunctionCall(String,Vec<(String,Expr)>),
}

impl Display for Expr
{
	fn fmt(&self, f: &mut Formatter) -> Result<(),Error>
	{
		match self
		{
			&Expr::Literal(ref s) => write!(f,"\"{}\"",s),
			&Expr::Number(ref v) => write!(f,"{}",v),
			&Expr::Ident(ref s) => write!(f,"{}",s),
			&Expr::Member(ref expr,ref s) => write!(f,"{}.{}",expr,s),
			&Expr::Name(ref expr) => write!(f,"@{}",expr),
			_ => write!(f,"fix this expr <{:?}>",self),
		}
	}
}


// ---- Start of the grammar ----
keyword_terminal!(True,"true");
keyword_terminal!(False,"false");
keyword_terminal!(Where,"where");

re_terminal!(Number(f64),"-?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?");

terminal LitStr(String)
{
	//This function has limited escaping capabilities
	fn _match(parser: &mut Parser<Token,ParsingTables>, source:&str) -> Option<(usize,String)>
	{
		let mut ret=None;
		let mut characters=source.chars();
		if (characters.next())!=(Some('"'))
		{
		}
		else
		{
			let mut size=1;
			//let mut r=String::from("\"");
			let mut r=String::new();
			loop
			{
				match characters.next()
				{
					None => break,
					Some('"') =>
					{
						//ret=(Some((size+1,r+&"\"")));
						ret={Some((size+1,r))};
						break;
					},
					Some('\\') =>
					{
						match characters.next()
						{
							None => break,
							//Some(c) => r+='\\'+c,
							Some(c) =>
							{
								r.push('\\');
								r.push(c);
							}
						};
						size+=2;
					},
					Some(c) =>
					{
						//r+=&String::from(c);
						r.push(c);
						size+=1;
					},
				};
			}
		}
		ret
	}
}

re_terminal!(Ident(String),"[a-zA-Z\\x80-\\xff_][a-zA-Z0-9\\x80-\\xff_]*");

re_terminal!(EqualEqual,"==");

re_terminal!(LBrace,"\\{");
re_terminal!(RBrace,"\\}");
re_terminal!(LBracket,"\\[");
re_terminal!(RBracket,"\\]");
re_terminal!(LPar,"\\(");
re_terminal!(RPar,"\\)");
re_terminal!(Comma,",");
re_terminal!(Colon,":");
re_terminal!(Bang,"!");
re_terminal!(At,"@");
re_terminal!(Equal,"=");
re_terminal!(Dot,"\\.");
re_terminal!(_,"\\s+|\n|//[^\n]*\n|/\\*([^*]|\\*+[^/])*\\*+/");//Otherwise skip spaces and comments

nonterminal Value(ConfigurationValue)
{
	(LitStr(ref s)) => ConfigurationValue::Literal(s.clone()),
	(Number(ref v)) => ConfigurationValue::Number(*v),
	(Object(ref mut value)) => std::mem::take(value),
	(Array(ref mut list)) => ConfigurationValue::Array(std::mem::take(list)),
	(Bang,Array(ref mut list)) => ConfigurationValue::Experiments(std::mem::take(list)),
	(Ident(ref name),Bang,Array(ref mut list)) => ConfigurationValue::NamedExperiments(name.clone(),std::mem::take(list)),
	(True) => ConfigurationValue::True,
	(False) => ConfigurationValue::False,
	(Value(ref mut value),Where,Expression(ref expr)) => ConfigurationValue::Where(Rc::new(std::mem::take(value)),expr.clone()),
	(Equal,Expression(ref e)) => ConfigurationValue::Expression(e.clone()),
}

nonterminal Object(ConfigurationValue)
{
	(Ident(ref name)) => ConfigurationValue::Object(name.clone(),vec![]),
	(Ident(ref name),LBrace,RBrace) => ConfigurationValue::Object(name.clone(),vec![]),
	(Ident(ref name),LBrace,Members(ref mut list),RBrace) => ConfigurationValue::Object(name.clone(),std::mem::take(list)),
	(Ident(ref name),LBrace,Members(ref mut list),Comma,RBrace) => ConfigurationValue::Object(name.clone(),std::mem::take(list)),
}

nonterminal Members(Vec<(String,ConfigurationValue)>)
{
	(Pair(ref s,ref mut value)) => vec![(s.clone(),std::mem::take(value))],
	//(Pair,Comma,Members) => (),
	(Members(ref mut list),Comma,Pair(ref s,ref mut value)) =>
	{
		let mut new=(std::mem::take(list));
		new.push((s.clone(),std::mem::take(value)));
		new
	},
}

nonterminal Pair(String,ConfigurationValue)
{
	(Ident(ref s),Colon,Value(ref mut value)) => (s.clone(),std::mem::take(value)),
}

nonterminal Array(Vec<ConfigurationValue>)
{
	(LBracket,RBracket) => vec![],
	(LBracket,Elements(ref mut list),RBracket) => std::mem::take(list),
	(LBracket,Elements(ref mut list),Comma,RBracket) => std::mem::take(list),
}

nonterminal Elements(Vec<ConfigurationValue>)
{
	(Value(ref mut value)) => vec![std::mem::take(value)],
	//(Value,Comma,Elements) => (),
	(Elements(ref mut list),Comma,Value(ref mut value)) =>
	{
		let mut new=(std::mem::take(list));
		new.push(std::mem::take(value));
		new
	},
}

nonterminal Expression(Expr)
{
	#[priority(comparison)]
	(Expression(ref left),EqualEqual,Expression(ref right)) => Expr::Equality(Rc::new(left.clone()),Rc::new(right.clone())),
	(LitStr(ref s)) => Expr::Literal(s.clone()),
	(Number(ref v)) => Expr::Number(*v),
	(Ident(ref s)) => Expr::Ident(s.clone()),
	#[priority(membership)]
	(Expression(ref path),Dot,Ident(ref element)) => Expr::Member(Rc::new(path.clone()),element.clone()),
	(LPar,Expression(ref expr),RPar) => Expr::Parentheses(Rc::new(expr.clone())),
	#[priority(getname)]
	(At,Expression(ref expr)) => Expr::Name(Rc::new(expr.clone())),
	(FunctionCall(ref value)) => value.clone(),
}

nonterminal FunctionCall(Expr)
{
	//(Ident(ref name)) => Expr::FunctionCall(name.clone(),vec![]),
	(Ident(ref name),LBrace,RBrace) => Expr::FunctionCall(name.clone(),vec![]),
	(Ident(ref name),LBrace,Arguments(ref list),RBrace) => Expr::FunctionCall(name.clone(),list.clone()),
	(Ident(ref name),LBrace,Arguments(ref list),Comma,RBrace) => Expr::FunctionCall(name.clone(),list.clone()),
}

nonterminal Arguments(Vec<(String,Expr)>)
{
	(ExprPair(ref s,ref value)) => vec![(s.clone(),value.clone())],
	//(ExprPair,Comma,Arguments) => (),
	(Arguments(ref list),Comma,ExprPair(ref s,ref value)) =>
	{
		let mut new=(list.clone());
		new.push((s.clone(),value.clone()));
		new
	},
}

nonterminal ExprPair(String,Expr)
{
	(Ident(ref s),Colon,Expression(ref expr)) => (s.clone(),expr.clone()),
}

ordering!(membership,getname,comparison);

// ---- End of the grammar ----

//use std::io::{BufRead,Read};
//
//fn main()
//{
//	let stdin=std::io::stdin();
//	let mut buf=String::new();
//	stdin.lock().read_to_string(&mut buf);
//	match Parser::<Token,ParsingTables>::parse(&buf,None)
//	{
//		Err(x) => println!("error parsing: {:?}",x),
//		Ok(x) => println!("parsed correctly: {:?}",x),
//	};
//}

pub fn parse(source:&str) -> Result<Token,ParsingError>
{
	Parser::<Token,ParsingTables>::parse(source,None)
}

pub fn parse_expression(source:&str) -> Result<Token,ParsingError>
{
	Parser::<Token,ParsingTables>::parse(source,Some(26))
}