XText w/ XBase - Initialize generated variable - dsl

I'm using Xtext with XBase grammar.
In every generated java class I need to initialize class variable in my model inferer. This variable isn't defined in my model, but that makes no difference.
I already can generate this variable via function
element.toField("isSomethingSet", newTypeRef("boolean"))
, but I can't initialize it. I'm sure I should use toField function with additional parameter called initializer, but as this is of type Procedure1 I don't know how to use it.
Here is my slightly changed example taken from Xtext documentation.
Grammar:
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.xbase.Xbase
generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"
Domainmodel:
(elements += AbstractElement)*;
AbstractElement:
Entity;
Entity:
'entity' name = ID ('extends' superType = JvmTypeReference)?
'{'
(features += Feature)*
'}';
Feature:
name = ID ':' type = JvmTypeReference;
ModelInferrer.xtend
import com.google.inject.Inject
import org.eclipse.xtext.naming.IQualifiedNameProvider
import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder
import org.xtext.example.mydsl.myDsl.Entity
class MyDslJvmModelInferrer extends AbstractModelInferrer {
#Inject extension JvmTypesBuilder
#Inject extension IQualifiedNameProvider
def dispatch void infer(Entity element, IJvmDeclaredTypeAcceptor acceptor,
boolean isPrelinkingPhase) {
acceptor.accept(element.toClass(element.fullyQualifiedName)).initializeLater [
documentation = element.documentation
members += element.toField("isSomethingSet", newTypeRef("boolean"))
for (feature : element.features) {
members += feature.toField(feature.name, feature.type)
members += feature.toSetter(feature.name, feature.type)
members += feature.toGetter(feature.name, feature.type)
}
]
}
}

The procedure encapsulates the code that is required to configure the field, e.g. set the visibility, static flags, documentation or the field initializer:
element.toField("isSomethingSet", newTypeRef("boolean")) [
initializer = '''false''' // with Xtext 2.5 or
initializer = [ append('false') ] // prior to 2.5
]

Related

Groovy class factory pattern gives weird error

I am new to groovy and I am trying with some groovy code. I have this scenario. I have the following modules
package com.utils
abstract class Base {
static String data = ''
}
package com.utils
class A extends Base {
static String data = 'dummy'
}
package com.utils
class B extends Base {
static String data = 'dummy'
}
package com.utils
class ShapeFactory {
static Map <String,Object> shapes = [
"a": A,
"b": B
]
static Object get_shapes(String shape) {
return shapes.get(shape);
}
}
And in the main file I am using
and in the main file and here is where it fails with weird error. I couldn't identify the reason, I would appreciate any help.
import com.utils.ShapeFactory
def shapeA = ShapeFactory.get_shapes('a')
shapeA.data // here it fails with the below error
hudson.remoting.ProxyException: org.codehaus.groovy.runtime.typehandling.GroovyCastException:
Cannot cast object '[]' with class 'java.util.ArrayList' to class 'java.util.Map'
due to: groovy.lang.GroovyRuntimeException:
Could not find matching constructor for: java.util.Map()
Any help will be appreciated, Thanks
Apologies, I found the issue, In the Base class I had a Map variable as well which was initialized as an array
abstract class Base {
static String data = ''
static Map mapper = [] // This has to be [:]
}

In a class difference between using `this.x` and just `x` to access a field?

In the haxe manual in the section about class instances they list the following code sample (simplified by me):
class Point {
var x : Int;
public function new(x) {
this.x = x;
}
}
In the section about class fields they list the following:
class Main {
static var member:String = "bar";
public static function main() {
member = "foo";
}
}
In the previous example they use this to access the x field, but in the next example they don't. Is this code equivalent or is there some nuance to it?
In first example in functions passed variable x, that have same name as class member. So this.x refers to class member.
You could always use this to refer class members, but usually it omits if we not have such case as in first example, where we need explicitly refer to class member.

Groovy Compile time AST transformation: Assignment to a field

I'm currently trying to implement some Groovy compile time AST transformations, but I ran into trouble:
How do I specify an AST transformation for an assignment statement to a field? i.e. the AST transformation should transform the following code:
class MyClass {
#MyTransformation
String myField
public void init() {
}
}
into something like
class MyClass {
String myField
public void init() {
this.myField = "initialized!"
}
}
I tried it with this AST builder invocation:
def ast = new AstBuilder().buildFromSpec {
expression{
declaration {
variable "myField"
token "="
constant "initialized!"
}
}
}
But after inserting the resulting statement in the "init" method of the declaring class, it instead inserted a variable assignment, as in
java.lang.Object myField = "initialized!"
I looked through the examples incorporated in the Ast Builder TestCase, but they only cover field declaration in the class body, not assignments to fields. My own tries using fieldNode all resulted in compiler errors. I set the compile phase to INSTRUCTION_SELECTION; I think this should be fine.
How do I achieve this? A solution based on the AstBuilder#buildFromSpec method is preferred, but any help would be highly appreciated.
I usually recommand not to use the AST builder. It's good for prototyping, but you don't really control what it generates. In particular, here, it's not capable of handling the fact that the variable expression you create should reference the field node. AST Builder is very nice to learn about the AST, but shouldn't be used in production code IMHO.
Here is a self contained example that demonstrates how you can acheive what you want. The code inside #ASTTest would correspond to your transform code:
import groovy.transform.ASTTest
import org.codehaus.groovy.ast.expr.BinaryExpression
import org.codehaus.groovy.ast.expr.VariableExpression
import org.codehaus.groovy.ast.expr.ConstantExpression
import org.codehaus.groovy.ast.stmt.ExpressionStatement
import org.codehaus.groovy.syntax.Token
import org.codehaus.groovy.syntax.Types
class MyClass {
String myField
#ASTTest(phase=SEMANTIC_ANALYSIS,value={
def classNode = node.declaringClass
def field = classNode.getDeclaredField('myField')
def assignment = new BinaryExpression(
new VariableExpression(field),
Token.newSymbol(Types.EQUAL, 0, 0),
new ConstantExpression('initialized!')
)
node.code.addStatement(new ExpressionStatement(assignment))
})
public void init() {
}
}
def c = new MyClass()
c.init()
println c.myField
Hope this helps!

initializing derived class member variables using base class reference object

I came across a lot of code in our company codebase with the following structure
class Base
{
public Base (var a, var b)
{
base_a = a;
base_b = b;
}
var base_a;
var base_b;
}
class Derived:Base
{
publc Derived (var a,b,c,d): base (a,d)
{
der_c = c;
der_d = d;
}
var der_c;
var der_d;
var der_e;
}
class Ref
{
Base _ref;
public Ref( var a,b,c,d)
{
_ref = new Derived (a,b,c,d)
}
public void method( )
{
_ref.der_e = 444; // won't compile
}
}
What is the correct way to initialize der_e ? What is the advantages of having a reference of base class and using an object derived class for _ref ? Just the fact that using a base class reference can hold multiple derived class objects ? If that's the case, should all the member variables of derived class be initialized during construction itself (like this: _ref = new Derived (a,b,c,d) ). What if I want to initialize _ref.der_e later in a method ? I know I can do this (var cast_ref = _ref as Derived; cast_ref.der_e = 444) but this look doesn't seem to the best practice. What is the idea of having such a structure and what is the correct of initializing a member of a derived class object after it has been constructed ?
Those are too many questions in a single post.
What is the correct way to initialize der_e ?
For initializing der_e you will have to have Reference of Derived class as it knows about the der_e property and not Base class.
What is the advantages of having a reference of base class and using
an object derived class for _ref ?
Yes that's called Polymorphism which is the essence of Object Oriented Programming. It allows us to hold various concrete implementations without knowing about the actual implementation.
If that's the case, should all the member variables of derived class
be initialized during construction itself (like this: _ref = new
Derived (a,b,c,d) )
There is no such rule. It depends on your scenario. If the values are not meant to be changed after the creation of the object and the values are known before hand during construction of the object then they should be initialized during construction.
Again if there are various scenarios like sometimes values are known and sometimes not then there can be Overloaded Constructors, which take different arguments.
What if I want to initialize _ref.der_e later in a method ?
That is perfectly fine, it depends on what you are trying to achieve. The question is not a concrete one but an abstract one in which it is difficult to comment on what you are trying to achieve.
I know I can do this (var cast_ref = _ref as Derived; cast_ref.der_e =
444) but this look doesn't seem to the best practice.
I am sharing some Java code which is similar to C# as I am from Java background
//This class knows about Base and nothing about the Derived class
class UserOfBase{
Base ref;
//Constructor of UserOfBase gets passed an instance of Base
public UserOfBase(Base bInstance){
this.ref = bInstance;
}
//Now this class should not cast it into Derived class as that would not be a polymorphic behavior. In that case you have got your design wrong.
public void someMethod(){
Derived derivedRef = (Derived)ref; //This should not happen here
}
}
I am sharing some references which would help you with this, as I think the answer can be very long to explain.
Factory Pattern
Dependency Injection
Head First Design Patterns
Posts on SO regarding polymorphism
You can create a constructor in your derived class and map the objects or create an extension method like this:
public static class Extensions
{
public static void FillPropertiesFromBaseClass<T1, T2>(this T2 drivedClass, T1 baseClass) where T2 : T1
{
//Get the list of properties available in base class
System.Reflection.PropertyInfo[] properties = typeof(T1).GetProperties();
properties.ToList().ForEach(property =>
{
//Check whether that property is present in derived class
System.Reflection.PropertyInfo isPresent = drivedClass.GetType().GetProperty(property.Name);
if (isPresent != null && property.CanWrite)
{
//If present get the value and map it
object value = baseClass.GetType().GetProperty(property.Name).GetValue(baseClass, null);
drivedClass.GetType().GetProperty(property.Name).SetValue(drivedClass, value, null);
}
});
}
}
for example when you have to class like this:
public class Fruit {
public float Sugar { get; set; }
public int Size { get; set; }
}
public class Apple : Fruit {
public int NumberOfWorms { get; set; }
}
you can initialize derived class by this code:
//constructor
public Apple(Fruit fruit)
{
this.FillPropertiesFromBaseClass(fruit);
}

Groovy type definitions

class GroovyClass {
def aVariable
void setAVariable(aVariable)
{
this.aVariable = aVariable;
}
}
My understanding was that we don't need to specify the type of a variable in a groovy class. But Groovy compiler complains if I declare 'aVariable' , why isn't it considered as a typeless variable with default accessibility ? Should every variable be defined with a def in Groovy both local and class ? Why is it that the function definition doesn't have to begin with a def ? and when I'm passing in a variable to the setter, it doesn't need any def in there ?
That code works fine. What do you mean by "Groovy compiler complains"?
You can define that function with a def if you wanted, and it would return aVariable (as that is what the assignment operatop returns), however, it wouldnt be following the standard for Java Beans in that setters should return null
Given that however, I can run:
a = new GroovyClass()
a.aVariable = 3
And it works fine
Edit
Basically, it's all down to the Groovy parser. The parser expects some sort of list of 1..N keywords defining it's type or visibility, and then a name for the variable. So the following are all valid:
class OkA {
def aValue
}
class OkB {
private aValue
}
class OkC {
private String aValue
}
But you cannot just (with the current parser) say:
class BadA {
aValue
}
Thinking about it, there's no reason I can currently think of for this restriction (as you can declare vars without def in Groovy), but the restriction is there, so you need to type def when defining class attributes.

Resources