donet_core/parser/
ast.rs

1/*
2    This file is part of Donet.
3
4    Copyright © 2024 Max Rodriguez
5
6    Donet is free software; you can redistribute it and/or modify
7    it under the terms of the GNU Affero General Public License,
8    as published by the Free Software Foundation, either version 3
9    of the License, or (at your option) any later version.
10
11    Donet is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14    GNU Affero General Public License for more details.
15
16    You should have received a copy of the GNU Affero General Public
17    License along with Donet. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20//! Enum and Struct definitions that are used to build the DC File [`AST`].
21//! Used by [`crate::parser::parser`].
22//!
23//! [`AST`]: https://en.wikipedia.org/wiki/Abstract_syntax_tree
24
25use super::lexer::{DCToken, Span};
26use crate::dctype::DCTypeEnum;
27
28/// Paired with the `type_declarations` production in the Context Free Grammar.
29#[derive(Debug, Clone)]
30pub struct Root {
31    pub type_declarations: Vec<TypeDeclaration>,
32}
33
34/// Paired with the `type_decl` production in the Context Free Grammar.
35#[derive(Debug, Clone)]
36pub enum TypeDeclaration {
37    // A single Python-style DC Import line can translate to
38    // multiple [`PythonImport`] structures per symbol imported.
39    PythonImport(PythonImport),
40    KeywordType(KeywordDefinition),
41    StructType(Struct),
42    DClassType(DClass),
43    TypedefType(TypeDefinition),
44    // Returned by productions that parsed certain grammar that may be
45    // deprecated but ignored for compatibility & should not be added
46    // to the output DC file element structure.
47    Ignore,
48}
49
50/// Paired with the `python_style_import` production in the Context Free Grammar.
51#[derive(Debug, Clone)]
52pub struct PythonImport {
53    pub span: Span,
54    pub module: SymbolWithViews,
55    pub class: SymbolWithViews,
56}
57
58/// Paired with the `py_module` and `dclass_import`
59/// productions in the Context Free Grammar.
60#[derive(Debug, Clone)]
61pub struct SymbolWithViews {
62    pub span: Span,
63    pub symbol: String,
64    pub symbol_views: Vec<ViewSuffix>,
65}
66
67/// Paired with the `view_suffixes` production in the Context Free Grammar.
68pub type ViewSuffixes = Vec<ViewSuffix>;
69
70/// Paired with the `view_suffix` production in the Context Free Grammar.
71#[derive(Debug, Clone)]
72pub struct ViewSuffix {
73    pub span: Span,
74    pub view: String, // 'AI', 'OV', 'UD', etc.
75}
76
77/// Paired with the `type_definition` production in the Context Free Grammar.
78#[derive(Debug, Clone)]
79pub struct TypeDefinition {
80    pub span: Span,
81    /// Used if deprecated type aliases are found, such as `typedef uint8 bool;`
82    pub deprecated: bool,
83    pub data_type: NonMethodDataType,
84    pub array_range: Option<ArrayRange>,
85    pub alias_identifier: Option<String>,
86}
87
88/// Paired with the `keyword_type` production in the Context Free Grammar.
89#[derive(Debug, Clone)]
90pub struct KeywordDefinition {
91    pub span: Span,
92    pub identifier: String,
93    pub historical: bool,
94}
95
96/// Paired with the `distributed_class_type` production in the Context Free Grammar.
97#[derive(Debug, Clone)]
98pub struct DClass {
99    pub span: Span,
100    pub identifier: String,
101    pub parents: Vec<String>,
102    pub fields: ClassFields,
103}
104
105/// Paired with the `optional_class_fields` production in the Context Free Grammar.
106pub type ClassFields = Vec<AtomicOrMolecular>;
107
108/// Paired with the `class_field` production in the Context Free Grammar.
109#[derive(Debug, Clone)]
110pub enum AtomicOrMolecular {
111    Atomic(AtomicField),
112    Molecular(MolecularField),
113}
114
115/// The Atomic Field variant of the [`AtomicOrMolecular`] enum.
116#[derive(Debug, Clone)]
117pub struct AtomicField {
118    pub span: Span,
119    pub identifier: Option<String>,
120    pub keywords: Vec<String>,
121    pub parameters: MethodBody,
122}
123
124impl AtomicField {
125    pub fn from_named_field(field: NamedField, kw_list: KeywordList, span: Span) -> Self {
126        match field {
127            NamedField::ParameterField(pf) => Self {
128                span,
129                identifier: pf.parameter.identifier.clone(),
130                keywords: kw_list,
131                parameters: vec![pf.parameter],
132            },
133            NamedField::MethodAsField(mf) => Self {
134                span,
135                identifier: Some(mf.identifier),
136                keywords: kw_list,
137                parameters: mf.parameters,
138            },
139        }
140    }
141}
142
143/// Paired with the `molecular_field` production in the Context Free Grammar.
144#[derive(Debug, Clone)]
145pub struct MolecularField {
146    pub span: Span,
147    pub identifier: String,
148    pub atomic_field_identifiers: Vec<String>,
149}
150
151/// Paired with the `parameter_values` production in the Context Free Grammar.
152pub type ParameterValues = Vec<TypeValue>;
153
154/// Paired with the `struct_type` production in the Context Free Grammar.
155#[derive(Debug, Clone)]
156pub struct Struct {
157    pub span: Span,
158    pub identifier: String,
159    pub fields: Vec<StructField>,
160}
161
162/// Paired with the `struct_field` production in the Context Free Grammar.
163#[derive(Debug, Clone)]
164pub enum StructField {
165    ParameterField(ParameterField),
166    MethodAsField(MethodAsField),
167    Switch(Switch),
168}
169
170impl From<NamedField> for StructField {
171    fn from(value: NamedField) -> Self {
172        match value {
173            NamedField::ParameterField(pf) => Self::ParameterField(pf),
174            NamedField::MethodAsField(mf) => Self::MethodAsField(mf),
175        }
176    }
177}
178
179/// Paired with the `switch_type` production in the Context Free Grammar.
180#[derive(Debug, Clone)]
181pub struct Switch {
182    pub span: Span,
183    pub identifier: Option<String>,
184    pub key_parameter: ParameterField,
185    pub cases: Vec<Case>,
186}
187
188/// Paired with the `switch_case` production in the Context Free Grammar.
189#[derive(Debug, Clone)]
190pub struct Case {
191    pub span: Span,
192    // `None` condition means this is a default case.
193    pub condition: Option<TypeValue>,
194    pub fields: Vec<NamedField>,
195    pub breaks: bool, // if case ends with a break
196}
197
198/// Paired with the `named_field` production in the Context Free Grammar.
199#[derive(Debug, Clone)]
200pub enum NamedField {
201    ParameterField(ParameterField),
202    MethodAsField(MethodAsField),
203}
204
205/// Paired with the `method_as_field` production in the Context Free Grammar.
206#[derive(Debug, Clone)]
207pub struct MethodAsField {
208    pub span: Span,
209    pub identifier: String,
210    pub parameters: MethodBody,
211}
212
213/// Paired with the `method_body` production in the Context Free Grammar.
214pub type MethodBody = Vec<Parameter>;
215
216/// Paired with the `parameter_field` production in the Context Free Grammar.
217#[derive(Debug, Clone)]
218pub struct ParameterField {
219    pub parameter: Parameter,
220    pub keywords: KeywordList,
221}
222
223impl From<Parameter> for ParameterField {
224    fn from(value: Parameter) -> Self {
225        Self {
226            parameter: value,
227            keywords: vec![],
228        }
229    }
230}
231
232/// Paired with the `dc_keyword_list` production in the Context Free Grammar.
233pub type KeywordList = Vec<String>;
234
235/// Paired with the `parameter` production in the Context Free Grammar.
236#[derive(Debug, Clone)]
237pub struct Parameter {
238    pub span: Span,
239    pub data_type: NonMethodDataType,
240    pub identifier: Option<String>,
241    pub default_value: Option<TypeValue>,
242}
243
244impl From<NonMethodType> for Parameter {
245    fn from(value: NonMethodType) -> Self {
246        Self {
247            span: value.span,
248            data_type: value.data_type,
249            identifier: value.identifier,
250            default_value: None,
251        }
252    }
253}
254
255/// Paired with the `nonmethod_type` production in the Context Free Grammar.
256#[derive(Debug, Clone)]
257pub struct NonMethodType {
258    pub span: Span,
259    pub identifier: Option<String>,
260    pub data_type: NonMethodDataType,
261}
262
263#[derive(Debug, Clone)]
264pub enum NonMethodDataType {
265    NumericType(NumericType),
266    StructType(String),
267    TypeWithArray(TypeWithArray),
268}
269
270/// Paired with the `type_with_array` production in the Context Free Grammar.
271#[derive(Debug, Clone)]
272pub struct TypeWithArray {
273    pub span: Span,
274    pub data_type: ArrayableType,
275    pub array_ranges: Vec<ArrayRange>,
276}
277
278#[derive(Debug, Clone)]
279pub enum ArrayableType {
280    Numeric(NumericType),
281    Struct(String),
282    Sized(SizedTypeToken),
283}
284
285/// Paired with the `array_expansion` production in the Context Free Grammar.
286pub type ArrayExpansion = (TypeValue, u32);
287
288/// Paired with the `type_or_sized_value` production in the Context Free Grammar.
289#[derive(Debug, Clone)]
290pub enum TypeOrSizedValue {
291    Type(TypeValue),
292    Sized(DCToken),
293}
294
295/// Paired with the `type_value` production in the Context Free Grammar.
296#[derive(Debug, Clone)]
297pub enum TypeValue {
298    I64(i64),
299    Char(char),
300    String(String),
301    ArrayValue(Vec<ArrayExpansion>),
302}
303
304/// Paired with the `numeric_type` production in the Context Free Grammar.
305#[derive(Debug, Clone)]
306pub struct NumericType {
307    pub span: Span,
308    pub base_type: DCTypeEnum,
309    // Transforms
310    pub cast: Option<DataType>,
311    pub modulus: Option<f64>,
312    pub divisor: Option<f64>,
313    pub range: Option<NumericRange>,
314}
315
316impl NumericType {
317    pub fn from_type(value: DCTypeEnum, span: Span) -> Self {
318        Self {
319            span,
320            base_type: value,
321            cast: None,
322            modulus: None,
323            divisor: None,
324            range: None,
325        }
326    }
327
328    pub fn add_modulus(&mut self, value: Number) {
329        match value {
330            Number::Decimal(dl) => {
331                self.modulus = Some(dl as f64);
332            }
333            Number::Float(fl) => {
334                self.modulus = Some(fl);
335            }
336        }
337    }
338
339    pub fn add_divisor(&mut self, value: Number) {
340        match value {
341            Number::Decimal(dl) => {
342                self.divisor = Some(dl as f64);
343            }
344            Number::Float(fl) => {
345                self.divisor = Some(fl);
346            }
347        }
348    }
349}
350
351/// Paired with the `numeric_range` production in the Context Free Grammar.
352pub type NumericRange = std::ops::Range<f64>;
353
354/// Paired with the `array_range` production in the Context Free Grammar.
355pub type ArrayRange = std::ops::Range<f64>;
356
357/// Paired with the `sized_type_token` production in the Context Free Grammar.
358#[derive(Debug, Clone)]
359pub enum SizedTypeToken {
360    String,
361    Blob,
362    Blob32,
363    Int8Array,
364    Int16Array,
365    Int32Array,
366    UInt8Array,
367    UInt16Array,
368    UInt32Array,
369    UInt32UInt8Array,
370}
371
372/// Paired with the `char_or_number` production in the Context Free Grammar.
373#[derive(Debug, Clone, Copy)]
374pub enum CharOrNumber {
375    Char(char),
376    I64(i64),
377    F64(f64),
378}
379
380/// Paired with the 'number' production in the Context Free Grammar.
381pub enum Number {
382    Decimal(i64),
383    Float(f64),
384}
385
386/// Paired with the `char_or_u16` production in the Context Free Grammar.
387#[derive(Debug, Clone, Copy)]
388pub enum CharOrU16 {
389    Char(char),
390    U16(u16),
391}
392
393#[derive(Debug, Clone)]
394pub struct DataType {
395    pub span: Span,
396    pub token: DCToken,
397    pub dctype: DCTypeEnum,
398}
399
400impl DataType {
401    pub fn from_token(value: DCToken, span: Span) -> Self {
402        Self {
403            span,
404            token: value.clone(),
405            dctype: match value {
406                DCToken::Float32T => DCTypeEnum::TFloat32,
407                DCToken::Float64T => DCTypeEnum::TFloat64,
408                DCToken::Int8T => DCTypeEnum::TInt8,
409                DCToken::Int16T => DCTypeEnum::TInt16,
410                DCToken::Int32T => DCTypeEnum::TInt32,
411                DCToken::Int64T => DCTypeEnum::TInt64,
412                DCToken::UInt8T => DCTypeEnum::TUInt8,
413                DCToken::UInt16T => DCTypeEnum::TUInt16,
414                DCToken::UInt32T => DCTypeEnum::TUInt32,
415                DCToken::UInt64T => DCTypeEnum::TUInt64,
416                DCToken::Int8ArrayT => DCTypeEnum::TArray,
417                DCToken::Int16ArrayT => DCTypeEnum::TArray,
418                DCToken::Int32ArrayT => DCTypeEnum::TArray,
419                DCToken::UInt8ArrayT => DCTypeEnum::TArray,
420                DCToken::UInt16ArrayT => DCTypeEnum::TArray,
421                DCToken::UInt32ArrayT => DCTypeEnum::TArray,
422                DCToken::UInt32UInt8ArrayT => DCTypeEnum::TArray,
423                _ => panic!("DC token matches no production in CFG."),
424            },
425        }
426    }
427}