Assigning values to concept properties

I have a language which extends BaseLanguage.
I've defined a concept which has several properties.
This concept is represented by its name (it extends INamedConcept) as its properties values should be initiated by an external code.

I've followed the generic guide-lines on "how extend the DotExpression with references to your own concepts" created by Vaclav Pech: https://confluence.jetbrains.com/display/MPSD32/Common+language+patterns#Commonlanguagepatterns-ExtendingtheDotExpressionforyourownreferences

This enabled me to refer to the concept properties values, e.g. in an ifStatement.
I also want to be able to assign values to those properties.
Therefore I've defined a concept reference for each property, which extends VariableReference and has my original concept in its "references:" section.
e.g. my original concept is
concept Person extends BaseConcept      
     implements INamedConcept  

properties:
name : string
age : integer
credit : integer

and the reference concept for the credit property:
concept PersonCreditVarRef extends VariableReference  
    implements <none>         

person : Person[1]  

and the editor for the reference concept:
[- ( % person % -> { name } ) .credit -]

I've also created an inference rule for it:
typeof(personCreditVarRef) :==: <int>;

In the sandbox I have:
myPerson
  
if (myPerson.age > 65) {
  myPerson .credit = 60;
} else
  myPerson .credit = 50;
}
     
and there are errors for the assignment:
"Error: No reference in role "variableDeclaration" (declared cardinality is 1)"
"Incompatible types: int and null"  although if you check the node explorer you see that myPerson .credit  is identified as PersonCreditVarRef and that its type is {int}

The first error is probably due to the fact that the reference concept extends VariableReference which has variableDeclaration [1] in its reference section.
So extending VariableReference is not the way to do this?
I'm sure there's an easy way to achieve assignment to properties (hopefully without having to create a separate concept reference for each property), I just don't know how to do this and would appreciate any help.   
7 comments
Both errors step from the fact that your reference extends VariableReferennce. The link to VariableDeclaration is empty and thus also the type of your reference is calculated to "null". I recommend to extend Expression directly.
0
I've tried extending Expression and got an error:
"Error: unexpected in left part or assignment"
I think this error is because if I extend Expression then the assignment is not a Statement and ifStatement expects Statement (only ifStatement condition is an Expression).
0
If you Control+Alt+Click on the error, it will take you to the check_BaseAssignmentExpression rule, which ensures the left side of an assignment is a legal left-side expression. Some expressions, such as constants, cannot be on the left side of assignments.

You need to override the lvalue() behaviour method for your reference:

public static boolean lvalue() 
  overrides Expression.lvalue { 
  return true; 
}
       
prettyPrint();
0
I've overridden the lvalue() behavior method but then I get a new error:
"unexpected in left part or assignment"
This error origin is the check_BaseAssignmentExpression rule which checks the isLValue() method.
So I've overridden the isLValue() method too:

public boolean isLValue()
  overrides Expression.isLValue {
  return true;
}

Yet even though I've rebuilt my Language I still get the same error ("unexpected in left part or assignment").
I think I'm not extending Expression correctly. How should such a reference concept look like?
0
This is how I have done the reference so that it can be uses on the left side of assignment:
concept ItemReference extends Expression            
       implements <none>             
       
  instance can be root: false 
alias: <no alias> 
short description: <no short description> 
 
properties: 
<< ... >> 
 
children: 
<< ... >> 
 
references: 
item : Item[1]
prettyPrint();

and the behaviour:
concept behavior ItemReference {
  
  constructor { 
  <no statements> 
}          
  
  public static boolean lvalue() 
  overrides Expression.lvalue { 
  true; 
}
  
} 
prettyPrint();

I can't see a problem in your code, but perhaps I'm missing some part.
0
Maybe I'm missing something but I don't know what as my reference and my behavior seem to be as they should. I've opened a bug and attached my project:
https://youtrack.jetbrains.com/issue/MPS-22154
0
The solution (by Vaclav Pech) is that the isLValue() (or lvalue()) needs to be defined in the behavior  of the operation which is used by the DotExpression:
The left side of the assignment contains the DotExpression from BaseLanguage and thus its isLValue() gets called:

public boolean isLValue()
overrides Expression.isLValue {
this.operation.isLValue();
}

The DotExpression calls isLValue() on the operation, which is PersonCreditOperation - this concept needs to override the isLValue() or lvalue() behaviour methods.
0

Please sign in to leave a comment.