1use indexmap::IndexMap;
2use pest::iterators::Pairs;
3use std::fmt::Display;
4use std::rc::Rc;
5
6use crate::rc_world;
7
8use super::value::Value;
9use super::ErrorLogger;
10use super::Rule;
11use super::State;
12
13#[derive(Debug, Clone, PartialEq)]
15pub enum Literal {
16 Null,
18 Integer(i64),
20 Float(f64),
22 Bool(bool),
24 Text(String),
26 Identifier(Rc<str>),
28}
29
30impl Default for Literal {
31 fn default() -> Self {
32 Literal::Integer(0)
33 }
34}
35
36impl Display for Literal {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 match self {
39 Self::Null => write!(f, "null"),
40 Self::Integer(int) => write!(f, "{int}"),
41 Self::Float(float) => write!(f, "{float}"),
42 Self::Bool(b) => write!(f, "{b}"),
43 Self::Text(text) => write!(f, "{text:?}"),
44 Self::Identifier(id) => write!(f, "{id}"),
45 }
46 }
47}
48
49impl Literal {
50 pub(super) fn parse(logger: &mut ErrorLogger, mut pairs: Pairs<'_, Rule>) -> Self {
51 let pair = pairs.next().expect("there is always a token in a literal");
52
53 let literal = match pair.as_rule() {
54 Rule::null => Literal::Null,
55 Rule::number => logger.absorb(
56 &pair,
57 pair.as_str()
58 .replace('_', "")
59 .parse::<i64>()
60 .map(|int| Literal::Integer(int))
61 .or_else(|_| {
62 pair.as_str()
63 .replace('_', "")
64 .parse::<f64>()
65 .map(|float| Literal::Float(float))
66 }),
67 ),
68 Rule::bool => match pair.as_str() {
69 "true" => Literal::Bool(true),
70 "false" => Literal::Bool(false),
71 _ => unreachable!(),
72 },
73 Rule::text => {
74 Literal::Text(logger.absorb(&pair, crate::utils::unescape(pair.as_str())))
75 }
76 Rule::identifier => Literal::Identifier(rc_world::str_to_rc(pair.as_str())),
77 _ => unreachable!(),
78 };
79
80 literal
81 }
82
83 #[must_use]
84 pub(super) fn capture(
85 &self,
86 state: &mut State<'_>,
87 provided: &[Rc<str>],
88 values: &mut IndexMap<Rc<str>, Value>,
89 ) -> Option<()> {
90 if let Self::Identifier(id) = self {
91 match state.try_get(id) {
92 Ok(cap) => {
93 values.insert(id.clone(), cap.clone());
94 }
95 Err(err) => {
96 if !provided.contains(&id) {
97 state.absorb(Err(err))?;
98 }
99 }
100 }
101 }
102
103 Some(())
104 }
105
106 pub(super) fn eval(&self, state: &mut State<'_>) -> Option<Value> {
107 let value = match self {
108 Self::Null => Value::Null,
109 Self::Bool(b) => Value::Bool(*b),
110 Self::Integer(int) => Value::Integer(*int),
111 Self::Float(float) => Value::Float(*float),
112 Self::Text(text) => Value::Text(rc_world::str_to_rc(&text)),
113 Self::Identifier(id) => state.get(id)?,
114 };
115
116 Some(value)
117 }
118}