private NameAllocator nameAllocator(List<DataConstructor> constructors) { NameAllocator nameAllocator = new NameAllocator(); constructors .stream() .forEach( dc -> nameAllocator.newName( MapperDerivator.mapperFieldName(dc), MapperDerivator.mapperFieldName(dc) + " arg")); nameAllocator.newName("cata", "cata"); nameAllocator.newName( Utils.uncapitalize(adt.typeConstructor().declaredType().asElement().getSimpleName()), "adt var"); return nameAllocator; }
private DeriveResult<DerivedCodeSpec> functionDispatchImpl(List<DataConstructor> constructors) { NameAllocator nameAllocator = nameAllocator(constructors); TypeElement f = FlavourImpl.findF(context.flavour(), utils.elements()); TypeName returnType = TypeName.get( utils .types() .getDeclaredType( f, adt.typeConstructor().declaredType(), adt.matchMethod().returnTypeVariable())); TypeSpec wrapper = TypeSpec.anonymousClassBuilder("") .addField( FieldSpec.builder(returnType, nameAllocator.get("cata")) .initializer( CodeBlock.builder() .addStatement( "$L -> $L.$L($L)", nameAllocator.get("adt var"), nameAllocator.get("adt var"), adt.matchMethod().element().getSimpleName(), Utils.joinStringsAsArguments( constructors .stream() .map( constructor -> constructor .arguments() .stream() .map(DataArguments::getType) .noneMatch( tm -> utils .types() .isSameType( tm, adt.typeConstructor() .declaredType())) ? constructor.name() : CodeBlock.builder() .add( "($L) -> $L.$L($L)", Utils.asLambdaParametersString( constructor.arguments(), constructor.typeRestrictions()), constructor.name(), MapperDerivator.mapperApplyMethod( utils, context, constructor), Utils.joinStringsAsArguments( Stream.concat( constructor .arguments() .stream() .map( argument -> utils .types() .isSameType( argument .type(), adt.typeConstructor() .declaredType()) ? "() -> this." + nameAllocator .get( "cata") + "." + FlavourImpl .functionApplyMethod( utils, context) + "(" + argument .fieldName() + ")" : argument .fieldName()), constructor .typeRestrictions() .stream() .map( TypeRestriction ::idFunction) .map( DataArgument ::fieldName)))) .build() .toString()))) .build()) .build()) .build(); MethodSpec cataMethod = MethodSpec.methodBuilder("cata") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .addTypeVariables( Stream.concat( adt.typeConstructor().typeVariables().stream(), Stream.of(adt.matchMethod().returnTypeVariable())) .map(TypeVariableName::get) .collect(Collectors.toList())) .returns(returnType) .addParameters( constructors .stream() .map( dc -> ParameterSpec.builder( cataMapperTypeName(dc), MapperDerivator.mapperFieldName(dc)) .build()) .collect(toList())) .addStatement("return $L.$L", wrapper, nameAllocator.get("cata")) .build(); return result(methodSpec(cataMethod)); }