Adjust test suite parser update to conform with API changes
[yangtools.git] / yang / yang-parser-rfc7950 / 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.Preconditions;
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.SchemaPath;
16 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
17 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
18 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
19 import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
20 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement;
21 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
22 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement;
23 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
28 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
29 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
30 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
31 import org.opendaylight.yangtools.yang.model.api.type.Int16TypeDefinition;
32 import org.opendaylight.yangtools.yang.model.api.type.Int32TypeDefinition;
33 import org.opendaylight.yangtools.yang.model.api.type.Int64TypeDefinition;
34 import org.opendaylight.yangtools.yang.model.api.type.Int8TypeDefinition;
35 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
36 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
37 import org.opendaylight.yangtools.yang.model.api.type.Uint16TypeDefinition;
38 import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition;
39 import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
40 import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
41 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
42 import org.opendaylight.yangtools.yang.model.util.type.RestrictedTypes;
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.QNameCacheNamespace;
52 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
53 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
54 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
55 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
56 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
57 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
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     static final String BINARY = "binary";
76     static final String BITS = "bits";
77     static final String BOOLEAN = "boolean";
78     static final String DECIMAL64 = "decimal64";
79     static final String EMPTY = "empty";
80     static final String ENUMERATION = "enumeration";
81     static final String IDENTITY_REF = "identityref";
82     static final String INSTANCE_IDENTIFIER = "instance-identifier";
83     static final String INT8 = "int8";
84     static final String INT16 = "int16";
85     static final String INT32 = "int32";
86     static final String INT64 = "int64";
87     static final String LEAF_REF = "leafref";
88     static final String STRING = "string";
89     static final String UINT8 = "uint8";
90     static final String UINT16 = "uint16";
91     static final String UINT32 = "uint32";
92     static final String UINT64 = "uint64";
93     static final String UNION = "union";
94
95     private static final Map<String, String> BUILT_IN_TYPES = ImmutableMap.<String, String>builder()
96         .put(BINARY, BINARY)
97         .put(BITS, BITS)
98         .put(BOOLEAN, BOOLEAN)
99         .put(DECIMAL64, DECIMAL64)
100         .put(EMPTY, EMPTY)
101         .put(ENUMERATION, ENUMERATION)
102         .put(IDENTITY_REF,IDENTITY_REF)
103         .put(INSTANCE_IDENTIFIER, INSTANCE_IDENTIFIER)
104         .put(INT8, INT8)
105         .put(INT16, INT16)
106         .put(INT32, INT32)
107         .put(INT64, INT64)
108         .put(LEAF_REF, LEAF_REF)
109         .put(STRING, STRING)
110         .put(UINT8, UINT8)
111         .put(UINT16, UINT16)
112         .put(UINT32, UINT32)
113         .put(UINT64, UINT64)
114         .put(UNION, UNION)
115         .build();
116
117     private static final Map<String, StatementSupport<?, ?, ?>> ARGUMENT_SPECIFIC_SUPPORTS =
118             ImmutableMap.<String, StatementSupport<?, ?, ?>>builder()
119             .put(BITS, new BitsSpecificationSupport())
120             .put(DECIMAL64, new Decimal64SpecificationSupport())
121             .put(ENUMERATION, new EnumSpecificationSupport())
122             .put(IDENTITY_REF, new IdentityRefSpecificationRFC6020Support())
123             .put(INSTANCE_IDENTIFIER, new InstanceIdentifierSpecificationSupport())
124             .put(LEAF_REF, new LeafrefSpecificationRFC6020Support())
125             .put(UNION, new UnionSpecificationSupport())
126             .build();
127
128     AbstractTypeStatementSupport() {
129         super(YangStmtMapping.TYPE);
130     }
131
132     @Override
133     public final String parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
134         return value;
135     }
136
137     @Override
138     public final TypeStatement createDeclared(final StmtContext<String, TypeStatement, ?> ctx) {
139         return BuiltinTypeStatement.maybeReplace(new TypeStatementImpl(ctx));
140     }
141
142     @Override
143     public final TypeEffectiveStatement<TypeStatement> createEffective(
144             final StmtContext<String, TypeStatement, EffectiveStatement<String, TypeStatement>> ctx) {
145
146         // First look up the proper base type
147         final TypeEffectiveStatement<TypeStatement> typeStmt;
148         switch (ctx.getStatementArgument()) {
149             case BINARY:
150                 typeStmt = BuiltinEffectiveStatement.BINARY;
151                 break;
152             case BOOLEAN:
153                 typeStmt = BuiltinEffectiveStatement.BOOLEAN;
154                 break;
155             case EMPTY:
156                 typeStmt = BuiltinEffectiveStatement.EMPTY;
157                 break;
158             case INSTANCE_IDENTIFIER:
159                 typeStmt = BuiltinEffectiveStatement.INSTANCE_IDENTIFIER;
160                 break;
161             case INT8:
162                 typeStmt = BuiltinEffectiveStatement.INT8;
163                 break;
164             case INT16:
165                 typeStmt = BuiltinEffectiveStatement.INT16;
166                 break;
167             case INT32:
168                 typeStmt = BuiltinEffectiveStatement.INT32;
169                 break;
170             case INT64:
171                 typeStmt = BuiltinEffectiveStatement.INT64;
172                 break;
173             case STRING:
174                 typeStmt = BuiltinEffectiveStatement.STRING;
175                 break;
176             case UINT8:
177                 typeStmt = BuiltinEffectiveStatement.UINT8;
178                 break;
179             case UINT16:
180                 typeStmt = BuiltinEffectiveStatement.UINT16;
181                 break;
182             case UINT32:
183                 typeStmt = BuiltinEffectiveStatement.UINT32;
184                 break;
185             case UINT64:
186                 typeStmt = BuiltinEffectiveStatement.UINT64;
187                 break;
188             default:
189                 final QName qname = StmtContextUtils.qnameFromArgument(ctx, ctx.getStatementArgument());
190                 final StmtContext<?, TypedefStatement, TypedefEffectiveStatement> typedef =
191                         SourceException.throwIfNull(ctx.getFromNamespace(TypeNamespace.class, qname),
192                             ctx.getStatementSourceReference(), "Type '%s' not found", qname);
193                 typeStmt = typedef.buildEffective().asTypeEffectiveStatement();
194         }
195
196         if (ctx.declaredSubstatements().isEmpty() && ctx.effectiveSubstatements().isEmpty()) {
197             return typeStmt;
198         }
199
200         // Now instantiate the proper effective statement for that type
201         final TypeDefinition<?> baseType = typeStmt.getTypeDefinition();
202         if (baseType instanceof BinaryTypeDefinition) {
203             return new BinaryTypeEffectiveStatementImpl(ctx, (BinaryTypeDefinition) baseType);
204         } else if (baseType instanceof BitsTypeDefinition) {
205             return new BitsTypeEffectiveStatementImpl(ctx, (BitsTypeDefinition) baseType);
206         } else if (baseType instanceof BooleanTypeDefinition) {
207             return new BooleanTypeEffectiveStatementImpl(ctx, (BooleanTypeDefinition) baseType);
208         } else if (baseType instanceof DecimalTypeDefinition) {
209             return new DecimalTypeEffectiveStatementImpl(ctx, (DecimalTypeDefinition) baseType);
210         } else if (baseType instanceof EmptyTypeDefinition) {
211             return new EmptyTypeEffectiveStatementImpl(ctx, (EmptyTypeDefinition) baseType);
212         } else if (baseType instanceof EnumTypeDefinition) {
213             return new EnumTypeEffectiveStatementImpl(ctx, (EnumTypeDefinition) baseType);
214         } else if (baseType instanceof IdentityrefTypeDefinition) {
215             return new IdentityrefTypeEffectiveStatementImpl(ctx, (IdentityrefTypeDefinition) baseType);
216         } else if (baseType instanceof InstanceIdentifierTypeDefinition) {
217             return new InstanceIdentifierTypeEffectiveStatementImpl(ctx,
218                 (InstanceIdentifierTypeDefinition) baseType);
219         } else if (baseType instanceof Int8TypeDefinition) {
220             return new IntegralTypeEffectiveStatementImpl<>(ctx,
221                     RestrictedTypes.newInt8Builder((Int8TypeDefinition) baseType, typeEffectiveSchemaPath(ctx)));
222         } else if (baseType instanceof Int16TypeDefinition) {
223             return new IntegralTypeEffectiveStatementImpl<>(ctx,
224                     RestrictedTypes.newInt16Builder((Int16TypeDefinition) baseType, typeEffectiveSchemaPath(ctx)));
225         } else if (baseType instanceof Int32TypeDefinition) {
226             return new IntegralTypeEffectiveStatementImpl<>(ctx,
227                     RestrictedTypes.newInt32Builder((Int32TypeDefinition) baseType, typeEffectiveSchemaPath(ctx)));
228         } else if (baseType instanceof Int64TypeDefinition) {
229             return new IntegralTypeEffectiveStatementImpl<>(ctx,
230                     RestrictedTypes.newInt64Builder((Int64TypeDefinition) baseType, typeEffectiveSchemaPath(ctx)));
231         } else if (baseType instanceof LeafrefTypeDefinition) {
232             return new LeafrefTypeEffectiveStatementImpl(ctx, (LeafrefTypeDefinition) baseType);
233         } else if (baseType instanceof StringTypeDefinition) {
234             return new StringTypeEffectiveStatementImpl(ctx, (StringTypeDefinition) baseType);
235         } else if (baseType instanceof Uint8TypeDefinition) {
236             return new IntegralTypeEffectiveStatementImpl<>(ctx,
237                     RestrictedTypes.newUint8Builder((Uint8TypeDefinition) baseType, typeEffectiveSchemaPath(ctx)));
238         } else if (baseType instanceof Uint16TypeDefinition) {
239             return new IntegralTypeEffectiveStatementImpl<>(ctx,
240                     RestrictedTypes.newUint16Builder((Uint16TypeDefinition) baseType, typeEffectiveSchemaPath(ctx)));
241         } else if (baseType instanceof Uint32TypeDefinition) {
242             return new IntegralTypeEffectiveStatementImpl<>(ctx,
243                     RestrictedTypes.newUint32Builder((Uint32TypeDefinition) baseType, typeEffectiveSchemaPath(ctx)));
244         } else if (baseType instanceof Uint64TypeDefinition) {
245             return new IntegralTypeEffectiveStatementImpl<>(ctx,
246                     RestrictedTypes.newUint64Builder((Uint64TypeDefinition) baseType, typeEffectiveSchemaPath(ctx)));
247         } else if (baseType instanceof UnionTypeDefinition) {
248             return new UnionTypeEffectiveStatementImpl(ctx, (UnionTypeDefinition) baseType);
249         } else {
250             throw new IllegalStateException("Unhandled base type " + baseType);
251         }
252     }
253
254     @Override
255     public final void onFullDefinitionDeclared(
256             final Mutable<String, TypeStatement, EffectiveStatement<String, TypeStatement>> stmt) {
257         super.onFullDefinitionDeclared(stmt);
258
259         // if it is yang built-in type, no prerequisite is needed, so simply return
260         if (BUILT_IN_TYPES.containsKey(stmt.getStatementArgument())) {
261             return;
262         }
263
264         final QName typeQName = StmtContextUtils.qnameFromArgument(stmt, stmt.getStatementArgument());
265         final ModelActionBuilder typeAction = stmt.newInferenceAction(ModelProcessingPhase.EFFECTIVE_MODEL);
266         final Prerequisite<StmtContext<?, ?, ?>> typePrereq = typeAction.requiresCtx(stmt, TypeNamespace.class,
267                 typeQName, ModelProcessingPhase.EFFECTIVE_MODEL);
268         typeAction.mutatesEffectiveCtx(stmt.getParentContext());
269
270         /*
271          * If the type does not exist, throw new InferenceException.
272          * Otherwise perform no operation.
273          */
274         typeAction.apply(new InferenceAction() {
275             @Override
276             public void apply(final InferenceContext ctx) {
277                 // Intentional NOOP
278             }
279
280             @Override
281             public void prerequisiteFailed(final Collection<? extends Prerequisite<?>> failed) {
282                 InferenceException.throwIf(failed.contains(typePrereq), stmt.getStatementSourceReference(),
283                     "Type [%s] was not found.", typeQName);
284             }
285         });
286     }
287
288     @Override
289     protected final SubstatementValidator getSubstatementValidator() {
290         return SUBSTATEMENT_VALIDATOR;
291     }
292
293     @Override
294     public final String internArgument(final String rawArgument) {
295         final String found = BUILT_IN_TYPES.get(rawArgument);
296         return found != null ? found : rawArgument;
297     }
298
299     @Override
300     public boolean hasArgumentSpecificSupports() {
301         return !ARGUMENT_SPECIFIC_SUPPORTS.isEmpty();
302     }
303
304     @Override
305     public StatementSupport<?, ?, ?> getSupportSpecificForArgument(final String argument) {
306         return ARGUMENT_SPECIFIC_SUPPORTS.get(argument);
307     }
308
309     static final SchemaPath typeEffectiveSchemaPath(final StmtContext<?, ?, ?> stmtCtx) {
310         final SchemaPath path = stmtCtx.getSchemaPath().get();
311         final SchemaPath parent = path.getParent();
312         final QName parentQName = parent.getLastComponent();
313         Preconditions.checkArgument(parentQName != null, "Path %s has an empty parent", path);
314
315         final QName qname = stmtCtx.getFromNamespace(QNameCacheNamespace.class,
316             QName.create(parentQName, path.getLastComponent().getLocalName()));
317         return parent.createChild(qname);
318     }
319 }