use quote::ToTokens;
use quote::quote;
use crate::types::*;
use crate::parse::parse_primitive;
fn err_ty(msg: &str) -> Ty {
Ty::Error(TyError(quote! { compile_error!(#msg); }))
}
pub(crate) trait Type {
fn apply(self, o: Ty) -> Ty;
}
impl Type for Ty {
fn apply(self, o: Ty) -> Ty {
if let Ty::Array(arr) = o {
return TyArray(arr.0.into_iter().map(|e| self.clone().apply(e)).collect()).into();
}
if let Ty::Group(g) = o {
return self.apply(*g.0);
}
if let Ty::WithCode(wc) = o{
return TyWithCode(self.apply(*wc.0).into(),wc.1).into()
}
match self {
Ty::Prefix(p) => p.apply(o),
Ty::Modified(m) => m.apply(o),
Ty::Unsafe(u) => u.apply(o),
Ty::Primitive(p) => p.apply(o),
Ty::Generic(g) => g.apply(o),
Ty::Trait(t) => t.apply(o),
Ty::Array(a) => a.apply(o),
Ty::Tuple(t) => t.apply(o),
Ty::Group(g) => g.apply(o),
Ty::Fn(f) => f.apply(o),
Ty::CodeBlock(b) => b.apply(o),
Ty::Attr(a) => a.apply(o),
Ty::WithAttr(w) => w.apply(o),
Ty::WithTrait(wt) => wt.apply(o),
Ty::WithType(wt) => wt.apply(o),
Ty::WithCode(wc) => wc.apply(o),
Ty::TypeParam(t) => t.apply(o),
Ty::Num(n) => n.apply(o),
Ty::Range(r) => r.apply(o),
Ty::Slice(s) => s.apply(o),
Ty::FixedArray(f) => f.apply(o),
Ty::Error(e) => e.into(),
}
}
}
impl Type for TyPrefix {
fn apply(self, o: Ty) -> Ty {
match self {
TyPrefix::Ref | TyPrefix::RefMut | TyPrefix::PtrConst | TyPrefix::PtrMut => {
TyModified(self, o.into()).into()
}
TyPrefix::SelfType => o,
TyPrefix::Fn => match o {
Ty::Tuple(t) => TyFn(t.0, None).into(),
Ty::Group(t) => TyFn(vec![*t.0],None).into(),
_ => err_ty("batch-impl: `fn` 前缀右侧必须是元组类型,如 fn^(i32, u32)"),
},
TyPrefix::Unsafe => TyUnsafe(o.into()).into(),
}
}
}
impl Type for TyModified {
fn apply(self, o: Ty) -> Ty {
TyModified(self.0, self.1.apply(o).into()).into()
}
}
impl Type for TyUnsafe {
fn apply(self, o: Ty) -> Ty {
TyUnsafe(self.0.apply(o).into()).into()
}
}
impl Type for TyPrimitive {
fn apply(self, o: Ty) -> Ty {
match o {
Ty::TypeParam(tp) => TyGeneric(self.into(), tp).into(),
_ => TyGeneric(self.into(), TyTypeParam::single(&o)).into(),
}
}
}
impl Type for TyGeneric {
fn apply(self, o: Ty) -> Ty {
let mut tp = self.1;
match o {
Ty::TypeParam(rhs) => tp.extend(rhs),
_ => tp.push_arg(&o),
}
TyGeneric(self.0, tp).into()
}
}
impl Type for TyTrait {
fn apply(self, o: Ty) -> Ty {
match o {
Ty::TypeParam(rhs) => {
let mut tp = self.1;
tp.extend(rhs);
TyTrait(self.0, tp).into()
}
_ => TyWithTrait(self, o.into()).into(),
}
}
}
impl Type for TyArray {
fn apply(self, o: Ty) -> Ty {
match o {
Ty::Array(right) => {
let mut result = vec![];
for left in self.0 {
for right_elem in &right.0 {
result.push(left.clone().apply(right_elem.clone()));
}
}
TyArray(result).into()
}
_ => {
let result = self.0.into_iter()
.map(|e| e.apply(o.clone()))
.collect();
TyArray(result).into()
}
}
}
}
fn map_range(start: u8, end: u8, inclusive: bool, f: impl Fn(u8) -> Ty) -> Ty {
let ns: Vec<u8> = if inclusive {
(start..=end).collect()
} else {
(start..end).collect()
};
TyArray(ns.into_iter().map(f).collect()).into()
}
fn tuple_pow(elems: Vec<Ty>, n: u8) -> Ty {
match elems.len() {
0 => pow_empty(n),
1 => pow_single(elems.into_iter().next().unwrap(), n),
_ => pow_cartesian(elems, n),
}
}
fn pow_empty(n: u8) -> Ty {
if n == 0 {
return TyTuple(vec![]).into();
}
let params = fresh_params(n);
let param_names = params.iter().map(|p| p.to_token_stream()).collect::<Vec<_>>();
TyTypeParam {
params: param_names.into_iter().map(|n| (n, None)).collect(),
bindings: vec![],
}.apply(TyTuple(params).into())
}
fn pow_single(template: Ty, n: u8) -> Ty {
if let Ty::TypeParam(tp) = template {
if tp.params.len() != 1 || tp.params[0].1.is_some() {
return err_ty("batch-impl: (<Trait>)⁁ 中意外收到了 bound 参数,这是内部错误");
}
let params = fresh_params(n);
let param_names = params.iter().map(|p| p.to_token_stream()).collect::<Vec<_>>();
let bound_tokens: Vec<_> = tp.params[0].0.clone().into_iter().collect();
return TyTypeParam {
params: param_names.into_iter()
.map(|n| (n, Some(parse_primitive(&bound_tokens, None))))
.collect(),
bindings: vec![],
}.apply(TyTuple(params).into());
}
TyTuple((0..n).map(|_| template.clone()).collect()).into()
}
fn pow_cartesian(elems: Vec<Ty>, n: u8) -> Ty {
let mut combos = vec![vec![]];
for _ in 0..n {
let mut next = vec![];
for existing in &combos {
for elem in &elems {
let mut extended = existing.clone();
extended.push(elem.clone());
next.push(extended);
}
}
combos = next;
}
TyArray(combos.into_iter().map(instantiate_combo).collect()).into()
}
fn instantiate_combo(elems: Vec<Ty>) -> Ty {
let mut tuple_elems = vec![];
let mut param_decls = vec![];
for elem in elems {
match elem {
Ty::TypeParam(tp) => {
let name = fresh_param();
let params = tp.params.iter()
.map(|(b, _)| (name.clone(), Some(Ty::from(TyPrimitive(b.clone())))))
.collect();
param_decls.push(TyTypeParam { params, bindings: vec![] });
tuple_elems.push(Ty::from(TyPrimitive(name)));
}
_ => tuple_elems.push(elem),
}
}
let tuple = Ty::from(TyTuple(tuple_elems));
if param_decls.is_empty() {
return tuple;
}
let mut merged = TyTypeParam { params: vec![], bindings: vec![] };
for tp in param_decls {
merged.extend(tp);
}
merged.apply(tuple)
}
fn fresh_params(n: u8) -> Vec<Ty> {
(0..n).map(|_| Ty::from(TyPrimitive(fresh_param()))).collect()
}
impl Type for TyTuple {
fn apply(mut self, o: Ty) -> Ty {
match o {
Ty::Num(TyNum(n)) => tuple_pow(self.0, n),
Ty::Range(TyRange { start, end, inclusive }) =>
map_range(start, end, inclusive, |n| tuple_pow(self.0.clone(), n)),
_ => {
self.0.push(o);
self.into()
}
}
}
}
impl Type for TyGroup {
fn apply(self, o: Ty) -> Ty {
match o {
Ty::Num(TyNum(n)) => tuple_pow(vec![*self.0], n),
Ty::Range(TyRange { start, end, inclusive }) =>
map_range(start, end, inclusive, |n| tuple_pow(vec![*self.0.clone()], n)),
_ => self.0.apply(o),
}
}
}
impl Type for TyFn {
fn apply(self, o: Ty) -> Ty {
if self.1.is_some() {
err_ty("batch-impl: `fn` 类型已有返回类型,不能重复应用")
} else {
TyFn(self.0, Some(o.into())).into()
}
}
}
impl Type for TyCodeBlock {
fn apply(self, o: Ty) -> Ty {
TyWithCode(o.into(), self.0).into()
}
}
impl Type for TyAttr {
fn apply(self, o: Ty) -> Ty {
TyWithAttr(self, o.into()).into()
}
}
impl Type for TyWithAttr {
fn apply(self, o: Ty) -> Ty {
TyWithAttr(self.0, o.into()).into()
}
}
impl Type for TyTypeParam {
fn apply(self, o: Ty) -> Ty {
TyWithType(self, o.into()).into()
}
}
impl Type for TyNum{
fn apply(self, _: Ty) -> Ty {
err_ty(&format!("batch-impl: 数字 `{}` 不能作为左侧操作数,只能出现在右侧(如 T^{})", self.0, self.0))
}
}
impl Type for TyRange{
fn apply(self, _: Ty) -> Ty {
let end_mark = if self.inclusive { "=" } else { "" };
err_ty(&format!("batch-impl: 范围 `{}..{}{}` 不能作为左侧操作数,只能出现在右侧(如 T^{}..{}{})",
self.start, self.end, end_mark, self.start, self.end, end_mark))
}
}
impl Type for TySlice{
fn apply(self, _: Ty) -> Ty {
err_ty("batch-impl: 切片类型 `[T]` 不能作为左侧操作数")
}
}
impl Type for TyFixedArray{
fn apply(self, _: Ty) -> Ty {
err_ty("batch-impl: 固定数组类型 `[T; N]` 不能作为左侧操作数")
}
}
impl Type for TyWithTrait {
fn apply(self, o: Ty) -> Ty {
TyWithTrait(self.0,self.1.apply(o).into()).into()
}
}
impl Type for TyWithType {
fn apply(self, o: Ty) -> Ty {
TyWithType(self.0, self.1.apply(o).into()).into()
}
}
impl Type for TyWithCode {
fn apply(self, o: Ty) -> Ty {
TyWithCode(self.0.apply(o).into(), self.1).into()
}
}