Amo/src/parser/pattern.rs

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)))
}
}