rune/ast/
lit_byte.rs
1use crate::ast::prelude::*;
2
3#[test]
4#[cfg(not(miri))]
5fn ast_parse() {
6 rt::<ast::LitByte>("b'a'");
7 rt::<ast::LitByte>("b'\\0'");
8 rt::<ast::LitByte>("b'\\n'");
9 rt::<ast::LitByte>("b'\\r'");
10 rt::<ast::LitByte>("b'\\\\''");
11}
12
13#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)]
15#[try_clone(copy)]
16#[non_exhaustive]
17pub struct LitByte {
18 pub span: Span,
20 #[rune(skip)]
22 pub source: ast::CopySource<u8>,
23}
24
25impl ToAst for LitByte {
26 fn to_ast(span: Span, kind: ast::Kind) -> compile::Result<Self> {
27 match kind {
28 K![byte(source)] => Ok(LitByte { span, source }),
29 _ => Err(compile::Error::expected(
30 ast::Token { span, kind },
31 Self::into_expectation(),
32 )),
33 }
34 }
35
36 #[inline]
37 fn matches(kind: &ast::Kind) -> bool {
38 matches!(kind, K![byte])
39 }
40
41 #[inline]
42 fn into_expectation() -> Expectation {
43 Expectation::Description("byte literal")
44 }
45}
46
47impl Parse for LitByte {
48 fn parse(parser: &mut Parser<'_>) -> Result<Self> {
49 let t = parser.next()?;
50 Self::to_ast(t.span, t.kind)
51 }
52}
53
54impl<'a> Resolve<'a> for LitByte {
55 type Output = u8;
56
57 fn resolve(&self, cx: ResolveContext<'a>) -> Result<u8> {
58 let source_id = match self.source {
59 ast::CopySource::Inline(b) => return Ok(b),
60 ast::CopySource::Text(source_id) => source_id,
61 };
62
63 let span = self.span;
64
65 let string = cx
66 .sources
67 .source(source_id, span.trim_start(2u32).trim_end(1u32))
68 .ok_or_else(|| compile::Error::new(span, ErrorKind::BadSlice))?;
69
70 let start = span.start.into_usize();
71
72 let mut it = string
73 .char_indices()
74 .map(|(n, c)| (start + n, c))
75 .peekable();
76
77 let (start, c) = match it.next() {
78 Some(c) => c,
79 None => {
80 return Err(compile::Error::new(span, ErrorKind::BadByteLiteral));
81 }
82 };
83
84 let c = match c {
85 '\\' => {
86 let c = match ast::unescape::parse_byte_escape(
87 &mut it,
88 ast::unescape::WithLineCont(false),
89 ) {
90 Ok(c) => c,
91 Err(kind) => {
92 let end = it
93 .next()
94 .map(|n| n.0)
95 .unwrap_or_else(|| span.end.into_usize());
96 return Err(compile::Error::new(Span::new(start, end), kind));
97 }
98 };
99
100 match c {
101 Some(c) => c,
102 None => {
103 let end = it
104 .next()
105 .map(|n| n.0)
106 .unwrap_or_else(|| span.end.into_usize());
107 return Err(compile::Error::new(
108 Span::new(start, end),
109 ErrorKind::BadByteLiteral,
110 ));
111 }
112 }
113 }
114 c if c.is_ascii() && !c.is_control() => c as u8,
115 _ => {
116 return Err(compile::Error::new(span, ErrorKind::BadByteLiteral));
117 }
118 };
119
120 if it.next().is_some() {
122 return Err(compile::Error::new(span, ErrorKind::BadByteLiteral));
123 }
124
125 Ok(c)
126 }
127}
128
129impl ToTokens for LitByte {
130 fn to_tokens(
131 &self,
132 _: &mut MacroContext<'_, '_, '_>,
133 stream: &mut TokenStream,
134 ) -> alloc::Result<()> {
135 stream.push(ast::Token {
136 span: self.span,
137 kind: ast::Kind::Byte(self.source),
138 })
139 }
140}