gramatica 0.2.1

A compiler compiler for Rust implementing Earley's parser.
Documentation
//A very basic xml grammar

extern crate gramatica;

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

// see https://www.w3.org/People/Bos/meta-bnf
// also http://cs.lmu.edu/~ray/notes/xmlgrammar/

use std::rc::Rc;

//We define an auxiliar type to store XML elements
#[derive(Clone,Debug,PartialEq)]
struct XMLElement
{
	name: String,
	attrs: Vec<(String,String)>,
	contents: Vec<XMLContent>,
}

#[derive(Clone,Debug,PartialEq)]
enum XMLContent
{
	Element(XMLElement),
	Data(String),
}


// ---- Start of the grammar ----

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

terminal LitStr(String)
{
	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("\"");
			while true
			{
				match characters.next()
				{
					None => break,
					Some('"') =>
					{
						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!(CloseEmpty,"/>");
re_terminal!(BeginClose,"</");

re_terminal!(Equal,"=");
re_terminal!(LT,"<");
re_terminal!(GT,">");

re_terminal!(Other(char),".");

nonterminal Document(XMLElement)
{
	(Element(ref elem)) => elem.clone(),
}

nonterminal Element(XMLElement)
{
	(EmptyElemTag(ref name,ref attrs)) => XMLElement{name:name.clone(),attrs:attrs.clone(),contents:vec![]},
	(STag(ref name, ref attrs),Content(ref content),ETag) => XMLElement{name:name.clone(),attrs:attrs.clone(),contents:content.clone()},
}

nonterminal EmptyElemTag(String,Vec<(String,String)>)
{
	(LT,Ident(ref name),Attributes(ref attrs),MaybeSpace,CloseEmpty) => (name.clone(),attrs.clone()),
}

nonterminal Attributes(Vec<(String,String)>)
{
	() => vec![],
	(Attributes(ref attrs),Space,Attribute(ref a, ref b)) =>
	{
		let mut new=(attrs.clone());
		new.push((a.clone(),b.clone()));
		new
	},
}

nonterminal Attribute(String,String)
{
	(Ident(ref a),Equal,LitStr(ref b)) => (a.clone(),b.clone()),
}

nonterminal STag(String,Vec<(String,String)>)
{
	(LT,Ident(ref name),Attributes(ref attrs),MaybeSpace,GT) => (name.clone(),attrs.clone()),
}

nonterminal ETag(String)
{
	(BeginClose,Ident(ref s),MaybeSpace,GT) => s.clone(),
}

nonterminal Content(Vec<XMLContent>)
{
	(CharData(ref s)) => vec![XMLContent::Data(s.clone())],
	(CharData(ref s),Contents(ref list)) =>
	{
		let mut new=vec![XMLContent::Data(s.clone())];
		new.extend(list.iter().map(|x|x.clone()));
		new
	},
}

nonterminal Contents(Vec<XMLContent>)
{
	() => vec![],
	(Contents(ref list),Element(ref elem),CharData(ref s)) =>
	{
		let mut new=(list.clone());
		new.push(XMLContent::Element(elem.clone()));
		if s!=""
		{
			new.push(XMLContent::Data(s.clone()));
		}
		new
	},
}

nonterminal MaybeSpace
{
	() => (),
	(Space) => (),
}

nonterminal CharData(String)
{
	() => String::new(),
	(CharData(ref s),Space(ref o)) => format!("{}{}",s,o),
	(CharData(ref s),Ident(ref o)) => format!("{}{}",s,o),
	(CharData(ref s),Equal) => format!("{}=",s),
	(CharData(ref s),Other(o)) => format!("{}{}",s,o),
}

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

use std::io::{BufRead,Read};

//As example, we parse stdin for a XML element
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),
	};
}