cairo_lang_syntax/node/
ast_ext.rs1use cairo_lang_filesystem::ids::SmolStrId;
6use cairo_lang_utils::require;
7use num_bigint::{BigInt, Sign};
8use num_traits::Num;
9use salsa::Database;
10use unescaper::unescape;
11
12use super::{
13 TerminalFalse, TerminalLiteralNumber, TerminalShortString, TerminalString, TerminalTrue,
14};
15use crate::node::Terminal;
16
17impl<'a> TerminalTrue<'a> {
18 #[inline(always)]
19 pub fn boolean_value(&self) -> bool {
20 true
21 }
22}
23
24impl<'a> TerminalFalse<'a> {
25 #[inline(always)]
26 pub fn boolean_value(&self) -> bool {
27 false
28 }
29}
30
31impl<'a> TerminalLiteralNumber<'a> {
32 pub fn numeric_value(&self, db: &'a dyn Database) -> Option<BigInt> {
34 self.numeric_value_and_suffix(db).map(|(value, _suffix)| value)
35 }
36
37 pub fn numeric_value_and_suffix(
39 &self,
40 db: &'a dyn Database,
41 ) -> Option<(BigInt, Option<SmolStrId<'a>>)> {
42 let text = self.text(db).long(db).as_str();
43
44 let (text, radix) = if let Some(num_no_prefix) = text.strip_prefix("0x") {
45 (num_no_prefix, 16)
46 } else if let Some(num_no_prefix) = text.strip_prefix("0o") {
47 (num_no_prefix, 8)
48 } else if let Some(num_no_prefix) = text.strip_prefix("0b") {
49 (num_no_prefix, 2)
50 } else {
51 (text, 10)
52 };
53
54 if let Ok(value) = BigInt::from_str_radix(text, radix) {
58 Some((value, None))
59 } else {
60 let (text, suffix) = match text.rsplit_once('_') {
61 Some((text, suffix)) => {
62 let suffix = if suffix.is_empty() { None } else { Some(suffix) };
63 (text, suffix)
64 }
65 None => (text, None),
66 };
67 Some((
68 BigInt::from_str_radix(text, radix).ok()?,
69 suffix.map(|s| SmolStrId::from(db, s)),
70 ))
71 }
72 }
73}
74
75impl<'a> TerminalShortString<'a> {
76 pub fn string_value(&self, db: &'a dyn Database) -> Option<String> {
78 let text = self.text(db).long(db);
79
80 let (text, _suffix) = string_value(text, '\'')?;
81
82 Some(text)
83 }
84
85 pub fn numeric_value(&self, db: &'a dyn Database) -> Option<BigInt> {
87 self.string_value(db).map(|string| BigInt::from_bytes_be(Sign::Plus, string.as_bytes()))
88 }
89
90 pub fn suffix(&self, db: &'a dyn Database) -> Option<&'a str> {
92 let text = self.text(db).long(db);
93 let (_literal, mut suffix) = text[1..].rsplit_once('\'')?;
94 require(!suffix.is_empty())?;
95 if suffix.starts_with('_') {
96 suffix = &suffix[1..];
97 }
98 Some(suffix)
99 }
100}
101
102impl<'a> TerminalString<'a> {
103 pub fn string_value(&self, db: &'a dyn Database) -> Option<String> {
105 let text = self.text(db).long(db);
106 let (text, suffix) = string_value(text, '"')?;
107 if !suffix.is_empty() {
108 unreachable!();
109 }
110
111 Some(text)
112 }
113}
114
115fn string_value(text: &str, delimiter: char) -> Option<(String, &str)> {
117 let (prefix, text) = text.split_once(delimiter)?;
118 if !prefix.is_empty() {
119 unreachable!();
120 }
121
122 let (text, suffix) = text.rsplit_once(delimiter)?;
123
124 let text = unescape(text).ok()?;
125
126 require(text.is_ascii())?;
127
128 Some((text, suffix))
129}