use pest::error::Error;
use pest::iterators::Pair;
use pest::Parser;
use pest_derive::Parser;
#[derive(Parser)]
#[grammar = "pest/wit.pest"] pub struct WitParser;
#[derive(Debug)]
pub enum ContextValue {
File(Vec<ContextValue>),
Package(String),
Interface(Vec<ContextValue>),
Variant(Vec<ContextValue>),
Case((String, Box<ContextValue>)),
Record((Box<ContextValue>, Box<ContextValue>)),
Name(String),
Field {
name: Box<ContextValue>,
ty: Box<ContextValue>,
},
Type(String),
}
pub fn parse_wit(file: &str) -> Result<ContextValue, Error<Rule>> {
let pairs = WitParser::parse(Rule::file, file)?.next().unwrap();
let pair_vec = pairs.into_inner().map(parse_pair).collect();
Ok(ContextValue::File(pair_vec))
}
fn parse_pair(pair: Pair<Rule>) -> ContextValue {
match pair.as_rule() {
Rule::interface => {
println!("\n*** interface: {:?}", pair);
ContextValue::Interface(pair.into_inner().map(parse_pair).collect())
}
Rule::variant => {
println!("\n*** variant: {:?}", pair);
ContextValue::Variant(pair.into_inner().map(parse_pair).collect())
}
Rule::record => {
println!("\n*** record: {:?}", pair);
let mut inner = pair.into_inner();
let name = inner.next().unwrap().as_str().to_string();
let field = inner.next().unwrap();
ContextValue::Record((
Box::new(ContextValue::Name(name)),
Box::new(parse_pair(field)),
))
}
Rule::name => {
println!("\n*** name: {:?}", pair);
ContextValue::Name(pair.as_str().to_string())
}
Rule::wit_type => {
println!("\n*** wit_type: {:?}", pair);
ContextValue::Type(pair.as_str().to_string())
}
Rule::package => {
println!("\n*** package: {:?}", pair);
let mut inner = pair.into_inner();
let name = inner.next().unwrap().as_str().to_string();
ContextValue::Package(name)
}
Rule::file => {
println!("\n*** file: {:?}", pair);
ContextValue::File(pair.into_inner().map(parse_pair).collect())
}
Rule::record_item => {
println!("\n*** record_item: {:?}", pair);
let mut inner = pair.into_inner();
let name = inner.next().unwrap().as_str().to_string();
let wit_type = inner.next().unwrap().as_str().to_string();
ContextValue::Field {
name: Box::new(ContextValue::Name(name)),
ty: Box::new(ContextValue::Type(wit_type)),
}
}
Rule::variant_item => {
println!("\n*** variant_item: {:?}", pair);
let mut inner = pair.into_inner();
let name = inner.next().unwrap().as_str().to_string();
let wit_type = inner.next().unwrap();
ContextValue::Case((name, Box::new(parse_pair(wit_type))))
}
Rule::EOI => {
println!("\n*** EOI: {:?}", pair);
ContextValue::File(vec![])
}
_ => {
println!("\n*** unreachable: {:?}", pair);
unreachable!()
}
}
}
#[cfg(test)]
mod test_pest_parser {
use super::*;
use pest::Parser;
#[test]
fn smoke() {
let unparsed_file =
std::fs::read_to_string("./tests/fixtures/basic.wit").expect("Cannot read file");
let successful_parse = WitParser::parse(Rule::file, &unparsed_file)
.expect("to be able to parse file")
.next()
.expect("to be able to get first rule");
println!("{:?}", successful_parse);
}
#[test]
fn test_parse_pairs() {
let unparsed_file =
std::fs::read_to_string("./tests/fixtures/basic.wit").expect("Cannot read file");
let context = parse_wit(&unparsed_file).expect("to be able to parse file");
println!("\n### Entire Context: \n{:?}", context);
}
}