Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Indenting multiline values on serialization
Indenting multiline values on serialization [message #1742148] Wed, 31 August 2016 18:36 Go to next message
Ernesto Posse is currently offline Ernesto PosseFriend
Messages: 397
Registered: March 2011
Senior Member
Hi. I have a language that contains some elements that are supposed to be "opaque" expressions, i.e. expressions in another language. These opaque expressions are not to be parsed by Xtext, but simply left as Strings.

An example is a state-machine DSL with actions on transitions, where those actions are in some external language, so you could write something like this

			transition onTimeout from pinger_running to pinger_running
				triggers on timerPort:timeout
				action
				{|#
					std::cout << getName() << ": timeout, sending ping( 0 )" << std::endl;
					pingPort.ping().send();
				#|}



The text between the {|# and #|} delimiters is the external code, i.e. the opaque expression.

Originally my grammar used Strings to encode these, instead of these delimiters, but that poses problems, such as the need to escape quotes inside the expression, or the fact that if the String object is modified externally, then, when Xtext serializes it, it will write the escape characters explicitly, e.g. "cout << \"something\";\n", and that is not good for my DSL.

I managed to solve the problem, adding the {|# and #|} delimiters in my grammar as follows:

TransitionAction returns TransitionAction:
    {TransitionAction}
    source=ActionCodeSource
;

ActionCodeSource returns ecore::EString:
	'{' ACTION_CODE_SOURCE '}'
;

terminal ACTION_CODE_SOURCE returns ecore::EString:
	'|#' -> '#|'
;


The problem I have now is serialization. If an external program produces a model where the 'source' of a 'TransitionAction' is a multi-line String that has its own formatting and spacing, then on serialization, that exact formatting is preserved, but unfortunately this doesn't yield a good result, because it can lead to lines whose indentation do not match that of the context, for example, the sample code above is serialized as

			transition onTimeout from pinger_running to pinger_running
				triggers on timerPort:timeout
				action
				{|#
    std::cout << getName() << ": timeout, sending ping( 0 )" << std::endl;
    pingPort.ping().send();
#|}


So the question is how to serialize such a value so that it is indented according to its context.

My idea was to create a custom value converter, like this:

class ActionCodeConverterImpl implements IValueConverter<String> {
	
	val CODE_START = "{|#"
	val CODE_END   = "#|}"
	val NEW_LINE   = "\n"
	
	override toString(String value) throws ValueConverterException {
		val rawString = value ?: ""
		if (rawString.contains(NEW_LINE)) {
			CODE_START + NEW_LINE + indentAllLines(rawString, ?) + CODE_END
		} else {
			CODE_START + rawString + CODE_END
		}
	}
	
	override toValue(String string, INode node) throws ValueConverterException {
		if (string !== null) {
			var startIndex = 0
			var endIndex = string.length
			if (string.startsWith(CODE_START)) {
				startIndex = CODE_START.length
			} 
			if (string.endsWith(CODE_END)) {
				endIndex = string.length - CODE_END.length
			}
			string.substring(startIndex, endIndex)
		} else {
			""
		}
	}
	
}


Indentation could be added in the "toString" method to the "rawString". The problem is that I don't know how much to indent (the ? in the indentAllLines(rawString, ?) call). We do not have the context in which the value is being serialized, as the toString method only receives the value.

Is there any way to get the context in which a value is being serialized?

Or is there another solution?

Thanks

Re: Indenting multiline values on serialization [message #1742220 is a reply to message #1742148] Wed, 31 August 2016 18:48 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 13885
Registered: July 2009
Senior Member
I think using the formatter could be an alternative

https://www.eclipse.org/forums/index.php/t/1073848/

But I have never used it for such a thing


Need professional support for Xtext, Xpand, EMF?
Go to: https://www.itemis.com/en/it-services/methods-and-tools/xtext
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Indenting multiline values on serialization [message #1742223 is a reply to message #1742220] Wed, 31 August 2016 20:19 Go to previous messageGo to next message
Ernesto Posse is currently offline Ernesto PosseFriend
Messages: 397
Registered: March 2011
Senior Member
Thanks Christian.

I actually tried the formatter, although I think I'm using the old one. But it doesn't seem to work.

Here's what I've tried

public class UmlrtFormatter extends AbstractDeclarativeFormatter {
	
	@Inject extension UmlrtGrammarAccess
	
	override protected configureFormatting(FormattingConfig c) {
		c.setLinewrap(1).around(getActionCodeSourceRule)
		c.setIndentationIncrement.before(getActionCodeSourceRule)
		c.setIndentationDecrement.after(getActionCodeSourceRule)
		c.setLinewrap(1).around(ACTION_CODE_SOURCERule)
		c.setIndentationIncrement.before(ACTION_CODE_SOURCERule)
		c.setIndentationDecrement.after(ACTION_CODE_SOURCERule)
		for(pair: findKeywordPairs('{|#', '#|}')) {
			c.setIndentation(pair.first, pair.second)
			c.setLinewrap(1).around(pair.first)
			c.setLinewrap(1).around(pair.second)
		}
		for(pair: findKeywordPairs('|#', '#|')) {
			c.setIndentation(pair.first, pair.second)
			c.setLinewrap(1).around(pair.first)
			c.setLinewrap(1).around(pair.second)
		}
		for(pair: findKeywordPairs('{', '}')) {
			c.setIndentation(pair.first, pair.second)
			c.setLinewrap(1).around(pair.first)
			c.setLinewrap(1).around(pair.second)
		}
		for(comma: findKeywords(',')) {
			c.setNoLinewrap().before(comma)
			c.setNoSpace().before(comma)
			c.setLinewrap().after(comma)
		}
		c.setLinewrap(0, 1, 2).before(SL_COMMENTRule)
		c.setLinewrap(0, 1, 2).before(ML_COMMENTRule)
		c.setLinewrap(0, 1, 1).after(ML_COMMENTRule)
	}
}


None of the "setIndentation*" methods seem to have any effect for the string contained inside the terminal ACTION_CODE_SOURCE.

Is there something in that formatter's API that would allow me to indent the string inside the terminal?



Re: Indenting multiline values on serialization [message #1742237 is a reply to message #1742223] Thu, 01 September 2016 04:57 Go to previous message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 13885
Registered: July 2009
Senior Member
I am sure it is not that easy in the old formatter sry

Need professional support for Xtext, Xpand, EMF?
Go to: https://www.itemis.com/en/it-services/methods-and-tools/xtext
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Previous Topic:Xtend Template Expressions using ' at the end of '''
Next Topic:How to disable cross reference on predefined methods?
Goto Forum:
  


Current Time: Sun Apr 18 07:20:37 GMT 2021

Powered by FUDForum. Page generated in 0.01939 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top