A type checking constraint verifies that related DSL content has types that make sense together. In its simplest form, it requires equality: an attribute and the attribute it references must have the same type. A violation becomes an issue shown to the domain expert before inconsistent content reaches generated Runtime code. section 9.3.3 section 9.4
Types describe domain-specific value ranges and meanings. For example, amount and percentage may both be represented as JavaScript numbers, yet a dollar amount is not interchangeable with a percentage; date ranges represent a different kind of value altogether. Type checking preserves these distinctions in DSL content. section 13.0
Implement a type checking constraint by:
- Computing the type of each relevant expression or attribute, including direct subexpressions where needed. section 13.4
- Comparing the computed types against the equality or compatibility rule required by the construct. section 13.0
- Reporting a precise issue that names the incompatible parts and their computed types, so the DSL content can be repaired. section 13.2
- Producing a sensible best-effort type, or an untype when necessary, to avoid obscuring the root problem with cascading mismatches. section 13.4
Checking an attribute value
An Attribute can compare its own computed type with the computed type of its value. This generalizes an earlier reference-only check: instead of assuming that an Attribute Reference is directly nested in an Attribute, it works for any expression used as the value. If the types differ, the issue states both types. section 13.2 section 9.3.3
Binary operations need constraints tailored to their operators. A subtraction check can require both operands to have number types such as amount or percentage, reporting a separate issue for each operand that fails the requirement. Other expression constructs similarly check whether their combination of subexpression types is meaningful. section 13.2 section 13.4
Listing 13.6 Type checking the value of an Attribute
case "Attribute": {
// ...code that checks existing constraints...
if (isAstObject(settings["value"])) {
const typeOfAttribute =
typeOf(astObject, ancestors) #1
const typeOfValue = #2
typeOf(settings["value"], [ astObject, ...ancestors ])
if (typeOfAttribute !== typeOfValue) { #3
issues.push(
`The types of this attribute and its value must match, #4
but they are: '${typeOfAttribute}', resp., '${typeOfValue}'`)
}
}
}
This implementation computes types for an Attribute and its value with the proper ancestor context, then emits an issue when they differ. section 13.2
