aiken_lang/parser/literal/
bytearray.rs

1use chumsky::prelude::*;
2
3use crate::{
4    ast,
5    parser::{
6        error::{self, ParseError},
7        token::{Base, Token},
8    },
9};
10
11pub fn parser<A>(
12    into: impl Fn(
13        Vec<(u8, ast::Span)>,
14        ast::ByteArrayFormatPreference,
15        Option<ast::CurveType>,
16        ast::Span,
17        &mut dyn FnMut(ParseError),
18    ) -> A,
19) -> impl Parser<Token, A, Error = ParseError> {
20    choice((
21        array_of_bytes(),
22        hex_string(),
23        utf8_string().map(|(p, b)| {
24            (
25                None,
26                p,
27                b.into_iter().map(|b| (b, ast::Span::empty())).collect(),
28            )
29        }),
30    ))
31    .validate(move |(curve, preferred_format, bytes), span, emit| {
32        into(bytes, preferred_format, curve, span, emit)
33    })
34}
35
36fn curve_point() -> impl Parser<Token, ast::CurveType, Error = ParseError> {
37    just(Token::Less)
38        .ignore_then(select! {Token::UpName {name} => name})
39        .then_ignore(just(Token::Comma))
40        .then(select! {Token::UpName {name} => name})
41        .then_ignore(just(Token::Greater))
42        .validate(
43            |(curve_type, point_type), span, emit| match curve_type.as_str() {
44                "Bls12_381" => {
45                    let point = match point_type.as_str() {
46                        "G1" => ast::Bls12_381PointType::G1,
47                        "G2" => ast::Bls12_381PointType::G2,
48                        _ => {
49                            emit(ParseError::unknown_point_curve(
50                                curve_type,
51                                Some(point_type),
52                                span,
53                            ));
54
55                            ast::Bls12_381PointType::G1
56                        }
57                    };
58
59                    ast::CurveType::Bls12_381(point)
60                }
61                _ => {
62                    emit(ParseError::unknown_point_curve(curve_type, None, span));
63
64                    ast::CurveType::Bls12_381(ast::Bls12_381PointType::G1)
65                }
66            },
67        )
68}
69
70pub fn array_of_bytes() -> impl Parser<
71    Token,
72    (
73        Option<ast::CurveType>,
74        ast::ByteArrayFormatPreference,
75        Vec<(u8, ast::Span)>,
76    ),
77    Error = ParseError,
78> {
79    just(Token::Hash)
80        .ignore_then(curve_point().or_not())
81        .then(
82            select! {Token::Int {value, base, ..} => (value, base)}
83                .validate(|(value, base), span, emit| {
84                    let byte: u8 = match value.parse() {
85                        Ok(b) => b,
86                        Err(_) => {
87                            emit(ParseError::expected_input_found(
88                                span,
89                                None,
90                                Some(error::Pattern::Byte),
91                            ));
92                            0
93                        }
94                    };
95                    (byte, base, span)
96                })
97                .separated_by(just(Token::Comma))
98                .allow_trailing()
99                .delimited_by(just(Token::LeftSquare), just(Token::RightSquare)),
100        )
101        .validate(|(curve, bytes), span, emit| {
102            let base = bytes.iter().try_fold(None, |acc, (_, base, _)| match acc {
103                None => Ok(Some(base)),
104                Some(previous_base) if previous_base == base => Ok(Some(base)),
105                _ => Err(()),
106            });
107
108            let base = match base {
109                Err(()) => {
110                    emit(ParseError::hybrid_notation_in_bytearray(span));
111                    Base::Decimal {
112                        numeric_underscore: false,
113                    }
114                }
115                Ok(None) => Base::Decimal {
116                    numeric_underscore: false,
117                },
118                Ok(Some(base)) => *base,
119            };
120
121            (
122                curve,
123                bytes
124                    .into_iter()
125                    .map(|(b, _, span)| (b, span))
126                    .collect::<Vec<(u8, ast::Span)>>(),
127                base,
128            )
129        })
130        .map(|(curve, bytes, base)| {
131            (
132                curve,
133                ast::ByteArrayFormatPreference::ArrayOfBytes(base),
134                bytes,
135            )
136        })
137}
138
139pub fn hex_string() -> impl Parser<
140    Token,
141    (
142        Option<ast::CurveType>,
143        ast::ByteArrayFormatPreference,
144        Vec<(u8, ast::Span)>,
145    ),
146    Error = ParseError,
147> {
148    just(Token::Hash)
149        .ignore_then(curve_point().or_not())
150        .then(
151            select! {Token::ByteString {value} => value}.validate(|value, span, emit| {
152                match hex::decode(value) {
153                    Ok(bytes) => bytes,
154                    Err(_) => {
155                        emit(ParseError::malformed_base16_string_literal(span));
156                        vec![]
157                    }
158                }
159            }),
160        )
161        .map(|(curve, token)| {
162            (
163                curve,
164                ast::ByteArrayFormatPreference::HexadecimalString,
165                token.into_iter().map(|b| (b, ast::Span::empty())).collect(),
166            )
167        })
168}
169
170pub fn utf8_string()
171-> impl Parser<Token, (ast::ByteArrayFormatPreference, Vec<u8>), Error = ParseError> {
172    select! {Token::ByteString {value} => value.into_bytes() }
173        .map(|token| (ast::ByteArrayFormatPreference::Utf8String, token))
174}