Type Resolution within XBlockExpression [message #1753499] |
Tue, 07 February 2017 04:29  |
Eclipse User |
|
|
|
I have a question on type resolution within XBlockExpression.
I asked before, using modified Domainmodel example, about two kinds of Property type (JvmTypeReference and CrossReference). Using example Domainmodel similarly:
Modified part of domainmodel grammar:
...
Property:
PropertyTypeA | PropertyTypeB;
PropertyTypeA:
'type_a' name=ValidID ':' type=JvmTypeReference;
PropertyTypeB:
'type_b' name=ValidID ':' type=[Entity|ValidID];
...
I also made modifications on IJvmModelInferrer and IFormatter. Created example model is as follows.
package demo {
entity Company {
type_a name : String
}
entity Person {
type_a name : String
type_b worksfor : Company
op init(String name, Company abc){
this.name = name
this.worksfor = abc
}
}
}
I see an error message in "this.worksfor = abc" section (red underline for "works for"), saying "The field Person.worksfor refers to the missing type Company." If I delete the operation section, error goes away and code is generated as expected. It seems within operation (XBlockExpression) section type resolution seems somehow limited or restricted. Is this related to "initializelater"? I would appreciate any advice you may have. Thank you very much in advance.
Akira
|
|
|
|
Re: Type Resolution within XBlockExpression [message #1753506 is a reply to message #1753505] |
Tue, 07 February 2017 05:31   |
Eclipse User |
|
|
|
Thank you for the response. Here are the files.
Grammar:
/*******************************************************************************
* Copyright (c) 2009 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
grammar org.eclipse.xtext.example.domainmodel.Domainmodel with org.eclipse.xtext.xbase.Xbase
generate domainmodel "http://www.xtext.org/example/Domainmodel"
DomainModel:
importSection=XImportSection?
elements+=AbstractElement*;
AbstractElement:
PackageDeclaration | Entity;
PackageDeclaration:
'package' name=QualifiedName '{'
elements+=AbstractElement*
'}';
Entity:
'entity' name=ValidID ('extends' superType=JvmParameterizedTypeReference)? '{'
features+=Feature*
'}';
Feature:
Property | Operation;
Property:
PropertyTypeA | PropertyTypeB;
PropertyTypeA:
'type_a' name=ValidID ':' type=JvmTypeReference;
PropertyTypeB:
'type_b' name=ValidID ':' type=[Entity|ValidID];
Operation:
'op' name=ValidID '(' (params+=FullJvmFormalParameter (',' params+=FullJvmFormalParameter)*)? ')' (':' type=JvmTypeReference)?
body=XBlockExpression;
Inferrer
package org.eclipse.xtext.example.domainmodel.jvmmodel
import com.google.inject.Inject
import org.eclipse.xtext.example.domainmodel.domainmodel.Entity
import org.eclipse.xtext.example.domainmodel.domainmodel.Operation
import org.eclipse.xtext.example.domainmodel.domainmodel.Property
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.eclipse.xtext.xbase.lib.Procedures.Procedure1
import org.eclipse.xtext.example.domainmodel.domainmodel.PropertyTypeA
import org.eclipse.xtext.example.domainmodel.domainmodel.PropertyTypeB
class DomainmodelJvmModelInferrer extends AbstractModelInferrer {
@Inject extension JvmTypesBuilder
@Inject extension IQualifiedNameProvider
def dispatch infer(Entity entity, extension IJvmDeclaredTypeAcceptor acceptor, boolean prelinkingPhase) {
accept(entity.toClass( entity.fullyQualifiedName )).initializeLater [
documentation = entity.documentation
if (entity.superType != null)
superTypes += entity.superType.cloneWithProxies
// let's add a default constructor
members += entity.toConstructor []
// and one which can be called with a lambda for initialization.
val procedureType = typeRef(Procedure1, typeRef(it)) /* Procedure<MyEntity> */
members += entity.toConstructor [
parameters += entity.toParameter("initializer", procedureType)
// here we implement the body using black box Java code.
body = '''
initializer.apply(this);
'''
]
// now let's go over the features
for ( f : entity.features ) {
switch f {
// for properties we create a field, a getter and a setter
Property : {
if (f instanceof PropertyTypeA) {
members += f.toField(f.name, f.type)
members += f.toGetter(f.name, f.type)
members += f.toSetter(f.name, f.type)
}
else if (f instanceof PropertyTypeB) {
val String name = f.type?.name
members += f.toField(f.name, name.typeRef)
members += f.toGetter(f.name, name.typeRef)
members += f.toSetter(f.name, name.typeRef)
}
}
// operations are mapped to methods
Operation : {
members += f.toMethod(f.name, f.type ?: inferredType) [
documentation = f.documentation
for (p : f.params) {
parameters += p.toParameter(p.name, p.parameterType)
}
// here the body is implemented using a user expression.
// Note that by doing this we set the expression into the context of this method,
// The parameters, 'this' and all the members of this method will be visible for the expression.
body = f.body
]
}
}
}
// finally we want to have a nice toString methods.
members += entity.toToStringMethod(it)
]
}
}
test model
package demo {
entity Company {
type_a name : String
}
entity Person {
type_a name : String
type_b worksfor : Company
op init(String name, Company abc){
this.name = name
this.worksfor = abc
}
}
}
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.26323 seconds