use crate::declaration::{CustomType, Declaration, TypeAlias, ValueConstructor};
use crate::exposing::Exposing;
use crate::expr::{Expr, Function, FunctionImplementation, RecordSetter, Signature};
use crate::file::ElmModule;
use crate::import::Import;
use crate::literal::Literal;
use crate::module_header::ModuleHeader;
use crate::node::Spanned;
use crate::pattern::Pattern;
use crate::span::Span;
use crate::type_annotation::TypeAnnotation;
pub fn spanned<T>(value: T) -> Spanned<T> {
Spanned::dummy(value)
}
pub fn int(n: i64) -> Spanned<Expr> {
spanned(Expr::Literal(Literal::Int(n)))
}
pub fn float(n: f64) -> Spanned<Expr> {
spanned(Expr::Literal(Literal::Float(n)))
}
pub fn string(s: impl Into<String>) -> Spanned<Expr> {
spanned(Expr::Literal(Literal::String(s.into())))
}
pub fn char_lit(c: char) -> Spanned<Expr> {
spanned(Expr::Literal(Literal::Char(c)))
}
pub fn var(name: impl Into<String>) -> Spanned<Expr> {
spanned(Expr::FunctionOrValue {
module_name: Vec::new(),
name: name.into(),
})
}
pub fn qualified(module: &[&str], name: impl Into<String>) -> Spanned<Expr> {
spanned(Expr::FunctionOrValue {
module_name: module.iter().map(|s| s.to_string()).collect(),
name: name.into(),
})
}
pub fn app(func: Spanned<Expr>, args: Vec<Spanned<Expr>>) -> Spanned<Expr> {
let mut all = vec![func];
all.extend(args);
spanned(Expr::Application(all))
}
pub fn binop(op: impl Into<String>, left: Spanned<Expr>, right: Spanned<Expr>) -> Spanned<Expr> {
spanned(Expr::OperatorApplication {
operator: op.into(),
direction: crate::operator::InfixDirection::Left,
left: Box::new(left),
right: Box::new(right),
})
}
pub fn list(elements: Vec<Spanned<Expr>>) -> Spanned<Expr> {
spanned(Expr::List(elements))
}
pub fn tuple(elements: Vec<Spanned<Expr>>) -> Spanned<Expr> {
spanned(Expr::Tuple(elements))
}
pub fn record(fields: Vec<(impl Into<String>, Spanned<Expr>)>) -> Spanned<Expr> {
spanned(Expr::Record(
fields
.into_iter()
.map(|(name, value)| {
spanned(RecordSetter {
field: spanned(name.into()),
value,
})
})
.collect(),
))
}
pub fn if_else(
condition: Spanned<Expr>,
then_branch: Spanned<Expr>,
else_branch: Spanned<Expr>,
) -> Spanned<Expr> {
spanned(Expr::IfElse {
branches: vec![(condition, then_branch)],
else_branch: Box::new(else_branch),
})
}
pub fn lambda(args: Vec<Spanned<Pattern>>, body: Spanned<Expr>) -> Spanned<Expr> {
spanned(Expr::Lambda {
args,
body: Box::new(body),
})
}
pub fn unit() -> Spanned<Expr> {
spanned(Expr::Unit)
}
pub fn pvar(name: impl Into<String>) -> Spanned<Pattern> {
spanned(Pattern::Var(name.into()))
}
pub fn pwild() -> Spanned<Pattern> {
spanned(Pattern::Anything)
}
pub fn pint(n: i64) -> Spanned<Pattern> {
spanned(Pattern::Literal(Literal::Int(n)))
}
pub fn pctor(name: impl Into<String>, args: Vec<Spanned<Pattern>>) -> Spanned<Pattern> {
spanned(Pattern::Constructor {
module_name: Vec::new(),
name: name.into(),
args,
})
}
pub fn precord(fields: Vec<impl Into<String>>) -> Spanned<Pattern> {
spanned(Pattern::Record(
fields.into_iter().map(|f| spanned(f.into())).collect(),
))
}
pub fn tname(
name: impl Into<String>,
args: Vec<Spanned<TypeAnnotation>>,
) -> Spanned<TypeAnnotation> {
spanned(TypeAnnotation::Typed {
module_name: Vec::new(),
name: spanned(name.into()),
args,
})
}
pub fn tvar(name: impl Into<String>) -> Spanned<TypeAnnotation> {
spanned(TypeAnnotation::GenericType(name.into()))
}
pub fn tfunc(
from: Spanned<TypeAnnotation>,
to: Spanned<TypeAnnotation>,
) -> Spanned<TypeAnnotation> {
spanned(TypeAnnotation::FunctionType {
from: Box::new(from),
to: Box::new(to),
})
}
pub fn tunit() -> Spanned<TypeAnnotation> {
spanned(TypeAnnotation::Unit)
}
pub fn func(
name: impl Into<String>,
args: Vec<Spanned<Pattern>>,
body: Spanned<Expr>,
) -> Spanned<Declaration> {
spanned(Declaration::FunctionDeclaration(Box::new(Function {
documentation: None,
signature: None,
declaration: spanned(FunctionImplementation {
name: spanned(name.into()),
args,
body,
}),
})))
}
pub fn func_with_sig(
name: impl Into<String>,
args: Vec<Spanned<Pattern>>,
body: Spanned<Expr>,
type_ann: Spanned<TypeAnnotation>,
) -> Spanned<Declaration> {
let name_str: String = name.into();
spanned(Declaration::FunctionDeclaration(Box::new(Function {
documentation: None,
signature: Some(spanned(Signature {
name: spanned(name_str.clone()),
type_annotation: type_ann,
})),
declaration: spanned(FunctionImplementation {
name: spanned(name_str),
args,
body,
}),
})))
}
pub fn type_alias(
name: impl Into<String>,
generics: Vec<impl Into<String>>,
type_ann: Spanned<TypeAnnotation>,
) -> Spanned<Declaration> {
spanned(Declaration::AliasDeclaration(TypeAlias {
documentation: None,
name: spanned(name.into()),
generics: generics.into_iter().map(|g| spanned(g.into())).collect(),
type_annotation: type_ann,
}))
}
pub fn custom_type(
name: impl Into<String>,
generics: Vec<impl Into<String>>,
constructors: Vec<(impl Into<String>, Vec<Spanned<TypeAnnotation>>)>,
) -> Spanned<Declaration> {
spanned(Declaration::CustomTypeDeclaration(CustomType {
documentation: None,
name: spanned(name.into()),
generics: generics.into_iter().map(|g| spanned(g.into())).collect(),
constructors: constructors
.into_iter()
.map(|(name, args)| {
spanned(ValueConstructor {
name: spanned(name.into()),
args,
})
})
.collect(),
}))
}
pub fn module(name: Vec<impl Into<String>>, declarations: Vec<Spanned<Declaration>>) -> ElmModule {
ElmModule {
header: spanned(ModuleHeader::Normal {
name: spanned(name.into_iter().map(|s| s.into()).collect()),
exposing: spanned(Exposing::All(Span::dummy())),
}),
module_documentation: None,
imports: Vec::new(),
declarations,
comments: Vec::new(),
}
}
pub fn import(module_name: Vec<impl Into<String>>) -> Spanned<Import> {
spanned(Import {
module_name: spanned(module_name.into_iter().map(|s| s.into()).collect()),
alias: None,
exposing: None,
})
}