cairo_lang_syntax/node/
ast_ext.rs1use cairo_lang_utils::require;
6use num_bigint::{BigInt, Sign};
7use num_traits::Num;
8use smol_str::SmolStr;
9use unescaper::unescape;
10
11use super::{
12 TerminalFalse, TerminalLiteralNumber, TerminalShortString, TerminalString, TerminalTrue,
13};
14use crate::node::Terminal;
15use crate::node::db::SyntaxGroup;
16
17impl TerminalTrue {
18 #[inline(always)]
19 pub fn boolean_value(&self) -> bool {
20 true
21 }
22}
23
24impl TerminalFalse {
25 #[inline(always)]
26 pub fn boolean_value(&self) -> bool {
27 false
28 }
29}
30
31impl TerminalLiteralNumber {
32 pub fn numeric_value(&self, db: &dyn SyntaxGroup) -> 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: &dyn SyntaxGroup,
41 ) -> Option<(BigInt, Option<SmolStr>)> {
42 let text = self.text(db);
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.as_str(), 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((BigInt::from_str_radix(text, radix).ok()?, suffix.map(SmolStr::new)))
68 }
69 }
70}
71
72impl TerminalShortString {
73 pub fn string_value(&self, db: &dyn SyntaxGroup) -> Option<String> {
75 let text = self.text(db);
76
77 let (text, _suffix) = string_value(&text, '\'')?;
78
79 Some(text)
80 }
81
82 pub fn numeric_value(&self, db: &dyn SyntaxGroup) -> Option<BigInt> {
84 self.string_value(db).map(|string| BigInt::from_bytes_be(Sign::Plus, string.as_bytes()))
85 }
86
87 pub fn suffix(&self, db: &dyn SyntaxGroup) -> Option<SmolStr> {
89 let text = self.text(db);
90 let (_literal, mut suffix) = text[1..].rsplit_once('\'')?;
91 require(!suffix.is_empty())?;
92 if suffix.starts_with('_') {
93 suffix = &suffix[1..];
94 }
95 Some(suffix.into())
96 }
97}
98
99impl TerminalString {
100 pub fn string_value(&self, db: &dyn SyntaxGroup) -> Option<String> {
102 let text = self.text(db);
103 let (text, suffix) = string_value(&text, '"')?;
104 if !suffix.is_empty() {
105 unreachable!();
106 }
107
108 Some(text)
109 }
110}
111
112fn string_value(text: &str, delimiter: char) -> Option<(String, &str)> {
114 let (prefix, text) = text.split_once(delimiter)?;
115 if !prefix.is_empty() {
116 unreachable!();
117 }
118
119 let (text, suffix) = text.rsplit_once(delimiter)?;
120
121 let text = unescape(text).ok()?;
122
123 require(text.is_ascii())?;
124
125 Some((text, suffix))
126}