aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/zwobble/couscous/transforms/SplitStaticsFromInterface.java
blob: f8623fc24d40077eb36c371330f7c33705bb510a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package org.zwobble.couscous.transforms;

import com.google.common.collect.Iterables;
import org.zwobble.couscous.ast.*;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
import org.zwobble.couscous.types.ScalarType;

import java.util.*;

import static org.zwobble.couscous.util.ExtraLists.eagerFilter;
import static org.zwobble.couscous.util.ExtraLists.list;
import static org.zwobble.couscous.util.ExtraSets.set;

public class SplitStaticsFromInterface {
    public static List<TypeNode> transform(List<TypeNode> typeNodes) {
        List<TypeNode> result = new ArrayList<>();
        Set<ScalarType> splitInterfaces = new HashSet<>();

        for (TypeNode typeNode : typeNodes) {
            if (isSplittable(typeNode)) {
                splitInterfaces.add(typeNode.getName());
                InterfaceNode interfaceNode = (InterfaceNode) typeNode;
                result.add(ClassNode.declareClass(
                    staticTypeFor(interfaceNode.getName()),
                    list(),
                    set(),
                    interfaceNode.getFields(),
                    interfaceNode.getStaticConstructor(),
                    ConstructorNode.DEFAULT,
                    eagerFilter(interfaceNode.getMethods(), method -> method.isStatic()),
                    list()
                ));
                result.add(InterfaceNode.declareInterface(
                    interfaceNode.getName(),
                    interfaceNode.getTypeParameters(),
                    interfaceNode.getSuperTypes(),
                    list(),
                    list(),
                    eagerFilter(interfaceNode.getMethods(), method -> !method.isStatic()),
                    interfaceNode.getInnerTypes()
                ));
            } else {
                result.add(typeNode);
            }
        }

        NodeTransformer transformer = NodeTransformer.builder()
            .transformReceiver((Receiver receiver) -> {
                if (receiver instanceof StaticReceiver && splitInterfaces.contains(((StaticReceiver) receiver).getType())) {
                    return StaticReceiver.staticReceiver(staticTypeFor(((StaticReceiver) receiver).getType()));
                } else {
                    return receiver;
                }
            })
            .build();
        return NodeTransformer.apply(transformer, result);
    }

    private static ScalarType staticTypeFor(ScalarType name) {
        return ScalarType.topLevel(name.getQualifiedName() + "_static");
    }

    private static boolean isSplittable(TypeNode typeNode) {
        if (!(typeNode instanceof InterfaceNode)) {
            return false;
        }
        InterfaceNode interfaceNode = (InterfaceNode) typeNode;
        return !interfaceNode.getFields().isEmpty() || Iterables.any(interfaceNode.getMethods(), MethodNode::isStatic);
    }
}