Hello,
I'm currently struggeling to implement list types correctly because they cannot be passed as Parameter to my operations (the error "the method e(Java.util.List<Integer>) from the type Test5 (my generated class) refers to the missing type java.util.list<Integer>). I achieve the same behaviour when I try do return a List from a operation and set it to a variable of the expected list type.
The important parts of my DSL are the following:
Grammar:
Variable returns XVariableDeclaration:
{Variable} writeable?='variable' simpleName=ID ':' (typing=DataType);
Method:
=> ({Method} 'operation' name=ValidID
'(') (parameter+=Parameter (',' parameter+=Parameter)*)? ')' ('returns' returnTyping=DataType)?
body=XBlockExpression;
Parameter:
{Parameter} 'parameter' name=ID ':' parameterTyping=DataType;
// more stuff [..]
DataType:
(SimpleDataType | ComplexDataType | ListType);
ListType:
=> ('list' '<' type=DataType) '>';
SimpleDataType:
{SimpleDataType} typeName=('integer' | 'string' | 'rational' | 'boolean');
To use ComplexDataTypes and SimpleDataTypes as variables works as expected. Return-values work, too.
My typecomputer looks like this:
if(XVariableDeclaration instanceof Variable){
/* other types, simple datatype and complex data type */
/* ... */ else if (vr.typing instanceof ListType) {
state.assignType(vr, getTypeForName(listTypeUtil.getListTypeString(vr.typing as ListType), state))
for (additional : vr.additionalVariables) {
state.assignType(additional,
getTypeForName(listTypeUtil.getListTypeString(vr.typing as ListType), state))
}
} }
The getListTypeString method returns for the variable "list<integer>" the type "java.util.List<Integer>" and works like this similiar for other cases.
My compiler looks like this:
override _toJavaStatement(XVariableDeclaration variable, ITreeAppendable a, boolean isReferenced) {
variable.name = variable.simpleName
if (variable instanceof Variable) {
a.newLine()
if (variable.typing instanceof SimpleDataType) {
a.append(createAppendString(variable.typing as SimpleDataType, variable))
} else if (variable.typing instanceof ComplexDataType) { /* ComplexDataType */
a.append(createAppendString(variable.typing as ComplexDataType, variable))
} else if (variable.typing instanceof ListType) {
a.append(createAppendString(variable.typing as ListType, variable))
}
} else {
super._toJavaStatement(variable, a, isReferenced)
}
}
/* Creates variable declaration of list type */
def createAppendString(ListType lt, Variable vr) {
var appendString = ""
appendString += "java.util.List<"
appendString += calculateInnerTypeString(lt)
appendString += "> "
appendString += vr.simpleName
appendString += " = new java.util.ArrayList<"
appendString += calculateInnerTypeString(lt)
appendString += ">();"
}
InnerTypeString calculates the innertypes of the List. For list<string> it will return "String".
An example translation looks like the following:
variable liste: list<integer>
-> java.util.List<Integer> liste = new java.util.ArrayList<Integer>();
This works as expected (at least as far as I know, maybe there are better ways..).
My operations in the inferrer will be converted like this:
/**
* Generates all operations in the program
*/
def inferMethods(List<Method> methods, List<JvmMember> members) {
for (method : methods) {
var type = method.returnTyping
var returntype = getTypeRefFor(type)
if (returntype === null) {
returntype = typeRef(Void.TYPE)
}
members += method.toMethod(method.name, returntype) [
for (param : method.parameter) {
parameters += param.toParameter(param.name, getTypeRefFor(param.parameterTyping))
}
static = true
body = method.body
]
}
}
/**
* Returns the typeRef for the given datatype
* null, if no type is found
*/
def /* @nullable */ getTypeRefFor(DataType parameterType) {
println(parameterType)
if (parameterType instanceof SimpleDataType) {
return getSimpleDataType(parameterType.typeName)
} else if (parameterType instanceof ComplexDataType) {
var cdt = parameterType as ComplexDataType
if (cdt.typeName instanceof Composition) {
return typeRef((cdt.typeName as Composition).name)
} else if (cdt.typeName instanceof Enumeration) {
return typeRef((cdt.typeName as Enumeration).name)
}
} else if (parameterType instanceof ListType) {
return typeRef("java.util.List<" + calculateInnerTypeString(parameterType as ListType) + ">")
} else {
return null
}
}
So it will return "java.util.List<String>" for a returnvalue of "list<string>".
The problem arises for calls like this:
operation e(parameter l : list<integer>){
}
main {
variable listInt : list<integer>;
listInt <-- [1,2,3]; // puts in 1,2,3 in the list
e(listInt);
}
On e the error mentioned above arrises and I'm not sure why.
My guess would be that I need to type the Method and the Parameter for it explictly, is this correct or do I need to change something else to make this work?
If there are any more relevant details I forgot, feel free to ask for them.
Thanks in Advance!