2.5 KiB
parser
Purpose
CDDL parser per RFC 8610 §3 grammar. Consumes the token stream from the
tokenize function and produces a typed AST (CddlAst) that the validator
walks. Supports the working subset of CDDL needed by real consumers (CWT,
COSE_Sign1, WebAuthn attestation, vault manifests, drive templates).
Features
- Rule definitions:
name = T,name<T> = ...(generic params). - Type expressions: primitive prelude, named references, generic instantiation.
- Type composition: choice (
/), inclusive (..) + exclusive (...) ranges, parenthesised grouping. - Group composition: arrays (
[ ... ]), maps ({ ... }), occurrence indicators (?,*,+,*N,M*N,M*), group choice (//). - Map keys: identifier-
:-T (text key),"quoted":T (text key with quoted syntax),<int> => T(numeric key),"quoted" => T. - Tagged items:
#6.<tag>(T)produces{ kind: "tagged", tag, inner }. - Literal values: text strings, byte strings (
h'…'), integers (positive and negative),true/false,null/nil,undefined. - Control operators applied to types:
tstr .size 1..32,tstr .regexp "pattern",bstr .cbor T. Both literal and range right-hand sides supported on.size.
Usage: Basic Example
import { parseCddl } from "@suaveplan/cbor/cddl";
const ast = parseCddl(`
cwt = { iss: tstr, ? exp: int }
`);
Usage: Advanced Example
import { parseCddl } from "@suaveplan/cbor/cddl";
const ast = parseCddl(`
attested-key = #6.18(cose-sign1)
cose-sign1 = [ protected: bstr, unprotected: { * any => any }, payload: bstr / nil, signature: bstr ]
protected = bstr .size 0..1024
pair<K, V> = [ K, V ]
`);
API Reference
parseCddl(source: string): CddlAst
Throws CborError(CDDL_PARSE_FAILED) with { line, col } for: empty
source (no rules), missing =, unexpected token, non-integer range bound,
#N with N != 6.
Implementation Notes
The parser is a hand-written recursive descent. Operator precedence mirrors RFC 8610 §3:
type(top): handles/choicetype1: handles../...ranges and control operators (.size,.regexp, etc.); the.sizecase can take a range right-hand sidetype2(atom): primitives, references, literals, parenthesised groups, arrays, maps, tagged items
Group choice (//) is implemented at the [/{ body level — when the
parser encounters // between two sets of entries, it returns a
{ kind: "choice", alternatives: [arrayA, arrayB] } so the validator
can short-circuit on the first matching alternative.