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
243 private_key,
245
246 As: "as",
248 assert,
249 assert_eq,
250 assert_neq,
251 caller,
252 Const: "const",
253 constant,
254 constructor,
255 decrement,
256 Else: "else",
257 For: "for",
258 function,
259 If: "if",
260 In: "in",
261 import,
262 increment,
263 inline,
264 input,
265 Let: "let",
266 leo,
267 main,
268 mapping,
269 Mut: "mut",
270 Return: "return",
271 script,
272 SelfLower: "self",
273 SelfUpper: "Self",
274 signer,
275 Star: "*",
276 transition,
277 Type: "type",
278
279 aleo,
280 public,
281 private,
282 owner,
283 _nonce,
284 program,
285 stub,
286 block,
287 height,
288 network,
289 id,
290}
291
292#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
297pub struct Symbol(
298 #[serde(deserialize_with = "Symbol::serde_to_symbol")]
299 #[serde(serialize_with = "Symbol::serde_from_symbol")]
300 NonZeroU32,
301);
302
303impl Default for Symbol {
304 fn default() -> Self {
305 Symbol(NonZeroU32::MIN)
306 }
307}
308
309impl Symbol {
310 pub const fn new(index: u32) -> Self {
312 let index = index.saturating_add(1);
313 Self(match NonZeroU32::new(index) {
314 None => unreachable!(),
315 Some(x) => x,
316 })
317 }
318
319 pub fn intern(string: &str) -> Self {
321 with_session_globals(|session_globals| session_globals.symbol_interner.intern(string))
322 }
323
324 pub fn as_str<R>(self, s: &SessionGlobals, with: impl FnOnce(&str) -> R) -> R {
326 s.symbol_interner.get(self, with)
327 }
328
329 pub const fn as_u32(self) -> u32 {
331 self.0.get() - 1
332 }
333
334 fn serde_to_symbol<'de, D: Deserializer<'de>>(de: D) -> Result<NonZeroU32, D::Error> {
335 Ok(Symbol::intern(<&str>::deserialize(de)?).0)
336 }
337
338 fn serde_from_symbol<S: Serializer>(index: &NonZeroU32, ser: S) -> Result<S::Ok, S::Error> {
339 with_session_globals(|sg| Self(*index).as_str(sg, |s| ser.serialize_str(s)))
340 }
341}
342
343impl fmt::Debug for Symbol {
344 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
345 with_session_globals(|s| self.as_str(s, |s| fmt::Debug::fmt(s, f)))
346 }
347}
348
349impl fmt::Display for Symbol {
350 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351 with_session_globals(|s| self.as_str(s, |s| fmt::Display::fmt(s, f)))
352 }
353}
354
355pub struct SessionGlobals {
357 symbol_interner: Interner,
359 pub source_map: SourceMap,
361}
362
363impl Default for SessionGlobals {
364 fn default() -> Self {
365 Self { symbol_interner: Interner::prefilled(), source_map: SourceMap::default() }
366 }
367}
368
369scoped_tls::scoped_thread_local!(pub static SESSION_GLOBALS: SessionGlobals);
370
371#[inline]
373pub fn create_session_if_not_set_then<R>(f: impl FnOnce(&SessionGlobals) -> R) -> R {
374 if !SESSION_GLOBALS.is_set() {
375 let sg = SessionGlobals::default();
376 SESSION_GLOBALS.set(&sg, || SESSION_GLOBALS.with(f))
377 } else {
378 SESSION_GLOBALS.with(f)
379 }
380}
381
382#[inline]
384pub fn with_session_globals<R>(f: impl FnOnce(&SessionGlobals) -> R) -> R {
385 SESSION_GLOBALS.with(f)
386}
387
388#[derive(Eq)]
392enum InternedStr {
393 Static(&'static str),
395 Owned(Box<str>),
397}
398
399impl Borrow<str> for InternedStr {
400 fn borrow(&self) -> &str {
401 self.deref()
402 }
403}
404
405impl Deref for InternedStr {
406 type Target = str;
407
408 fn deref(&self) -> &Self::Target {
409 match self {
410 Self::Static(s) => s,
411 Self::Owned(s) => s,
412 }
413 }
414}
415
416impl PartialEq for InternedStr {
417 fn eq(&self, other: &InternedStr) -> bool {
418 self.deref() == other.deref()
419 }
420}
421
422impl Hash for InternedStr {
423 fn hash<H: Hasher>(&self, state: &mut H) {
424 self.deref().hash(state);
425 }
426}
427
428struct InnerInterner {
431 set: IndexSet<InternedStr, FxBuildHasher>,
435}
436
437struct Interner {
439 inner: RefCell<InnerInterner>,
440}
441
442impl Interner {
443 fn prefilled() -> Self {
445 Self::prefill(PRE_DEFINED)
446 }
447
448 fn prefill(init: &[&'static str]) -> Self {
450 let inner = InnerInterner {
451 set: init.iter().copied().map(InternedStr::Static).collect(),
453 };
454 Self { inner: RefCell::new(inner) }
455 }
456
457 fn intern(&self, string: &str) -> Symbol {
459 let InnerInterner { set } = &mut *self.inner.borrow_mut();
460
461 if let Some(sym) = set.get_index_of(string) {
462 return Symbol::new(sym as u32);
464 }
465
466 Symbol::new(set.insert_full(InternedStr::Owned(string.into())).0 as u32)
467 }
468
469 fn get<R>(&self, symbol: Symbol, with: impl FnOnce(&str) -> R) -> R {
471 let set = &self.inner.borrow().set;
472 with(set.get_index(symbol.as_u32() as usize).unwrap())
473 }
474}