tytanic_filter/ast/
str.rs1use std::fmt::Debug;
2use std::ops::Deref;
3
4use ecow::EcoString;
5use ecow::eco_vec;
6use pest::iterators::Pair;
7
8use super::Error;
9use super::PairExt;
10use super::PairsExt;
11use super::Rule;
12use crate::eval;
13use crate::eval::Context;
14use crate::eval::Eval;
15use crate::eval::Test;
16use crate::eval::TryFromValue;
17use crate::eval::Type;
18use crate::eval::Value;
19
20#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub struct Str(pub EcoString);
23
24impl Str {
25 pub fn as_str(&self) -> &str {
27 self.0.as_str()
28 }
29
30 pub fn into_inner(self) -> EcoString {
32 self.0
33 }
34}
35
36impl Debug for Str {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 self.0.fmt(f)
39 }
40}
41
42impl Deref for Str {
43 type Target = str;
44
45 fn deref(&self) -> &Self::Target {
46 self.as_str()
47 }
48}
49
50impl AsRef<str> for Str {
51 fn as_ref(&self) -> &str {
52 self.as_str()
53 }
54}
55
56impl From<EcoString> for Str {
57 fn from(value: EcoString) -> Self {
58 Self(value)
59 }
60}
61
62impl From<String> for Str {
63 fn from(value: String) -> Self {
64 Self(value.into())
65 }
66}
67
68impl From<&str> for Str {
69 fn from(value: &str) -> Self {
70 Self(value.into())
71 }
72}
73
74impl From<Str> for EcoString {
75 fn from(value: Str) -> Self {
76 value.into_inner()
77 }
78}
79
80impl<T: Test> Eval<T> for Str {
81 fn eval(&self, _ctx: &Context<T>) -> Result<Value<T>, eval::Error> {
82 Ok(Value::Str(self.clone()))
83 }
84}
85
86impl<T> TryFromValue<T> for Str {
87 fn try_from_value(value: Value<T>) -> Result<Self, eval::Error> {
88 Ok(match value {
89 Value::Str(str) => str,
90 _ => {
91 return Err(eval::Error::TypeMismatch {
92 expected: eco_vec![Type::Str],
93 found: value.as_type(),
94 });
95 }
96 })
97 }
98}
99
100impl Str {
101 pub(super) fn parse(pair: Pair<'_, Rule>) -> Result<Self, Error> {
102 pair.expect_rules(&[Rule::str_single, Rule::str_double])?;
103
104 let mut pairs = pair.into_inner();
105 let start = pairs.expect_pair(&[Rule::str_single_delim, Rule::str_double_delim])?;
106 let inner = pairs.expect_pair(&[Rule::str_single_inner, Rule::str_double_inner])?;
107 let _ = pairs.expect_pair(&[start.as_rule()])?;
108 pairs.expect_end()?;
109
110 match inner.as_rule() {
111 Rule::str_single_inner => Ok(Self(inner.as_str().into())),
112 Rule::str_double_inner => {
113 if !inner.as_str().contains('\\') {
114 Ok(Self(inner.as_str().into()))
115 } else {
116 let mut buf = String::with_capacity(inner.as_str().len());
117
118 let mut rest = inner.as_str();
119 while let Some((lit, esc)) = rest.split_once('\\') {
120 buf.push_str(lit);
121
122 if esc.starts_with(['\\', '"', 'n', 'r', 't']) {
123 match esc.as_bytes()[0] {
124 b'\\' => buf.push('\\'),
125 b'"' => buf.push('"'),
126 b'n' => buf.push('\n'),
127 b'r' => buf.push('\r'),
128 b't' => buf.push('\t'),
129 _ => unreachable!(),
130 }
131 rest = &esc[1..];
132 } else if let Some(esc) = esc.strip_prefix("u{") {
133 let (digits, other) =
134 esc.split_once('}').expect("parser ensures closing '}'");
135
136 buf.push(
137 u32::from_str_radix(digits, 16)
138 .expect("parser ensures hex digits only")
139 .try_into()?,
140 );
141
142 rest = other;
143 } else {
144 unreachable!(
145 "unhandled string escape sequence: {:?}",
146 esc.split_once(' ').map(|(p, _)| p).unwrap_or(esc)
147 );
148 }
149 }
150
151 Ok(Self(buf.into()))
152 }
153 }
154 _ => unreachable!(),
155 }
156 }
157}