Skip to content

Commit

Permalink
Improve ecore type generation for predefined metamodels
Browse files Browse the repository at this point in the history
  • Loading branch information
dhuebner committed Dec 5, 2022
1 parent 0a17737 commit a933618
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class Xtext2LangiumFragmentTest extends AbstractXtext2LangiumTest {
}

@Test
def void testEcoreGeneration_on() {
def void testEcoreGeneration_on_01() {
'''
Model:
name=ID
Expand Down Expand Up @@ -174,6 +174,38 @@ class Xtext2LangiumFragmentTest extends AbstractXtext2LangiumTest {
''')
}

@Test
def void testEcoreGeneration_on_02() {
'''
Model:
age=Number;
Number returns ecore::EInt:
INT;
terminal INT: ('0'..'9')+;
'''.assertGeneratedLangium('''
grammar FragmentTest
import 'Ecore-types'
entry Model infers Model:
age=Number
;
Number returns EInt:
INT
;
terminal INT returns EString:'0' ..'9' +;
''', [generateEcoreTypes = true])
assertGeneratedFile('Ecore-types.langium', '''
type EInt = number;
type EString = string;
''')
}

@Test
def void testEcoreGeneration_off() {
'''
Expand Down Expand Up @@ -206,4 +238,28 @@ class Xtext2LangiumFragmentTest extends AbstractXtext2LangiumTest {
assertGeneratedFile('Ecore-types.langium', null) // no ecore types generated
}

@Test
def void testEcoreGeneration_off_02() {
'''
Model:
age=Number;
Number returns ecore::EInt:
INT;
terminal INT: ('0'..'9')+;
'''.assertGeneratedLangium('''
grammar FragmentTest
entry Model infers Model:
age=Number
;
Number returns number:
INT
;
terminal INT returns string:'0' ..'9' +;
''', [generateEcoreTypes = false])
assertGeneratedFile('Ecore-types.langium', null)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class TransformationContext {
}

def usedMetamodels() {
return if(!interfaces.isEmpty) interfaces.keySet else types.keySet
return (interfaces.keySet + types.keySet).toSet
}

protected def void doAddType(EClassifier classifier) {
Expand All @@ -42,10 +42,7 @@ class TransformationContext {
classifier.ESuperTypes.forEach [ type |
doAddType(type)
]
classifier.EReferences.forEach [ ref |
doAddType(ref.EReferenceType)
]
classifier.EAttributes.forEach [ attr |
classifier.EStructuralFeatures.filter[!isTransient].forEach [ attr |
doAddType(attr.EType)
]
} else if (classifier instanceof EDataType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import org.eclipse.xtext.EnumLiteralDeclaration
import org.eclipse.xtext.EnumRule
import org.eclipse.xtext.GeneratedMetamodel
import org.eclipse.xtext.Grammar
import org.eclipse.xtext.GrammarUtil
import org.eclipse.xtext.Group
import org.eclipse.xtext.Keyword
import org.eclipse.xtext.LiteralCondition
Expand All @@ -48,6 +47,7 @@ import org.eclipse.xtext.nodemodel.util.NodeModelUtils
import org.eclipse.xtext.xtext.generator.AbstractXtextGeneratorFragment

import static org.eclipse.xtext.XtextPackage.Literals.*
import org.eclipse.emf.ecore.EDataType

class Xtext2LangiumFragment extends AbstractXtextGeneratorFragment {
static val Logger LOG = Logger.getLogger(Xtext2LangiumFragment)
Expand Down Expand Up @@ -152,6 +152,9 @@ class Xtext2LangiumFragment extends AbstractXtextGeneratorFragment {
return feature instanceof EReference && !(feature as EReference).isContainment &&
!feature.EType.isEcoreType // ecore types are handled as primitives
]
val featureType = [EClassifier type|
if(type instanceof EDataType && type.isEcoreType && generateEcoreTypes) type.name.idEscaper else langiumTypeName(type)
]
val isOptional = [ EStructuralFeature feature |
return !feature.isRequired && !feature.isMany && langiumTypeName(feature.EType) != 'boolean'
]
Expand All @@ -163,15 +166,15 @@ class Xtext2LangiumFragment extends AbstractXtextGeneratorFragment {
type «enumLiteralName(type.name.idEscaper, literal.name.idEscaper)» = '«literal.literal»';
«ENDFOR»
«ELSE»
type «type.name.idEscaper» = «langiumTypeName(type)»;
type «type.name.idEscaper» = «if(!type.isEcoreType) 'string' else langiumTypeName(type)»;
«ENDIF»
«ENDFOR»
«FOR _interface : ctx.interfaces.get(metamodel)»
interface «_interface.name.idEscaper»«IF !_interface.ESuperTypes.empty» extends «checkImports.apply(_interface.ESuperTypes).join(', ')[name.idEscaper]»«ENDIF» {
«FOR feature: _interface.EStructuralFeatures.filter[!it.transient]»
«checkImport.apply(feature.EType)»
«feature.name.idEscaper»«IF isOptional.apply(feature)»?«ENDIF»: «IF isReference.apply(feature)»@«ENDIF»«langiumTypeName(feature.EType)»«IF feature.isMany»[]«ENDIF»
«feature.name.idEscaper»«IF isOptional.apply(feature)»?«ENDIF»: «IF isReference.apply(feature)»@«ENDIF»«featureType.apply(feature.EType)»«IF feature.isMany»[]«ENDIF»
«ENDFOR»
}
Expand Down Expand Up @@ -215,12 +218,8 @@ class Xtext2LangiumFragment extends AbstractXtextGeneratorFragment {
ctx.out.append('*')
}

// TODO returns / infers
if (GrammarUtil.isDatatypeRule(rule)) {
ctx.out.append(' returns string')
} else {
handleType(rule.type, ctx)
}
handleType(rule.type, ctx)

ctx.out.append(':')
ctx.out.newLine
ctx.out.append(INDENT)
Expand Down

0 comments on commit a933618

Please sign in to comment.