6b0e06271ac7ab0fa0b40b3649ecdd03a10912ae
[mdsal.git] / binding / mdsal-binding-generator / src / main / java / org / opendaylight / mdsal / binding / generator / impl / reactor / TypedefGenerator.java
1 /*
2  * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.mdsal.binding.generator.impl.reactor;
9
10 import static com.google.common.base.Verify.verify;
11 import static com.google.common.base.Verify.verifyNotNull;
12 import static java.util.Objects.requireNonNull;
13
14 import java.util.ArrayList;
15 import java.util.List;
16 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultTypedefRuntimeType;
17 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
18 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
19 import org.opendaylight.mdsal.binding.model.api.Type;
20 import org.opendaylight.mdsal.binding.model.api.YangSourceDefinition;
21 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTOBuilder;
22 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
23 import org.opendaylight.mdsal.binding.model.ri.TypeConstants;
24 import org.opendaylight.mdsal.binding.model.ri.Types;
25 import org.opendaylight.mdsal.binding.runtime.api.TypedefRuntimeType;
26 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
28 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
29 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
30
31 /**
32  * Generator corresponding to a {@code typedef} statement.
33  */
34 final class TypedefGenerator extends AbstractTypeObjectGenerator<TypedefEffectiveStatement, TypedefRuntimeType> {
35     /**
36      * List of all generators for types directly derived from this typedef. We populate this list during initial type
37      * linking. It allows us to easily cascade inferences made by this typedef down the type derivation tree.
38      */
39     private List<AbstractTypeObjectGenerator<?, ?>> derivedGenerators = null;
40
41     TypedefGenerator(final TypedefEffectiveStatement statement, final AbstractCompositeGenerator<?, ?> parent) {
42         super(statement, parent);
43     }
44
45     @Override
46     StatementNamespace namespace() {
47         return StatementNamespace.TYPEDEF;
48     }
49
50     @Override
51     void pushToInference(final SchemaInferenceStack dataTree) {
52         dataTree.enterTypedef(statement().argument());
53     }
54
55     void addDerivedGenerator(final AbstractTypeObjectGenerator<?, ?> derivedGenerator) {
56         if (derivedGenerators == null) {
57             derivedGenerators = new ArrayList<>(4);
58         }
59         derivedGenerators.add(requireNonNull(derivedGenerator));
60     }
61
62     @Override
63     void bindDerivedGenerators(final TypeReference reference) {
64         // Trigger any derived resolvers ...
65         if (derivedGenerators != null) {
66             for (AbstractTypeObjectGenerator<?, ?> derived : derivedGenerators) {
67                 derived.bindTypeDefinition(reference);
68             }
69         }
70         // ... and make sure nobody can come in late
71         derivedGenerators = List.of();
72     }
73
74     @Override
75     ClassPlacement classPlacementImpl() {
76         return ClassPlacement.TOP_LEVEL;
77     }
78
79     @Override
80     TypeDefinition<?> extractTypeDefinition() {
81         return statement().getTypeDefinition();
82     }
83
84     @Override
85     GeneratedTransferObject createDerivedType(final TypeBuilderFactory builderFactory,
86             final GeneratedTransferObject baseType) {
87         final GeneratedTOBuilder builder = builderFactory.newGeneratedTOBuilder(typeName());
88         builder.setTypedef(true);
89         builder.setExtendsType(baseType);
90         builder.setIsUnion(baseType.isUnionType());
91         builder.setRestrictions(computeRestrictions());
92         YangSourceDefinition.of(currentModule().statement(), statement()).ifPresent(builder::setYangSourceDefinition);
93
94         final TypeDefinition<?> typedef = statement().getTypeDefinition();
95         annotateDeprecatedIfNecessary(typedef, builder);
96         addStringRegExAsConstant(builder, resolveRegExpressions(typedef));
97         addUnits(builder, typedef);
98
99         if (typedef instanceof BitsTypeDefinition bits) {
100             addValidBits(builder, bits, baseType);
101         }
102
103         makeSerializable(builder);
104         return builder.build();
105     }
106
107     private static void addValidBits(final GeneratedTOBuilder builder, final BitsTypeDefinition typedef,
108             final GeneratedTransferObject baseType) {
109         final var baseDef = verifyNotNull(baseBitsDefinition(baseType), "Could not find definition in %s", baseType);
110         final var myBits = typedef.getBits();
111         if (myBits.size() != baseDef.getBits().size()) {
112             builder.addConstant(Types.immutableSetTypeFor(Types.STRING), TypeConstants.VALID_NAMES_NAME, typedef);
113         }
114     }
115
116     private static BitsTypeDefinition baseBitsDefinition(final GeneratedTransferObject gto) {
117         var wlk = gto;
118         while (wlk != null) {
119             for (var constant : wlk.getConstantDefinitions()) {
120                 if (TypeConstants.VALID_NAMES_NAME.equals(constant.getName())) {
121                     return (BitsTypeDefinition) constant.getValue();
122                 }
123             }
124
125             wlk = wlk.getSuperType();
126         }
127         return null;
128     }
129
130     @Override
131     TypedefRuntimeType createExternalRuntimeType(final Type type) {
132         verify(type instanceof GeneratedType, "Unexpected type %s", type);
133         return new DefaultTypedefRuntimeType((GeneratedType) type, statement());
134     }
135
136     @Override
137     TypedefRuntimeType createInternalRuntimeType(final AugmentResolver resolver,
138             final TypedefEffectiveStatement statement, final Type type) {
139         // 'typedef' statements are not schema tree statements, they should not have internal references
140         throw new UnsupportedOperationException("Should never be called");
141     }
142
143     @Override
144     void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
145         // typedefs are a separate concept
146     }
147 }