return inProgressPhase;
}
- StatementContextBase<?, ?, ?> createDeclaredChild(final StatementContextBase<?, ?, ?> current, final int childId,
- final QName name, final String argument, final StatementSourceReference ref) {
- if (current != null) {
- // Fast path: we are entering a statement which was emitted in previous phase
- StatementContextBase<?, ?, ?> existing = current.lookupSubstatement(childId);
- while (existing != null && StatementSource.CONTEXT == existing.getStatementSource()) {
- existing = existing.lookupSubstatement(childId);
- }
- if (existing != null) {
- return existing;
- }
+ Optional<StatementContextBase<?, ?, ?>> lookupDeclaredChild(final StatementContextBase<?, ?, ?> current,
+ final int childId) {
+ if (current == null) {
+ return Optional.empty();
}
+ // Fast path: we are entering a statement which was emitted in previous phase
+ StatementContextBase<?, ?, ?> existing = current.lookupSubstatement(childId);
+ while (existing != null && StatementSource.CONTEXT == existing.getStatementSource()) {
+ existing = existing.lookupSubstatement(childId);
+ }
+
+ return Optional.ofNullable(existing);
+ }
+
+ StatementContextBase<?, ?, ?> createDeclaredChild(final StatementContextBase<?, ?, ?> current, final int childId,
+ final QName name, final String argument, final StatementSourceReference ref) {
StatementDefinitionContext<?, ?, ?> def = currentContext.getStatementDefinition(getRootVersion(), name);
if (def == null) {
def = currentContext.getModelDefinedStatementDefinition(name);
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.util.OptionalBoolean;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.parser.spi.source.ImplicitSubstatement;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter.ResumedStatement;
import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace;
import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace.SupportedFeatures;
import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.KeyedValueAddedListener;
import org.slf4j.LoggerFactory;
public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
- extends NamespaceStorageSupport implements Mutable<A, D, E> {
+ extends NamespaceStorageSupport implements Mutable<A, D, E>, ResumedStatement {
/**
* Event listener when an item is added to model namespace.
*/
// BooleanFields value
private byte supportedByFeatures;
+ private boolean fullyDefined;
+
StatementContextBase(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
final String rawArgument) {
this.definition = Preconditions.checkNotNull(def);
return substatements.get(offset);
}
+ final void setFullyDefined() {
+ this.fullyDefined = true;
+ }
+
+ final void walkChildren(final ModelProcessingPhase phase) {
+ Preconditions.checkState(fullyDefined);
+ substatements.values().forEach(stmt -> {
+ stmt.walkChildren(phase);
+ stmt.endDeclared(phase);
+ });
+ }
+
@Override
public D buildDeclared() {
Preconditions.checkArgument(completedPhase == ModelProcessingPhase.FULL_DECLARATION
/**
* Ends declared section of current node.
*/
- void endDeclared(final StatementSourceReference ref, final ModelProcessingPhase phase) {
+ void endDeclared(final ModelProcessingPhase phase) {
definition().onDeclarationFinished(this, phase);
}
return copy;
}
+
+ @Override
+ public @NonNull StatementDefinition getDefinition() {
+ return getPublicDefinition();
+ }
+
+ @Override
+ public @NonNull StatementSourceReference getSourceReference() {
+ return getStatementSourceReference();
+ }
+
+ @Override
+ public boolean isFullyDefined() {
+ return fullyDefined;
+ }
+
final void copyTo(final StatementContextBase<?, ?, ?> target, final CopyType typeOfCopy,
@Nullable final QNameModule targetModule) {
final Collection<Mutable<?, ?, ?>> buffer = new ArrayList<>(substatements.size() + effective.size());
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
+import java.util.Optional;
import javax.annotation.Nonnull;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
this.phase = Preconditions.checkNotNull(phase);
}
+ @Override
+ public Optional<? extends ResumedStatement> resumeStatement(final int childId) {
+ final Optional<StatementContextBase<?, ?, ?>> existing = ctx.lookupDeclaredChild(current, childId);
+ existing.ifPresent(this::resumeStatement);
+ return existing;
+ }
+
+ private void resumeStatement(final StatementContextBase<?, ?, ?> child) {
+ if (child.isFullyDefined()) {
+ child.walkChildren(phase);
+ child.endDeclared(phase);
+ } else {
+ current = child;
+ }
+ }
+
+ @Override
+ public void storeStatement(final int expectedChildren, final boolean fullyDefined) {
+ Preconditions.checkState(current != null);
+ Preconditions.checkArgument(expectedChildren >= 0);
+
+ if (fullyDefined) {
+ current.setFullyDefined();
+ }
+ }
+
@Override
public void startStatement(final int childId, @Nonnull final QName name, final String argument,
@Nonnull final StatementSourceReference ref) {
- current = Verify.verifyNotNull(ctx.createDeclaredChild(current, childId, name, argument, ref));
+ final Optional<StatementContextBase<?, ?, ?>> existing = ctx.lookupDeclaredChild(current, childId);
+ current = existing.isPresent() ? existing.get()
+ : Verify.verifyNotNull(ctx.createDeclaredChild(current, childId, name, argument, ref));
}
@Override
public void endStatement(@Nonnull final StatementSourceReference ref) {
Preconditions.checkState(current != null);
- current.endDeclared(ref, phase);
- StatementContextBase<?, ?, ?> parentContext = current.getParentContext();
- while (parentContext != null && StatementSource.CONTEXT == parentContext.getStatementSource()) {
- parentContext.endDeclared(ref, phase);
- parentContext = parentContext.getParentContext();
- }
- current = parentContext;
+ current.endDeclared(phase);
+ exitStatement();
}
@Nonnull
public ModelProcessingPhase getPhase() {
return phase;
}
+
+ private void exitStatement() {
+ StatementContextBase<?, ?, ?> parentContext = current.getParentContext();
+ while (parentContext != null && StatementSource.CONTEXT == parentContext.getStatementSource()) {
+ parentContext.endDeclared(phase);
+ parentContext = parentContext.getParentContext();
+ }
+ current = parentContext;
+ }
}
import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;
+import java.util.Optional;
import org.antlr.v4.runtime.tree.ParseTree;
import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.ArgumentContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.KeywordContext;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter.ResumedStatement;
class StatementContextVisitor {
private final QNameToStatementDefinition stmtDef;
return stmtDef.get(QName.create(module, localName));
}
- private void processStatement(final int myOffset, final StatementContext ctx) {
- final String keywordTxt = verifyNotNull(ctx.getChild(KeywordContext.class, 0)).getText();
- final StatementSourceReference ref = DeclarationInTextSource.atPosition(sourceName, ctx.getStart().getLine(),
- ctx.getStart().getCharPositionInLine());
- final QName def = getValidStatementDefinition(keywordTxt, ref);
- if (def == null) {
- return;
- }
+ private boolean processStatement(final int myOffset, final StatementContext ctx) {
+ final Optional<? extends ResumedStatement> optResumed = writer.resumeStatement(myOffset);
+ final StatementSourceReference ref;
+ if (optResumed.isPresent()) {
+ final ResumedStatement resumed = optResumed.get();
+ if (resumed.isFullyDefined()) {
+ return true;
+ }
- final ArgumentContext argumentCtx = ctx.getChild(ArgumentContext.class, 0);
- final String argument = argumentCtx == null ? null
- : ArgumentContextUtils.stringFromStringContext(argumentCtx, yangVersion, ref);
- writer.startStatement(myOffset, def, argument, ref);
+ ref = resumed.getSourceReference();
+ } else {
+ final String keywordTxt = verifyNotNull(ctx.getChild(KeywordContext.class, 0)).getText();
+ ref = DeclarationInTextSource.atPosition(sourceName, ctx.getStart().getLine(),
+ ctx.getStart().getCharPositionInLine());
+ final QName def = getValidStatementDefinition(keywordTxt, ref);
+ if (def == null) {
+ return false;
+ }
+
+ final ArgumentContext argumentCtx = ctx.getChild(ArgumentContext.class, 0);
+ final String argument = argumentCtx == null ? null
+ : ArgumentContextUtils.stringFromStringContext(argumentCtx, yangVersion, ref);
+ writer.startStatement(myOffset, def, argument, ref);
+ }
+ int childOffset = 0;
+ boolean fullyDefined = true;
if (ctx.children != null) {
- int childOffset = 0;
for (ParseTree s : ctx.children) {
if (s instanceof StatementContext) {
- processStatement(childOffset++, (StatementContext) s);
+ if (!processStatement(childOffset++, (StatementContext) s)) {
+ fullyDefined = false;
+ }
}
}
}
+ writer.storeStatement(childOffset, fullyDefined);
writer.endStatement(ref);
+ return fullyDefined;
}
}
*/
package org.opendaylight.yangtools.yang.parser.spi.source;
+import com.google.common.annotations.Beta;
+import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
public interface StatementWriter {
+ /**
+ * Resumed statement state.
+ *
+ * @author Robert Varga
+ */
+ @Beta
+ @NonNullByDefault
+ interface ResumedStatement {
+ /**
+ * Return statement definition.
+ *
+ * @return statement definition.
+ */
+ StatementDefinition getDefinition();
+
+ /**
+ * Return statement source reference.
+ *
+ * @return statement source reference.
+ */
+ StatementSourceReference getSourceReference();
+
+ /**
+ * Check if the statement has been fully defined. This implies that all its children have been fully defined.
+ *
+ * @return True if the statement has been fully defined.
+ */
+ boolean isFullyDefined();
+ }
+
+ /**
+ * Attempt to resume a child statement. If the statement has been previously defined, a {@link ResumedStatement}
+ * instance is returned.
+ *
+ * <p>
+ * If an empty optional is returned, the caller is expected to follow-up with
+ * {@link #startStatement(int, QName, String, StatementSourceReference)} to define the statement.
+ *
+ * <p>
+ * If the returned resumed statement indicates {@link ResumedStatement#isFullyDefined()}, the caller should take
+ * no further action with this or any of the child statements. Otherwise this call is equivalent of issuing
+ * {@link #startStatement(int, QName, String, StatementSourceReference)} and the caller is expected to process
+ * any child statements. The caller should call {@link #storeStatement(int, boolean)} before finishing processing
+ * with {@link #endStatement(StatementSourceReference)}.
+ *
+ * @param childId Child
+ * @return A resumed statement or empty if the statement has not previously been defined.
+ */
+ @Beta
+ default Optional<? extends ResumedStatement> resumeStatement(final int childId) {
+ return Optional.empty();
+ }
+
+ /**
+ * Store a defined statement, hinting at the number of children it is expected to have and indicating whether
+ * it has been fully defined. This method should be called before {@link #endStatement(StatementSourceReference)}
+ * when the caller is taking advantage of {@link #resumeStatement(int)}.
+ *
+ * @param expectedChildren Number of expected children, cannot be negative
+ * @param fullyDefined True if the statement and all its descendants have been defined.
+ */
+ @Beta
+ default void storeStatement(final int expectedChildren, final boolean fullyDefined) {
+ // No-op
+ }
+
/**
* Starts statement with supplied name and location in source.
*
* If statement has substatements, in order to start substatement, call to
* {@link #startStatement(int, QName, String, StatementSourceReference)} needs to be done for substatement.
*
- * @param childId
- * Child identifier, unique among siblings
- * @param name
- * Fully qualified name of statement.
- * @param argument
- * String representation of value as appeared in source, null if not present
- * @param ref
- * Identifier of location in source, which will be used for
- * reporting in case of statement processing error.
- * @throws SourceException
- * if statement is not valid according to current context.
+ * @param childId Child identifier, unique among siblings
+ * @param name Fully qualified name of statement.
+ * @param argument String representation of value as appeared in source, null if not present
+ * @param ref Identifier of location in source, which will be used for reporting in case of statement processing
+ * error.
+ * @throws SourceException if statement is not valid according to current context.
*/
void startStatement(int childId, @Nonnull QName name, @Nullable String argument,
@Nonnull StatementSourceReference ref);
/**
* Ends current opened statement.
*
- * @param ref
- * Identifier of location in source, which will be used for
- * reporting in case of statement processing error.
- * @throws SourceException
- * if closed statement is not valid in current context, or there
- * is no such statement
+ * @param ref Identifier of location in source, which will be used for reporting in case of statement processing
+ * error.
+ * @throws SourceException if closed statement is not valid in current context, or there is no such statement
*/
void endStatement(@Nonnull StatementSourceReference ref);