Properties are a fundamental component of CDDL that define the members of groups and elements of arrays. This document explains how properties are represented in the AST.
In the AST, a property is represented by the following structure:
export type Property = {
HasCut: boolean
Occurrence: Occurrence
Name: PropertyName
Type: PropertyType | PropertyType[]
Comments: Comment[]
Operator?: Operator
}
Where:
HasCut
: A boolean indicating if the property has a “cut” marker (/)Occurrence
: An object defining how many times the property can occurName
: The name of the property (string)Type
: The type(s) of the propertyComments
: An array of comments associated with the propertyOperator
: An optional operator modifying the propertyProperty names are simple strings that identify the property within a group or array. A property can also have an empty name (""
), which is used for:
The occurrence of a property defines how many times it can appear. It is represented by:
export type Occurrence = {
n: number // Minimum occurrence
m: number // Maximum occurrence
}
Common occurrence patterns:
{ n: 1, m: 1 }
: Exactly one time (default){ n: 0, m: Infinity }
: Zero or more times (*
){ n: 1, m: Infinity }
: One or more times (+
){ n: 0, m: 1 }
: Zero or one time (?
){ n: a, m: b }
: At least a
and at most b
times (a*b
)The HasCut
field indicates whether the property has a cut marker (/
) in CDDL. In CDDL syntax, a cut marker indicates that the property should be matched exactly once, even if the property appears later in an extended group.
Example in CDDL:
person = {
name: tstr,
/ age: uint,
}
AST representation:
{
"HasCut": true,
"Occurrence": { "n": 1, "m": 1 },
"Name": "age",
"Type": ["uint"],
"Comments": []
}
The Type
field can contain various types of values:
"Type": ["tstr"]
"Type": [
{
"Type": "group",
"Value": "address",
"Unwrapped": false
}
]
"Type": ["tstr", "uint"]
"Type": [
{
"Type": "literal",
"Value": "active",
"Unwrapped": false
}
]
"Type": [
{
"Type": "group",
"Name": "",
"Properties": [...],
"Comments": []
}
]
person = {
name: tstr,
age: uint
}
AST representation of the “name” property:
{
"HasCut": true,
"Occurrence": { "n": 1, "m": 1 },
"Name": "name",
"Type": ["tstr"],
"Comments": []
}
person = {
name: tstr,
?email: tstr
}
AST representation of the “email” property:
{
"HasCut": true,
"Occurrence": { "n": 0, "m": Infinity },
"Name": "email",
"Type": ["tstr"],
"Comments": []
}
someGroup = {
optional: tstr ?, ; zero or more
anotherOptional: tstr *, ; zero or more
atLeastOne: tstr +, ; one or more
numberedOccurence: tstr 23*42, ; between 23 and 42
withoutLeftSide: tstr *42, ; at most 42
withoutRightSide: tstr 23* ; at least 23
}
AST representation of “numberedOccurence”:
{
"HasCut": true,
"Occurrence": { "n": 23, "m": 42 },
"Name": "numberedOccurence",
"Type": ["tstr"],
"Comments": []
}
person = {
; a good employer
employer: tstr
}
AST representation:
{
"HasCut": true,
"Occurrence": { "n": 1, "m": 1 },
"Name": "employer",
"Type": ["tstr"],
"Comments": [
{
"Type": "comment",
"Content": "a good employer",
"Leading": false
}
]
}
person = {
id: uint / tstr
}
AST representation:
{
"HasCut": true,
"Occurrence": { "n": 1, "m": 1 },
"Name": "id",
"Type": ["uint", "tstr"],
"Comments": []
}
someGroup = {
optional: tstr .default "foobar" ?,
orientation: ("portrait" / "landscape") .default "portrait" ?,
scale: (0.1..2) .default 1 ?,
shrinkToFit: bool .default true ?
}
AST representation of “optional”:
{
"HasCut": true,
"Occurrence": { "n": 0, "m": Infinity },
"Name": "optional",
"Type": [
{
"Type": "tstr",
"Operator": {
"Type": "default",
"Value": {
"Type": "literal",
"Value": "foobar",
"Unwrapped": false
}
}
}
],
"Comments": []
}
AST representation of “orientation”:
{
"HasCut": true,
"Occurrence": { "n": 0, "m": Infinity },
"Name": "orientation",
"Type": [
{
"Type": "literal",
"Value": "portrait",
"Unwrapped": false
},
{
"Type": "literal",
"Value": "landscape",
"Unwrapped": false
}
],
"Operator": {
"Type": "default",
"Value": {
"Type": "literal",
"Value": "portrait",
"Unwrapped": false
}
},
"Comments": []
}
Properties are used in both groups and arrays, but their interpretation differs slightly:
Array element example:
Geography = [
city: tstr,
* float
]
AST representation of the unnamed element:
{
"HasCut": false,
"Occurrence": { "n": 0, "m": Infinity },
"Name": "",
"Type": ["float"],
"Comments": []
}
By understanding these different property representations in the AST, you can properly interpret and process CDDL property definitions for further transformation or analysis.