X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-rfc7950%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Frfc7950%2Fstmt%2Ftypedef%2FTypedefStatementSupport.java;h=f929ee3f116f8e1bb7f8869c523f52069acc94c9;hb=a9c6528602b30a65af8aa6afc89e465f202ef129;hp=b9ac420391ab187f35ca71deb59ecb6b8b39255e;hpb=1cc6359e5bae1459582e9262a24ca56f23bcc70f;p=yangtools.git diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/TypedefStatementSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/TypedefStatementSupport.java index b9ac420391..f929ee3f11 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/TypedefStatementSupport.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/TypedefStatementSupport.java @@ -7,20 +7,38 @@ */ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.typedef; +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.collect.ImmutableList; +import java.util.Collection; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.Status; import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; +import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseQNameStatementSupport; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.EffectiveStatementWithFlags.FlagsBuilder; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStmtUtils; import org.opendaylight.yangtools.yang.parser.spi.TypeNamespace; -import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractQNameStatementSupport; +import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current; +import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder; +import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceAction; +import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceContext; +import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.Prerequisite; +import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils; import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator; import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; public final class TypedefStatementSupport extends - AbstractQNameStatementSupport> { + BaseQNameStatementSupport { private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder( YangStmtMapping.TYPEDEF) .addOptional(YangStmtMapping.DEFAULT) @@ -30,39 +48,52 @@ public final class TypedefStatementSupport extends .addMandatory(YangStmtMapping.TYPE) .addOptional(YangStmtMapping.UNITS) .build(); + private static final TypedefStatementSupport INSTANCE = new TypedefStatementSupport(); - public TypedefStatementSupport() { - super(YangStmtMapping.TYPEDEF); - } - - @Override - public QName parseArgumentValue(final StmtContext ctx, final String value) { - return StmtContextUtils.qnameFromArgument(ctx, value); + private TypedefStatementSupport() { + super(YangStmtMapping.TYPEDEF, StatementPolicy.reject()); } - @Override - public TypedefStatement createDeclared(final StmtContext ctx) { - return new TypedefStatementImpl(ctx); + public static TypedefStatementSupport getInstance() { + return INSTANCE; } @Override - public EffectiveStatement createEffective( - final StmtContext> ctx) { - return new TypedefEffectiveStatementImpl(ctx); + public QName parseArgumentValue(final StmtContext ctx, final String value) { + return StmtContextUtils.parseIdentifier(ctx, value); } @Override - public void onFullDefinitionDeclared(final StmtContext.Mutable> stmt) { + public void onFullDefinitionDeclared(final Mutable stmt) { super.onFullDefinitionDeclared(stmt); - if (stmt != null && stmt.getParentContext() != null) { - final StmtContext existing = stmt.getParentContext() - .getFromNamespace(TypeNamespace.class, stmt.getStatementArgument()); - SourceException.throwIf(existing != null, stmt.getStatementSourceReference(), - "Duplicate name for typedef %s", stmt.getStatementArgument()); + final Mutable parent = stmt.getParentContext(); + if (parent != null) { + // Shadowing check: make sure we do not trample on pre-existing definitions. This catches sibling + // declarations and parent declarations which have already been declared. + checkConflict(parent, stmt); + parent.addContext(TypeNamespace.class, stmt.getArgument(), stmt); + + final StmtContext grandParent = parent.getParentContext(); + if (grandParent != null) { + // Shadowing check: make sure grandparent does not see a conflicting definition. This is required to + // ensure that a typedef in child scope does not shadow a typedef in parent scope which occurs later in + // the text. For that check we need the full declaration of our model. + + final ModelActionBuilder action = stmt.newInferenceAction(ModelProcessingPhase.FULL_DECLARATION); + action.requiresCtx(grandParent.getRoot(), ModelProcessingPhase.FULL_DECLARATION); + action.apply(new InferenceAction() { + @Override + public void apply(final InferenceContext ctx) { + checkConflict(grandParent, stmt); + } - stmt.getParentContext().addContext(TypeNamespace.class, stmt.getStatementArgument(), stmt); + @Override + public void prerequisiteFailed(final Collection> failed) { + // No-op + } + }); + } } } @@ -70,4 +101,45 @@ public final class TypedefStatementSupport extends protected SubstatementValidator getSubstatementValidator() { return SUBSTATEMENT_VALIDATOR; } + + @Override + protected TypedefStatement createDeclared(final StmtContext ctx, + final ImmutableList> substatements) { + return new RegularTypedefStatement(ctx.getArgument(), substatements); + } + + @Override + protected TypedefStatement createEmptyDeclared(final StmtContext ctx) { + return new EmptyTypedefStatement(ctx.getArgument()); + } + + @Override + protected TypedefEffectiveStatement createEffective(final Current stmt, + final ImmutableList> substatements) { + final TypedefStatement declared = stmt.declared(); + checkState(!substatements.isEmpty(), "Refusing to create empty typedef for %s", stmt.declared()); + + final TypeEffectiveStatement typeEffectiveStmt = findFirstStatement(substatements, + TypeEffectiveStatement.class); + final String dflt = findFirstArgument(substatements, DefaultEffectiveStatement.class, null); + SourceException.throwIf( + EffectiveStmtUtils.hasDefaultValueMarkedWithIfFeature(stmt.yangVersion(), typeEffectiveStmt, dflt), stmt, + "Typedef '%s' has default value '%s' marked with an if-feature statement.", stmt.argument(), dflt); + + return new TypedefEffectiveStatementImpl(declared, stmt.wrapSchemaPath(), computeFlags(substatements), + substatements); + } + + private static void checkConflict(final StmtContext parent, final StmtContext stmt) { + final QName arg = stmt.getArgument(); + final StmtContext existing = parent.getFromNamespace(TypeNamespace.class, arg); + // RFC7950 sections 5.5 and 6.2.1: identifiers must not be shadowed + SourceException.throwIf(existing != null, stmt, "Duplicate name for typedef %s", arg); + } + + private static int computeFlags(final ImmutableList> substatements) { + return new FlagsBuilder() + .setStatus(findFirstArgument(substatements, StatusEffectiveStatement.class, Status.CURRENT)) + .toFlags(); + } } \ No newline at end of file