extern crate pest;
#[macro_use]
extern crate pest_derive;
#[derive(Parser)]
#[grammar = "scheme.pest"]
struct SchemeParser;
use pest::{Parser, RuleType};
use pest::iterators::{Pairs, Pair};
use pest::inputs::{Input,StringInput};
#[cfg(test)]
mod tests;
#[derive(Debug)]
pub enum Value{
List(Cons),
Symbol(String),
Number(usize),
Bool(bool),
Literal(String),
Null
}
impl Value{
pub fn car(self) -> Box<Value>{
match self{
Value::List(c) => c.car,
_ => panic!("Not a pair")
}
}
pub fn cdr(self) -> Box<Value>{
match self{
Value::List(c) => c.cdr,
_ => panic!("Not a pair")
}
}
pub fn is_symbol(&self) -> bool{
match self{
&Value::Symbol(_) => true,
_ => false
}
}
pub fn is_number(&self) -> bool{
match self{
&Value::Number(_) => true,
_ => false
}
}
pub fn is_true(&self) -> bool{
match self{
&Value::Bool(val) => val,
_ => false
}
}
pub fn is_false(&self) -> bool{
!self.is_true()
}
pub fn unwrap_symbol(self) -> String{
match self{
Value::Symbol(symb) => symb,
_ => panic!("value is not a symbol")
}
}
pub fn unwrap_number(self) -> usize{
match self{
Value::Number(n) => n,
_ => panic!("value is not a number")
}
}
pub fn unwrap_literal(self) -> String{
match self{
Value::Literal(lit) => lit,
_ => panic!("value is not a literal")
}
}
}
#[derive(Debug)]
pub struct Cons{
car: Box<Value>, cdr: Box<Value> }
trait PairMixin{
fn string_value(self) -> String;
fn usize_value(self) -> usize;
}
impl<R: RuleType,I: Input> PairMixin for Pair<R,I>{
fn string_value(self) -> String{
self.into_span().as_str().to_string()
}
fn usize_value(self) -> usize{
self.into_span().as_str().to_string().parse().unwrap()
}
}
trait PairsMixin<R: RuleType, I: Input>{
fn first_pair(self) -> Option<Pair<R,I>>;
}
impl<R: RuleType, I: Input> PairsMixin<R,I> for Pairs<R,I>{
fn first_pair(mut self) -> Option<Pair<R,I>>{
self.next()
}
}
pub fn parse(input: &'static str) -> Value{
let pairs = SchemeParser::parse_str(Rule::scheme, input).expect("Parsed output");
make_ast(pairs.first_pair().unwrap().into_inner().first_pair().unwrap())
}
fn make_ast(pair: Pair<Rule, StringInput>) -> Value{
match pair.as_rule(){
Rule::list => make_list(pair.into_inner()),
Rule::symbol => Value::Symbol(pair.string_value()),
Rule::number => Value::Number(pair.usize_value()),
Rule::true_lit => Value::Bool(true),
Rule::false_lit => Value::Bool(false),
Rule::literal => Value::Literal(pair.string_value()),
_ => panic!("Not covered expression {:?}. Please implement.", pair.as_rule())
}
}
fn make_list(mut pairs: Pairs<Rule, StringInput>) -> Value{
let element = pairs.next();
match element{
Some(el) => Value::List(Cons{car: Box::new(make_ast(el)),
cdr: Box::new(make_list(pairs))}),
None => Value::Null
}
}