YANGTOOLS-706: reorganize statement definitions
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / type / AbstractTypeStatementSupport.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies, 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.yangtools.yang.parser.rfc7950.stmt.type;
9
10 import com.google.common.base.Verify;
11 import com.google.common.collect.ImmutableMap;
12 import java.util.Collection;
13 import java.util.Map;
14 import org.opendaylight.yangtools.yang.common.QName;
15 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
16 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
17 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
18 import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
19 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement;
20 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
21 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement;
22 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
23 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
28 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
29 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
30 import org.opendaylight.yangtools.yang.model.api.type.Int16TypeDefinition;
31 import org.opendaylight.yangtools.yang.model.api.type.Int32TypeDefinition;
32 import org.opendaylight.yangtools.yang.model.api.type.Int64TypeDefinition;
33 import org.opendaylight.yangtools.yang.model.api.type.Int8TypeDefinition;
34 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
35 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
36 import org.opendaylight.yangtools.yang.model.api.type.Uint16TypeDefinition;
37 import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition;
38 import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
39 import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
40 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
41 import org.opendaylight.yangtools.yang.model.util.type.RestrictedTypes;
42 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.typedef.TypedefEffectiveStatementImpl;
43 import org.opendaylight.yangtools.yang.parser.spi.TypeNamespace;
44 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
45 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
46 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
47 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceAction;
48 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceContext;
49 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.Prerequisite;
50 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
51 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
52 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
53 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
54 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
55 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
56 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
57 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.TypeUtils;
58
59 abstract class AbstractTypeStatementSupport
60         extends AbstractStatementSupport<String, TypeStatement, EffectiveStatement<String, TypeStatement>> {
61     private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(
62         YangStmtMapping.TYPE)
63         .addOptional(YangStmtMapping.BASE)
64         .addAny(YangStmtMapping.BIT)
65         .addAny(YangStmtMapping.ENUM)
66         .addOptional(YangStmtMapping.FRACTION_DIGITS)
67         .addOptional(YangStmtMapping.LENGTH)
68         .addOptional(YangStmtMapping.PATH)
69         .addAny(YangStmtMapping.PATTERN)
70         .addOptional(YangStmtMapping.RANGE)
71         .addOptional(YangStmtMapping.REQUIRE_INSTANCE)
72         .addAny(YangStmtMapping.TYPE)
73         .build();
74
75     private static final Map<String, StatementSupport<?, ?, ?>> ARGUMENT_SPECIFIC_SUPPORTS =
76             ImmutableMap.<String, StatementSupport<?, ?, ?>>builder()
77             .put(TypeUtils.BITS, new BitsSpecificationSupport())
78             .put(TypeUtils.DECIMAL64, new Decimal64SpecificationSupport())
79             .put(TypeUtils.ENUMERATION, new EnumSpecificationSupport())
80             .put(TypeUtils.IDENTITY_REF, new IdentityRefSpecificationRFC6020Support())
81             .put(TypeUtils.INSTANCE_IDENTIFIER, new InstanceIdentifierSpecificationSupport())
82             .put(TypeUtils.LEAF_REF, new LeafrefSpecificationRFC6020Support())
83             .put(TypeUtils.UNION, new UnionSpecificationSupport())
84             .build();
85
86     AbstractTypeStatementSupport() {
87         super(YangStmtMapping.TYPE);
88     }
89
90     @Override
91     public final String parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
92         return value;
93     }
94
95     @Override
96     public final TypeStatement createDeclared(final StmtContext<String, TypeStatement, ?> ctx) {
97         return BuiltinTypeStatement.maybeReplace(new TypeStatementImpl(ctx));
98     }
99
100     @Override
101     public final TypeEffectiveStatement<TypeStatement> createEffective(
102             final StmtContext<String, TypeStatement, EffectiveStatement<String, TypeStatement>> ctx) {
103
104         // First look up the proper base type
105         final TypeEffectiveStatement<TypeStatement> typeStmt;
106         switch (ctx.getStatementArgument()) {
107             case TypeUtils.BINARY:
108                 typeStmt = BuiltinEffectiveStatement.BINARY;
109                 break;
110             case TypeUtils.BOOLEAN:
111                 typeStmt = BuiltinEffectiveStatement.BOOLEAN;
112                 break;
113             case TypeUtils.EMPTY:
114                 typeStmt = BuiltinEffectiveStatement.EMPTY;
115                 break;
116             case TypeUtils.INSTANCE_IDENTIFIER:
117                 typeStmt = BuiltinEffectiveStatement.INSTANCE_IDENTIFIER;
118                 break;
119             case TypeUtils.INT8:
120                 typeStmt = BuiltinEffectiveStatement.INT8;
121                 break;
122             case TypeUtils.INT16:
123                 typeStmt = BuiltinEffectiveStatement.INT16;
124                 break;
125             case TypeUtils.INT32:
126                 typeStmt = BuiltinEffectiveStatement.INT32;
127                 break;
128             case TypeUtils.INT64:
129                 typeStmt = BuiltinEffectiveStatement.INT64;
130                 break;
131             case TypeUtils.STRING:
132                 typeStmt = BuiltinEffectiveStatement.STRING;
133                 break;
134             case TypeUtils.UINT8:
135                 typeStmt = BuiltinEffectiveStatement.UINT8;
136                 break;
137             case TypeUtils.UINT16:
138                 typeStmt = BuiltinEffectiveStatement.UINT16;
139                 break;
140             case TypeUtils.UINT32:
141                 typeStmt = BuiltinEffectiveStatement.UINT32;
142                 break;
143             case TypeUtils.UINT64:
144                 typeStmt = BuiltinEffectiveStatement.UINT64;
145                 break;
146             default:
147                 final QName qname = StmtContextUtils.qnameFromArgument(ctx, ctx.getStatementArgument());
148                 final StmtContext<?, TypedefStatement, TypedefEffectiveStatement> typedef =
149                         SourceException.throwIfNull(ctx.getFromNamespace(TypeNamespace.class, qname),
150                             ctx.getStatementSourceReference(), "Type '%s' not found", qname);
151
152                 final TypedefEffectiveStatement effectiveTypedef = typedef.buildEffective();
153                 Verify.verify(effectiveTypedef instanceof TypedefEffectiveStatementImpl);
154                 typeStmt = ((TypedefEffectiveStatementImpl) effectiveTypedef).asTypeEffectiveStatement();
155         }
156
157         if (ctx.declaredSubstatements().isEmpty() && ctx.effectiveSubstatements().isEmpty()) {
158             return typeStmt;
159         }
160
161         // Now instantiate the proper effective statement for that type
162         final TypeDefinition<?> baseType = typeStmt.getTypeDefinition();
163         if (baseType instanceof BinaryTypeDefinition) {
164             return new BinaryTypeEffectiveStatementImpl(ctx, (BinaryTypeDefinition) baseType);
165         } else if (baseType instanceof BitsTypeDefinition) {
166             return new BitsTypeEffectiveStatementImpl(ctx, (BitsTypeDefinition) baseType);
167         } else if (baseType instanceof BooleanTypeDefinition) {
168             return new BooleanTypeEffectiveStatementImpl(ctx, (BooleanTypeDefinition) baseType);
169         } else if (baseType instanceof DecimalTypeDefinition) {
170             return new DecimalTypeEffectiveStatementImpl(ctx, (DecimalTypeDefinition) baseType);
171         } else if (baseType instanceof EmptyTypeDefinition) {
172             return new EmptyTypeEffectiveStatementImpl(ctx, (EmptyTypeDefinition) baseType);
173         } else if (baseType instanceof EnumTypeDefinition) {
174             return new EnumTypeEffectiveStatementImpl(ctx, (EnumTypeDefinition) baseType);
175         } else if (baseType instanceof IdentityrefTypeDefinition) {
176             return new IdentityrefTypeEffectiveStatementImpl(ctx, (IdentityrefTypeDefinition) baseType);
177         } else if (baseType instanceof InstanceIdentifierTypeDefinition) {
178             return new InstanceIdentifierTypeEffectiveStatementImpl(ctx,
179                 (InstanceIdentifierTypeDefinition) baseType);
180         } else if (baseType instanceof Int8TypeDefinition) {
181             return new IntegralTypeEffectiveStatementImpl<>(ctx,
182                     RestrictedTypes.newInt8Builder((Int8TypeDefinition) baseType,
183                         TypeUtils.typeEffectiveSchemaPath(ctx)));
184         } else if (baseType instanceof Int16TypeDefinition) {
185             return new IntegralTypeEffectiveStatementImpl<>(ctx,
186                     RestrictedTypes.newInt16Builder((Int16TypeDefinition) baseType,
187                         TypeUtils.typeEffectiveSchemaPath(ctx)));
188         } else if (baseType instanceof Int32TypeDefinition) {
189             return new IntegralTypeEffectiveStatementImpl<>(ctx,
190                     RestrictedTypes.newInt32Builder((Int32TypeDefinition) baseType,
191                         TypeUtils.typeEffectiveSchemaPath(ctx)));
192         } else if (baseType instanceof Int64TypeDefinition) {
193             return new IntegralTypeEffectiveStatementImpl<>(ctx,
194                     RestrictedTypes.newInt64Builder((Int64TypeDefinition) baseType,
195                         TypeUtils.typeEffectiveSchemaPath(ctx)));
196         } else if (baseType instanceof LeafrefTypeDefinition) {
197             return new LeafrefTypeEffectiveStatementImpl(ctx, (LeafrefTypeDefinition) baseType);
198         } else if (baseType instanceof StringTypeDefinition) {
199             return new StringTypeEffectiveStatementImpl(ctx, (StringTypeDefinition) baseType);
200         } else if (baseType instanceof Uint8TypeDefinition) {
201             return new IntegralTypeEffectiveStatementImpl<>(ctx,
202                     RestrictedTypes.newUint8Builder((Uint8TypeDefinition) baseType,
203                         TypeUtils.typeEffectiveSchemaPath(ctx)));
204         } else if (baseType instanceof Uint16TypeDefinition) {
205             return new IntegralTypeEffectiveStatementImpl<>(ctx,
206                     RestrictedTypes.newUint16Builder((Uint16TypeDefinition) baseType,
207                         TypeUtils.typeEffectiveSchemaPath(ctx)));
208         } else if (baseType instanceof Uint32TypeDefinition) {
209             return new IntegralTypeEffectiveStatementImpl<>(ctx,
210                     RestrictedTypes.newUint32Builder((Uint32TypeDefinition) baseType,
211                         TypeUtils.typeEffectiveSchemaPath(ctx)));
212         } else if (baseType instanceof Uint64TypeDefinition) {
213             return new IntegralTypeEffectiveStatementImpl<>(ctx,
214                     RestrictedTypes.newUint64Builder((Uint64TypeDefinition) baseType,
215                         TypeUtils.typeEffectiveSchemaPath(ctx)));
216         } else if (baseType instanceof UnionTypeDefinition) {
217             return new UnionTypeEffectiveStatementImpl(ctx, (UnionTypeDefinition) baseType);
218         } else {
219             throw new IllegalStateException("Unhandled base type " + baseType);
220         }
221     }
222
223     @Override
224     public final void onFullDefinitionDeclared(
225             final Mutable<String, TypeStatement, EffectiveStatement<String, TypeStatement>> stmt) {
226         super.onFullDefinitionDeclared(stmt);
227
228         // if it is yang built-in type, no prerequisite is needed, so simply return
229         if (TypeUtils.isYangBuiltInTypeString(stmt.getStatementArgument())) {
230             return;
231         }
232
233         final QName typeQName = StmtContextUtils.qnameFromArgument(stmt, stmt.getStatementArgument());
234         final ModelActionBuilder typeAction = stmt.newInferenceAction(ModelProcessingPhase.EFFECTIVE_MODEL);
235         final Prerequisite<StmtContext<?, ?, ?>> typePrereq = typeAction.requiresCtx(stmt, TypeNamespace.class,
236                 typeQName, ModelProcessingPhase.EFFECTIVE_MODEL);
237         typeAction.mutatesEffectiveCtx(stmt.getParentContext());
238
239         /*
240          * If the type does not exist, throw new InferenceException.
241          * Otherwise perform no operation.
242          */
243         typeAction.apply(new InferenceAction() {
244             @Override
245             public void apply(final InferenceContext ctx) {
246                 // Intentional NOOP
247             }
248
249             @Override
250             public void prerequisiteFailed(final Collection<? extends Prerequisite<?>> failed) {
251                 InferenceException.throwIf(failed.contains(typePrereq), stmt.getStatementSourceReference(),
252                     "Type [%s] was not found.", typeQName);
253             }
254         });
255     }
256
257     @Override
258     protected final SubstatementValidator getSubstatementValidator() {
259         return SUBSTATEMENT_VALIDATOR;
260     }
261
262     @Override
263     public final String internArgument(final String rawArgument) {
264         final String found = TypeUtils.findBuiltinString(rawArgument);
265         return found != null ? found : rawArgument;
266     }
267
268     @Override
269     public boolean hasArgumentSpecificSupports() {
270         return !ARGUMENT_SPECIFIC_SUPPORTS.isEmpty();
271     }
272
273     @Override
274     public StatementSupport<?, ?, ?> getSupportSpecificForArgument(final String argument) {
275         return ARGUMENT_SPECIFIC_SUPPORTS.get(argument);
276     }
277 }