aiken_lang/parser/literal/
bytearray.rs1use 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}