Skip to content

Commit

Permalink
yang-tool: Support add, replace and delete deviation
Browse files Browse the repository at this point in the history
  • Loading branch information
dhuebner committed Dec 18, 2023
1 parent 81eea95 commit 2694fc4
Show file tree
Hide file tree
Showing 11 changed files with 513 additions and 120 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
package io.typefox.yang.processor

import io.typefox.yang.processor.ProcessedDataTree.AccessKind
import io.typefox.yang.processor.ProcessedDataTree.ElementData
import io.typefox.yang.processor.ProcessedDataTree.HasStatements
import io.typefox.yang.processor.ProcessedDataTree.ListData
import io.typefox.yang.processor.ProcessedDataTree.ModuleData
import java.util.List
import io.typefox.yang.processor.ProcessedDataTree.ElementKind
import io.typefox.yang.processor.ProcessedDataModel.ElementKind
import io.typefox.yang.processor.ProcessedDataModel.AccessKind
import io.typefox.yang.processor.ProcessedDataModel.ModuleData
import io.typefox.yang.processor.ProcessedDataModel.ListData
import io.typefox.yang.processor.ProcessedDataModel.ElementData
import io.typefox.yang.processor.ProcessedDataModel.HasStatements

class DataTreeSerializer {

def CharSequence serialize(ModuleData moduleData) {
'''
module: «moduleData.simpleName»
«FOR child : moduleData.children?:#[]»
«doSerialize(child, '', needsConnect(child, moduleData.children))»
«FOR child : moduleData.getChildren?:#[]»
«doSerialize(child, '', needsConnect(child, moduleData.getChildren))»
«ENDFOR»
rpcs:
«FOR rpc : moduleData.rpcs?:#[]»
«doSerialize(rpc, '', needsConnect(rpc, moduleData.rpcs))»
«FOR rpc : moduleData.getRpcs?:#[]»
«doSerialize(rpc, '', needsConnect(rpc, moduleData.getRpcs))»
«ENDFOR»
'''
}
Expand Down Expand Up @@ -48,24 +48,24 @@ class DataTreeSerializer {
}
}
val keys = if (ele instanceof ListData) {
ele.keys.empty ? null : ''' [«ele.keys.join(', ')»]'''
ele.getKeys.empty ? null : ''' [«ele.getKeys.join(', ')»]'''
}

val type = ele.getType
// no idea why this indentation is needed in pyang
val additionalIdent = if(ele.elementKind === ElementKind.Choice && prevSibling(ele)?.elementKind === ElementKind.Container) ' ' else ''
'''
«indent»«additionalIdent»+«prefix»«label»«ele.cardinality?.toString()»«keys»«IF type !== null» «type»«ENDIF»«IF ele.featureConditions !== null» {«ele.featureConditions.join(',')»}?«ENDIF»
«IF ele.children !== null»
«FOR child : ele.children»
«doSerialize(child, indent + (needsConnect?'| ':' '), needsConnect(child, ele.children))»
«indent»«additionalIdent»+«prefix»«label»«ele.cardinality?.toString()»«keys»«IF type !== null» «type»«ENDIF»«IF ele.getFeatureConditions !== null» {«ele.getFeatureConditions.join(',')»}?«ENDIF»
«IF ele.getChildren !== null»
«FOR child : ele.getChildren»
«doSerialize(child, indent + (needsConnect?'| ':' '), needsConnect(child, ele.getChildren))»
«ENDFOR»
«ENDIF»
'''
}

private def ElementData prevSibling(ElementData ele) {
val siblings = ele.parent?.children
val siblings = ele.getParent?.getChildren
if(siblings === null) {
return null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import io.typefox.yang.processor.ProcessedDataTree.ElementIdentifier;
import io.typefox.yang.processor.ProcessedDataModel.ElementIdentifier;
import io.typefox.yang.yang.Feature;

public class FeatureEvaluationContext {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import org.eclipse.xtext.nodemodel.util.NodeModelUtils;

import io.typefox.yang.processor.ProcessedDataTree.ElementIdentifier;
import io.typefox.yang.processor.ProcessedDataModel.ElementIdentifier;
import io.typefox.yang.yang.BinaryOperation;
import io.typefox.yang.yang.Expression;
import io.typefox.yang.yang.Feature;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.typefox.yang.processor;

import com.google.gson.GsonBuilder;

import io.typefox.yang.processor.ProcessedDataModel.ModuleData;

public class JsonSerializer {

public CharSequence serialize(ModuleData moduleData) {
var writer = new StringBuilder();
serialize(moduleData, writer);
return writer.toString();
}

public void serialize(ModuleData moduleData, Appendable writer) {
new GsonBuilder().setPrettyPrinting().create().toJson(moduleData, writer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,32 @@

import static com.google.common.collect.Lists.newArrayList;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;

import com.google.common.base.Objects;
import com.google.common.collect.Sets;

import io.typefox.yang.processor.FeatureExpressions.FeatureCondition;
import io.typefox.yang.yang.Config;
import io.typefox.yang.yang.Default;
import io.typefox.yang.yang.IfFeature;
import io.typefox.yang.yang.Key;
import io.typefox.yang.yang.Mandatory;
import io.typefox.yang.yang.MaxElements;
import io.typefox.yang.yang.MinElements;
import io.typefox.yang.yang.Must;
import io.typefox.yang.yang.Path;
import io.typefox.yang.yang.Presence;
import io.typefox.yang.yang.SchemaNode;
import io.typefox.yang.yang.Type;
import io.typefox.yang.yang.TypeReference;
import io.typefox.yang.yang.Typedef;
import io.typefox.yang.yang.XpathExpression;

public class ProcessedDataTree {
public class ProcessedDataModel {

private List<ModuleData> modules;

Expand Down Expand Up @@ -169,8 +172,12 @@ public String toString() {
}

static public enum ElementKind {
Container, Leaf, LeafList, List, Rpc, Choice, Case, Action, Grouping, Refine, Uses, Input, Output, Notification,
AnyXml;
// SchemaNodes
Action, Case, Choice,
// DataSchemaNodes
AnyXml, Container, Leaf, LeafList, List,
// SchemaNodes
Grouping, Input, Notification, Output, Rpc;

public static Set<ElementKind> mayOmitCase = Sets.newHashSet(AnyXml, Container, Leaf, List, LeafList);
}
Expand Down Expand Up @@ -204,6 +211,16 @@ public static class ElementData extends HasStatements {

transient private SchemaNode origin;

/**
* 0..1 Node properties that can be changed by a Deviate
*/
public String defaultValue, maxElements, minElements = null;

/**
* 0..n Node properties that can be changed by a Deviate
*/
public List<String> mustConstraint = null;

private ElementData(ElementIdentifier elementId, ElementKind elementKind) {
super(elementId);
this.elementKind = elementKind;
Expand Down Expand Up @@ -268,6 +285,18 @@ protected void configureElement(SchemaNode ele) {
this.cardinality = Cardinality.mandatory;
} else if (sub instanceof Presence) {
this.cardinality = Cardinality.presence;
} else if (sub instanceof Default) {
this.defaultValue = ((Default) sub).getDefaultStringValue();
} else if (sub instanceof MaxElements) {
this.maxElements = ((MaxElements) sub).getMaxElements();
} else if (sub instanceof MinElements) {
this.minElements = ((MinElements) sub).getMinElements();
} else if (sub instanceof Must) {
if (this.mustConstraint == null) {
this.mustConstraint = new ArrayList<>();
}
var exprAsString = ProcessorUtility.serializedXpath(((Must) sub).getConstraint());
this.mustConstraint.add(exprAsString);
}
});
}
Expand All @@ -279,7 +308,7 @@ private ValueType createValueType(Type typeStatement) {
Path pathRef = (Path) typeStatement.getSubstatements().stream().filter(s -> s instanceof Path)
.findFirst().get();
if (pathRef != null && pathRef.getReference() != null) {
return new ValueType(null, "-> " + serializedXpath(pathRef.getReference()));
return new ValueType(null, "-> " + ProcessorUtility.serializedXpath(pathRef.getReference()));
}
}
return new ValueType(null, typeRef.getBuiltin());
Expand Down Expand Up @@ -308,22 +337,6 @@ private String referenceText(TypeReference typeRef) {
return NodeModelUtils.getTokenText(node);
}

private String serializedXpath(XpathExpression reference) {
// TODO use serializer or implement a an own simple one
ICompositeNode nodeFor = NodeModelUtils.findActualNodeFor(reference);
if (nodeFor != null) {
var nodeText = nodeFor.getText();
nodeText = nodeText.replaceAll("\"|'|\\s|\n|\r", "").replaceAll("\\+", "");
int firstColon = nodeText.indexOf(":");
if (firstColon > 0) {
nodeText = nodeText.substring(0, firstColon)
+ nodeText.substring(firstColon).replaceAll("\\/[a-zA-Z]+:", "/");
}
return nodeText;
}
return "leafref";
}

private void addFeatureCondition(String condition) {
if (condition == null) {
throw new IllegalArgumentException("Feature condition may not be null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.impl.CompositeNodeWithSemanticElement;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;

import io.typefox.yang.processor.FeatureExpressions.FeatureCondition;
import io.typefox.yang.processor.ProcessedDataTree.ElementIdentifier;
import io.typefox.yang.processor.ProcessedDataModel.ElementIdentifier;
import io.typefox.yang.processor.YangProcessor.ForeignModuleAdapter;
import io.typefox.yang.utils.YangExtensions;
import io.typefox.yang.yang.AbstractModule;
Expand All @@ -22,6 +23,7 @@
import io.typefox.yang.yang.SchemaNode;
import io.typefox.yang.yang.Statement;
import io.typefox.yang.yang.Submodule;
import io.typefox.yang.yang.XpathExpression;

public class ProcessorUtility {

Expand Down Expand Up @@ -108,4 +110,24 @@ protected EObject createCopy(EObject eObject) {
copier.copyReferences();
return result;
}

public static String serializedXpath(XpathExpression reference) {
if(reference == null) {
return null;
}
// TODO use serializer or implement a an own simple one
ICompositeNode nodeFor = NodeModelUtils.findActualNodeFor(reference);
if (nodeFor != null) {
var nodeText = nodeFor.getText();
nodeText = nodeText.replaceAll("\"|'|\\s|\n|\r", "").replaceAll("\\+", "");
int firstColon = nodeText.indexOf(":");
if (firstColon > 0) {
nodeText = nodeText.substring(0, firstColon)
+ nodeText.substring(firstColon).replaceAll("\\/[a-zA-Z]+:", "/");
}
return nodeText;
}
return "leafref";
}

}
Loading

0 comments on commit 2694fc4

Please sign in to comment.