extending the xbase typesystem
TRANSCRIPT
Extending the Xbase TypesystemSebastian Zarnekow
Understanding the Xbase TS
LazyLinking vs BatchLinking
IBatchTypeResolverCancelable Type Resolution for a Resource
Returns IResolvedTypes
Type for each JvmIdentifiableElement (Local Var, Param, ..)
Resolved Generics
For each XExpression:
Actual Type and Expected Type
Return Type and Expected Return Type
Actual Type vs Return Type
Type: What would ‘Extract Local Var’ do? == boolean
Return Type: What would ‘Extract Method’ yield? == void
{ if (!isValid(value)) return; hashSet.add(value);}
LightweightTypeReference
LightweightTypeReference
Solve the EMF Dilemma
Rich API
getSuperTypes, getTypeArguments, isAssignableFrom, …
Context and Service Access via getOwner()
Lossless conversion from/to JvmTypeReference
ITypeReferenceOwner
Provides Context: Current ResourceSet
Provides CommonTypeComputationServices
Factory API to Create Valid Type References
Facade for Clients
Find Relevant Root Elements in Resource
Traverse Root Instance Tree
Guard Against Infinite Recursion
Prepare and Compute
Traverse Expression Trees
First Candidate for Customizing
IBatchTypeResolver
IReentrantTypeResolver
ITypeComputer
IBatchTypeResolver
IBatchTypeResolver
IReentrantTypeResolver
ITypeComputer
BatchLinkableResource
IJvmModelInferrer
InferredTypeIndicator
<<installs>> <<detects>>
<<initialized by>>
XbaseTypeComputer
computeTypes(XExpression, ITypeComputationState)
MyDslTypeComputer
Called by the Framework
Never Invoke computeTypes(..) Manually
Implements Default XExpression Typing
Dispatches for given XExpression
Optional Customization
Required for New Expressions
ITypeComputer
ITypeComputercomputeTypes(XExpression, ITypeComputationState)
ITypeComputationState
computeTypes(XExpression): ITypeComputationResult withExpectation(LightweightTypeReference): ITCState
getExpectations(): List<ITypeExpectation> acceptActualType(LightweightTypeReference, Hints)
assignTypes(..): ITypeComputationState
ITypeExpectation ITypeComputationResult
<<yields>>
<<calls>>
<<uses>>
<<creates>>
<<influences>>
<<calls>>
<<uses>>
Type System Invariants
All Expressions Must be Visited
All InferredTypes Must be Resolved
JvmMember Signatures Must be Complete
Explicit Tree TraversalNo eAllContents.forEach in Framework Code
Cookbook: Extending the Xbase TS
DateLiteral
DateLiteral returns xbase::XExpression: day=INT ’.’ month=INT ’.’ year=INT;
DateLiteral
Use java.util.Date (at your own risk)
DateLiteral
class MyDslTypeComputer extends XbaseTypeComputer { def dispatch computeTypes(DateLiteral date, ITCState s) { s.acceptActualType(getTypeForName(j.u.Date, s)) } }
DateLiteral
Support Different Date Implementations
Exploit Type Expectation
def dispatch computeTypes(DateLiteral date, ITCState s) { for(e: s.expectations) e.acceptActualType(getTypeForName(switch it: e.expectedType { case it === null: java.util.Date // no expected type given case isType(java.sql.Date): java.sql.Date case isType(LocalDate): LocalDate // fancy Java8 impl default: java.util.Date // eeek }, s))}
DateLiteral
Validate Literal Values
Validate Expressions
def dispatch computeTypes(DateLiteral date, ITCState s) { if (isInvalid(date.day, date.month, date.year)) { s.addDiagnostic(new EObjectDiagnosticImpl( Severity.ERROR, IssueCodes.INVALID_DATE_LITERAL, ’’’«day».«month».«year» is not a valid date’’’, date, null, -1, Strings.EMPTY_ARRAY)); } ..}
Library TypesGlobally Available Types
XImportSectionNamespaceScopeProvider and IImportsConfiguration
Globally Available Features
ImplicitlyImportedFeatures
Locally Available Features
ITypeComputationState.addImports
Library Typesdef dispatch computeTypes(MyExpression e, ITCState s) { s.addImports [ ITypeImporter it | for(e: s.expectations) { if (isEnum(e.expectedType)) { it.importStatic( e.expectedType.type as JvmEnumerationType) } } ] // see also s.addTypeToStaticImportScope(..) s.computeTypes(e.childExpression)}
Different Qualities of Assignability
Synonyms
Type A is Convertable to Type B
Compiler / Interpreter Need Special Treatment
Native Assignability
Only Reasonable with Custom Interpreter / Runtime
Assignable According to Runtime
Custom Assignability Rules
class MySynonymTypesProvider extends SynonymTypesProvider { @Override def boolean collectCustomSynonymTypes(LightweightTypeReference type, Acceptor acceptor) { if (type.invariantBoundSubstitute.isType(j.t.LocalDate)) { return announceSynonym( getUtilDate(type), ConformanceFlags.DEMAND_CONVERSION, acceptor); } return true; }}
Custom Assignability Rules
Custom Assignability Rules
TypeConformanceComputer
Native Assignability Rules
Uses Custom SynonymTypesProvider
Common SuperType Computation
Usually not Customized
Recap: What to customize if …
JvmModelInferrer
Always
Put XExpression into “some” Context
Mark Types as Inferred
Recap: What to customize if …
XbaseTypeComputer
Newly Introduced Expression
Modified Expression Semantics
Recap: What to customize if …
DefaultReentrantTypeResolver
iff Expressions without JVM Model (Discouraged)
and Expressions not at Root Level
LogicalContainerAwareReentrantTypeResolver
Handle AntLR Error Recovery Situations
Recap: What to customize if …
*ReentrantTypeResolver
Prepare Special Cases of InferredTypeIndicators e.g. InferredType 1:n or 1:0 XExpression
Recap: What to customize if …
DefaultBatchTypeResolver
Non-JVM Model Entry Points on Resource Level
LogicalContainerAwareBatchTypeResolver
Handle AntLR Error Recovery Situations
Usually Not Necessary
Unit Test Utility
@RunWith(XtextSmokeTestRunner) @ProcessedBy( value = TypeSystemSmokeTester, processInParallel = true) @SuiteClasses(ParserTest, ValidationTest) class SmokeTest {}
Q & A