简体   繁体   中英

Pass multiple types as parameter in filter function of Iterable object in Xtend

I am using the DSL generator interface of Xtext in order to generate some models based on my Xtext DSL. This is working fine, but right now I am facing a bit of a problem in writing the generator. I am using the generator to filter out Rules declared in my Xtext DSL. I do this by selecting certain Rules and then convert them in an Iterable object, which I can then use to filter on certain types (see the toIterable.filter() parts in my code below). The code below contains one for loop which itself again contains 3 nested for loops. These nested loops all filter on one specific kind of Method Statement (types that I declared in my DSL). I would like to combine these 3 for loops in one for loop by passing the 3 types as parameters in the filter() method. In this case there would be one nested for loop where the condition would ideally look something like:

for (eachMethodStatement : ifStatement.expression.eAllContents.toIterable.filter(StatementSort1, StatementSort2, StatementSort3)

The problem is that the filter() method only takes one argument (one type), so right now I have to write three dispatch methods called getDemand which all basically do the same. It works right now, but this forces me to write a lot of boilerplate code for each type that I want to filter.

Is there a way to filter multiple types (in one for loop) without creating a lot of boilerplate code?

for (ifStatement : ifElseStatement.eAllContents.toIterable.filter(IfStatements)){
    for (persistenceFunction : ifStatement.expression.eAllContents.toIterable.filter(SingleLibraryPersistenceMethodStatement)) {
            expressionDemand += getDemand(persistenceFunction,resourceTable)                            
        }
    for (interfaceFunction : ifStatement.expression.eAllContents.toIterable.filter(SingleLibraryInterFaceMethodStatement)) {                    
            expressionDemand += getDemand(interfaceFunction,resourceTable)                          
        }
    for (businessFunction : ifStatement.expression.eAllContents.toIterable.filter(SingleLibraryBusinessMethodStatement)) {                  
            expressionDemand += getDemand(businessFunction,resourceTable)
        }
    for (persistenceFunction : ifStatement.expression.eAllContents.toIterable.filter(RelationalOperator)) {
            expressionDemand += getDemand(persistenceFunction,resourceTable)                            
        }
}

<T> T filter(Class<T>) cannot do multiple types because then the return type could not be T but - in the extreme case Object which must be cast later.

But: If your four types ( SingleLibraryPersistenceMethodStatement , SingleLibraryInterFaceMethodStatement , SingleLibraryBusinessMethodStatement , RelationalOperator ) share a specific interface or supertype you can used that with the existing filter() method:

for (ifStatement : ifElseStatement.eAllContents.toIterable.filter(IfStatements)){
    for (statement : ifStatement.expression.eAllContents.toIterable.filter(Statement)) {
            expressionDemand += getDemand(statement,resourceTable)                          
    }
}
def Demand getDemand(Statement statement, ResourceTable resourceTable){
    ...
}

Another solution is to avoid filter in this case and use switch with type guards like this:

for (ifStatement : ifElseStatement.eAllContents.toIterable.filter(IfStatements)){
    for (it : ifStatement.expression.eAllContents) {
        switch(it){
            SingleLibraryPersistenceMethodStatement,
            SingleLibraryPersistenceMethodStatement,
            SingleLibraryBusinessMethodStatement:
                 expressionDemand += getDemand(it,resourceTable)
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM