wardenclyffe 0.1.0

A tiny Rust query engine that supports SQL-like filters, CSV scanning, projections, and a custom DSL powered by Pest.
Documentation
use pest::Parser;
use pest_derive::Parser;

use crate::ast::Expr;
// use pest::iterators::{Pairs, Pair};
use pest::iterators::Pairs;


#[derive(Parser)]
#[grammar = "query.pest"]
pub struct QueryParser;

pub fn parse_expr(input: &str) -> Expr {
    println!("\nDEBUG: parsing: {:?}", input);

    match QueryParser::parse(Rule::query, input) {
        Ok(pairs) => {
            println!("DEBUG: PARSED PAIRS:");
            for p in pairs.clone() {
                println!("  {:?}", p.as_rule());
            }
            println!("{:#?}", pairs);

            build_expr(pairs)
        }
        Err(e) => {
            println!("DEBUG: PARSE ERROR: {:?}", e);
            panic!("Parse failed");
        }
    }
}


fn build_expr(pairs: Pairs<Rule>) -> Expr {
    use Expr::*;

    for pair in pairs {
        match pair.as_rule() {
            Rule::expr => {
                return build_expr(pair.into_inner());
            }

            Rule::or_expr => {
                let mut inner = pair.into_inner();
                let mut expr = build_expr(inner.next().unwrap().into_inner());

                for next in inner {
                    expr = Or(Box::new(expr), Box::new(build_expr(next.into_inner())));
                }

                return expr;
            }

            Rule::and_expr => {
                let mut inner = pair.into_inner();
                let mut expr = build_expr(inner.next().unwrap().into_inner());

                for next in inner {
                    expr = And(Box::new(expr), Box::new(build_expr(next.into_inner())));
                }

                return expr;
            }

            Rule::cmp_expr => {
                let mut inner = pair.into_inner();
                let field = inner.next().unwrap().as_str().to_string();
                let op = inner.next().unwrap().as_str().to_string();
                let val = inner.next().unwrap().as_str().to_string();

                return Cmp { field, op, value: val };
            }

            _ => {}
        }
    }

    panic!("Empty expression");
}