ellie_core/
defs.rs

1use alloc::{string::String, vec::Vec};
2
3#[cfg(feature = "compiler_utils")]
4use alloc::{borrow::ToOwned, format};
5use core::fmt::{Display, Error, Formatter};
6
7#[cfg(feature = "compiler_utils")]
8use regex::Regex;
9
10#[cfg(feature = "compiler_utils")]
11use serde::{Deserialize, Serialize};
12
13#[cfg(feature = "compiler_utils")]
14#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
15#[derive(Default)]
16pub enum TokenizerType {
17    #[default]
18    Raw,
19    ClassParser,
20    FunctionParser,
21    HeaderParser,
22}
23
24#[cfg(feature = "compiler_utils")]
25
26#[cfg(feature = "compiler_utils")]
27#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
28pub struct TokenizerOptions {
29    pub path: String,
30    pub functions: bool,
31    pub break_on_error: bool,
32    pub loops: bool,
33    pub enums: bool,
34    pub classes: bool,
35    pub getters: bool,
36    pub setters: bool,
37    pub conditions: bool,
38    pub global_variables: bool,
39    pub line_ending: String,
40    pub dynamics: bool,
41    pub collectives: bool,
42    pub variables: bool,
43    pub import_std: bool,
44    pub constants: bool,
45    pub ignore_imports: bool,
46    pub parser_type: TokenizerType,
47    pub allow_import: bool,
48}
49
50#[cfg(feature = "compiler_utils")]
51impl Default for TokenizerOptions {
52    fn default() -> Self {
53        TokenizerOptions {
54            path: "".to_owned(),
55            functions: true,
56            break_on_error: false,
57            loops: true,
58            conditions: true,
59            getters: true,
60            setters: true,
61            classes: true,
62            enums: true,
63            global_variables: true,
64            line_ending: "\\r\\n".to_owned(),
65            dynamics: true,
66            import_std: true,
67            collectives: true,
68            ignore_imports: false,
69            variables: true,
70            constants: true,
71            parser_type: TokenizerType::Raw,
72            allow_import: true,
73        }
74    }
75}
76
77/// A struct that represents a position in a file.
78/// (line, column)
79#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize, Default)]
80#[cfg(feature = "compiler_utils")]
81pub struct CursorPosition(pub usize, pub usize);
82
83/// A struct that represents a position in a file.
84/// (line, column)
85#[cfg(not(feature = "compiler_utils"))]
86#[derive(PartialEq, Debug, Clone, Copy, Default)]
87pub struct CursorPosition(pub usize, pub usize);
88
89impl core::fmt::Display for CursorPosition {
90    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
91        write!(f, "{}:{}", self.0, self.1)
92    }
93}
94
95impl CursorPosition {
96    pub fn is_bigger(&self, other: &CursorPosition) -> bool {
97        self.0 > other.0 || (self.0 == other.0 && self.1 > other.1)
98    }
99
100    pub fn skip_char(&mut self, n: usize) -> CursorPosition {
101        let mut clone = *self;
102        clone.1 += n;
103        clone
104    }
105
106    pub fn pop_char(&mut self, n: usize) -> CursorPosition {
107        let mut clone = *self;
108        if clone.1 != 0 {
109            clone.1 -= n;
110        }
111        clone
112    }
113
114    pub fn is_zero(&self) -> bool {
115        self.0 == 0 && self.1 == 0
116    }
117
118    pub fn increase_line(&mut self, n: usize) -> CursorPosition {
119        let mut clone = *self;
120        clone.0 += n;
121        clone
122    }
123}
124
125/// Cursor position
126/// ## Fields
127/// * `range_start` - Start of range [`CursorPosition`]
128/// * `range_end` - End of range [`CursorPosition`]
129#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize, Default)]
130#[cfg(feature = "compiler_utils")]
131pub struct Cursor {
132    pub range_start: CursorPosition,
133    pub range_end: CursorPosition,
134}
135
136/// Cursor position
137/// ## Fields
138/// * `range_start` - Start of range [`CursorPosition`]
139/// * `range_end` - End of range [`CursorPosition`]
140#[derive(PartialEq, Debug, Clone, Copy, Default)]
141#[cfg(not(feature = "compiler_utils"))]
142pub struct Cursor {
143    pub range_start: CursorPosition,
144    pub range_end: CursorPosition,
145}
146
147impl Cursor {
148    /// Check range_start and range_end is zero by column and lines
149    pub fn is_zero(&self) -> bool {
150        self.range_start.is_zero() && self.range_end.is_zero()
151    }
152
153    /// Check current cursor bigger than given [`Cursor`]
154    /// ## Arguments
155    /// * `cursor` - [`Cursor`] to compare
156    pub fn is_bigger(&self, than: Cursor) -> bool {
157        if than.range_end.0 == self.range_end.0 {
158            self.range_end.1 > than.range_end.1
159        } else {
160            than.range_end.0 <= self.range_end.0
161        }
162    }
163
164    /// Create new [`Cursor`] range start and skip one column pos to define the end
165    /// ## Arguments
166    /// * `start` - Start of range [`CursorPosition`]
167    pub fn build_with_skip_char(range_start: CursorPosition) -> Self {
168        Cursor {
169            range_start,
170            range_end: range_start.clone().skip_char(1),
171        }
172    }
173
174    /// Create new [`Cursor`]
175    /// ## Arguments
176    /// * `start` - Start of range [`CursorPosition`]
177    pub fn build_from_cursor(range_start: CursorPosition) -> Self {
178        Cursor {
179            range_start,
180            range_end: range_start,
181        }
182    }
183
184    /// Gets [`Cursor`] range end and skip one char
185    /// ## Arguments
186    /// * `n` - Number of chars to skip
187    /// ## Returns
188    /// [`Cursor`] with new range end
189    pub fn range_end_skip_char(&self, n: usize) -> Self {
190        self.range_end.clone().skip_char(n);
191        *self
192    }
193
194    /// Gets [`Cursor`] range start and skip one char
195    /// ## Arguments
196    /// * `n` - Number of chars to skip
197    /// ## Returns
198    /// [`Cursor`] with new range start and end
199    pub fn range_start_skip_char(&self, n: usize) -> Self {
200        self.range_start.clone().skip_char(n);
201        *self
202    }
203}
204
205/// Version
206/// ## Fields
207/// * `major` - Major version [`u8`]
208/// * `minor` - Minor version [`u8`]
209/// * `bug` - Bug version [`u8`]
210#[cfg(feature = "compiler_utils")]
211#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct Version {
213    pub major: usize,
214    pub minor: usize,
215    pub patch: usize,
216    pub pre_release: Option<String>,
217    pub build_metadata: Option<String>,
218}
219
220#[cfg(feature = "compiler_utils")]
221impl PartialEq for Version {
222    fn eq(&self, other: &Self) -> bool {
223        //Ignore bug
224        self.minor == other.minor && self.major == other.major
225    }
226}
227
228#[cfg(feature = "compiler_utils")]
229impl Version {
230    /// Create new [`Version`] from given [`String`]
231    /// ## Arguments
232    /// * `version` - [`String`] to parse
233    pub fn build_from_string(input: &String) -> Version {
234        let semver_regex = Regex::new(r"^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$").unwrap();
235        let caps = semver_regex.captures(input).unwrap();
236
237        Version {
238            major: caps
239                .name("major")
240                .unwrap()
241                .as_str()
242                .parse::<usize>()
243                .unwrap(),
244            minor: caps
245                .name("minor")
246                .unwrap()
247                .as_str()
248                .parse::<usize>()
249                .unwrap(),
250            patch: caps
251                .name("patch")
252                .unwrap()
253                .as_str()
254                .parse::<usize>()
255                .unwrap(),
256            pre_release: caps.name("prerelease").map(|x| x.as_str().to_owned()),
257            build_metadata: caps.name("buildmetadata").map(|x| x.as_str().to_owned()),
258        }
259    }
260
261    /// Create new [`Version`] from given [`String`] with checks
262    /// ## Arguments
263    /// * `input` - [`String`] to parse
264    /// ## Return
265    /// [`Result`] - If versionb is valid [`Ok(Version)`] otherwise [`Err(u8)`]-
266    pub fn build_from_string_checked(input: &String) -> Result<Version, u8> {
267        let semver_regex = Regex::new(r"^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$").unwrap();
268        match semver_regex.captures(input) {
269            Some(caps) => {
270                let major = caps
271                    .name("major")
272                    .unwrap()
273                    .as_str()
274                    .parse::<usize>()
275                    .unwrap_or(0);
276                let minor = caps
277                    .name("minor")
278                    .unwrap()
279                    .as_str()
280                    .parse::<usize>()
281                    .unwrap_or(0);
282                let patch = caps
283                    .name("patch")
284                    .unwrap()
285                    .as_str()
286                    .parse::<usize>()
287                    .unwrap_or(0);
288
289                let pre_release = caps.name("prerelease").map(|x| x.as_str().to_owned());
290                let build_metadata = caps.name("buildmetadata").map(|x| x.as_str().to_owned());
291
292                if major == 0 && minor == 0 && patch == 0 {
293                    Err(1)
294                } else {
295                    Ok(Version {
296                        minor,
297                        major,
298                        patch,
299                        pre_release,
300                        build_metadata,
301                    })
302                }
303            }
304            None => Err(1),
305        }
306    }
307
308    pub fn to_string(&self) -> String {
309        format!(
310            "{}.{}.{}{}{}",
311            self.major,
312            self.minor,
313            self.patch,
314            if let Some(ref pre_release) = self.pre_release {
315                format!("-{}", pre_release)
316            } else {
317                "".to_owned()
318            },
319            if let Some(ref build_metadata) = self.build_metadata {
320                format!("+{}", build_metadata)
321            } else {
322                "".to_owned()
323            }
324        )
325    }
326}
327
328#[derive(Clone, Debug, PartialEq, Copy)]
329pub enum PlatformArchitecture {
330    B16,
331    B32,
332    B64,
333}
334
335impl Display for PlatformArchitecture {
336    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
337        match self {
338            PlatformArchitecture::B16 => write!(f, "b16"),
339            PlatformArchitecture::B32 => write!(f, "b32"),
340            PlatformArchitecture::B64 => write!(f, "b64"),
341        }
342    }
343}
344
345impl PlatformArchitecture {
346    pub fn is_16(&self) -> bool {
347        match self {
348            PlatformArchitecture::B16 => true,
349            _ => false,
350        }
351    }
352
353    pub fn is_32(&self) -> bool {
354        match self {
355            PlatformArchitecture::B32 => true,
356            _ => false,
357        }
358    }
359
360    pub fn get_code(&self) -> u8 {
361        match self {
362            PlatformArchitecture::B16 => 16,
363            PlatformArchitecture::B32 => 32,
364            PlatformArchitecture::B64 => 64,
365        }
366    }
367
368    pub fn type_id_size(&self) -> u8 {
369        match self {
370            PlatformArchitecture::B16 => 3,
371            PlatformArchitecture::B32 => 5,
372            PlatformArchitecture::B64 => 9,
373        }
374    }
375
376    pub fn usize_len(&self) -> u8 {
377        match self {
378            PlatformArchitecture::B16 => 2,
379            PlatformArchitecture::B32 => 4,
380            PlatformArchitecture::B64 => 8,
381        }
382    }
383
384    pub fn from_byte(byte: u8) -> Option<PlatformArchitecture> {
385        match byte {
386            16 => Some(PlatformArchitecture::B16),
387            32 => Some(PlatformArchitecture::B32),
388            64 => Some(PlatformArchitecture::B64),
389            _ => None,
390        }
391    }
392}
393
394#[derive(Clone, Debug, PartialEq)]
395pub enum DebugHeaderType {
396    Variable,
397    SetterCall,
398    GetterCall,
399    Class,
400    Parameter,
401    Function,
402    NativeFunction,
403    Condition,
404}
405
406#[derive(Clone, Debug)]
407pub struct DebugHeader {
408    /// Element Type
409    pub rtype: DebugHeaderType,
410    /// Element's hash
411    pub hash: usize,
412    /// Module Name
413    pub module_name: String,
414    /// Module Hash
415    pub module_hash: usize,
416    /// Element Name
417    pub name: String,
418    /// Instruction start -> end,
419    pub start_end: (usize, usize),
420    /// Code pos
421    pub pos: Cursor,
422}
423
424#[derive(Debug, Clone)]
425pub struct ModuleMap {
426    pub module_name: String,
427    pub module_hash: usize,
428    pub module_path: Option<String>,
429}
430
431#[derive(Debug, Clone)]
432pub struct NativeCallTrace {
433    pub module_name: String,
434    pub function_hash: usize,
435    pub function_name: String,
436}
437
438#[derive(Debug, Clone)]
439pub struct DebugInfo {
440    pub module_map: Vec<ModuleMap>,
441    pub debug_headers: Vec<DebugHeader>,
442}