1use super::sigma::combiners::StatementTree;
4use super::sigma::types::*;
5use quote::format_ident;
6use std::collections::HashMap;
7use std::fmt;
8use syn::ext::IdentExt;
9use syn::parse::{Parse, ParseStream, Result};
10use syn::punctuated::Punctuated;
11use syn::{parenthesized, Error, Expr, Ident, Token};
12
13#[derive(Clone, Debug, PartialEq, Eq)]
25pub struct TaggedScalar {
26 pub id: Ident,
27 pub is_pub: bool,
28 pub is_rand: bool,
29 pub is_vec: bool,
30}
31
32impl Parse for TaggedScalar {
33 fn parse(input: ParseStream) -> Result<Self> {
34 let (mut is_pub, mut is_rand, mut is_vec) = (false, false, false);
35 loop {
36 let id = input.call(Ident::parse_any)?;
37 match id.to_string().as_str() {
38 "pub" if !is_rand => {
40 is_pub = true;
41 }
42 "rand" if !is_pub => {
43 is_rand = true;
44 }
45 "pub" | "rand" | "cind" | "const" => {
47 return Err(Error::new(id.span(), "tag not allowed in this position"));
48 }
49 "vec" => {
51 is_vec = true;
52 }
53 _ => {
54 return Ok(TaggedScalar {
55 id,
56 is_pub,
57 is_rand,
58 is_vec,
59 });
60 }
61 }
62 }
63 }
64}
65
66impl fmt::Display for TaggedScalar {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 let mut res = String::new();
69 if self.is_pub {
70 res += "pub ";
71 }
72 if self.is_rand {
73 res += "rand ";
74 }
75 if self.is_vec {
76 res += "vec ";
77 }
78 res += &self.id.to_string();
79
80 write!(f, "{res}")
81 }
82}
83
84#[derive(Clone, Debug, PartialEq, Eq)]
99pub struct TaggedPoint {
100 pub id: Ident,
101 pub is_cind: bool,
102 pub is_const: bool,
103 pub is_vec: bool,
104}
105
106impl Parse for TaggedPoint {
107 fn parse(input: ParseStream) -> Result<Self> {
108 let (mut is_cind, mut is_const, mut is_vec) = (false, false, false);
110 loop {
111 let id = input.call(Ident::parse_any)?;
112 match id.to_string().as_str() {
113 "cind" => {
114 is_cind = true;
115 }
116 "const" => {
117 is_const = true;
118 }
119 "pub" | "rand" => {
121 return Err(Error::new(id.span(), "tag not allowed in this position"));
122 }
123 "vec" => {
124 is_vec = true;
125 }
126 _ => {
127 return Ok(TaggedPoint {
128 id,
129 is_cind,
130 is_const,
131 is_vec,
132 });
133 }
134 }
135 }
136 }
137}
138
139impl fmt::Display for TaggedPoint {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 let mut res = String::new();
142 if self.is_vec {
143 res += "vec ";
144 }
145 if self.is_const {
146 res += "const ";
147 }
148 if self.is_cind {
149 res += "cind ";
150 }
151 res += &self.id.to_string();
152
153 write!(f, "{res}")
154 }
155}
156
157#[derive(Clone, Debug, PartialEq, Eq)]
160pub enum TaggedIdent {
161 Scalar(TaggedScalar),
162 Point(TaggedPoint),
163}
164
165impl From<&TaggedIdent> for AExprType {
167 fn from(ti: &TaggedIdent) -> Self {
168 match ti {
169 TaggedIdent::Scalar(ts) => Self::Scalar {
170 is_pub: ts.is_pub,
171 is_vec: ts.is_vec,
172 val: None,
173 },
174 TaggedIdent::Point(tp) => Self::Point {
175 is_pub: true,
176 is_vec: tp.is_vec,
177 },
178 }
179 }
180}
181
182pub type TaggedVarDict = HashMap<String, TaggedIdent>;
187
188pub fn taggedvardict_to_vardict(vd: &TaggedVarDict) -> VarDict {
192 vd.iter()
193 .map(|(k, v)| (k.clone(), AExprType::from(v)))
194 .collect()
195}
196
197pub fn collect_cind_points(vars: &TaggedVarDict) -> Vec<Ident> {
200 let mut cind_points: Vec<Ident> = vars
201 .values()
202 .filter_map(|ti| {
203 if let TaggedIdent::Point(TaggedPoint {
204 is_cind: true,
205 is_vec: false,
206 id,
207 ..
208 }) = ti
209 {
210 Some(id.clone())
211 } else {
212 None
213 }
214 })
215 .collect();
216 cind_points.sort();
217 cind_points
218}
219
220#[cfg(test)]
221pub fn taggedvardict_from_strs((scalar_strs, point_strs): (&[&str], &[&str])) -> TaggedVarDict {
224 let mut vars = HashMap::new();
225
226 for scalar in scalar_strs {
227 let ts: TaggedScalar = syn::parse_str(scalar).unwrap();
228 vars.insert(ts.id.to_string(), TaggedIdent::Scalar(ts));
229 }
230 for point in point_strs {
231 let tp: TaggedPoint = syn::parse_str(point).unwrap();
232 vars.insert(tp.id.to_string(), TaggedIdent::Point(tp));
233 }
234 vars
235}
236
237#[derive(Debug)]
240pub struct SigmaCompSpec {
241 pub proto_name: Ident,
244
245 pub group_name: Ident,
252
253 pub vars: TaggedVarDict,
257
258 pub statements: StatementTree,
261}
262
263fn paren_taggedidents<T: Parse>(input: ParseStream) -> Result<Vec<T>> {
265 let content;
266 parenthesized!(content in input);
267 let punc: Punctuated<T, Token![,]> = content.parse_terminated(T::parse, Token![,])?;
268 Ok(punc.into_iter().collect())
269}
270
271impl Parse for SigmaCompSpec {
272 fn parse(input: ParseStream) -> Result<Self> {
273 let proto_name: Ident = input.parse()?;
274 let group_name = if input.peek(Token![<]) {
276 input.parse::<Token![<]>()?;
277 let gr: Ident = input.parse()?;
278 input.parse::<Token![>]>()?;
279 gr
280 } else {
281 format_ident!("G")
282 };
283 input.parse::<Token![,]>()?;
284
285 let mut vars: TaggedVarDict = HashMap::new();
286
287 let scalars = paren_taggedidents::<TaggedScalar>(input)?;
288 vars.extend(
289 scalars
290 .into_iter()
291 .map(|ts| (ts.id.to_string(), TaggedIdent::Scalar(ts))),
292 );
293 input.parse::<Token![,]>()?;
294
295 let points = paren_taggedidents::<TaggedPoint>(input)?;
296 vars.extend(
297 points
298 .into_iter()
299 .map(|tp| (tp.id.to_string(), TaggedIdent::Point(tp))),
300 );
301 input.parse::<Token![,]>()?;
302
303 let statementpunc: Punctuated<Expr, Token![,]> =
304 input.parse_terminated(Expr::parse, Token![,])?;
305 let statementlist: Vec<Expr> = statementpunc.into_iter().collect();
306 let statements = StatementTree::parse_andlist(&statementlist)?;
307
308 Ok(SigmaCompSpec {
309 proto_name,
310 group_name,
311 vars,
312 statements,
313 })
314 }
315}