use teleparse::syntax::{Error, ErrorKind};
use teleparse::{prelude::*, GrammarError, Parser};
#[derive_lexicon]
#[teleparse(
ignore(r#"\s+"#), // ignore whitespaces, separate multiple with comma
)]
pub enum TokenType {
#[teleparse(regex(r#"\w+"#), terminal(Ident))]
Ident,
#[teleparse(terminal(OpAdd = "+", OpMul = "*",))]
Op,
#[teleparse(terminal(ParenOpen = "(", ParenClose = ")"))]
Paren,
}
#[derive_syntax]
#[teleparse(root)]
#[derive(Debug, PartialEq)]
struct E {
first: T,
rest: Eprime,
}
impl E {
fn to_string(&self, input: &str) -> String {
format!(
"{}{}",
self.first.to_string(input),
self.rest.to_string(input)
)
}
}
#[derive_syntax]
#[derive(Debug, PartialEq)]
struct Eprime(tp::Option<Eplus>);
impl Eprime {
fn to_string(&self, input: &str) -> String {
match &*self.0 {
Some(eplus) => format!(" {}", eplus.to_string(input)),
None => "".to_string(),
}
}
}
#[derive_syntax]
#[derive(Debug, PartialEq)]
struct Eplus {
op: OpAdd,
t: T,
rest: Box<Eprime>,
}
impl Eplus {
fn to_string(&self, input: &str) -> String {
format!(
"{} {}{}",
self.op.0.src(input),
self.t.to_string(input),
self.rest.to_string(input)
)
}
}
#[derive_syntax]
#[derive(Debug, PartialEq)]
struct T {
first: F,
rest: Tprime,
}
impl T {
fn to_string(&self, input: &str) -> String {
format!(
"{}{}",
self.first.to_string(input),
self.rest.to_string(input)
)
}
}
#[derive_syntax]
#[derive(Debug, PartialEq)]
struct Tprime(tp::Option<Tstar>);
impl Tprime {
fn to_string(&self, input: &str) -> String {
match &*self.0 {
Some(tstar) => format!(" {}", tstar.to_string(input)),
None => "".to_string(),
}
}
}
#[derive_syntax]
#[derive(Debug, PartialEq)]
struct Tstar {
op: OpMul,
f: F,
rest: Box<Tprime>,
}
impl Tstar {
fn to_string(&self, input: &str) -> String {
format!(
"{} {}{}",
self.op.0.src(input),
self.f.to_string(input),
self.rest.to_string(input)
)
}
}
#[derive_syntax]
#[derive(Debug, PartialEq)]
enum F {
Ident(Ident),
Paren((ParenOpen, Box<E>, ParenClose)),
}
impl F {
fn to_string(&self, input: &str) -> String {
match self {
F::Paren((open, e, close)) => {
format!(
"{}{}{}",
open.0.src(input),
e.to_string(input),
close.0.src(input)
)
}
F::Ident(id) => id.0.src(input).to_string(),
}
}
}
#[test]
fn first_table() {
let first_e_t_f = first_set!( TokenType { Ident:*, Paren:"(" });
let first_e_prime = first_set!(TokenType { e, Op: "+" });
let first_t_prime = first_set!(TokenType { e, Op: "*" });
let meta = E::metadata().as_ref().unwrap();
assert_eq!(meta.first.get(&E::prod_id()), &first_e_t_f);
assert_eq!(meta.first.get(&T::prod_id()), &first_e_t_f);
assert_eq!(meta.first.get(&F::prod_id()), &first_e_t_f);
assert_eq!(meta.first.get(&Eprime::prod_id()), &first_e_prime);
assert_eq!(meta.first.get(&Tprime::prod_id()), &first_t_prime);
}
#[test]
fn follow_table() {
let follow_e_eprime = follow_set!(TokenType { e, Paren: ")" });
let follow_t_tprime = follow_set!(TokenType {
e,
Op: "+",
Paren: ")"
});
let follow_f = follow_set!(TokenType {
e,
Op: "*",
Op: "+",
Paren: ")"
});
let meta = E::metadata().as_ref().unwrap();
assert_eq!(meta.follow.get(&E::prod_id()), &follow_e_eprime);
assert_eq!(meta.follow.get(&Eprime::prod_id()), &follow_e_eprime);
assert_eq!(meta.follow.get(&T::prod_id()), &follow_t_tprime);
assert_eq!(meta.follow.get(&Tprime::prod_id()), &follow_t_tprime);
assert_eq!(meta.follow.get(&F::prod_id()), &follow_f);
}
#[test]
fn parse() {
let source = "a+b*c";
let t = E::parse(source).unwrap().unwrap();
let c = Ident(Token::new((4, 5), TokenType::Ident));
let b = Ident(Token::new((2, 3), TokenType::Ident));
let a = Ident(Token::new((0, 1), TokenType::Ident));
let plus = OpAdd(Token::new((1, 2), TokenType::Op));
let mul = OpMul(Token::new((3, 4), TokenType::Op));
let plus_b_mul_c = Eplus {
op: plus,
t: T {
first: F::Ident(b),
rest: Tprime(
Node::new(
3..5,
Some(Tstar {
op: mul,
f: F::Ident(c),
rest: Box::new(Tprime(Node::new(5..5, None).into())),
}),
)
.into(),
),
},
rest: Box::new(Eprime(Node::new(5..5, None).into())),
};
let a_plus_b_mul_c = E {
first: T {
first: F::Ident(a),
rest: Tprime(Node::new(1..1, None).into()),
},
rest: Eprime(Node::new(1..5, Some(plus_b_mul_c)).into()),
};
assert_eq!(t, a_plus_b_mul_c);
assert_eq!(t.to_string(source), "a + b * c");
}
#[test]
fn parse_paren() {
let source = "(a+b)*(c+d)";
let t = E::parse(source).unwrap().unwrap();
assert_eq!(t.to_string(source), "(a + b) * (c + d)");
}
#[test]
fn parse_with_error() -> Result<(), GrammarError> {
let source = "a+(b*)+c";
let mut parser = Parser::new(source)?;
let t = parser.parse::<E>()?.unwrap();
let expecting = first_set!(TokenType { Ident:*, Paren:"(" });
assert_eq!(
parser.info().errors,
vec![Error::new(5..6, ErrorKind::Expecting(expecting))]
);
assert_eq!(t.to_string(source), "a + (b) + c");
Ok(())
}