package org.opendaylight.yangtools.yang.parser.impl;
import com.google.common.base.Verify;
+import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Deque;
import java.util.List;
import javax.annotation.concurrent.Immutable;
import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.ArgumentContext;
@Immutable
public class YangStatementParserListenerImpl extends YangStatementParserBaseListener {
+ private static final class Counter {
+ private int value = 0;
+
+ int getAndIncrement() {
+ return value++;
+ }
+ }
+
private final List<String> toBeSkipped = new ArrayList<>();
+ private final Deque<Counter> counters = new ArrayDeque<>();
private final String sourceName;
private QNameToStatementDefinition stmtDef;
private PrefixToModule prefixes;
public void setAttributes(final StatementWriter writer, final QNameToStatementDefinition stmtDef) {
this.writer = writer;
this.stmtDef = stmtDef;
+ initCounters();
}
- public void setAttributes(final StatementWriter writer, final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes) {
+ public void setAttributes(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
+ final PrefixToModule prefixes) {
this.writer = writer;
this.stmtDef = stmtDef;
this.prefixes = prefixes;
+ initCounters();
+ }
+
+ private void initCounters() {
+ counters.clear();
+ counters.push(new Counter());
}
@Override
final QName identifier = QName.create(YangConstants.RFC6020_YIN_MODULE, keywordTxt);
final QName validStatementDefinition = Utils.getValidStatementDefinition(prefixes, stmtDef, identifier);
+ final int childId = counters.peek().getAndIncrement();
+ counters.push(new Counter());
if (stmtDef == null || validStatementDefinition == null || !toBeSkipped.isEmpty()) {
SourceException.throwIf(writer.getPhase() == ModelProcessingPhase.FULL_DECLARATION, ref,
"%s is not a YANG statement or use of extension.", keywordTxt);
final ArgumentContext argumentCtx = ctx.getChild(ArgumentContext.class, 0);
final String argument = argumentCtx != null ? Utils.stringFromStringContext(argumentCtx) : null;
- writer.startStatement(validStatementDefinition, argument, ref);
+ writer.startStatement(childId, validStatementDefinition, argument, ref);
}
@Override
// No-op if the statement is not on the list
toBeSkipped.remove(statementName);
+ counters.pop();
}
}
return def;
}
- private static void processAttribute(final Attr attr, final StatementWriter writer,
+ private static void processAttribute(final int childId, final Attr attr, final StatementWriter writer,
final QNameToStatementDefinition stmtDef, final StatementSourceReference ref) {
final StatementDefinition def = getValidDefinition(attr, writer, stmtDef, ref);
if (def == null) {
}
final String value = attr.getValue();
- writer.startStatement(def.getStatementName(), value.isEmpty() ? null : value, ref);
+ writer.startStatement(childId, def.getStatementName(), value.isEmpty() ? null : value, ref);
writer.endStatement(ref);
}
return attr.getValue();
}
- private static void processElement(final Element element, final StatementWriter writer,
+ private static void processElement(final int childId, final Element element, final StatementWriter writer,
final QNameToStatementDefinition stmtDef) {
final StatementSourceReference ref = extractRef(element);
final StatementDefinition def = getValidDefinition(element, writer, stmtDef, ref);
allElements = false;
}
- writer.startStatement(def.getStatementName(), argValue, ref);
+ writer.startStatement(childId, def.getStatementName(), argValue, ref);
+
+ // Child counter
+ int childCounter = 0;
// First process any statements defined as attributes. We need to skip argument, if present
final NamedNodeMap attributes = element.getAttributes();
for (int i = 0, len = attributes.getLength(); i < len; ++i) {
final Attr attr = (Attr) attributes.item(i);
if (allAttrs || !isArgument(argName, attr)) {
- processAttribute(attr, writer, stmtDef, ref);
+ processAttribute(childCounter++, attr, writer, stmtDef, ref);
}
}
}
final Node child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
if (allElements || !isArgument(argName, child)) {
- processElement((Element) child, writer, stmtDef);
+ processElement(childCounter++, (Element) child, writer, stmtDef);
}
}
}
private void walkTree(final StatementWriter writer, final QNameToStatementDefinition stmtDef) {
final NodeList children = root.getChildNodes();
+
+ int childCounter = 0;
for (int i = 0, len = children.getLength(); i < len; ++i) {
final Node child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
- processElement((Element) child, writer, stmtDef);
+ processElement(childCounter++, (Element) child, writer, stmtDef);
}
}
}
* </p>
* <p>
* If statement has substatements, in order to start substatement, call to
- * {@link #startStatement(QName, String, StatementSourceReference)} needs to be done
+ * {@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
* @throws SourceException
* if statement is not valid according to current context.
*/
- void startStatement(@Nonnull QName name, @Nullable String argument, @Nonnull StatementSourceReference ref);
+ void startStatement(final int childId, @Nonnull QName name, @Nullable String argument,
+ @Nonnull StatementSourceReference ref);
/**
* Ends current opened statement.
return inProgressPhase;
}
- ContextBuilder<?, ?, ?> createDeclaredChild(final StatementContextBase<?, ?, ?> current, QName name,
- final String argument, final StatementSourceReference ref) {
+ ContextBuilder<?, ?, ?> createDeclaredChild(final StatementContextBase<?, ?, ?> current, final int childId,
+ QName name, final String argument, final StatementSourceReference ref) {
// FIXME: BUG-7038: Refactor/clean up this special case
if (TYPE.equals(name)) {
SourceException.throwIfNull(argument, ref, "Type statement requires an argument");
if (current == null) {
ret = new RootContextBuilder(def, ref);
} else {
- ret = current.substatementBuilder(def, ref);
+ ret = current.substatementBuilder(childId, def, ref);
}
if (argument != null) {
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EventListener;
-import java.util.HashMap;
import java.util.Iterator;
-import java.util.Map;
import javax.annotation.Nonnull;
import org.opendaylight.yangtools.concepts.Identifiable;
-import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
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.meta.IdentifierNamespace;
@SuppressWarnings({ "rawtypes", "unchecked" })
private final class SubContextBuilder extends ContextBuilder {
- SubContextBuilder(final StatementDefinitionContext def, final StatementSourceReference sourceRef) {
+ final int childId;
+
+ SubContextBuilder(final int childId, final StatementDefinitionContext def,
+ final StatementSourceReference sourceRef) {
super(def, sourceRef);
+ this.childId = childId;
}
@Override
public StatementContextBase build() {
- StatementContextBase<?, ?, ?> potential = null;
-
- final StatementDefinition stmtDef = getDefinition().getPublicView();
- // FIXME: this is rather ugly. Rather than having an explicit blacklist, StatementDefinitionContext should
- // give us information whether we should really bother with the substatements map.
- if (stmtDef != Rfc6020Mapping.AUGMENT && stmtDef != Rfc6020Mapping.DEVIATION
- && stmtDef != Rfc6020Mapping.IMPORT && stmtDef != Rfc6020Mapping.TYPE) {
- potential = substatements.get(createIdentifier());
- }
+ StatementContextBase<?, ?, ?> potential = substatements.get(childId);
if (potential == null) {
potential = new SubstatementContext(StatementContextBase.this, this);
- if (substatements.isEmpty()) {
- substatements = new HashMap<>(1);
- }
- substatements.put(createIdentifier(), potential);
+ substatements = substatements.put(childId, potential);
getDefinition().onStatementAdded(potential);
}
potential.resetLists();
private Multimap<ModelProcessingPhase, OnPhaseFinished> phaseListeners = ImmutableMultimap.of();
private Multimap<ModelProcessingPhase, ContextMutation> phaseMutation = ImmutableMultimap.of();
- private Map<StatementIdentifier, StatementContextBase<?, ?, ?>> substatements = ImmutableMap.of();
private Collection<StatementContextBase<?, ?, ?>> declared = ImmutableList.of();
private Collection<StatementContextBase<?, ?, ?>> effective = ImmutableList.of();
private Collection<StatementContextBase<?, ?, ?>> effectOfStatement = ImmutableList.of();
+ private StatementMap substatements = StatementMap.empty();
private SupportedByFeatures supportedByFeatures = SupportedByFeatures.UNDEFINED;
private CopyHistory copyHistory = CopyHistory.original();
*
* @return instance of ContextBuilder
*/
- public ContextBuilder<?, ?, ?> substatementBuilder(final StatementDefinitionContext<?, ?, ?> def,
+ ContextBuilder<?, ?, ?> substatementBuilder(final int childId, final StatementDefinitionContext<?, ?, ?> def,
final StatementSourceReference ref) {
- return new SubContextBuilder(def, ref);
+ return new SubContextBuilder(childId, def, ref);
}
/**
}
@Override
- public void startStatement(final QName name, final String argument, final StatementSourceReference ref) {
+ public void startStatement(final int childId, final QName name, final String argument,
+ final StatementSourceReference ref) {
deferredCreate();
- current = ctx.createDeclaredChild(parent, name, argument, ref);
+ current = ctx.createDeclaredChild(parent, childId, name, argument, ref);
}
@Override
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.stmt.reactor;
+
+import com.google.common.base.Preconditions;
+import java.util.Arrays;
+import javax.annotation.Nonnull;
+
+/**
+ * Simple integer-to-StatementContextBase map optimized for size and restricted in scope of operations.
+ *
+ * @author Robert Varga
+ */
+abstract class StatementMap {
+ private static final class Empty extends StatementMap {
+ @Override
+ StatementContextBase<?, ?, ?> get(final int index) {
+ return null;
+ }
+
+ @Override
+ StatementMap put(final int index, final StatementContextBase<?, ?, ?> object) {
+ return index == 0 ? new Singleton(object) : new Regular(index, object);
+ }
+ }
+
+ private static final class Regular extends StatementMap {
+ private StatementContextBase<?, ?, ?>[] elements;
+
+ Regular(final int index, final StatementContextBase<?, ?, ?> object) {
+ elements = new StatementContextBase<?, ?, ?>[index + 1];
+ elements[index] = Preconditions.checkNotNull(object);
+ }
+
+ Regular(final StatementContextBase<?, ?, ?> object0, final int index,
+ final StatementContextBase<?, ?, ?> object) {
+ elements = new StatementContextBase<?, ?, ?>[index + 1];
+ elements[0] = Preconditions.checkNotNull(object0);
+ elements[index] = Preconditions.checkNotNull(object);
+ }
+
+ @Override
+ StatementContextBase<?, ?, ?> get(final int index) {
+ if (index >= elements.length) {
+ return null;
+ }
+
+ return elements[index];
+ }
+
+ @Override
+ StatementMap put(final int index, final StatementContextBase<?, ?, ?> object) {
+ if (index < elements.length) {
+ Preconditions.checkArgument(elements[index] == null);
+ } else {
+ elements = Arrays.copyOf(elements, index + 1);
+ }
+
+ elements[index] = Preconditions.checkNotNull(object);
+ return this;
+ }
+ }
+
+ private static final class Singleton extends StatementMap {
+ private final StatementContextBase<?, ?, ?> object;
+
+ Singleton(final StatementContextBase<?, ?, ?> object) {
+ this.object = Preconditions.checkNotNull(object);
+ }
+
+ @Override
+ StatementContextBase<?, ?, ?> get(final int index) {
+ return index == 0 ? object : null;
+ }
+
+ @Override
+ StatementMap put(final int index, final StatementContextBase<?, ?, ?> object) {
+ Preconditions.checkArgument(index != 0);
+ return new Regular(this.object, index, object);
+ }
+ }
+
+ private static final StatementMap EMPTY = new Empty();
+
+ static StatementMap empty() {
+ return EMPTY;
+ }
+
+ abstract StatementContextBase<?, ?, ?> get(int index);
+ abstract @Nonnull StatementMap put(int index, @Nonnull StatementContextBase<?, ?, ?> object);
+}