use std::convert::TryFrom;
use crate::common::{
span::Spanned,
data::Data,
};
#[derive(Debug, Clone, PartialEq)]
pub enum ArgPattern {
Keyword(String),
Symbol(String),
Group(Vec<Spanned<ArgPattern>>),
}
impl TryFrom<AST> for ArgPattern {
type Error = String;
fn try_from(ast: AST) -> Result<Self, Self::Error> {
Ok(
match ast {
AST::Symbol(s) => ArgPattern::Symbol(s),
AST::ArgPattern(p) => p,
AST::Form(f) => {
let mut mapped = vec![];
for a in f { mapped.push(a.map(ArgPattern::try_from)?); }
ArgPattern::Group(mapped)
}
_ => Err("Unexpected construct inside argument pattern")?,
}
)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ASTPattern {
Symbol(String),
Data(Data),
Chain(Vec<Spanned<ASTPattern>>), Label(String, Box<Spanned<ASTPattern>>),
Tuple(Vec<Spanned<ASTPattern>>),
}
impl ASTPattern {
pub fn label(name: String, pattern: Spanned<ASTPattern>) -> ASTPattern {
ASTPattern::Label(name, Box::new(pattern))
}
}
impl TryFrom<AST> for ASTPattern {
type Error = String;
fn try_from(ast: AST) -> Result<Self, Self::Error> {
Ok(
match ast {
AST::Symbol(s) => ASTPattern::Symbol(s),
AST::Data(d) => ASTPattern::Data(d),
AST::Label(k, a) => ASTPattern::Label(k, Box::new(a.map(ASTPattern::try_from)?)),
AST::CSTPattern(p) => p,
AST::Form(f) => {
let mut patterns = vec![];
for item in f {
patterns.push(item.map(ASTPattern::try_from)?);
}
ASTPattern::Chain(patterns)
},
AST::Tuple(t) => {
let mut patterns = vec![];
for item in t {
patterns.push(item.map(ASTPattern::try_from)?);
}
ASTPattern::Tuple(patterns)
}
AST::Group(e) => e.map(ASTPattern::try_from)?.item,
_ => Err("Unexpected construct inside pattern")?,
}
)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum AST {
Symbol(String),
Data(Data),
Block(Vec<Spanned<AST>>),
Form(Vec<Spanned<AST>>),
Group(Box<Spanned<AST>>),
CSTPattern(ASTPattern),
ArgPattern(ArgPattern),
Tuple(Vec<Spanned<AST>>),
Assign {
pattern: Box<Spanned<ASTPattern>>,
expression: Box<Spanned<AST>>,
},
Lambda {
pattern: Box<Spanned<ASTPattern>>,
expression: Box<Spanned<AST>>,
},
Composition {
argument: Box<Spanned<AST>>,
function: Box<Spanned<AST>>,
},
Label(String, Box<Spanned<AST>>),
Syntax {
arg_pat: Box<Spanned<ArgPattern>>,
expression: Box<Spanned<AST>>,
},
FFI {
name: String,
expression: Box<Spanned<AST>>,
},
}
impl AST {
pub fn assign(
pattern: Spanned<ASTPattern>,
expression: Spanned<AST>
) -> AST {
AST::Assign {
pattern: Box::new(pattern),
expression: Box::new(expression)
}
}
pub fn lambda(
pattern: Spanned<ASTPattern>,
expression: Spanned<AST>
) -> AST {
AST::Lambda {
pattern: Box::new(pattern),
expression: Box::new(expression)
}
}
pub fn composition(
argument: Spanned<AST>,
function: Spanned<AST>,
) -> AST {
AST::Composition {
argument: Box::new(argument),
function: Box::new(function),
}
}
pub fn syntax(
arg_pat: Spanned<ArgPattern>,
expression: Spanned<AST>,
) -> AST {
AST::Syntax {
arg_pat: Box::new(arg_pat),
expression: Box::new(expression),
}
}
pub fn label(name: &str, expression: Spanned<AST>) -> AST {
AST::Label(name.to_string(), Box::new(expression))
}
pub fn ffi(name: &str, expression: Spanned<AST>) -> AST {
AST::FFI {
name: name.to_string(),
expression: Box::new(expression),
}
}
pub fn group(expression: Spanned<AST>) -> AST {
AST::Group(Box::new(expression))
}
}