use crate::ast::{ShapeField, TypeExpr};
pub use harn_builtin_meta::{
BuiltinMetadata, BuiltinSignature, Param, ShapeFieldDescriptor, Ty, TY_ANY, TY_BOOL, TY_BYTES,
TY_BYTES_OR_NIL, TY_CLOSURE, TY_DECIMAL, TY_DICT, TY_DICT_OR_NIL, TY_DURATION, TY_FLOAT,
TY_INT, TY_INT_OR_NIL, TY_LIST, TY_NEVER, TY_NIL, TY_NUMBER, TY_STRING, TY_STRING_OR_NIL,
};
pub fn ty_to_type_expr(ty: &Ty) -> TypeExpr {
match ty {
Ty::Named(name) => TypeExpr::Named((*name).into()),
Ty::Generic(name) => TypeExpr::Named((*name).into()),
Ty::Any => TypeExpr::Named("any".into()),
Ty::Optional(inner) => {
TypeExpr::Union(vec![ty_to_type_expr(inner), TypeExpr::Named("nil".into())])
}
Ty::Apply("list", [inner]) => TypeExpr::List(Box::new(ty_to_type_expr(inner))),
Ty::Apply("dict", [key, value]) => TypeExpr::DictType(
Box::new(ty_to_type_expr(key)),
Box::new(ty_to_type_expr(value)),
),
Ty::Apply("iter", [inner]) => TypeExpr::Iter(Box::new(ty_to_type_expr(inner))),
Ty::Apply("generator" | "Generator", [inner]) => {
TypeExpr::Generator(Box::new(ty_to_type_expr(inner)))
}
Ty::Apply("stream" | "Stream", [inner]) => {
TypeExpr::Stream(Box::new(ty_to_type_expr(inner)))
}
Ty::Apply("owned", [inner]) => TypeExpr::Owned(Box::new(ty_to_type_expr(inner))),
Ty::Apply(name, args) => TypeExpr::Applied {
name: (*name).into(),
args: args.iter().map(ty_to_type_expr).collect(),
},
Ty::Union(members) => TypeExpr::Union(members.iter().map(ty_to_type_expr).collect()),
Ty::Fn(params, return_type) => TypeExpr::FnType {
params: params.iter().map(ty_to_type_expr).collect(),
return_type: Box::new(ty_to_type_expr(return_type)),
},
Ty::Shape(fields) => TypeExpr::Shape(
fields
.iter()
.map(|f| ShapeField::synthetic(f.name, ty_to_type_expr(&f.ty), f.optional))
.collect(),
),
Ty::OpenShape(fields, rests) => TypeExpr::OpenShape {
fields: fields
.iter()
.map(|f| ShapeField::synthetic(f.name, ty_to_type_expr(&f.ty), f.optional))
.collect(),
rests: rests.iter().map(ty_to_type_expr).collect(),
},
Ty::SchemaOf(name) => TypeExpr::Applied {
name: "Schema".into(),
args: vec![TypeExpr::Named((*name).into())],
},
Ty::Never => TypeExpr::Never,
Ty::LitInt(v) => TypeExpr::LitInt(*v),
Ty::LitString(s) => TypeExpr::LitString((*s).into()),
}
}
pub trait TyExt {
fn to_type_expr(&self) -> TypeExpr;
}
impl TyExt for Ty {
fn to_type_expr(&self) -> TypeExpr {
ty_to_type_expr(self)
}
}
pub trait BuiltinSignatureExt {
fn param_type_exprs(&self) -> Vec<TypeExpr>;
fn return_type_expr(&self) -> TypeExpr;
}
impl BuiltinSignatureExt for BuiltinSignature {
fn param_type_exprs(&self) -> Vec<TypeExpr> {
self.params.iter().map(|p| ty_to_type_expr(&p.ty)).collect()
}
fn return_type_expr(&self) -> TypeExpr {
ty_to_type_expr(&self.returns)
}
}
#[cfg(test)]
mod tests {
use super::*;
const STRING: Ty = Ty::Named("string");
const LIST_ARGS: &[Ty] = &[STRING];
#[test]
fn builtin_container_metadata_uses_language_ast_variants() {
assert_eq!(
ty_to_type_expr(&Ty::Apply("list", LIST_ARGS)),
TypeExpr::List(Box::new(TypeExpr::Named("string".into())))
);
}
}