104 lines
3.0 KiB
Rust
104 lines
3.0 KiB
Rust
// <binding_pattern> ::= Symbol { <tight_binding_pattern> }
|
|
// <tight_binding_pattern> ::= Literal
|
|
// | Symbol
|
|
// | OpenParen <binding_pattern> 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<Identifier>, 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<Discriminant<Token>>, bool) {
|
|
(
|
|
vec![
|
|
discriminant(&Token::Literal(Literal::Int(0))),
|
|
discriminant(&Token::Symbol(String::new())),
|
|
discriminant(&Token::OpenParen),
|
|
],
|
|
false,
|
|
)
|
|
}
|
|
fn parse(l: &mut WrappedLexer) -> Result<Self, ParseError> {
|
|
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<TightBindingPattern>);
|
|
|
|
impl Parsable for BindingPattern {
|
|
fn expected() -> (Vec<Discriminant<Token>>, bool) {
|
|
(
|
|
vec![
|
|
discriminant(&Token::Symbol(String::new())),
|
|
], false
|
|
)
|
|
}
|
|
fn parse(l: &mut WrappedLexer) -> Result<Self, ParseError> {
|
|
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<Identifier>, 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)))
|
|
}
|
|
}
|