1use crate::source_map::SourceMap;
18
19use core::{
20 borrow::Borrow,
21 cmp::PartialEq,
22 fmt,
23 hash::{Hash, Hasher},
24 num::NonZeroU32,
25 ops::Deref,
26 str,
27};
28use fxhash::FxBuildHasher;
29use indexmap::IndexSet;
30use serde::{Deserialize, Deserializer, Serialize, Serializer};
31use std::cell::RefCell;
32
33macro_rules! consts {
37 ($val: expr, $sym:ident $(,)?) => {
38 #[allow(non_upper_case_globals)]
39 pub const $sym: $crate::symbol::Symbol = $crate::symbol::Symbol::new($val);
40 };
41 ($val: expr, $sym:ident: $_s:literal $(,)?) => {
42 consts!($val, $sym);
43 };
44 ($val: expr, $sym:ident: $_s:literal, $($rest:tt)*) => {
45 consts!($val, $sym);
46 consts!($val + 1, $($rest)*);
47 };
48 ($val: expr, $sym:ident, $($rest:tt)*) => {
49 consts!($val, $sym);
50 consts!($val + 1, $($rest)*);
51 };
52}
53
54macro_rules! strings {
58 ([$($acc:expr),*] []) => {
63 [$($acc),*]
64 };
65 ([$($acc:expr),*] [$_sym:ident: $string:literal, $($rest:tt)*]) => {
68 strings!([$($acc,)* $string] [$($rest)*])
69 };
70 ([$($acc:expr),*] [$sym:ident, $($rest:tt)*]) => {
72 strings!([$($acc,)* stringify!($sym)] [$($rest)*])
73 };
74 ([$($acc:expr),*] [$_sym:ident: $string:literal $(,)?]) => {
76 strings!([$($acc,)* $string] [])
77 };
78 ([$($acc:expr),*] [$sym:ident $(,)?]) => {
81 strings!([$($acc,)* stringify!($sym)] [])
82 };
83}
84
85macro_rules! symbols {
94 ($($symbols:tt)*) => {
95 const PRE_DEFINED: &[&str] = &strings!([] [$($symbols)*]);
96
97 pub mod sym {
98 consts!(0, $($symbols)*);
99 }
100 };
101}
102
103symbols! {
104 abs,
106 abs_wrapped,
107 double,
108 inv,
109 neg,
110 not,
111 square,
112 square_root,
113
114 add,
116 add_wrapped,
117 and,
118 div,
119 div_wrapped,
120 eq,
121 gte,
122 gt,
123 lte,
124 lt,
125 Mod: "mod",
126 mul,
127 mul_wrapped,
128 nand,
129 neq,
130 nor,
131 or,
132 pow,
133 pow_wrapped,
134 rem,
135 rem_wrapped,
136 shl,
137 shl_wrapped,
138 shr,
139 shr_wrapped,
140 sub,
141 sub_wrapped,
142 xor,
143
144 GEN,
146
147 BHP256,
149 BHP512,
150 BHP768,
151 BHP1024,
152 ChaCha,
153 commit_to_address,
154 commit_to_field,
155 commit_to_group,
156 contains,
157 get,
158 get_or_use,
159 hash_to_address,
160 hash_to_field,
161 hash_to_group,
162 hash_to_i8,
163 hash_to_i16,
164 hash_to_i32,
165 hash_to_i64,
166 hash_to_i128,
167 hash_to_u8,
168 hash_to_u16,
169 hash_to_u32,
170 hash_to_u64,
171 hash_to_u128,
172 hash_to_scalar,
173 Keccak256,
174 Keccak384,
175 Keccak512,
176 Mapping,
177 Pedersen64,
178 Pedersen128,
179 Poseidon2,
180 Poseidon4,
181 Poseidon8,
182 rand_address,
183 rand_bool,
184 rand_field,
185 rand_group,
186 rand_i8,
187 rand_i16,
188 rand_i32,
189 rand_i64,
190 rand_i128,
191 rand_scalar,
192 rand_u8,
193 rand_u16,
194 rand_u32,
195 rand_u64,
196 rand_u128,
197 remove,
198 set,
199 SHA3_256,
200 SHA3_384,
201 SHA3_512,
202 to_x_coordinate,
203 to_y_coordinate,
204 verify,
205 Await: "await",
206
207 CheatCode,
209 print_mapping,
210 set_block_height,
211
212 address,
214 bool,
215 field,
216 group,
217 i8,
218 i16,
219 i32,
220 i64,
221 i128,
222 Future,
223 Fn,
224 record,
225 scalar,
226 signature,
227 string,
228 Struct: "struct",
229 u8,
230 u16,
231 u32,
232 u64,
233 u128,
234
235 False: "false",
237 True: "true",
238
239 should_fail,
241 test,
242 noupgrade,
243 custom,
244 admin,
245 key,
246
247 private_key,
249
250 As: "as",
252 assert,
253 assert_eq,
254 assert_neq,
255 Async: "async",
256 caller,
257 Const: "const",
258 constant,
259 constructor,
260 decrement,
261 Else: "else",
262 For: "for",
263 function,
264 If: "if",
265 In: "in",
266 import,
267 increment,
268 inline,
269 input,
270 Let: "let",
271 leo,
272 main,
273 mapping,
274 Mut: "mut",
275 Return: "return",
276 script,
277 SelfLower: "self",
278 SelfUpper: "Self",
279 signer,
280 Star: "*",
281 transition,
282 Type: "type",
283
284 aleo,
285 public,
286 private,
287 owner,
288 _nonce,
289 program,
290 ProgramCore: "Program",
291 stub,
292 block,
293 height,
294 network,
295 id,
296 checksum,
297 edition,
298 program_owner,
299}
300
301#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
306pub struct Symbol(
307 #[serde(deserialize_with = "Symbol::serde_to_symbol")]
308 #[serde(serialize_with = "Symbol::serde_from_symbol")]
309 NonZeroU32,
310);
311
312impl Default for Symbol {
313 fn default() -> Self {
314 Symbol(NonZeroU32::MIN)
315 }
316}
317
318impl Symbol {
319 pub const fn new(index: u32) -> Self {
321 let index = index.saturating_add(1);
322 Self(match NonZeroU32::new(index) {
323 None => unreachable!(),
324 Some(x) => x,
325 })
326 }
327
328 pub fn intern(string: &str) -> Self {
330 with_session_globals(|session_globals| session_globals.symbol_interner.intern(string))
331 }
332
333 pub fn as_str<R>(self, s: &SessionGlobals, with: impl FnOnce(&str) -> R) -> R {
335 s.symbol_interner.get(self, with)
336 }
337
338 pub const fn as_u32(self) -> u32 {
340 self.0.get() - 1
341 }
342
343 fn serde_to_symbol<'de, D: Deserializer<'de>>(de: D) -> Result<NonZeroU32, D::Error> {
344 Ok(Symbol::intern(<&str>::deserialize(de)?).0)
345 }
346
347 fn serde_from_symbol<S: Serializer>(index: &NonZeroU32, ser: S) -> Result<S::Ok, S::Error> {
348 with_session_globals(|sg| Self(*index).as_str(sg, |s| ser.serialize_str(s)))
349 }
350}
351
352impl fmt::Debug for Symbol {
353 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354 with_session_globals(|s| self.as_str(s, |s| fmt::Debug::fmt(s, f)))
355 }
356}
357
358impl fmt::Display for Symbol {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 with_session_globals(|s| self.as_str(s, |s| fmt::Display::fmt(s, f)))
361 }
362}
363
364pub struct SessionGlobals {
366 symbol_interner: Interner,
368 pub source_map: SourceMap,
370}
371
372impl Default for SessionGlobals {
373 fn default() -> Self {
374 Self { symbol_interner: Interner::prefilled(), source_map: SourceMap::default() }
375 }
376}
377
378scoped_tls::scoped_thread_local!(pub static SESSION_GLOBALS: SessionGlobals);
379
380#[inline]
382pub fn create_session_if_not_set_then<R>(f: impl FnOnce(&SessionGlobals) -> R) -> R {
383 if !SESSION_GLOBALS.is_set() {
384 let sg = SessionGlobals::default();
385 SESSION_GLOBALS.set(&sg, || SESSION_GLOBALS.with(f))
386 } else {
387 SESSION_GLOBALS.with(f)
388 }
389}
390
391#[inline]
393pub fn with_session_globals<R>(f: impl FnOnce(&SessionGlobals) -> R) -> R {
394 SESSION_GLOBALS.with(f)
395}
396
397#[derive(Eq)]
401enum InternedStr {
402 Static(&'static str),
404 Owned(Box<str>),
406}
407
408impl Borrow<str> for InternedStr {
409 fn borrow(&self) -> &str {
410 self.deref()
411 }
412}
413
414impl Deref for InternedStr {
415 type Target = str;
416
417 fn deref(&self) -> &Self::Target {
418 match self {
419 Self::Static(s) => s,
420 Self::Owned(s) => s,
421 }
422 }
423}
424
425impl PartialEq for InternedStr {
426 fn eq(&self, other: &InternedStr) -> bool {
427 self.deref() == other.deref()
428 }
429}
430
431impl Hash for InternedStr {
432 fn hash<H: Hasher>(&self, state: &mut H) {
433 self.deref().hash(state);
434 }
435}
436
437struct InnerInterner {
440 set: IndexSet<InternedStr, FxBuildHasher>,
444}
445
446struct Interner {
448 inner: RefCell<InnerInterner>,
449}
450
451impl Interner {
452 fn prefilled() -> Self {
454 Self::prefill(PRE_DEFINED)
455 }
456
457 fn prefill(init: &[&'static str]) -> Self {
459 let inner = InnerInterner {
460 set: init.iter().copied().map(InternedStr::Static).collect(),
462 };
463 Self { inner: RefCell::new(inner) }
464 }
465
466 fn intern(&self, string: &str) -> Symbol {
468 let InnerInterner { set } = &mut *self.inner.borrow_mut();
469
470 if let Some(sym) = set.get_index_of(string) {
471 return Symbol::new(sym as u32);
473 }
474
475 Symbol::new(set.insert_full(InternedStr::Owned(string.into())).0 as u32)
476 }
477
478 fn get<R>(&self, symbol: Symbol, with: impl FnOnce(&str) -> R) -> R {
480 let set = &self.inner.borrow().set;
481 with(set.get_index(symbol.as_u32() as usize).unwrap())
482 }
483}