syntax.rs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. use quote::format_ident;
  2. use syn::ext::IdentExt;
  3. use syn::parse::{Parse, ParseStream, Result};
  4. use syn::punctuated::Punctuated;
  5. use syn::{parenthesized, Error, Expr, Ident, Token};
  6. /// A `TaggedScalar` is an `Ident` representing a `Scalar`, preceded by
  7. /// zero or more of the following tags: `pub`, `rand`, `vec`
  8. ///
  9. /// The following combinations are valid:
  10. /// - (nothing)
  11. /// - `pub`
  12. /// - `rand`
  13. /// - `vec`
  14. /// - `pub vec`
  15. /// - `rand vec`
  16. #[derive(Debug)]
  17. pub struct TaggedScalar {
  18. pub id: Ident,
  19. pub is_pub: bool,
  20. pub is_rand: bool,
  21. pub is_vec: bool,
  22. }
  23. impl Parse for TaggedScalar {
  24. fn parse(input: ParseStream) -> Result<Self> {
  25. let (mut is_pub, mut is_rand, mut is_vec) = (false, false, false);
  26. loop {
  27. let id = input.call(Ident::parse_any)?;
  28. match id.to_string().as_str() {
  29. // pub and rand are mutually exclusive
  30. "pub" if !is_rand => {
  31. is_pub = true;
  32. }
  33. "rand" if !is_pub => {
  34. is_rand = true;
  35. }
  36. // any other use of the tagging keywords is not allowed
  37. "pub" | "rand" | "cind" | "const" => {
  38. return Err(Error::new(id.span(), "tag not allowed in this position"));
  39. }
  40. // vec is allowed with any other tag
  41. "vec" => {
  42. is_vec = true;
  43. }
  44. _ => {
  45. return Ok(TaggedScalar {
  46. id,
  47. is_pub,
  48. is_rand,
  49. is_vec,
  50. });
  51. }
  52. }
  53. }
  54. }
  55. }
  56. /// A `TaggedPoint` is an `Ident` representing a `Point`, preceded by
  57. /// zero or more of the following tags: `cind`, `const`, `vec`
  58. ///
  59. /// All combinations are valid:
  60. /// - (nothing)
  61. /// - `cind`
  62. /// - `const`
  63. /// - `cind const`
  64. /// - `vec`
  65. /// - `cind vec`
  66. /// - `const vec`
  67. /// - `cind const vec`
  68. #[derive(Debug)]
  69. pub struct TaggedPoint {
  70. pub id: Ident,
  71. pub is_cind: bool,
  72. pub is_const: bool,
  73. pub is_vec: bool,
  74. }
  75. impl Parse for TaggedPoint {
  76. fn parse(input: ParseStream) -> Result<Self> {
  77. // Points are always pub
  78. let (mut is_cind, mut is_const, mut is_vec) = (false, false, false);
  79. loop {
  80. let id = input.call(Ident::parse_any)?;
  81. match id.to_string().as_str() {
  82. "cind" => {
  83. is_cind = true;
  84. }
  85. "const" => {
  86. is_const = true;
  87. }
  88. // any other use of the tagging keywords is not allowed
  89. "pub" | "rand" => {
  90. return Err(Error::new(id.span(), "tag not allowed in this position"));
  91. }
  92. "vec" => {
  93. is_vec = true;
  94. }
  95. _ => {
  96. return Ok(TaggedPoint {
  97. id,
  98. is_cind,
  99. is_const,
  100. is_vec,
  101. });
  102. }
  103. }
  104. }
  105. }
  106. }
  107. #[derive(Debug)]
  108. pub struct SigmaCompSpec {
  109. pub proto_name: Ident,
  110. pub group_name: Ident,
  111. pub scalars: Vec<TaggedScalar>,
  112. pub points: Vec<TaggedPoint>,
  113. pub statements: Vec<Expr>,
  114. }
  115. // T is TaggedScalar or TaggedPoint
  116. fn paren_taggedidents<T: Parse>(input: ParseStream) -> Result<Vec<T>> {
  117. let content;
  118. parenthesized!(content in input);
  119. let punc: Punctuated<T, Token![,]> = content.parse_terminated(T::parse, Token![,])?;
  120. Ok(punc.into_iter().collect())
  121. }
  122. impl Parse for SigmaCompSpec {
  123. fn parse(input: ParseStream) -> Result<Self> {
  124. let proto_name: Ident = input.parse()?;
  125. // See if a group was specified
  126. let group_name = if input.peek(Token![<]) {
  127. input.parse::<Token![<]>()?;
  128. let gr: Ident = input.parse()?;
  129. input.parse::<Token![>]>()?;
  130. gr
  131. } else {
  132. format_ident!("G")
  133. };
  134. input.parse::<Token![,]>()?;
  135. let scalars = paren_taggedidents::<TaggedScalar>(input)?;
  136. input.parse::<Token![,]>()?;
  137. let points = paren_taggedidents::<TaggedPoint>(input)?;
  138. input.parse::<Token![,]>()?;
  139. let statementpunc: Punctuated<Expr, Token![,]> =
  140. input.parse_terminated(Expr::parse, Token![,])?;
  141. let statements: Vec<Expr> = statementpunc.into_iter().collect();
  142. Ok(SigmaCompSpec {
  143. proto_name,
  144. group_name,
  145. scalars,
  146. points,
  147. statements,
  148. })
  149. }
  150. }