// ::= Symbol { } // ::= Literal // | Symbol // | OpenParen CloseParen use std::mem::{discriminant, Discriminant}; use crate::{token::{Literal, Token}, ir::{BindingScope, Identifier, pattern::Pattern, self, IrError}, cons, join_vec}; use super::{Parsable, ParseError, WrappedLexer, absorb_token_or_error}; #[derive(Debug)] pub enum TightBindingPattern { Literal(Literal), Symbol(String), Group(BindingPattern), Universal, } impl TightBindingPattern { pub fn gen_ir(self, scope: &BindingScope, parent_ident: &Identifier, index: u32) -> ir::Result<(Vec, Pattern)> { match self { TightBindingPattern::Literal(l) => Ok((Vec::new(), Pattern::Literal(l))), TightBindingPattern::Symbol(s) => { let ident = parent_ident.subid_with_name(s, index); Ok(( vec![ident.clone()], Pattern::Binding(ident), )) } TightBindingPattern::Group(bp) => bp.gen_ir(scope, parent_ident, index), TightBindingPattern::Universal => Ok((Vec::new(), Pattern::Universal)), } } } impl Parsable for TightBindingPattern { fn expected() -> (Vec>, bool) { ( vec![ discriminant(&Token::Literal(Literal::Int(0))), discriminant(&Token::Symbol(String::new())), discriminant(&Token::OpenParen), ], false, ) } fn parse(l: &mut WrappedLexer) -> Result { let location = l.span(); match l.curtok() { Token::Literal(l) => Ok(TightBindingPattern::Literal(l.clone())), Token::Symbol(name) => Ok(TightBindingPattern::Symbol(name.to_owned())), Token::OpenParen => { let patt = BindingPattern::parse(l)?; absorb_token_or_error(l, discriminant(&Token::CloseParen))?; Ok(TightBindingPattern::Group(patt)) }, _ => { Err(ParseError { expected: Self::expected().0, location, }) } } } } #[derive(Debug)] pub struct BindingPattern(String, Vec); impl Parsable for BindingPattern { fn expected() -> (Vec>, bool) { ( vec![ discriminant(&Token::Symbol(String::new())), ], false ) } fn parse(l: &mut WrappedLexer) -> Result { let name = String::parse(l)?; let fields = Vec::parse(l)?; Ok(Self(name, fields)) } } impl BindingPattern { pub fn gen_ir(self, scope: &BindingScope, parent_ident: &Identifier, index: u32) -> ir::Result<(Vec, Pattern)> { let BindingPattern(variant, elements) = self; let self_ident = parent_ident.subid_generate_name(&variant, index); let variant_ident = scope.lookup(&variant).ok_or(IrError::Undefined(variant))?; let (idents, patts) = elements.into_iter() .enumerate() .map(|(idx, patt)| patt.gen_ir(scope, &self_ident, idx as u32)) .try_fold( (Vec::new(), Vec::with_capacity(8)), |(found_identifiers, found_patterns), res| { let (new_idents, new_patt) = res?; Ok((join_vec(found_identifiers, new_idents), cons(found_patterns, new_patt))) } )?; Ok((idents, Pattern::Variant(variant_ident.clone(), patts))) } }