Skip to main content

synta_codegen/
ast.rs

1//! Abstract Syntax Tree for ASN.1 schemas
2
3use std::fmt;
4
5/// Tagging mode for ASN.1 module
6#[derive(Debug, Clone, PartialEq)]
7pub enum TaggingMode {
8    /// EXPLICIT TAGS (default per X.680)
9    Explicit,
10    /// IMPLICIT TAGS
11    Implicit,
12    /// AUTOMATIC TAGS
13    Automatic,
14}
15
16/// An ASN.1 module definition
17#[derive(Debug, Clone, PartialEq)]
18pub struct Module {
19    pub name: String,
20    /// Optional module OID (e.g., {iso(1) identified-organization(3) ...})
21    pub oid: Option<Vec<String>>,
22    /// Tagging mode (defaults to EXPLICIT if not specified)
23    pub tagging_mode: Option<TaggingMode>,
24    pub imports: Vec<Import>,
25    pub exports: Vec<String>,
26    pub definitions: Vec<Definition>,
27    pub values: Vec<ValueAssignment>,
28}
29
30/// Import declaration (IMPORTS ... FROM ModuleName)
31#[derive(Debug, Clone, PartialEq)]
32pub struct Import {
33    /// Types imported from a module
34    pub symbols: Vec<String>,
35    /// Module name to import from
36    pub module_name: String,
37}
38
39/// A type definition within a module
40#[derive(Debug, Clone, PartialEq)]
41pub struct Definition {
42    pub name: String,
43    pub ty: Type,
44}
45
46/// A value assignment within a module (e.g., oidName OBJECT IDENTIFIER ::= { 1 2 3 })
47#[derive(Debug, Clone, PartialEq)]
48pub struct ValueAssignment {
49    pub name: String,
50    pub ty: Type,
51    pub value: Value,
52}
53
54/// ASN.1 value
55#[derive(Debug, Clone, PartialEq)]
56pub enum Value {
57    /// Object identifier value (e.g., { 1 2 3 } or { parent 4 })
58    ObjectIdentifier(Vec<OidComponent>),
59    /// Integer value
60    Integer(i64),
61    /// Boolean value
62    Boolean(bool),
63    /// String value
64    String(String),
65}
66
67/// Component of an object identifier value
68#[derive(Debug, Clone, PartialEq)]
69pub enum OidComponent {
70    /// Numeric component (e.g., 1, 2, 3)
71    Number(u32),
72    /// Named reference to another OID (e.g., id-ce in { id-ce 19 })
73    NamedRef(String),
74}
75
76/// Named number for INTEGER types (e.g., tcp(6) in INTEGER {tcp(6), udp(17)})
77#[derive(Debug, Clone, PartialEq)]
78pub struct NamedNumber {
79    pub name: String,
80    pub value: i64,
81}
82
83/// A field in an ASN.1 Information Object Class (X.681 §9)
84///
85/// Class fields use `&`-prefixed names (e.g., `&id`, `&Value`).
86/// They are meta-schema constructs and have no direct DER encoding.
87#[derive(Debug, Clone, PartialEq)]
88pub struct ClassField {
89    /// Field name without the leading `&` (e.g., `"id"`, `"Value"`)
90    pub name: String,
91    /// Whether the field has the `UNIQUE` qualifier
92    pub unique: bool,
93    /// Whether the field has the `OPTIONAL` qualifier
94    pub optional: bool,
95}
96
97/// ASN.1 type
98#[derive(Debug, Clone, PartialEq)]
99pub enum Type {
100    /// SEQUENCE type
101    Sequence(Vec<SequenceField>),
102    /// SEQUENCE OF type with optional size constraint (legacy)
103    SequenceOf(Box<Type>, Option<SizeConstraint>),
104    /// SET type
105    Set(Vec<SequenceField>),
106    /// SET OF type with optional size constraint (legacy)
107    SetOf(Box<Type>, Option<SizeConstraint>),
108    /// CHOICE type
109    Choice(Vec<ChoiceVariant>),
110    /// Reference to another type
111    TypeRef(String),
112    /// INTEGER with optional value constraint (legacy) and optional named numbers
113    Integer(Option<ValueConstraint>, Vec<NamedNumber>),
114    /// ENUMERATED with named values
115    Enumerated(Vec<NamedNumber>),
116    /// REAL (floating-point number)
117    Real,
118    /// BOOLEAN
119    Boolean,
120    /// OCTET STRING with optional size constraint (legacy)
121    OctetString(Option<SizeConstraint>),
122    /// BIT STRING with optional size constraint (legacy)
123    BitString(Option<SizeConstraint>),
124    /// OBJECT IDENTIFIER
125    ObjectIdentifier,
126    /// NULL
127    Null,
128    /// UTF8String with optional size constraint (legacy)
129    Utf8String(Option<SizeConstraint>),
130    /// PrintableString with optional size constraint (legacy)
131    PrintableString(Option<SizeConstraint>),
132    /// IA5String with optional size constraint (legacy)
133    IA5String(Option<SizeConstraint>),
134    /// TeletexString (also known as T61String) with optional size constraint
135    TeletexString(Option<SizeConstraint>),
136    /// UniversalString with optional size constraint
137    UniversalString(Option<SizeConstraint>),
138    /// BMPString (Basic Multilingual Plane) with optional size constraint
139    BmpString(Option<SizeConstraint>),
140    /// GeneralString with optional size constraint
141    GeneralString(Option<SizeConstraint>),
142    /// NumericString with optional size constraint
143    NumericString(Option<SizeConstraint>),
144    /// VisibleString with optional size constraint
145    VisibleString(Option<SizeConstraint>),
146    /// UTCTime
147    UtcTime,
148    /// GeneralizedTime
149    GeneralizedTime,
150    /// Tagged type
151    Tagged { tag: TagInfo, inner: Box<Type> },
152    /// Constrained type (X.680 compliant)
153    Constrained {
154        base_type: Box<Type>,
155        constraint: Constraint,
156    },
157    /// ANY type (legacy ASN.1, used for extensibility)
158    Any,
159    /// ANY DEFINED BY field (legacy ASN.1, value depends on another field)
160    AnyDefinedBy(String),
161    /// ASN.1 Information Object Class definition (X.681 §9)
162    ///
163    /// `NAME ::= CLASS { &field TYPE [UNIQUE] [OPTIONAL], ... } [WITH SYNTAX { ... }]`
164    ///
165    /// Classes are meta-schema constructs used to constrain parameterized types.
166    /// They have no DER encoding and generate only a documentation comment in Rust.
167    Class(Vec<ClassField>),
168}
169
170/// Constraint specification (X.680 compliant)
171#[derive(Debug, Clone, PartialEq)]
172pub struct Constraint {
173    pub spec: ConstraintSpec,
174    pub exception: Option<ExceptionSpec>,
175}
176
177/// Constraint specification type
178#[derive(Debug, Clone, PartialEq)]
179pub enum ConstraintSpec {
180    /// Subtype constraint (value ranges, size, alphabet, etc.)
181    Subtype(SubtypeConstraint),
182    /// General constraint (table constraints, user-defined)
183    General(GeneralConstraint),
184}
185
186/// Subtype constraint (X.680 Section 51)
187#[derive(Debug, Clone, PartialEq)]
188pub enum SubtypeConstraint {
189    /// Single value: INTEGER (42)
190    SingleValue(ConstraintValue),
191
192    /// Value range: INTEGER (0..100), INTEGER (MIN..100)
193    ValueRange {
194        min: ConstraintValue,
195        max: ConstraintValue,
196    },
197
198    /// Size constraint: OCTET STRING (SIZE (1..64))
199    SizeConstraint(Box<SubtypeConstraint>),
200
201    /// Permitted alphabet: IA5String (FROM ("A".."Z"))
202    PermittedAlphabet(Vec<CharRange>),
203
204    /// Pattern: IA5String (PATTERN "[0-9]+")
205    Pattern(String),
206
207    /// Contained subtype: OCTET STRING (CONTAINING INTEGER)
208    ContainedSubtype(Box<Type>),
209
210    /// Inner type constraint: SEQUENCE OF INTEGER (1..100)
211    InnerType(Box<SubtypeConstraint>),
212
213    /// Union: (constraint1 | constraint2)
214    Union(Vec<SubtypeConstraint>),
215
216    /// Intersection: (constraint1 ^ constraint2)
217    Intersection(Vec<SubtypeConstraint>),
218
219    /// Complement: ALL EXCEPT constraint
220    Complement(Box<SubtypeConstraint>),
221
222    /// Named bit list for BIT STRING { flag(0), delegFlag(1), ... }
223    NamedBitList(Vec<NamedNumber>),
224}
225
226/// Constraint value with support for named values and keywords
227#[derive(Debug, Clone, PartialEq)]
228pub enum ConstraintValue {
229    /// Integer literal
230    Integer(i64),
231    /// Named value reference (e.g., tcp in INTEGER {tcp(6), udp(17)})
232    NamedValue(String),
233    /// MIN keyword
234    Min,
235    /// MAX keyword
236    Max,
237}
238
239/// Character range for alphabet constraints
240#[derive(Debug, Clone, PartialEq)]
241pub struct CharRange {
242    pub min: char,
243    pub max: char,
244}
245
246/// General constraints (X.680 Section 52)
247#[derive(Debug, Clone, PartialEq)]
248pub enum GeneralConstraint {
249    /// Component relation constraint (table constraint)
250    ComponentRelation {
251        object_set: String,
252        component_refs: Vec<String>,
253    },
254    /// User-defined constraint
255    UserDefined(String),
256}
257
258/// Exception specification
259#[derive(Debug, Clone, PartialEq)]
260pub enum ExceptionSpec {
261    /// Exception identifier
262    Identifier(String),
263    /// Exception value
264    Value(ConstraintValue),
265}
266
267// Legacy constraint types for backward compatibility during migration
268/// Value constraint for INTEGER types (DEPRECATED - use Constraint)
269#[derive(Debug, Clone, PartialEq)]
270pub enum ValueConstraint {
271    /// Single value
272    Single(i64),
273    /// Range (min..max)
274    Range(Option<i64>, Option<i64>),
275}
276
277/// Size constraint for strings and sequences (DEPRECATED - use Constraint)
278#[derive(Debug, Clone, PartialEq)]
279pub enum SizeConstraint {
280    /// Fixed size
281    Fixed(u64),
282    /// Range (min..max)
283    Range(Option<u64>, Option<u64>),
284}
285
286/// Field in a SEQUENCE or SET
287#[derive(Debug, Clone, PartialEq)]
288pub struct SequenceField {
289    pub name: String,
290    pub ty: Type,
291    pub optional: bool,
292    pub default: Option<String>,
293}
294
295/// Variant in a CHOICE
296#[derive(Debug, Clone, PartialEq)]
297pub struct ChoiceVariant {
298    pub name: String,
299    pub ty: Type,
300}
301
302/// Tag information
303#[derive(Debug, Clone, PartialEq)]
304pub struct TagInfo {
305    pub class: TagClass,
306    pub number: u32,
307    pub tagging: Tagging,
308}
309
310/// Tag class
311#[derive(Debug, Clone, PartialEq)]
312pub enum TagClass {
313    Universal,
314    Application,
315    ContextSpecific,
316    Private,
317}
318
319/// Tagging mode
320#[derive(Debug, Clone, PartialEq)]
321pub enum Tagging {
322    Explicit,
323    Implicit,
324}
325
326impl fmt::Display for Type {
327    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
328        match self {
329            Type::Sequence(_) => write!(f, "SEQUENCE"),
330            Type::SequenceOf(inner, _) => write!(f, "SEQUENCE OF {}", inner),
331            Type::Set(_) => write!(f, "SET"),
332            Type::SetOf(inner, _) => write!(f, "SET OF {}", inner),
333            Type::Choice(_) => write!(f, "CHOICE"),
334            Type::TypeRef(name) => write!(f, "{}", name),
335            Type::Integer(_, _) => write!(f, "INTEGER"),
336            Type::Enumerated(_) => write!(f, "ENUMERATED"),
337            Type::Real => write!(f, "REAL"),
338            Type::Boolean => write!(f, "BOOLEAN"),
339            Type::OctetString(_) => write!(f, "OCTET STRING"),
340            Type::BitString(_) => write!(f, "BIT STRING"),
341            Type::ObjectIdentifier => write!(f, "OBJECT IDENTIFIER"),
342            Type::Null => write!(f, "NULL"),
343            Type::Utf8String(_) => write!(f, "UTF8String"),
344            Type::PrintableString(_) => write!(f, "PrintableString"),
345            Type::IA5String(_) => write!(f, "IA5String"),
346            Type::TeletexString(_) => write!(f, "TeletexString"),
347            Type::UniversalString(_) => write!(f, "UniversalString"),
348            Type::BmpString(_) => write!(f, "BMPString"),
349            Type::GeneralString(_) => write!(f, "GeneralString"),
350            Type::NumericString(_) => write!(f, "NumericString"),
351            Type::VisibleString(_) => write!(f, "VisibleString"),
352            Type::UtcTime => write!(f, "UTCTime"),
353            Type::GeneralizedTime => write!(f, "GeneralizedTime"),
354            Type::Tagged { tag, inner } => {
355                write!(f, "[{}] {:?} {}", tag.number, tag.tagging, inner)
356            }
357            Type::Constrained { base_type, .. } => {
358                write!(f, "{} (constrained)", base_type)
359            }
360            Type::Any => write!(f, "ANY"),
361            Type::AnyDefinedBy(field) => write!(f, "ANY DEFINED BY {}", field),
362            Type::Class(fields) => {
363                write!(f, "CLASS {{ ")?;
364                for (i, field) in fields.iter().enumerate() {
365                    if i > 0 {
366                        write!(f, ", ")?;
367                    }
368                    write!(f, "&{}", field.name)?;
369                    if field.unique {
370                        write!(f, " UNIQUE")?;
371                    }
372                    if field.optional {
373                        write!(f, " OPTIONAL")?;
374                    }
375                }
376                write!(f, " }}")
377            }
378        }
379    }
380}