cddl

Properties

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.

Property Definition

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:

Property Names

Property 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:

  1. Unnamed elements in arrays
  2. Group composition (including one group within another)

Occurrence Definition

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:

Cut Marker

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": []
}

Property Types

The Type field can contain various types of values:

  1. A string representing a primitive type:
    "Type": ["tstr"]
    
  2. A reference to a named type:
    "Type": [
      {
        "Type": "group",
        "Value": "address",
        "Unwrapped": false
      }
    ]
    
  3. An array of alternative types (choices):
    "Type": ["tstr", "uint"]
    
  4. A literal value:
    "Type": [
      {
        "Type": "literal",
        "Value": "active",
        "Unwrapped": false
      }
    ]
    
  5. A nested structure (group or array):
    "Type": [
      {
        "Type": "group",
        "Name": "",
        "Properties": [...],
        "Comments": []
      }
    ]
    

Property Examples

Basic Property

person = {
    name: tstr,
    age: uint
}

AST representation of the “name” property:

{
  "HasCut": true,
  "Occurrence": { "n": 1, "m": 1 },
  "Name": "name",
  "Type": ["tstr"],
  "Comments": []
}

Optional Property

person = {
    name: tstr,
    ?email: tstr
}

AST representation of the “email” property:

{
  "HasCut": true,
  "Occurrence": { "n": 0, "m": Infinity },
  "Name": "email",
  "Type": ["tstr"],
  "Comments": []
}

Property with Occurrence Indicator

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": []
}

Property with 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
    }
  ]
}

Property with Choice of Types

person = {
    id: uint / tstr
}

AST representation:

{
  "HasCut": true,
  "Occurrence": { "n": 1, "m": 1 },
  "Name": "id",
  "Type": ["uint", "tstr"],
  "Comments": []
}

Property with Default Value

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": []
}

Group Member Properties vs. Array Element Properties

Properties are used in both groups and arrays, but their interpretation differs slightly:

  1. In groups, properties typically have names (except for group composition cases)
  2. In arrays, elements can be named or unnamed and can have occurrence indicators

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.