mon_core/
ast.rs

1use log::error;
2use miette::SourceSpan;
3use std::fmt::{Debug, Display};
4use std::panic::Location;
5
6/// Represents a fully parsed MON document, including the root value and any import statements.
7#[derive(Debug, PartialEq, Clone)]
8pub struct MonDocument {
9    pub root: MonValue,
10    pub imports: Vec<ImportStatement>,
11}
12
13/// Represents a value in a MON document, such as a `string`, `number`, `object`, or `array`...
14/// It also includes metadata like its source position and any associated anchor.
15#[derive(Debug, PartialEq, Clone)]
16pub struct MonValue {
17    pub kind: MonValueKind,
18    pub anchor: Option<String>,
19    pub pos_start: usize,
20    pub pos_end: usize,
21}
22
23impl MonValue {
24    /// Returns the source span of the value, which can be used for error reporting.
25    #[must_use]
26    pub fn get_source_span(&self) -> SourceSpan {
27        SourceSpan::new(self.pos_start.into(), self.pos_end - self.pos_start)
28    }
29}
30
31/// An enum representing the different kinds of values that can exist in a MON document.
32#[derive(Debug, PartialEq, Clone)]
33pub enum MonValueKind {
34    /// A string literal.
35    String(String),
36    /// A floating-point number.
37    Number(f64),
38    /// A boolean value.
39    Boolean(bool),
40    /// A null value.
41    Null,
42    /// An object, containing a vector of `Member`s.
43    Object(Vec<Member>),
44    /// An array, containing a vector of `MonValue`s.
45    Array(Vec<MonValue>),
46    /// An alias to an anchored value.
47    Alias(String),
48    /// An enum variant.
49    EnumValue {
50        enum_name: String,
51        variant_name: String,
52    },
53    /// A spread of an array.
54    ArraySpread(String),
55}
56
57/// Represents a member of a MON object.
58#[derive(Debug, PartialEq, Clone)]
59pub enum Member {
60    /// A key-value pair.
61    Pair(Pair),
62    /// A spread of another object's members.
63    Spread(String),
64    /// An import statement.
65    Import(ImportStatement),
66    /// A type definition (`#struct` or `#enum`).
67    TypeDefinition(TypeDefinition),
68}
69
70/// Represents a key-value pair within a MON object.
71#[derive(Debug, PartialEq, Clone)]
72pub struct Pair {
73    /// The key of the pair.
74    pub key: String,
75    /// The value of the pair.
76    pub value: MonValue,
77    /// An optional type specification used for validation, e.g., `key::String`.
78    ///
79    /// [NOTE] This is lazily generated, check if it exists first
80    pub validation: Option<TypeSpec>,
81}
82
83/// Represents an `import` statement, e.g., `import "path/to/file.mon" as my_namespace;`
84#[derive(Debug, PartialEq, Clone)]
85pub struct ImportStatement {
86    /// The file path to the imported file.
87    pub path: String,
88    /// The specification of what to import (either a namespace or a list of named items).
89    pub spec: ImportSpec,
90    /// The starting character position of this statement in the source text.
91    pub pos_start: usize,
92    /// The ending character position of this statement in the source text.
93    pub pos_end: usize,
94}
95
96/// Defines what is being imported from a file.
97#[derive(Debug, PartialEq, Clone)]
98pub enum ImportSpec {
99    /// Imports the entire file into a single namespace, e.g., `as my_namespace`.
100    Namespace(String),
101    /// Imports specific items (anchors or types) from the file, e.g., `{ MyType, &my_anchor }`.
102    Named(Vec<ImportSpecifier>),
103}
104
105/// Represents a single item being imported by name.
106#[derive(Debug, PartialEq, Clone)]
107pub struct ImportSpecifier {
108    /// The name of the type or anchor to import.
109    pub name: String,
110    /// Whether the imported item is an anchor (e.g., `&my_anchor`).
111    pub is_anchor: bool,
112}
113
114/// Represents a type definition, either a `#struct` or an `#enum`.
115#[derive(Debug, PartialEq, Clone)]
116pub struct TypeDefinition {
117    /// The name of the type being defined.
118    pub name: String,
119    /// The source span of the type's name.
120    pub name_span: SourceSpan,
121    /// The actual definition of the type.
122    pub def_type: TypeDef,
123    /// The starting character position of this definition in the source text.
124    pub pos_start: usize,
125    /// The ending character position of this definition in the source text.
126    pub pos_end: usize,
127}
128
129/// An enum that holds either a struct or an enum definition.
130#[derive(Debug, PartialEq, Clone)]
131pub enum TypeDef {
132    /// A struct definition.
133    Struct(StructDef),
134    /// An enum definition.
135    Enum(EnumDef),
136}
137
138impl TypeDef {
139    /// Returns the source span of the entire type definition.
140    #[must_use]
141    pub fn get_span(&self) -> SourceSpan {
142        match self {
143            TypeDef::Struct(s) => (s.pos_start, s.pos_end - s.pos_start).into(),
144            TypeDef::Enum(e) => (e.pos_start, e.pos_end - e.pos_start).into(),
145        }
146    }
147}
148
149/// Represents a `#struct` definition.
150#[derive(Debug, PartialEq, Clone)]
151pub struct StructDef {
152    /// The fields that make up the struct.
153    pub fields: Vec<FieldDef>,
154    /// The starting character position of this struct definition in the source text.
155    pub pos_start: usize,
156    /// The ending character position of this struct definition in the source text.
157    pub pos_end: usize,
158}
159
160/// Represents a single field within a `#struct` definition.
161#[derive(Debug, PartialEq, Clone)]
162pub struct FieldDef {
163    /// The name of the field.
164    pub name: String,
165    /// The type specification for this field.
166    pub type_spec: TypeSpec,
167    /// An optional default value for this field.
168    pub default_value: Option<MonValue>,
169}
170
171/// Represents an `#enum` definition.
172#[derive(Debug, PartialEq, Clone)]
173pub struct EnumDef {
174    /// The variants of the enum.
175    pub variants: Vec<String>,
176    /// The starting character position of this enum definition in the source text.
177    pub pos_start: usize,
178    /// The ending character position of this enum definition in the source text.
179    pub pos_end: usize,
180}
181
182/// Represents a type specification used for validation, e.g., `:: String` or `:: [Number, String]`.
183#[derive(Debug, PartialEq, Clone)]
184pub enum TypeSpec {
185    /// A simple type, e.g., `String`, `MyStruct`.
186    Simple(String, SourceSpan),
187    /// A collection type, e.g., `[Number, String]`.
188    Collection(Vec<TypeSpec>, SourceSpan),
189    /// A spread type within a collection, e.g., `[Number...]`.
190    Spread(Box<TypeSpec>, SourceSpan),
191}
192
193impl TypeSpec {
194    #[must_use]
195    pub fn get_span(&self) -> SourceSpan {
196        match self {
197            TypeSpec::Simple(_, span)
198            | TypeSpec::Collection(_, span)
199            | TypeSpec::Spread(_, span) => *span,
200        }
201    }
202}
203
204impl Display for Member {
205    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206        match self {
207            Member::Pair(p) => write!(f, "Pair({}: {})", p.key, p.value),
208            Member::Spread(s) => write!(f, "Spread(...*{s})"),
209            Member::Import(i) => write!(f, "Import({i:?})"),
210            Member::TypeDefinition(t) => write!(f, "TypeDef({t:?})"),
211        }
212    }
213}
214
215/// A table to store resolved symbols, such as type definitions, from a MON document and its imports.
216#[derive(Debug, Default)]
217pub struct SymbolTable {
218    /// A map of type names to their definitions.
219    pub types: std::collections::HashMap<String, TypeDefinition>,
220}
221
222impl SymbolTable {
223    /// Creates a new, empty symbol table.
224    #[must_use]
225    pub fn new() -> Self {
226        Self::default()
227    }
228}
229
230impl Display for MonDocument {
231    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
232        write!(f, "{}", self.root)
233    }
234}
235
236impl Display for MonValueKind {
237    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
238        match self {
239            MonValueKind::String(s) => write!(f, "\"{s}\""),
240            MonValueKind::Number(n) => write!(f, "{n}"),
241            MonValueKind::Boolean(b) => write!(f, "{b}"),
242            MonValueKind::Null => write!(f, "null"),
243            MonValueKind::Object(o) => {
244                write!(f, "{{")?;
245                for (i, member) in o.iter().enumerate() {
246                    write!(f, "{member}")?;
247                    if i < o.len() - 1 {
248                        write!(f, ", ")?;
249                    }
250                }
251                write!(f, "}}")
252            }
253            MonValueKind::Array(a) => {
254                write!(f, "[")?;
255                for (i, value) in a.iter().enumerate() {
256                    write!(f, "{value}")?;
257                    if i < a.len() - 1 {
258                        write!(f, ", ")?;
259                    }
260                }
261                write!(f, "]")
262            }
263            MonValueKind::Alias(a) => write!(f, "*{a}"),
264            MonValueKind::EnumValue {
265                enum_name,
266                variant_name,
267            } => {
268                write!(f, "${enum_name}.{variant_name}")
269            }
270            MonValueKind::ArraySpread(s) => write!(f, "...*{s}"),
271        }
272    }
273}
274
275impl Display for MonValue {
276    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
277        if let Some(anchor) = &self.anchor {
278            write!(f, "&{anchor} ")?;
279        }
280        write!(f, "{}", self.kind)
281    }
282}
283
284impl Pair {
285    #[track_caller]
286    #[must_use]
287    pub fn get_span(&self) -> SourceSpan {
288        match &self.validation {
289            None => {
290                error!(
291                    "No validation for `Pair`found for source span called by {}",
292                    Location::caller()
293                );
294                SourceSpan::new(0.into(), 0)
295            }
296            Some(valid) => match valid {
297                TypeSpec::Simple(_, source_span)
298                | TypeSpec::Collection(_, source_span)
299                | TypeSpec::Spread(_, source_span) => *source_span,
300            },
301        }
302    }
303}