voile 0.2.6

Voile, a dependently-typed row-polymorphic programming language
Documentation
use pest_derive::Parser;

use voile_util::level::Level;
use voile_util::loc::{Ident, Loc};
use voile_util::pest_util::{end_of_rule, strict_parse};
use voile_util::tags::{Plicit, VarRec};
use voile_util::vec1::Vec1;

use crate::syntax::surf::LabExpr;

use super::ast::Param;
use super::{Decl, DeclKind, Expr};

#[derive(Parser)]
#[grammar = "syntax/surf/grammar.pest"]
/// The name stands for "Voile's Parser"
struct VoileParser;

tik_tok!();

pub fn parse_str(input: &str) -> Result<Vec<Decl>, String> {
    strict_parse::<VoileParser, _, _, _>(Rule::file, input, declarations)
}

pub fn parse_str_expr(input: &str) -> Result<Expr, String> {
    strict_parse::<VoileParser, _, _, _>(Rule::standalone_expr, input, expr)
}

macro_rules! expr_parser {
    ($name:ident,$smaller:ident,$cons:ident) => {
        fn $name(rules: Tok) -> Expr {
            let mut exprs: Vec<Expr> = Default::default();
            for smaller in rules.into_inner() {
                exprs.push($smaller(smaller));
            }
            let first = exprs.remove(0);
            if exprs.is_empty() {
                first
            } else {
                Expr::$cons(first, exprs)
            }
        }
    };
}

#[inline]
fn next_ident(inner: &mut Tik) -> Ident {
    next_rule!(inner, ident)
}

fn declarations(the_rule: Tok) -> Vec<Decl> {
    the_rule.into_inner().into_iter().map(declaration).collect()
}

fn rec_field(rules: Tok) -> LabExpr {
    labelled(rules)
}

fn labelled(rules: Tok) -> LabExpr {
    let mut inner: Tik = rules.into_inner();
    let label = next_ident(&mut inner);
    let expr = next_rule!(inner, expr);
    end_of_rule(&mut inner);
    LabExpr { expr, label }
}

fn row_rest(rules: Tok) -> Expr {
    let mut inner: Tik = rules.into_inner();
    let expr = next_rule!(inner, expr);
    end_of_rule(&mut inner);
    expr
}

many_prefix_parser!(row_polymorphic, LabExpr, labelled, row_rest, Expr);
many_prefix_parser!(record_literal, LabExpr, rec_field, row_rest, Expr);

fn record(rules: Tok) -> Expr {
    let info = Loc::from(rules.as_span());
    let (fields, rest) = record_literal(rules);
    Expr::record(info, fields, rest)
}

fn variant_record(rules: Tok, kind: VarRec) -> Expr {
    let info = Loc::from(rules.as_span());
    let mut inner: Tik = rules.into_inner();
    let (labels, rest) = next_rule!(inner, row_polymorphic);
    Expr::row_polymorphic_type(info, labels, kind, rest)
}

fn variant_record_kind(rules: Tok, kind: VarRec) -> Expr {
    let info = Loc::from(rules.as_span());
    let rules = rules.into_inner().next().unwrap();
    let labels = rules.into_inner().into_iter().map(ident).collect();
    Expr::RowKind(info, kind, labels)
}

fn declaration(rules: Tok) -> Decl {
    let the_rule: Tok = rules.into_inner().next().unwrap();
    let kind = match the_rule.as_rule() {
        Rule::signature => DeclKind::Sign,
        Rule::implementation => DeclKind::Impl,
        _ => unreachable!(),
    };
    let mut inner: Tik = the_rule.into_inner();
    let name = next_ident(&mut inner);
    let body = next_rule!(inner, expr);
    end_of_rule(&mut inner);
    Decl { kind, name, body }
}

expr_parser!(dollar_expr, comma_expr, app);
expr_parser!(comma_expr, pipe_expr, tup);
expr_parser!(pipe_expr, lift_expr, pipe);
// expr_parser!(lift_expr, app_expr, lift); customized
expr_parser!(app_expr, primary_expr, app);

fn lift_expr(rules: Tok) -> Expr {
    let mut lift_count = 0;
    let loc = From::from(rules.as_span());
    for smaller in rules.into_inner() {
        match smaller.as_rule() {
            Rule::lift_op => {
                lift_count += 1;
            }
            Rule::proj_expr => {
                let expr = proj_expr(smaller);
                return if lift_count == 0 {
                    expr
                } else {
                    Expr::lift(loc, lift_count, expr)
                };
            }
            _ => unreachable!(),
        }
    }
    unreachable!()
}

fn proj_expr(rules: Tok) -> Expr {
    let mut projections = None;
    let mut inner = rules.into_inner();
    let projected = next_rule!(inner, app_expr);
    for projection in inner {
        assert_eq!(projection.as_rule(), Rule::proj_op);
        let ident = Ident {
            loc: Loc::from(projection.as_span()),
            text: projection.as_str()[1..].to_owned(),
        };
        match projections {
            None => projections = Some(Vec1::from(ident)),
            Some(mut some_projections) => {
                some_projections.push(ident);
                projections = Some(some_projections);
            }
        };
    }
    match projections {
        Some(projections) => Expr::proj(projected, projections),
        None => projected,
    }
}

fn expr(rules: Tok) -> Expr {
    let mut inner: Tik = rules.into_inner();
    let expr = next_rule!(inner, sig_expr);
    end_of_rule(&mut inner);
    expr
}

fn primary_expr(rules: Tok) -> Expr {
    let mut inner: Tik = rules.into_inner();
    let the_rule: Tok = inner.next().unwrap();
    let expr = match the_rule.as_rule() {
        Rule::ident => Expr::Var(ident(the_rule)),
        Rule::cons => Expr::Cons(ident(the_rule)),
        Rule::meta => Expr::Meta(ident(the_rule)),
        Rule::no_cases => Expr::Whatever(From::from(the_rule.as_span())),
        Rule::case_expr => case_expr(the_rule),
        Rule::lambda => lambda(the_rule),
        Rule::record => variant_record(the_rule, VarRec::Record),
        Rule::variant => variant_record(the_rule, VarRec::Variant),
        Rule::record_kind => variant_record_kind(the_rule, VarRec::Record),
        Rule::variant_kind => variant_record_kind(the_rule, VarRec::Variant),
        Rule::record_literal => record(the_rule),
        Rule::type_keyword => type_keyword(the_rule),
        Rule::expr => expr(the_rule),
        e => panic!("Unexpected rule: {:?} with token {}", e, the_rule.as_str()),
    };
    end_of_rule(&mut inner);
    expr
}

fn one_param(rules: Tok, plicit: Plicit) -> Param {
    let mut inner: Tik = rules.into_inner();
    let (names, expr) = next_rule!(inner, multi_param);
    let ty = expr.unwrap();
    end_of_rule(&mut inner);
    Param { plicit, names, ty }
}

fn param(rules: Tok) -> Param {
    let mut inner: Tik = rules.into_inner();
    let the_rule: Tok = inner.next().unwrap();
    let param = match the_rule.as_rule() {
        Rule::explicit => one_param(the_rule, Plicit::Ex),
        Rule::implicit => one_param(the_rule, Plicit::Im),
        rule_type => Param {
            plicit: Plicit::Ex,
            names: Vec::with_capacity(0),
            ty: match rule_type {
                Rule::dollar_expr => dollar_expr(the_rule),
                Rule::pi_expr => pi_expr(the_rule),
                e => panic!("Unexpected rule: {:?} with token {}", e, the_rule.as_str()),
            },
        },
    };
    end_of_rule(&mut inner);
    param
}

many_prefix_parser!(pi_expr_internal, Param, param, dollar_expr, Expr);
many_prefix_parser!(sig_expr_internal, Param, param, pi_expr, Expr);
many_prefix_parser!(multi_param, Ident, ident, expr, Expr);
many_prefix_parser!(lambda_internal, Ident, ident, expr, Expr);

fn pi_expr(rules: Tok) -> Expr {
    let (params, ret) = pi_expr_internal(rules);
    let ret = ret.unwrap();
    if params.is_empty() {
        ret
    } else {
        Expr::pi(params, ret)
    }
}

fn sig_expr(rules: Tok) -> Expr {
    let (params, ret) = sig_expr_internal(rules);
    let ret = ret.unwrap();
    if params.is_empty() {
        ret
    } else {
        Expr::sig(params, ret)
    }
}

fn case_expr(rules: Tok) -> Expr {
    let mut inner: Tik = rules.into_inner();
    let label = next_ident(&mut inner);
    let binding = next_ident(&mut inner);
    let body = next_rule!(inner, expr);
    let rest = next_rule!(inner, expr);
    end_of_rule(&mut inner);
    Expr::cases(label, binding, body, rest)
}

fn lambda(rules: Tok) -> Expr {
    let loc = Loc::from(rules.as_span());
    let (params, ret) = lambda_internal(rules);
    let ret = ret.unwrap();
    Expr::lam(loc, params, ret)
}

fn type_keyword(rules: Tok) -> Expr {
    let loc = Loc::from(rules.as_span());
    let mut inner: Tik = rules.into_inner();
    let level_ast_node: Tok = inner.next().unwrap();
    debug_assert_eq!(level_ast_node.as_rule(), Rule::type_level);
    let level = Level::Num(level_ast_node.as_str().parse().unwrap_or(0));
    end_of_rule(&mut inner);
    Expr::Type(loc, level)
}

fn ident(rule: Tok) -> Ident {
    Ident {
        text: rule.as_str().to_owned(),
        loc: From::from(rule.as_span()),
    }
}