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}