Skip to content

Commit

Permalink
Serialization fails for comment between concatenated strings #209
Browse files Browse the repository at this point in the history
  • Loading branch information
dhuebner committed Jun 29, 2022
1 parent 604e042 commit c94dcbf
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import org.eclipse.xtext.validation.IssueSeveritiesProvider
import org.eclipse.xtext.validation.ResourceValidatorImpl
import org.eclipse.xtext.workspace.IProjectConfigProvider
import org.eclipse.xtext.workspace.ProjectConfigProvider
import org.eclipse.xtext.serializer.tokens.IValueSerializer
import io.typefox.yang.resource.YangValueSerializer

/**
* Use this class to register components to be used at runtime / without the Equinox extension registry.
Expand Down Expand Up @@ -129,4 +131,7 @@ class YangRuntimeModule extends AbstractYangRuntimeModule {
def Class<? extends JFlexBasedInternalYangLexer> bindJFlexBasedInternalYangLexer() {
return JFlexBasedYangLexerWithLookahead
}
def Class<? extends IValueSerializer> bindIValueSerializer() {
return YangValueSerializer
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import static extension io.typefox.yang.utils.YangStringUtils.*
import org.eclipse.xtend.lib.annotations.Accessors

class YangValueConverterService extends AbstractDeclarativeValueConverterService {


@Inject StringConverter stringValueConverter;

Expand All @@ -26,25 +27,20 @@ class YangValueConverterService extends AbstractDeclarativeValueConverterService
}

static class StringConverter implements IValueConverter<String>, IValueConverter.RuleSpecific {
public static val char[] QUOTES = #['"',"'"]

override toString(String value) throws ValueConverterException {
return value.addQuotesIfNecessary
}

static val char[] quotes = #['"','\'']

override toValue(String string, INode node) throws ValueConverterException {
val result = new StringBuilder
for (n : node.leafNodes) {
if (!n.hidden) {
val seg = n.text
if (seg.length>=2) {
val first = seg.charAt(0)
if (quotes.contains(first) && seg.charAt(seg.length-1) === first) {
result.append(seg.substring(1, seg.length-1))
} else {
result.append(seg)
}
val seg = n.text
if (isQuoted(seg)) {
result.append(seg.substring(1, seg.length-1))
} else {
result.append(seg)
}
Expand All @@ -53,6 +49,14 @@ class YangValueConverterService extends AbstractDeclarativeValueConverterService
return result.toString
}

def static boolean isQuoted(String text) {
if(text.length <= 2) {
return false
}
val first = text.charAt(0)
return QUOTES.contains(first) && text.charAt(text.length-1) === first
}

@Accessors AbstractRule rule
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.typefox.yang.resource;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic.Acceptor;
import org.eclipse.xtext.serializer.tokens.IValueSerializer;
import org.eclipse.xtext.serializer.tokens.ValueSerializer;

import com.google.inject.Inject;

import io.typefox.yang.YangValueConverterService.StringConverter;
import io.typefox.yang.services.YangGrammarAccess;
import io.typefox.yang.yang.Pattern;
import io.typefox.yang.yang.YangPackage;

public class YangValueSerializer extends ValueSerializer implements IValueSerializer {

@Inject
private YangGrammarAccess grammar;

@Override
public String serializeAssignedValue(EObject context, RuleCall ruleCall, Object value, INode node,
Acceptor errors) {
// when serializing programmatically created model, wrap regex in quotes. See
// #220
String result = super.serializeAssignedValue(context, ruleCall, value, node, errors);
if (node == null && result != null && context instanceof Pattern
&& ruleCall.getRule() == grammar.getStringValueRule()) {
if (ruleCall.eContainer() instanceof Assignment && YangPackage.eINSTANCE.getPattern_Regexp().getName()
.equals(((Assignment) ruleCall.eContainer()).getFeature())) {
if (result.length() > 2 && !StringConverter.isQuoted(result)) {
return "'" + result + "'";
}
}
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import io.typefox.yang.yang.List
import io.typefox.yang.yang.Module
import io.typefox.yang.yang.Namespace
import io.typefox.yang.yang.Organization
import io.typefox.yang.yang.Pattern
import io.typefox.yang.yang.Prefix
import io.typefox.yang.yang.Statement
import io.typefox.yang.yang.Type
import io.typefox.yang.yang.Typedef
import io.typefox.yang.yang.Uses
import io.typefox.yang.yang.YangFactory
import io.typefox.yang.yang.YangPackage
Expand Down Expand Up @@ -661,6 +664,31 @@ class SerializationTest extends AbstractYangTest {
'''.toString, serialized)
}

@Test
def void testIssue220() {
val module = YangFactory.eINSTANCE.createModule
module.setName("serialize-test")
val typeDef = module.create(YangPackage.eINSTANCE.typedef, Typedef)
typeDef.setName("my-dt")
val type = typeDef.create(YangPackage.eINSTANCE.type, Type)
type.typeRef = YangFactory.eINSTANCE.createTypeReference => [builtin = "string"]
val pattern = type.create(YangPackage.eINSTANCE.pattern, Pattern)
val resource = resourceSet.createResource(URI.createFileURI("serialize-test.yang")) as XtextResource
resource.contents.add(module)

pattern.regexp = "(/.*/i?)"

assertEquals('''
module serialize-test {
typedef my-dt {
type string {
pattern '(/.*/i?)';
}
}
}'''.toString, resource.serializer.serialize(module))

}

private def <T extends Statement> create(Statement it, EClass substmtEClass, Class<T> clazz) {
val Statement stmt = YangFactory.eINSTANCE.create(substmtEClass) as Statement
it.substatements.add(stmt)
Expand Down

0 comments on commit c94dcbf

Please sign in to comment.