Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Xtend local variable scope?(Noob)
Xtend local variable scope? [message #1171811] Tue, 05 November 2013 13:56 Go to next message
Gary Worsham is currently offline Gary WorshamFriend
Messages: 176
Registered: September 2013
Senior Member
I am developing my second grammar in 2 months! Very Happy

But as usual I have a problem. Sad

The goal is very simple. I wish to summarize a menu structure by listing the menu heading and then the list of elements that are supposed to be in that menu.

E.g.

@MENU_HEADER "File"
@MENU_ITEM "New" fileNew
@MENU_ITEM "Open" fileOpen
@MENU_ITEM "Close" fileClose
@MENU_HEADER "Edit"
@MENU_ITEM "Cut" editCut
@MENU_ITEM "Copy" editCopy
@MENU_ITEM "Paste" editPaste


So what this means (in my approach) is that the @MENU_HEADER method, in addition to creating template-based Java Swing code, should also create a local variable (in the Xtend file's scope) that is used subsequently by each @MENU_ITEM method. Note that in this example, the relationship between the MENU_HEADER name, the MENU_ITEM name, and the MENU_ITEM class, is purely coincidental. The MENU_ITEM class could be anything (although it does need to refer to a class that is actually in the project).

Here's what I tried:

		«val menuName = "testing"»
		«FOR Element m : mn.elements»
			«switch m {
				MENU_HEADER:{menuName = genMenu(m)}
				MENU_ITEM:{genMenuItem(m, menuName)}
			}»
		«ENDFOR»
		}
		'''

	def String genMenu(MENU_HEADER m) '''		
		«val menuNameX = "mn" + m.name.replaceAll("\\s+","")»
		JMenu «menuNameX» = new JMenu("«m.name»");
		menuBar.add(«menuNameX»);
		«return menuNameX»	
	'''

	def genMenuItem(MENU_ITEM m, String menuNameX) '''	
			
		final JMenuItem mntm«m.className» = new JMenuItem("«m.name»");
		mntm«m.className».addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				SpinCADBlock pcB = new «m.className»CADBlock(50, 100);
				dropBlock(panel, pcB);
			}
		});
		«menuNameX».add(mntm«m.className»);
			
'''


On this line:

MENU_HEADER:{menuName = genMenu(m)}


I get this error: Assignment to final variable

and on this line:

«return menuNameX»	


I get Unreachable code

The grammar, code generator, and sample DSL file are attached as a ZIP.

Thanks for any insight!

GW

[Updated on: Tue, 05 November 2013 14:16]

Report message to a moderator

Re: Xtend local variable scope? [message #1172410 is a reply to message #1171811] Tue, 05 November 2013 22:42 Go to previous messageGo to next message
Gary Worsham is currently offline Gary WorshamFriend
Messages: 176
Registered: September 2013
Senior Member
Well I answered the first part anyway:

Quote:
Variable Declarations
Variable declarations are only allowed within blocks. They are visible from any subsequent expressions in the block.

A variable declaration starting with the keyword val denotes a value, which is essentially a final, unsettable variable. The variable needs to be declared with the keyword var, which stands for 'variable' if it should be allowed to reassign its value.


Will check the remainder later.
Re: Xtend local variable scope? [message #1172422 is a reply to message #1172410] Tue, 05 November 2013 22:55 Go to previous messageGo to next message
Gary Worsham is currently offline Gary WorshamFriend
Messages: 176
Registered: September 2013
Senior Member
I may have also answered the second question, although I'm not sure what I should do instead. Will experiment, meanwhile if the answer is burning a hole in your fingertips, don't hesitate to let me in on it!

Quote:
Blocks
The block expression allows to have imperative code sequences. It consists of a sequence of expressions. The value of the last expression in the block is the value of the complete block. The type of a block is also the type of the last expression. Empty blocks return null and have the type Object. Variable declarations are only allowed within blocks and cannot be used as a block's last expression.
Re: Xtend local variable scope? [message #1172910 is a reply to message #1172422] Wed, 06 November 2013 06:42 Go to previous messageGo to next message
Sven Efftinge is currently offline Sven EfftingeFriend
Messages: 1823
Registered: July 2009
Senior Member
It's not clear what you try to accomplish.
Do you rally want the method to return the menuName?

def String genMenu(MENU_HEADER m) '''
«val menuNameX = "mn" + m.name.replaceAll("\\s+","")»
JMenu «menuNameX» = new JMenu("«m.name»");
menuBar.add(«menuNameX»);
«return menuNameX»
'''

Or do you want to generate a return statement?
That would be :

def String genMenu(MENU_HEADER m) '''
«val menuNameX = "mn" + m.name.replaceAll("\\s+","")»
JMenu «menuNameX» = new JMenu("«m.name»");
menuBar.add(«menuNameX»);
return «menuNameX»;
'''

Am 11/5/13 11:55 PM, schrieb Gary Worsham:
> I may have also answered the second question, although I'm not sure what
> I should do instead. Will experiment, meanwhile if the answer is
> burning a hole in your fingertips, don't hesitate to let me in on it!
>
> Quote:
>> Blocks
>> The block expression allows to have imperative code sequences. It
>> consists of a sequence of expressions. The value of the last
>> expression in the block is the value of the complete block. The type
>> of a block is also the type of the last expression. Empty blocks
>> return null and have the type Object. Variable declarations are only
>> allowed within blocks and cannot be used as a block's last expression.
>


--
Need professional support for Xtext or other Eclipse Modeling technologies?
Go to: http://xtext.itemis.com
Twitter : @svenefftinge
Blog : http://blog.efftinge.de
Re: Xtend local variable scope? [message #1173364 is a reply to message #1172910] Wed, 06 November 2013 13:19 Go to previous messageGo to next message
Gary Worsham is currently offline Gary WorshamFriend
Messages: 176
Registered: September 2013
Senior Member
Hi Sven,

Thanks for your response.

I don't want to generate a return statement in my Java output. I want the Xtend generated menu name to be returned so that I can use it repeatedly in my following template code.

For example, given this:

@MENU_HEADER "Control"
@MENU_ITEM "Sin/Cos LFO" SinCosLFO
@MENU_ITEM "Ramp LFO" RampLFO


I want this to come out in my generated Java:

		JMenu mnControl = new JMenu("Control");
		menuBar.add(mnControl);

		JMenuItem mntmLFO = new JMenuItem("Sin/Cos LFO");
		mntmLFO.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				SpinCADBlock pcB = new SinCosLFOCADBlock(50, 100);
				dropBlock(panel, pcB);
				pb.update();
			}
		});
		mnControl.add(mntmLFO);

		JMenuItem mntmRampLFO = new JMenuItem("Ramp LFO");
		mntmRampLFO.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				SpinCADBlock pcB = new RampLFOCADBlock(50, 100);
				dropBlock(panel, pcB);
				pb.update();
			}
		});
		mnControl.add(mntmRampLFO);


I have rearranged a few things and am very close, however I have a new problem.

	def String genMenu(MENU_HEADER m) {
		var menuNameX = "mn_" + m.name.replaceAll("\\s+","")
//		'''
//		JMenu «menuNameX» = new JMenu("«m.name»");
//		menuBar.add(«menuNameX»);
//		''' 
		menuNameX.toLowerCase()
		}


This section works OK as far as returning the generated menu name. Unfortunately, if I uncomment the middle 4 lines, I get an error on the first ''' which says:

This expression is not allowed in this context, since it doesn't cause any side effects.

Also, the return value menuNameX.toLowerCase() is still getting inserted into my Java code, even though it's outside of the template section delimiters in genMenu. Perhap's that's getting emitted by the calling code?

			«var menuName = "testing"»
			«FOR Element m : mn.elements»
				«switch m {
					MENU_HEADER:{menuName = genMenu(m)}
					MENU_ITEM:{genMenuItem(m, menuName)}
				}»
			«ENDFOR»


I looked at the given Xtend example:

def toText(Node n) {
  switch n {
    Contents : n.text
 
    A : '''<a href="«n.href»">«n.applyContents»</a>'''
 
    default : '''
        <«n.tagName»>
          «n.applyContents»
        </«n.tagName»>
    '''
  }
}
and thought I was doing something roughly equivalent, but I guess not?

Thanks for your help.

GW

[Updated on: Wed, 06 November 2013 14:46]

Report message to a moderator

Re: Xtend local variable scope? [message #1173462 is a reply to message #1172910] Wed, 06 November 2013 14:38 Go to previous messageGo to next message
Gary Worsham is currently offline Gary WorshamFriend
Messages: 176
Registered: September 2013
Senior Member
I realize that I could solve this problem by adding an explicit parameter to each MENU_ITEM indicating which menu the specific feature was to get added under. I just feel that I should be able to somehow get the computer to do this!

[Updated on: Wed, 06 November 2013 17:08]

Report message to a moderator

Re: Xtend local variable scope? [message #1173883 is a reply to message #1173462] Wed, 06 November 2013 20:30 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 13662
Registered: July 2009
Senior Member
Hi,


maybe this one helps

the code
	def String genMenu(MENU_HEADER m) {
		var menuNameX = "mn_" + m.name.replaceAll("\\s+","")
		'''
		JMenu «menuNameX» = new JMenu("«m.name»");
		menuBar.add(«menuNameX»);
		''' 
		menuNameX.toLowerCase()
		}


translates to Java (Pseudo)Code

	public String genMenu(MENU_HEADER m) {
		String menuNameX = "mn_" + m.getName().replaceAll("\\s+","");
                StringBuilder b = new StringBuilder();
                b.append("....");
                 b.append(m.getName());
                b.append("...");
		return menuNameX.toLowerCase()
		}




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: Xtend local variable scope? [message #1173901 is a reply to message #1173883] Wed, 06 November 2013 20:43 Go to previous messageGo to next message
Gary Worsham is currently offline Gary WorshamFriend
Messages: 176
Registered: September 2013
Senior Member
Hi Christian,

That is exactly what I am trying to accomplish. I still don't understand:

#1 Why do I get this error: This expression is not allowed in this context, since it doesn't cause any side effects.
#2 Why does the return value from genMenu() - which is menuNameX.toLowerCase() - show up in my Java code?

Thanks,

GW
Re: Xtend local variable scope? [message #1173939 is a reply to message #1173901] Wed, 06 November 2013 21:16 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 13662
Registered: July 2009
Senior Member
Hi,

you add stuff to the buffer but you do not anything with the buffer. xtend wants to prevent you from doing such things.
the last expression of a block is its return value
=> you return menuNameX.toLowerCase()

you call getmenu here

«switch m {
					MENU_HEADER:{menuName = genMenu(m)}
					MENU_ITEM:{genMenuItem(m, menuName)}
				}»


the switch expression itself returns a string and this is embedded into the rich string ''''''


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: Xtend local variable scope? [message #1173945 is a reply to message #1173939] Wed, 06 November 2013 21:24 Go to previous messageGo to next message
Gary Worsham is currently offline Gary WorshamFriend
Messages: 176
Registered: September 2013
Senior Member
Hi Christian,

I think I am doing something with the buffer (menuNameX). I'm using it in my emitted template code for genMenu() and I'm trying to use it subsequently (after being passed back as a return value) as a parameter for genMenuItem(). Why does Xtend think I'm not trying to do anything with it?

Can you suggest any way around these issues?

Thanks,

GW
Re: Xtend local variable scope? [message #1173957 is a reply to message #1173945] Wed, 06 November 2013 21:35 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 13662
Registered: July 2009
Senior Member
hi,

i dont see where you do anything with that
replace '''''' and println("bla") has the same effect


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: Xtend local variable scope? [message #1174190 is a reply to message #1173957] Thu, 07 November 2013 01:11 Go to previous messageGo to next message
Gary Worsham is currently offline Gary WorshamFriend
Messages: 176
Registered: September 2013
Senior Member
I'll look at it more closely. Thanks.
Re: Xtend local variable scope? [message #1175084 is a reply to message #1174190] Thu, 07 November 2013 14:14 Go to previous messageGo to next message
Gary Worsham is currently offline Gary WorshamFriend
Messages: 176
Registered: September 2013
Senior Member
Well, I solved my problem, which was to just go back and add the name of the MENU_HEADER to each MENU_ITEM, like this:

@menu "Wave Shaper" 
@menuitem "Bit Crusher" BitCrusher "Wave Shaper"
@menuitem "Distortion" Distortion "Wave Shaper"
@menuitem "Gain" Gain "Wave Shaper"

@menu "Modulation"
@menuitem "GA Demo Phaser" ga_demo_phaser "Modulation"
@menuitem "GA Demo Flanger" ga_demo_flanger "Modulation"
@menuitem "GA Demo Wah" ga_demo_wah "Modulation"


It seems somewhat stupid and redundant to do this, but let me pause. I am trying to create a hierarchy without explicitly representing that hierarchy in my input data. I wanted there to be a "state" within my Xtend code generator (the name of the current MENU_HEADER) and whatever MENU_ITEMS were declared, would be associated with that MENU_HEADER until such time that a new MENU_HEADER was declared. Either Xtend doesn't like this approach or I am currently too dense to devise a workable solution.

Given that I have a workable (although slightly annoying) solution, I am going to move forward with it. I welcome any comments about appropriate software design, alternative tools that might be better, or whatever you like. I do have half a mind to (eventually) look at something like the ECore diagram generator, where it would be more straightforward to allow a non-programmer to easily create a hierarchical menu definition.

[Updated on: Thu, 07 November 2013 14:15]

Report message to a moderator

Re: Xtend local variable scope? [message #1176194 is a reply to message #1175084] Fri, 08 November 2013 07:16 Go to previous messageGo to next message
Uli Merkel is currently offline Uli MerkelFriend
Messages: 248
Registered: June 2013
Senior Member
Hi Garry,

to implement some linePosition, I had to circumvent the variable problems.
watch the 'return ""' at the end of the methods to deliver nothing for the generated text.

class UmeFormgen1Generator implements IGenerator {
var Integer linePosition = 0;
def incrementLinePosition() {linePosition = linePosition + 1;return""}
def resetLinePosition() {linePosition = 0;return""}
def Integer getLinePosition() {return linePosition}
...
Re: Xtend local variable scope when using template code? [message #1176716 is a reply to message #1176194] Fri, 08 November 2013 14:06 Go to previous messageGo to next message
Gary Worsham is currently offline Gary WorshamFriend
Messages: 176
Registered: September 2013
Senior Member
Thanks for the response Uli.

I still have the problem about trying to create a variable in my method that can both be used in the template section as well as be a return value.

For example, this is fine, but doesn't emit any template code:
	def figureItOut2(MENU_HEADER m) {
		var menuNameX = getMenuName(m.name)
		menuNameX
		}


This is fine, but doesn't return any useful value:
	def figureItOut(MENU_HEADER m) {
		var menuNameX = getMenuName(m.name)
		'''
		JMenu «menuNameX» = new JMenu("«m.name»");
		menuBar.add(«menuNameX»);
	''' 
		}


This is NOT fine (it's what I originally tried):
	def figureItOut(MENU_HEADER m) {
		var menuNameX = getMenuName(m.name)
		'''
		JMenu «menuNameX» = new JMenu("«m.name»");
		menuBar.add(«menuNameX»);
	''' 
                menuNameX  
		}


And this is NOT fine - attempting to use the menuNameX value past the end of the template section (it was declared within the template section):

	def figureItOut1(MENU_HEADER m) {
		'''
		JMenu «var menuNameX=getMenuName(m.name)» = new JMenu("«m.name»");
		menuBar.add(«menuNameX»);
	''' 
		menuNameX
		}


Error: The method or field menuNameX is undefined for the type SpinCADMenuGenerator

So it looks to me as though the template section represents a scope boundary. There's no way to insert a template section in the middle of some code without breaking the scope in half.

For reference, the getMenuName() method is:

	def getMenuName(String header) {
		var menuNameX = "mn_" + header.replaceAll("\\s+","")
		menuNameX.toLowerCase()
	}

[Updated on: Fri, 08 November 2013 14:12]

Report message to a moderator

Re: Xtend local variable scope? [message #1176760 is a reply to message #1171811] Fri, 08 November 2013 14:39 Go to previous message
Gary Worsham is currently offline Gary WorshamFriend
Messages: 176
Registered: September 2013
Senior Member
OK I figured it out! Thanks Uli for the clue. Very Happy

Here's the fundamental difference:

Before:
			«FOR Element m : mn.elements»
				«switch m {
					MENU_HEADER:{menuNameY = genMenu(m)}
					MENU_ITEM:{genMenuItem(m, menuNameY)}
				}»
			«ENDFOR»


After:
			«FOR Element m : mn.elements»
				«switch m {
					MENU_HEADER:{menuNameY = getMenuName(m.name); genMenu(m)}
					MENU_ITEM:{genMenuItem(m, menuNameY)}
				}»
			«ENDFOR»

So, rather than getting the menu name from genMenu(), I created a different method getMenuName() to just get the menu name. And I suppressed the extra menu name being generated in the code by creating a compound statement within the switch, then making the retrieval of the menu name the first of the two statements. Only the final statement is considered the return of the switch case (it appears).


/*
 * generated by Xtext
 */
package com.holycityaudio.spincad.generator

import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.generator.IGenerator
import org.eclipse.xtext.generator.IFileSystemAccess
import com.holycityaudio.spincad.spinCADMenu.Menu
import com.holycityaudio.spincad.spinCADMenu.MENU_ITEM
import com.holycityaudio.spincad.spinCADMenu.MENU_HEADER
import com.holycityaudio.spincad.spinCADMenu.Element

/**
 * Generates code from your model files on save.
 * 
 * see http://www.eclipse.org/Xtext/documentation.html#TutorialCodeGeneration
 */
class SpinCADMenuGenerator implements IGenerator {
	
	override void doGenerate(Resource resource, IFileSystemAccess fsa) {
		var pkage = "\\com\\holycityaudio\\SpinCAD\\"
		fsa.generateFile(pkage + resource.className+"Menu"+".java", toMenuCode(resource.contents.head as Menu))
		}
		
		def className(Resource res) {
			var name = res.URI.lastSegment
			println(name)
			return name.substring(0, name.indexOf('.'))
		}
	
	def toMenuCode(Menu mn) {
		var menuNameY = "testing"
		'''
			package com.holycityaudio.SpinCAD;
			import com.holycityaudio.SpinCAD.SpinCADBlock;

			import java.awt.event.ActionEvent;
			import java.awt.event.ActionListener;
		
			import javax.swing.JMenu;
			import javax.swing.JMenuBar;
			import javax.swing.JMenuItem;
		
			public class «mn.eResource.className+"Menu"» {

			private static final long serialVersionUID = 1L;

			public «mn.eResource.className+"Menu"»(final SpinCADFrame f, final SpinCADPanel panel, JMenuBar menuBar) {
		
			«FOR Element m : mn.elements»
				«switch m {
					MENU_HEADER:{menuNameY = getMenuName(m.name); genMenu(m)}
					MENU_ITEM:{genMenuItem(m, menuNameY)}
				}»
			«ENDFOR»
			}
		}
		'''
		}

	def String genMenu(MENU_HEADER m) {
		'''
		JMenu «getMenuName(m.name)» = new JMenu("«m.name»");
		menuBar.add(«getMenuName(m.name)»);
	''' 
		}
				
	def genMenuItem(MENU_ITEM m, String menuName) '''	
		final JMenuItem mntm«m.className» = new JMenuItem("«m.name»");
		mntm«m.className».addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				SpinCADBlock pcB = new «m.className»CADBlock(50, 100);
				f.dropBlock(panel, pcB);
			}
		});
		«menuName».add(mntm«m.className»);
			
'''

	def getMenuName(String header) {
		var menuNameX = "mn_" + header.replaceAll("\\s+","")
		menuNameX.toLowerCase()
	}	
}

[Updated on: Fri, 08 November 2013 18:04]

Report message to a moderator

Previous Topic:What is generated by fornax-oaw-m2-plugin?
Next Topic:Two DSLs in one Eclipse project
Goto Forum:
  


Current Time: Mon Nov 30 08:54:10 GMT 2020

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

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

Back to the top