darklua_core/nodes/
literal_expression.rs1use std::{convert::TryFrom, num::FpCategory};
2
3use crate::nodes::{
4 BinaryNumber, DecimalNumber, Expression, HexNumber, Identifier, NumberExpression,
5 StringExpression, TableEntry, TableExpression, TableFieldEntry, TableTokens, Token, Trivia,
6};
7
8#[derive(Clone, Debug, PartialEq, Eq)]
13pub enum LiteralExpression {
14 True(Option<Token>),
16 False(Option<Token>),
18 Nil(Option<Token>),
20 Number(NumberExpression),
22 String(StringExpression),
24 Table(Box<LiteralTable>),
26}
27
28impl LiteralExpression {
29 pub fn nil() -> Self {
31 Self::Nil(None)
32 }
33}
34
35impl From<LiteralTable> for LiteralExpression {
36 fn from(v: LiteralTable) -> Self {
37 Self::Table(Box::new(v))
38 }
39}
40
41impl From<StringExpression> for LiteralExpression {
42 fn from(v: StringExpression) -> Self {
43 Self::String(v)
44 }
45}
46
47impl From<bool> for LiteralExpression {
48 fn from(v: bool) -> Self {
49 if v {
50 Self::True(None)
51 } else {
52 Self::False(None)
53 }
54 }
55}
56
57impl TryFrom<f64> for LiteralExpression {
58 type Error = &'static str;
59
60 fn try_from(value: f64) -> Result<Self, Self::Error> {
61 match value.classify() {
62 FpCategory::Nan => Err("NaN is not a valid literal expression"),
63 FpCategory::Infinite => Err("Infinity is not a valid literal expression"),
64 FpCategory::Zero => {
65 Ok(DecimalNumber::new(if value.is_sign_positive() {
66 0.0
67 } else {
68 0.0
71 })
72 .into())
73 }
74 FpCategory::Subnormal | FpCategory::Normal => {
75 if value < 0.0 {
76 Err("Negative numbers are not a valid literal expression")
77 } else if value < 0.1 {
78 let exponent = value.log10().floor();
79
80 Ok(DecimalNumber::new(value)
81 .with_exponent(exponent as i64, true)
82 .into())
83 } else if value > 999.0 && (value / 100.0).fract() == 0.0 {
84 let mut exponent = value.log10().floor();
85 let mut power = 10_f64.powf(exponent);
86
87 while exponent > 2.0 && (value / power).fract() != 0.0 {
88 exponent -= 1.0;
89 power /= 10.0;
90 }
91
92 Ok(DecimalNumber::new(value)
93 .with_exponent(exponent as i64, true)
94 .into())
95 } else {
96 Ok(DecimalNumber::new(value).into())
97 }
98 }
99 }
100 }
101}
102
103impl TryFrom<f32> for LiteralExpression {
104 type Error = &'static str;
105
106 fn try_from(value: f32) -> Result<Self, Self::Error> {
107 LiteralExpression::try_from(value as f64)
108 }
109}
110
111impl From<NumberExpression> for LiteralExpression {
112 fn from(v: NumberExpression) -> Self {
113 Self::Number(v)
114 }
115}
116
117impl TryFrom<u64> for LiteralExpression {
118 type Error = &'static str;
119
120 fn try_from(value: u64) -> Result<Self, Self::Error> {
121 LiteralExpression::try_from(value as f64)
122 }
123}
124
125impl From<u32> for LiteralExpression {
126 fn from(value: u32) -> Self {
127 LiteralExpression::try_from(value as f64)
128 .expect("converting a u32 to a literal number expression should never fail")
129 }
130}
131
132impl From<u16> for LiteralExpression {
133 fn from(value: u16) -> Self {
134 LiteralExpression::try_from(value as f64)
135 .expect("converting a u16 to a literal number expression should never fail")
136 }
137}
138
139impl From<u8> for LiteralExpression {
140 fn from(value: u8) -> Self {
141 LiteralExpression::try_from(value as f64)
142 .expect("converting a u8 to a literal number expression should never fail")
143 }
144}
145
146impl TryFrom<i64> for LiteralExpression {
147 type Error = &'static str;
148
149 fn try_from(value: i64) -> Result<Self, Self::Error> {
150 LiteralExpression::try_from(value as f64)
151 }
152}
153
154impl TryFrom<i32> for LiteralExpression {
155 type Error = &'static str;
156
157 fn try_from(value: i32) -> Result<Self, Self::Error> {
158 LiteralExpression::try_from(value as f64)
159 }
160}
161
162impl TryFrom<i16> for LiteralExpression {
163 type Error = &'static str;
164
165 fn try_from(value: i16) -> Result<Self, Self::Error> {
166 LiteralExpression::try_from(value as f64)
167 }
168}
169
170impl TryFrom<i8> for LiteralExpression {
171 type Error = &'static str;
172
173 fn try_from(value: i8) -> Result<Self, Self::Error> {
174 LiteralExpression::try_from(value as f64)
175 }
176}
177
178impl From<DecimalNumber> for LiteralExpression {
179 fn from(number: DecimalNumber) -> Self {
180 Self::Number(NumberExpression::Decimal(number))
181 }
182}
183
184impl From<HexNumber> for LiteralExpression {
185 fn from(number: HexNumber) -> Self {
186 Self::Number(NumberExpression::Hex(number))
187 }
188}
189
190impl From<BinaryNumber> for LiteralExpression {
191 fn from(number: BinaryNumber) -> Self {
192 Self::Number(NumberExpression::Binary(number))
193 }
194}
195
196impl<T: Into<LiteralExpression>> From<Option<T>> for LiteralExpression {
197 fn from(value: Option<T>) -> Self {
198 match value {
199 None => Self::nil(),
200 Some(value) => value.into(),
201 }
202 }
203}
204
205impl From<LiteralExpression> for Expression {
206 fn from(literal: LiteralExpression) -> Self {
207 match literal {
208 LiteralExpression::True(token) => Self::True(token),
209 LiteralExpression::False(token) => Self::False(token),
210 LiteralExpression::Nil(token) => Self::Nil(token),
211 LiteralExpression::Number(num) => Self::Number(num),
212 LiteralExpression::String(string) => Self::String(string),
213 LiteralExpression::Table(table) => Self::Table((*table).into()),
214 }
215 }
216}
217
218#[derive(Clone, Debug, Default, PartialEq, Eq)]
222pub struct LiteralTable {
223 entries: Vec<LiteralTableEntry>,
224 tokens: Option<TableTokens>,
225}
226
227impl LiteralTable {
228 pub fn from_entries(entries: Vec<LiteralTableEntry>) -> Self {
230 Self {
231 entries,
232 tokens: None,
233 }
234 }
235
236 pub fn with_entry(mut self, entry: impl Into<LiteralTableEntry>) -> Self {
238 self.entries.push(entry.into());
239 self
240 }
241
242 pub fn append_entry(&mut self, entry: impl Into<LiteralTableEntry>) {
244 self.entries.push(entry.into());
245 }
246
247 pub fn append_field(&mut self, field: Identifier, value: impl Into<LiteralExpression>) {
249 self.append_entry(LiteralTableEntry::Field(Box::new(LiteralTableFieldEntry {
250 field,
251 value: value.into(),
252 token: None,
253 })));
254 }
255
256 pub fn append_array_value(&mut self, value: impl Into<LiteralExpression>) {
258 self.append_entry(LiteralTableEntry::Value(Box::new(value.into())));
259 }
260
261 pub fn iter_entries(&self) -> impl Iterator<Item = &LiteralTableEntry> {
263 self.entries.iter()
264 }
265
266 pub fn iter_mut_entries(&mut self) -> impl Iterator<Item = &mut LiteralTableEntry> {
268 self.entries.iter_mut()
269 }
270
271 pub fn with_tokens(mut self, tokens: TableTokens) -> Self {
273 self.tokens = Some(tokens);
274 self
275 }
276
277 pub fn set_tokens(&mut self, tokens: TableTokens) {
279 self.tokens = Some(tokens);
280 }
281
282 pub fn get_tokens(&self) -> Option<&TableTokens> {
284 self.tokens.as_ref()
285 }
286
287 pub fn len(&self) -> usize {
289 self.entries.len()
290 }
291
292 pub fn is_empty(&self) -> bool {
294 self.entries.is_empty()
295 }
296
297 super::impl_token_fns!(iter = [tokens, entries]);
298}
299
300#[derive(Clone, Debug, PartialEq, Eq)]
302pub enum LiteralTableEntry {
303 Field(Box<LiteralTableFieldEntry>),
305 Value(Box<LiteralExpression>),
307}
308
309impl LiteralTableEntry {
310 pub fn from_value(value: impl Into<LiteralExpression>) -> Self {
312 Self::Value(Box::new(value.into()))
313 }
314
315 pub fn clear_comments(&mut self) {
317 match self {
318 Self::Field(entry) => entry.clear_comments(),
319 Self::Value(_value) => {}
320 }
321 }
322
323 pub fn clear_whitespaces(&mut self) {
325 match self {
326 Self::Field(entry) => entry.clear_whitespaces(),
327 Self::Value(_value) => {}
328 }
329 }
330
331 pub(crate) fn replace_referenced_tokens(&mut self, code: &str) {
332 match self {
333 Self::Field(entry) => entry.replace_referenced_tokens(code),
334 Self::Value(_value) => {}
335 }
336 }
337
338 pub(crate) fn shift_token_line(&mut self, amount: isize) {
339 match self {
340 Self::Field(entry) => entry.shift_token_line(amount),
341 Self::Value(_value) => {}
342 }
343 }
344
345 pub(crate) fn filter_comments(&mut self, filter: impl Fn(&Trivia) -> bool) {
346 match self {
347 Self::Field(entry) => entry.filter_comments(filter),
348 Self::Value(_value) => {}
349 }
350 }
351}
352
353impl From<LiteralTableFieldEntry> for LiteralTableEntry {
354 fn from(v: LiteralTableFieldEntry) -> Self {
355 Self::Field(Box::new(v))
356 }
357}
358
359impl From<LiteralExpression> for LiteralTableEntry {
360 fn from(v: LiteralExpression) -> Self {
361 Self::Value(Box::new(v))
362 }
363}
364
365#[derive(Clone, Debug, PartialEq, Eq)]
369pub struct LiteralTableFieldEntry {
370 field: Identifier,
371 value: LiteralExpression,
372 token: Option<Token>,
373}
374
375impl LiteralTableFieldEntry {
376 pub fn with_token(mut self, token: Token) -> Self {
378 self.token = Some(token);
379 self
380 }
381
382 pub fn set_token(&mut self, token: Token) {
384 self.token = Some(token);
385 }
386
387 pub fn get_token(&self) -> Option<&Token> {
389 self.token.as_ref()
390 }
391
392 pub fn get_field(&self) -> &Identifier {
394 &self.field
395 }
396
397 pub fn mutate_field(&mut self) -> &mut Identifier {
399 &mut self.field
400 }
401
402 pub fn get_value(&self) -> &LiteralExpression {
404 &self.value
405 }
406
407 pub fn mutate_value(&mut self) -> &mut LiteralExpression {
409 &mut self.value
410 }
411
412 pub fn mutate_token(&mut self) -> Option<&mut Token> {
414 self.token.as_mut()
415 }
416
417 super::impl_token_fns!(
418 target = [field]
419 iter = [token]
420 );
421}
422
423impl From<LiteralTable> for TableExpression {
424 fn from(literal_table: LiteralTable) -> Self {
425 let entries = literal_table
426 .entries
427 .into_iter()
428 .map(|entry| match entry {
429 LiteralTableEntry::Field(field) => {
430 let field = *field;
431 TableEntry::Field(Box::new(TableFieldEntry::new(
432 field.field,
433 Expression::from(field.value),
434 )))
435 }
436 LiteralTableEntry::Value(value) => {
437 TableEntry::Value(Box::new(Expression::from(*value)))
438 }
439 })
440 .collect();
441
442 let mut table = TableExpression::new(entries);
443 if let Some(tokens) = literal_table.tokens {
444 table.set_tokens(tokens);
445 }
446 table
447 }
448}