use crate::mem::own;
use crate::mem::own_str;
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PartExpression {
pub expression: Box<crate::Expression>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PartInterpolation {
pub expression: Box<crate::Expression>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PartRaw {
pub content: Box<str>,
pub span: Box<crate::Span>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Part {
Expression(PartExpression),
Interpolation(PartInterpolation),
Raw(PartRaw),
}
impl Part {
pub fn span(&self) -> crate::Span {
match self {
Self::Expression(expression) => expression.expression.span(),
Self::Interpolation(interpolation) => {
interpolation.expression.span()
},
Self::Raw(raw) => raw.span.as_ref().clone(),
}
}
pub fn start(&self) -> crate::Position {
match self {
Self::Expression(expression) => expression.expression.start(),
Self::Interpolation(interpolation) => {
interpolation.expression.start()
},
Self::Raw(raw) => raw.span.start.as_ref().clone(),
}
}
pub fn end(&self) -> crate::Position {
match self {
Self::Expression(expression) => expression.expression.end(),
Self::Interpolation(interpolation) => {
interpolation.expression.end()
},
Self::Raw(raw) => raw.span.end.as_ref().clone(),
}
}
}
impl std::convert::From<*mut crate::ffi::Part> for Part {
fn from(part: *mut crate::ffi::Part) -> Self {
let crate::ffi::Part { kind, ptr } = own(part);
match kind {
crate::ffi::PartKind_PartKindExpression => {
let expression: crate::ffi::Expression = own(ptr);
Self::Expression(PartExpression {
expression: Box::new(crate::Expression::from(expression)),
})
},
crate::ffi::PartKind_PartKindInterpolation => {
let expression: crate::ffi::Expression = own(ptr);
Self::Interpolation(PartInterpolation {
expression: Box::new(crate::Expression::from(expression)),
})
},
crate::ffi::PartKind_PartKindRaw => {
let crate::ffi::PartRaw { content, span } = own(ptr);
let crate::ffi::UtilString { content, should_unescape } =
own(content);
let content = own_str(content);
Self::Raw(PartRaw {
content: if should_unescape {
unescape(&content)
} else {
content
},
span: Box::new(crate::Span::from(span)),
})
},
_ => unreachable!(),
}
}
}
fn unescape(content: &str) -> Box<str> {
let mut input_chars = content.chars().peekable();
let mut output = String::new();
loop {
let input_char = input_chars.next();
if input_char.is_none() {
break;
}
let mut input_char = input_char.unwrap();
match input_char {
'\\' => {
input_char = input_chars.next().unwrap();
if input_char == 'n' {
output.push('\n');
} else if input_char == 'r' {
output.push('\r');
} else if input_char == 't' {
output.push('\t');
} else {
output.push(input_char);
}
},
'\r' => {
output.push('\n');
input_chars.next_if(|s| *s == '\n');
},
c => {
output.push(c);
},
}
}
output.into_boxed_str()
}