Skip to main content

ad_astra/runtime/
ident.rs

1////////////////////////////////////////////////////////////////////////////////
2// This file is part of "Ad Astra", an embeddable scripting programming       //
3// language platform.                                                         //
4//                                                                            //
5// This work is proprietary software with source-available code.              //
6//                                                                            //
7// To copy, use, distribute, or contribute to this work, you must agree to    //
8// the terms of the General License Agreement:                                //
9//                                                                            //
10// https://github.com/Eliah-Lakhin/ad-astra/blob/master/EULA.md               //
11//                                                                            //
12// The agreement grants a Basic Commercial License, allowing you to use       //
13// this work in non-commercial and limited commercial products with a total   //
14// gross revenue cap. To remove this commercial limit for one of your         //
15// products, you must acquire a Full Commercial License.                      //
16//                                                                            //
17// If you contribute to the source code, documentation, or related materials, //
18// you must grant me an exclusive license to these contributions.             //
19// Contributions are governed by the "Contributions" section of the General   //
20// License Agreement.                                                         //
21//                                                                            //
22// Copying the work in parts is strictly forbidden, except as permitted       //
23// under the General License Agreement.                                       //
24//                                                                            //
25// If you do not or cannot agree to the terms of this Agreement,              //
26// do not use this work.                                                      //
27//                                                                            //
28// This work is provided "as is", without any warranties, express or implied, //
29// except where such disclaimers are legally invalid.                         //
30//                                                                            //
31// Copyright (c) 2024 Ilya Lakhin (Илья Александрович Лахин).                 //
32// All rights reserved.                                                       //
33////////////////////////////////////////////////////////////////////////////////
34
35use std::{
36    cmp::Ordering,
37    fmt::{Debug, Display, Formatter},
38    hash::{Hash, Hasher},
39};
40
41use compact_str::CompactString;
42use lady_deirdre::lexis::{TokenRef, NIL_TOKEN_REF};
43
44use crate::runtime::{Origin, RustOrigin};
45
46/// An identifier within the Rust or Script code: `let identifier = 10;`.
47///
48/// You can retrieve the actual string of the identifier using the [Display],
49/// [Debug], and [AsRef<str>](AsRef) implementations of this type.
50///
51/// Unlike [Origin] and [ScriptOrigin](crate::runtime::ScriptOrigin), the
52/// identifier's string does not become obsolete or change even if the
53/// underlying Script source code has been modified. This object holds a copy of
54/// the string as it was at the time of the identifier's creation.
55#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
56pub enum Ident {
57    /// An identifier declared in the Rust source code.
58    Rust(&'static RustIdent),
59
60    /// An identifier declared in the Script source code.
61    Script(ScriptIdent),
62}
63
64impl Debug for Ident {
65    #[inline(always)]
66    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
67        match self {
68            Ident::Rust(ident) => Debug::fmt(*ident, formatter),
69            Ident::Script(ident) => Debug::fmt(ident, formatter),
70        }
71    }
72}
73
74impl Display for Ident {
75    #[inline(always)]
76    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
77        match self {
78            Ident::Rust(ident) => Display::fmt(*ident, formatter),
79            Ident::Script(ident) => Display::fmt(ident, formatter),
80        }
81    }
82}
83
84impl From<&'static RustIdent> for Ident {
85    #[inline(always)]
86    fn from(value: &'static RustIdent) -> Self {
87        Self::Rust(value)
88    }
89}
90
91impl From<ScriptIdent> for Ident {
92    #[inline(always)]
93    fn from(value: ScriptIdent) -> Self {
94        Self::Script(value)
95    }
96}
97
98impl AsRef<str> for Ident {
99    #[inline(always)]
100    fn as_ref(&self) -> &str {
101        match self {
102            Self::Rust(ident) => ident.as_ref(),
103            Self::Script(ident) => ident.as_ref(),
104        }
105    }
106}
107
108impl Ident {
109    #[inline(always)]
110    pub(crate) fn from_string(string: impl Into<CompactString>) -> Self {
111        Self::Script(ScriptIdent {
112            origin: NIL_TOKEN_REF,
113            string: string.into(),
114        })
115    }
116
117    /// Returns the range in the Rust or Script source code that spans the
118    /// underlying identifier.
119    #[inline(always)]
120    pub fn origin(&self) -> Origin {
121        match self {
122            Self::Rust(ident) => Origin::from(ident.origin),
123            Self::Script(ident) => Origin::from(ident.origin),
124        }
125    }
126}
127
128/// An identifier within the Rust code: `let identifier = 10;`.
129///
130/// This object is typically created in static memory
131/// (`static IDENT: RustIdent = RustIdent { ... }`) using the
132/// [export](crate::export) macro. Generally, you don't need to create it
133/// manually.
134#[derive(Clone, Copy)]
135pub struct RustIdent {
136    /// The range in the Rust source code that points to the underlying
137    /// identifier.
138    pub origin: &'static RustOrigin,
139
140    /// The string representation of the identifier.
141    pub string: &'static str,
142}
143
144impl Debug for RustIdent {
145    #[inline(always)]
146    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
147        Debug::fmt(self.string, formatter)
148    }
149}
150
151impl Display for RustIdent {
152    #[inline(always)]
153    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
154        Display::fmt(self.string, formatter)
155    }
156}
157
158impl AsRef<str> for RustIdent {
159    #[inline(always)]
160    fn as_ref(&self) -> &str {
161        self.string
162    }
163}
164
165impl PartialEq for RustIdent {
166    #[inline(always)]
167    fn eq(&self, other: &Self) -> bool {
168        self.string.eq(other.string)
169    }
170}
171
172impl Eq for RustIdent {}
173
174impl Hash for RustIdent {
175    #[inline(always)]
176    fn hash<H: Hasher>(&self, state: &mut H) {
177        self.string.hash(state)
178    }
179}
180
181impl PartialOrd for RustIdent {
182    #[inline(always)]
183    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
184        Some(self.cmp(other))
185    }
186}
187
188impl Ord for RustIdent {
189    #[inline(always)]
190    fn cmp(&self, other: &Self) -> Ordering {
191        self.string.cmp(&other.string)
192    }
193}
194
195/// An identifier within the Script code: `let identifier = 10;`.
196///
197/// You cannot instantiate this object manually, but certain API functions
198/// return instances of it (e.g.,
199/// [VarSymbol::var_name](crate::analysis::symbols::VarSymbol::var_name)).
200///
201/// You can retrieve the actual string of the identifier using the [Display],
202/// [Debug], and [AsRef<str>](AsRef) implementations of this type.
203///
204/// The `ScriptIdent` holds a copy of the identifier's string from the time
205/// of its creation. Therefore, the string does not become obsolete or change
206/// even if the source code of the Script is modified.
207#[derive(Clone)]
208pub struct ScriptIdent {
209    origin: TokenRef,
210    string: CompactString,
211}
212
213impl Debug for ScriptIdent {
214    #[inline(always)]
215    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
216        Debug::fmt(&self.string, formatter)
217    }
218}
219
220impl Display for ScriptIdent {
221    #[inline(always)]
222    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
223        Display::fmt(&self.string, formatter)
224    }
225}
226
227impl AsRef<str> for ScriptIdent {
228    #[inline(always)]
229    fn as_ref(&self) -> &str {
230        self.string.as_ref()
231    }
232}
233
234impl PartialEq for ScriptIdent {
235    #[inline(always)]
236    fn eq(&self, other: &Self) -> bool {
237        self.string.eq(&other.string)
238    }
239}
240
241impl Eq for ScriptIdent {}
242
243impl Hash for ScriptIdent {
244    #[inline(always)]
245    fn hash<H: Hasher>(&self, state: &mut H) {
246        self.string.hash(state)
247    }
248}
249
250impl PartialOrd for ScriptIdent {
251    #[inline(always)]
252    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
253        Some(self.cmp(other))
254    }
255}
256
257impl Ord for ScriptIdent {
258    #[inline(always)]
259    fn cmp(&self, other: &Self) -> Ordering {
260        self.string.cmp(&other.string)
261    }
262}
263
264impl ScriptIdent {
265    #[inline(always)]
266    pub(crate) fn from_string(token_ref: TokenRef, string: impl Into<CompactString>) -> Self {
267        Self {
268            origin: token_ref,
269            string: string.into(),
270        }
271    }
272}