c77394bd63be5eef14a56f442d7be9ce8230a213
[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.binding.contract.StatementNamespace;
27 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
28 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
29 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
30 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
31
32 /**
33  * Generator corresponding to a {@code typedef} statement.
34  */
35 final class TypedefGenerator extends AbstractTypeObjectGenerator<TypedefEffectiveStatement, TypedefRuntimeType> {
36     /**
37      * List of all generators for types directly derived from this typedef. We populate this list during initial type
38      * linking. It allows us to easily cascade inferences made by this typedef down the type derivation tree.
39      */
40     private List<AbstractTypeObjectGenerator<?, ?>> derivedGenerators = null;
41
42     TypedefGenerator(final TypedefEffectiveStatement statement, final AbstractCompositeGenerator<?, ?> parent) {
43         super(statement, parent);
44     }
45
46     @Override
47     StatementNamespace namespace() {
48         return StatementNamespace.TYPEDEF;
49     }
50
51     @Override
52     void pushToInference(final SchemaInferenceStack dataTree) {
53         dataTree.enterTypedef(statement().argument());
54     }
55
56     void addDerivedGenerator(final AbstractTypeObjectGenerator<?, ?> derivedGenerator) {
57         if (derivedGenerators == null) {
58             derivedGenerators = new ArrayList<>(4);
59         }
60         derivedGenerators.add(requireNonNull(derivedGenerator));
61     }
62
63     @Override
64     void bindDerivedGenerators(final TypeReference reference) {
65         // Trigger any derived resolvers ...
66         if (derivedGenerators != null) {
67             for (AbstractTypeObjectGenerator<?, ?> derived : derivedGenerators) {
68                 derived.bindTypeDefinition(reference);
69             }
70         }
71         // ... and make sure nobody can come in late
72         derivedGenerators = List.of();
73     }
74
75     @Override
76     ClassPlacement classPlacementImpl() {
77         return ClassPlacement.TOP_LEVEL;
78     }
79
80     @Override
81     TypeDefinition<?> extractTypeDefinition() {
82         return statement().getTypeDefinition();
83     }
84
85     @Override
86     GeneratedTransferObject createDerivedType(final TypeBuilderFactory builderFactory,
87             final GeneratedTransferObject baseType) {
88         final GeneratedTOBuilder builder = builderFactory.newGeneratedTOBuilder(typeName());
89         builder.setTypedef(true);
90         builder.setExtendsType(baseType);
91         builder.setIsUnion(baseType.isUnionType());
92         builder.setRestrictions(computeRestrictions());
93         YangSourceDefinition.of(currentModule().statement(), statement()).ifPresent(builder::setYangSourceDefinition);
94
95         final TypeDefinition<?> typedef = statement().getTypeDefinition();
96         annotateDeprecatedIfNecessary(typedef, builder);
97         addStringRegExAsConstant(builder, resolveRegExpressions(typedef));
98         addUnits(builder, typedef);
99
100         if (typedef instanceof BitsTypeDefinition bits) {
101             addValidBits(builder, bits, baseType);
102         }
103
104         makeSerializable(builder);
105         return builder.build();
106     }
107
108     private static void addValidBits(final GeneratedTOBuilder builder, final BitsTypeDefinition typedef,
109             final GeneratedTransferObject baseType) {
110         final var baseDef = verifyNotNull(baseBitsDefinition(baseType), "Could not find definition in %s", baseType);
111         final var myBits = typedef.getBits();
112         if (myBits.size() != baseDef.getBits().size()) {
113             builder.addConstant(Types.immutableSetTypeFor(Types.STRING), TypeConstants.VALID_NAMES_NAME, typedef);
114         }
115     }
116
117     private static BitsTypeDefinition baseBitsDefinition(final GeneratedTransferObject gto) {
118         var wlk = gto;
119         while (wlk != null) {
120             for (var constant : wlk.getConstantDefinitions()) {
121                 if (TypeConstants.VALID_NAMES_NAME.equals(constant.getName())) {
122                     return (BitsTypeDefinition) constant.getValue();
123                 }
124             }
125
126             wlk = wlk.getSuperType();
127         }
128         return null;
129     }
130
131     @Override
132     TypedefRuntimeType createExternalRuntimeType(final Type type) {
133         verify(type instanceof GeneratedType, "Unexpected type %s", type);
134         return new DefaultTypedefRuntimeType((GeneratedType) type, statement());
135     }
136
137     @Override
138     TypedefRuntimeType createInternalRuntimeType(final AugmentResolver resolver,
139             final TypedefEffectiveStatement statement, final Type type) {
140         // 'typedef' statements are not schema tree statements, they should not have internal references
141         throw new UnsupportedOperationException("Should never be called");
142     }
143
144     @Override
145     void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
146         // typedefs are a separate concept
147     }
148 }