1extern crate proc_macro;
2extern crate proc_macro2;
3extern crate quote;
4extern crate syn;
5use proc_macro::TokenStream;
6use quote::{quote, ToTokens};
7use std::collections::HashSet;
8use syn::parse::{Parse, ParseStream, Result};
9use syn::punctuated::Punctuated;
10use syn::spanned::Spanned;
11use syn::token::{Brace, Bracket, Paren};
12use syn::{braced, bracketed, parenthesized, parse_macro_input, Error, Ident, Token};
13
14#[allow(dead_code)]
15#[derive(Clone)]
16struct Project {
17 project: Ident,
18 or1_token: Token![|],
19 variables: Punctuated<Ident, Token![,]>,
20 or2_token: Token![|],
21 brace_token: Brace,
22 body: Punctuated<Clause, Token![,]>,
23}
24
25impl Parse for Project {
26 fn parse(input: ParseStream) -> Result<Self> {
27 let project: Ident = input.parse()?;
28 if project.to_string().as_str() != "project" {
29 return Err(Error::new(
30 project.span(),
31 "Identifier \"project\" expected",
32 ));
33 }
34
35 let or1_token: Token![|] = input.parse()?;
36 let mut variables = Punctuated::new();
37 loop {
38 if input.peek(Token![|]) {
39 break;
40 }
41 let var: Ident = input.parse()?;
42 variables.push_value(var);
43 if input.peek(Token![|]) {
44 break;
45 }
46 let punct: Token![,] = input.parse()?;
47 variables.push_punct(punct);
48 }
49 let or2_token: Token![|] = input.parse()?;
50
51 let content;
52 Ok(Project {
53 project,
54 or1_token,
55 variables,
56 or2_token,
57 brace_token: braced!(content in input),
58 body: content.parse_terminated(Clause::parse)?,
59 })
60 }
61}
62
63impl ToTokens for Project {
64 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
65 let variables: Vec<&Ident> = self.variables.iter().collect();
66 let body: Vec<&Clause> = self.body.iter().collect();
67 let output = quote! {{
68 #( let #variables = ::proto_vulcan::lterm::LTerm::projection(::std::clone::Clone::clone(&#variables)); )*
69 ::proto_vulcan::operator::project::Project::new(
70 vec![ #( ::std::clone::Clone::clone(&#variables) ),* ],
71 ::proto_vulcan::GoalCast::cast_into(
72 ::proto_vulcan::operator::conj::InferredConj::from_conjunctions(&[ #( &[ ::proto_vulcan::GoalCast::cast_into( #body ) ] ),* ])
73 )
74 )
75 }};
76 output.to_tokens(tokens);
77 }
78}
79
80#[allow(dead_code)]
81#[derive(Clone)]
82struct FnGoal {
83 fngoal: Ident,
84 m: Option<Token![move]>,
85 or1_token: Token![|],
86 engine: Ident,
87 state: Ident,
88 or2_token: Token![|],
89 body: syn::Block,
90}
91
92impl Parse for FnGoal {
93 fn parse(input: ParseStream) -> Result<Self> {
94 let fngoal: Ident = input.parse()?;
95 if fngoal.to_string().as_str() != "fngoal" {
96 return Err(Error::new(fngoal.span(), "Identifier \"fngoal\" expected"));
97 }
98
99 let m = if input.peek(Token![move]) {
100 Some(input.parse()?)
101 } else {
102 None
103 };
104
105 let or1_token: Token![|] = input.parse()?;
106 let engine: Ident = input.parse()?;
107 let _: Token![,] = input.parse()?;
108 let state: Ident = input.parse()?;
109 let or2_token: Token![|] = input.parse()?;
110
111 Ok(FnGoal {
112 fngoal,
113 m,
114 or1_token,
115 engine,
116 state,
117 or2_token,
118 body: input.parse()?,
119 })
120 }
121}
122
123impl ToTokens for FnGoal {
124 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
125 let m = &self.m;
126 let engine = &self.engine;
127 let state = &self.state;
128 let body: &syn::Block = &self.body;
129 let output = quote! {{
130 ::proto_vulcan::operator::fngoal::FnGoal::new(Box::new(#m |#engine, #state| { #body } ))
131 }};
132 output.to_tokens(tokens);
133 }
134}
135
136#[derive(Clone)]
137struct TypedVariable {
138 name: Ident,
139 path: syn::Path,
140}
141
142impl Parse for TypedVariable {
143 fn parse(input: ParseStream) -> Result<Self> {
144 let name = input.parse()?;
145 let path;
146 if input.peek(Token![:]) {
147 let _: Token![:] = input.parse()?;
148 path = input.parse()?;
149 } else {
150 path = syn::parse_quote!(::proto_vulcan::lterm::LTerm);
151 }
152 Ok(TypedVariable { name, path })
153 }
154}
155
156#[allow(dead_code)]
157#[derive(Clone)]
158struct Fresh {
159 or1_token: Token![|],
160 variables: Punctuated<TypedVariable, Token![,]>,
161 or2_token: Token![|],
162 brace_token: Brace,
163 body: Punctuated<Clause, Token![,]>,
164}
165
166impl Parse for Fresh {
167 fn parse(input: ParseStream) -> Result<Self> {
168 let or1_token: Token![|] = input.parse()?;
169 let mut variables = Punctuated::new();
170 loop {
171 if input.peek(Token![|]) {
172 break;
173 }
174 let var: TypedVariable = input.parse()?;
175 variables.push_value(var);
176 if input.peek(Token![|]) {
177 break;
178 }
179 let punct: Token![,] = input.parse()?;
180 variables.push_punct(punct);
181 }
182 let or2_token: Token![|] = input.parse()?;
183
184 let content;
185 Ok(Fresh {
186 or1_token,
187 variables,
188 or2_token,
189 brace_token: braced!(content in input),
190 body: content.parse_terminated(Clause::parse)?,
191 })
192 }
193}
194
195impl ToTokens for Fresh {
196 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
197 let variables: Vec<Ident> = self.variables.iter().map(|x| &x.name).cloned().collect();
198 let variable_types: Vec<syn::Path> =
199 self.variables.iter().map(|x| &x.path).cloned().collect();
200 let body: Vec<&Clause> = self.body.iter().collect();
201 let output = quote! {{
202 #( let #variables: #variable_types <_, _> = ::proto_vulcan::compound::CompoundTerm::new_var(stringify!(#variables)); )*
203 ::proto_vulcan::operator::fresh::Fresh::new(vec![ #( ::proto_vulcan::Upcast::to_super(&#variables) ),* ],
204 ::proto_vulcan::GoalCast::cast_into(
205 ::proto_vulcan::operator::conj::InferredConj::from_array(&[ #( ::proto_vulcan::GoalCast::cast_into( #body ) ),* ]))
206 )
207 }};
208 output.to_tokens(tokens);
209 }
210}
211
212#[allow(dead_code)]
213#[derive(Clone)]
214struct Conjunction {
215 bracket_token: Bracket,
216 body: Punctuated<Clause, Token![,]>,
217}
218
219impl Parse for Conjunction {
220 fn parse(input: ParseStream) -> Result<Self> {
221 let content;
222 Ok(Conjunction {
223 bracket_token: bracketed!(content in input),
224 body: content.parse_terminated(Clause::parse)?,
225 })
226 }
227}
228
229impl ToTokens for Conjunction {
230 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
231 let body: Vec<&Clause> = self.body.iter().collect();
232 let output = quote! { &[ #( ::proto_vulcan::GoalCast::cast_into(#body) ),* ] };
233 output.to_tokens(tokens)
234 }
235}
236
237#[derive(Clone, Debug)]
238struct UnnamedCompoundConstructorArgument {
239 pattern: Pattern,
240}
241
242impl Parse for UnnamedCompoundConstructorArgument {
243 fn parse(input: ParseStream) -> Result<Self> {
244 Ok(UnnamedCompoundConstructorArgument {
245 pattern: input.parse()?,
246 })
247 }
248}
249
250impl ToTokens for UnnamedCompoundConstructorArgument {
251 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
252 match &self.pattern {
253 Pattern::Term(treeterm) => match treeterm {
254 TreeTerm::Var(x) => {
255 let output = quote! { ::proto_vulcan::Upcast::to_super(&#x) };
256 output.to_tokens(tokens);
257 }
258 TreeTerm::Any(_) => {
259 let output = quote! { ::proto_vulcan::compound::CompoundTerm::new_wildcard() };
260 output.to_tokens(tokens);
261 }
262 _ => treeterm.to_tokens(tokens),
263 },
264 _ => self.pattern.to_tokens(tokens),
265 }
266 }
267}
268
269#[derive(Clone, Debug)]
270struct NamedCompoundConstructorArgument {
271 ident: Ident,
272 colon_token: Token![:],
273 pattern: Pattern,
274}
275
276impl Parse for NamedCompoundConstructorArgument {
277 fn parse(input: ParseStream) -> Result<Self> {
278 let ident;
279 let colon_token;
280 let pattern;
281 if input.peek(Ident) && input.peek2(Token![:]) {
282 ident = input.parse()?;
283 colon_token = input.parse()?;
284 pattern = input.parse()?;
285 } else {
286 pattern = input.parse()?;
287 match pattern {
288 Pattern::Term(TreeTerm::Var(ref var_ident)) => {
289 ident = var_ident.clone();
290 colon_token = syn::parse_quote!(:);
291 }
292 _ => return Err(input.error("Expected variable identifier for unnamed field.")),
293 }
294 }
295
296 Ok(NamedCompoundConstructorArgument {
297 ident,
298 colon_token,
299 pattern,
300 })
301 }
302}
303
304impl ToTokens for NamedCompoundConstructorArgument {
305 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
306 let ident = &self.ident;
307 let colon_token = &self.colon_token;
308 match &self.pattern {
309 Pattern::Term(treeterm) => match treeterm {
310 TreeTerm::Var(x) => {
311 let output =
313 quote! { #ident #colon_token ::proto_vulcan::Upcast::to_super(&#x) };
314 output.to_tokens(tokens);
315 }
316 TreeTerm::Any(_) => {
317 let output = quote! { #ident #colon_token ::proto_vulcan::compound::CompoundTerm::new_wildcard() };
318 output.to_tokens(tokens);
319 }
320 _ => {
321 let output = quote! { #ident #colon_token #treeterm };
322 output.to_tokens(tokens);
323 }
324 },
325 _ => {
326 let pattern = &self.pattern;
327 let output = quote! { #ident #colon_token #pattern };
328 output.to_tokens(tokens);
329 }
330 }
331 }
332}
333
334#[derive(Clone, Debug)]
335struct TupleCompoundConstructorArgument {
336 pattern: Pattern,
337}
338
339impl Parse for TupleCompoundConstructorArgument {
340 fn parse(input: ParseStream) -> Result<Self> {
341 Ok(TupleCompoundConstructorArgument {
342 pattern: input.parse()?,
343 })
344 }
345}
346
347impl ToTokens for TupleCompoundConstructorArgument {
348 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
349 match &self.pattern {
350 Pattern::Term(treeterm) => match treeterm {
351 TreeTerm::Var(x) => {
352 let output = quote! { ::proto_vulcan::Upcast::to_super(&#x) };
353 output.to_tokens(tokens);
354 }
355 TreeTerm::Any(_) => {
356 let output = quote! { ::proto_vulcan::compound::CompoundTerm::new_wildcard() };
357 output.to_tokens(tokens);
358 }
359 _ => treeterm.to_tokens(tokens),
360 },
361 _ => self.pattern.to_tokens(tokens),
362 }
363 }
364}
365
366#[derive(Clone, Debug)]
367struct UnnamedCompoundConstructor {
368 compound_path: CompoundPath,
369 paren_token: Option<Paren>,
370 arguments: Option<Punctuated<UnnamedCompoundConstructorArgument, Token![,]>>,
371}
372
373impl ToTokens for UnnamedCompoundConstructor {
374 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
375 let compound_path = &self.compound_path;
376 let output;
377 if self.arguments.is_some() {
378 let arguments: Vec<UnnamedCompoundConstructorArgument> =
379 self.arguments.as_ref().unwrap().iter().cloned().collect();
380 output = quote! { ::proto_vulcan::Upcast::into_super(::proto_vulcan::Downcast::into_sub( #compound_path ( #( #arguments ),* ) ) )};
381 } else {
382 output = quote! { ::proto_vulcan::Upcast::into_super(::proto_vulcan::Downcast::into_sub( #compound_path ) )};
383 }
384 output.to_tokens(tokens);
385 }
386}
387
388#[derive(Clone, Debug)]
389struct NamedCompoundConstructor {
390 compound_path: CompoundPath,
391 brace_token: Option<Brace>,
392 arguments: Option<Punctuated<NamedCompoundConstructorArgument, Token![,]>>,
393}
394
395impl ToTokens for NamedCompoundConstructor {
396 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
397 let compound_path = &self.compound_path;
398 let output;
399 if self.arguments.is_some() {
400 let arguments: Vec<NamedCompoundConstructorArgument> =
401 self.arguments.as_ref().unwrap().iter().cloned().collect();
402 output = quote! { ::proto_vulcan::Upcast::into_super(::proto_vulcan::Downcast::into_sub( #compound_path { #( #arguments ),* } ) )};
403 } else {
404 output = quote! { ::proto_vulcan::Upcast::into_super(::proto_vulcan::Downcast::into_sub( #compound_path { } ) )};
405 }
406 output.to_tokens(tokens);
407 }
408}
409
410#[derive(Clone, Debug)]
411struct TupleCompoundConstructor {
412 paren_token: Paren,
413 arguments: Punctuated<TupleCompoundConstructorArgument, Token![,]>,
414}
415
416impl ToTokens for TupleCompoundConstructor {
417 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
418 let arguments: Vec<TupleCompoundConstructorArgument> =
419 self.arguments.iter().cloned().collect();
420 let output = quote! { ::proto_vulcan::Upcast::into_super(::proto_vulcan::Downcast::into_sub( ( #( #arguments ),* ) ) )};
421 output.to_tokens(tokens);
422 }
423}
424
425#[derive(Clone, Debug)]
426enum CompoundConstructor {
427 Unnamed(UnnamedCompoundConstructor),
428 Named(NamedCompoundConstructor),
429 Tuple(TupleCompoundConstructor),
430}
431
432impl Parse for CompoundConstructor {
433 fn parse(input: ParseStream) -> Result<Self> {
434 if input.peek(Paren) {
436 let content;
437 return Ok(CompoundConstructor::Tuple(TupleCompoundConstructor {
438 paren_token: parenthesized!(content in input),
439 arguments: content.parse_terminated(TupleCompoundConstructorArgument::parse)?,
440 }));
441 }
442
443 let compound_path: CompoundPath = input.parse()?;
444
445 if input.peek(Brace) {
446 let content;
447 Ok(CompoundConstructor::Named(NamedCompoundConstructor {
448 compound_path,
449 brace_token: Some(braced!(content in input)),
450 arguments: Some(content.parse_terminated(NamedCompoundConstructorArgument::parse)?),
451 }))
452 } else if input.peek(Paren) {
453 let content;
454 Ok(CompoundConstructor::Unnamed(UnnamedCompoundConstructor {
455 compound_path,
456 paren_token: Some(parenthesized!(content in input)),
457 arguments: Some(
458 content.parse_terminated(UnnamedCompoundConstructorArgument::parse)?,
459 ),
460 }))
461 } else {
462 Ok(CompoundConstructor::Unnamed(UnnamedCompoundConstructor {
463 compound_path,
464 paren_token: None,
465 arguments: None,
466 }))
467 }
468 }
469}
470
471impl ToTokens for CompoundConstructor {
472 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
473 match self {
474 CompoundConstructor::Unnamed(pattern) => pattern.to_tokens(tokens),
475 CompoundConstructor::Named(pattern) => pattern.to_tokens(tokens),
476 CompoundConstructor::Tuple(pattern) => pattern.to_tokens(tokens),
477 }
478 }
479}
480
481#[derive(Clone)]
482enum Argument {
483 TreeTerm(TreeTerm),
484 Compound(CompoundConstructor),
485 Quoted(syn::Expr),
486 Expr(syn::Expr),
487}
488
489impl Parse for Argument {
490 fn parse(input: ParseStream) -> Result<Self> {
491 if input.peek(Token![#]) {
493 let _: Token![#] = input.parse()?;
494 let expr: syn::Expr = input.parse()?;
495 Ok(Argument::Quoted(expr))
496 } else if input.peek(Token![&]) {
497 let expr: syn::Expr = input.parse()?;
498 Ok(Argument::Quoted(expr))
499 } else {
500 if (input.peek(syn::token::Colon2) && input.peek2(Ident))
501 || (input.peek(Ident) && (input.peek2(syn::token::Colon2) || input.peek2(Paren))
502 || input.peek(Paren))
503 {
504 let compound: CompoundConstructor = input.parse()?;
505 Ok(Argument::Compound(compound))
506 } else if let Ok(term) = input.parse() {
507 Ok(Argument::TreeTerm(term))
509 } else {
510 if input.peek(Paren) {
512 let content;
513 let _ = parenthesized!(content in input);
514 let expr = content.parse()?;
515 Ok(Argument::Expr(expr))
516 } else {
517 let expr = input.parse()?;
518 Ok(Argument::Expr(expr))
519 }
520 }
521 }
522 }
523}
524
525impl ToTokens for Argument {
526 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
527 match self {
528 Argument::TreeTerm(term) => {
529 let output = quote! { #term };
530 output.to_tokens(tokens);
531 }
532 Argument::Compound(compound_term) => {
533 let output = quote! { #compound_term };
534 output.to_tokens(tokens);
535 }
536 Argument::Quoted(expr) => {
537 expr.to_tokens(tokens);
538 }
539 Argument::Expr(expr) => {
540 let output = quote! { ::proto_vulcan::lterm::LTerm::from(#expr) };
541 output.to_tokens(tokens);
542 }
543 }
544 }
545}
546
547#[allow(dead_code)]
548#[derive(Clone)]
549struct Relation {
550 name: Ident,
551 paren_token: Paren,
552 body: Punctuated<Argument, Token![,]>,
553}
554
555impl Parse for Relation {
556 fn parse(input: ParseStream) -> Result<Self> {
557 let content;
558 Ok(Relation {
559 name: input.parse()?,
560 paren_token: parenthesized!(content in input),
561 body: content.parse_terminated(Argument::parse)?,
562 })
563 }
564}
565
566impl ToTokens for Relation {
567 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
568 let name = &self.name;
569 let body: Vec<&Argument> = self.body.iter().collect();
570 let output = quote! { #name ( #( #body ),* ) };
571 output.to_tokens(tokens);
572 }
573}
574
575#[allow(dead_code)]
576#[derive(Clone)]
577struct Closure {
578 body: Vec<Clause>,
579}
580
581impl Closure {
582 fn new(body: Vec<Clause>) -> Closure {
583 Closure { body }
584 }
585}
586
587impl Parse for Closure {
588 fn parse(input: ParseStream) -> Result<Self> {
589 let name: Ident = input.parse()?;
590 if name != String::from("closure") {
591 return Err(input.error("Expected \"closure\""));
592 }
593 let content;
594 let _ = braced!(content in input);
595 let mut body = vec![];
596 for clause in content.parse_terminated::<Clause, Clause>(Clause::parse)? {
597 body.push(clause);
598 }
599 Ok(Closure { body })
600 }
601}
602
603impl ToTokens for Closure {
604 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
605 let body: Vec<&Clause> = self.body.iter().collect();
606 let output = quote! {{
607 ::proto_vulcan::operator::closure::Closure::new(
608 ::proto_vulcan::operator::ClosureOperatorParam::new(
609 Box::new(move || ::proto_vulcan::GoalCast::cast_into(::proto_vulcan::operator::conj::InferredConj::from_array( &[ #( ::proto_vulcan::GoalCast::cast_into( #body ) ),* ] ) ))
610 )
611 )
612 }};
613 output.to_tokens(tokens);
614 }
615}
616
617#[allow(dead_code)]
618#[derive(Clone)]
619struct Loop {
620 kw: Token![loop],
621 brace_token: Brace,
622 body: Punctuated<ClauseInOperator, Token![,]>,
623}
624
625impl Parse for Loop {
626 fn parse(input: ParseStream) -> Result<Self> {
627 let kw = input.parse()?;
628 let content;
629 Ok(Loop {
630 kw,
631 brace_token: braced!(content in input),
632 body: content.parse_terminated(ClauseInOperator::parse)?,
633 })
634 }
635}
636
637impl ToTokens for Loop {
638 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
639 let body: Vec<&ClauseInOperator> = self.body.iter().collect();
640 let output = quote! {{
641 ::proto_vulcan::operator::anyo::anyo(::proto_vulcan::operator::OperatorParam::new( &[ #( #body ),* ] ))
642 }};
643 output.to_tokens(tokens);
644 }
645}
646
647#[allow(dead_code)]
648#[derive(Clone)]
649struct Operator {
650 name: Ident,
651 brace_token: Brace,
652 body: Punctuated<ClauseInOperator, Token![,]>,
653}
654
655impl Parse for Operator {
656 fn parse(input: ParseStream) -> Result<Self> {
657 let content;
658 Ok(Operator {
659 name: input.parse()?,
660 brace_token: braced!(content in input),
661 body: content.parse_terminated(ClauseInOperator::parse)?,
662 })
663 }
664}
665
666impl ToTokens for Operator {
667 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
668 let name = &self.name;
669 let body: Vec<&ClauseInOperator> = self.body.iter().collect();
670 let output =
671 quote! { #name ( ::proto_vulcan::operator::OperatorParam::new( &[ #( #body ),* ] ) )};
672 output.to_tokens(tokens);
673 }
674}
675
676struct PatternVariableSet {
677 idents: HashSet<Ident>,
678
679 is_compound: HashSet<Ident>,
691}
692
693impl PatternVariableSet {
694 fn new() -> PatternVariableSet {
695 PatternVariableSet {
696 idents: HashSet::new(),
697 is_compound: HashSet::new(),
698 }
699 }
700
701 fn set_compound(&mut self, ident: &Ident) {
702 self.is_compound.insert(ident.clone());
703 }
704
705 fn is_compound(&self, ident: &Ident) -> bool {
706 self.is_compound.contains(ident)
707 }
708}
709
710impl std::ops::Deref for PatternVariableSet {
711 type Target = HashSet<Ident>;
712
713 fn deref(&self) -> &Self::Target {
714 &self.idents
715 }
716}
717
718impl std::ops::DerefMut for PatternVariableSet {
719 fn deref_mut(&mut self) -> &mut Self::Target {
720 &mut self.idents
721 }
722}
723
724#[derive(Clone, Debug)]
725struct CompoundArgument {
726 pattern: Pattern,
727}
728
729impl CompoundArgument {
730 fn get_vars(&self, vars: &mut PatternVariableSet) {
731 self.pattern.get_vars(vars);
732 if let Pattern::Term(TreeTerm::Var(ref x)) = self.pattern {
733 vars.set_compound(x);
734 }
735 }
736}
737
738impl Parse for CompoundArgument {
739 fn parse(input: ParseStream) -> Result<Self> {
740 Ok(CompoundArgument {
741 pattern: input.parse()?,
742 })
743 }
744}
745
746impl ToTokens for CompoundArgument {
747 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
748 match &self.pattern {
749 Pattern::Term(treeterm) => match treeterm {
750 TreeTerm::Var(x) => {
751 let output = quote! { ::std::clone::Clone::clone(&#x) };
753 output.to_tokens(tokens);
754 }
755 TreeTerm::Any(_) => {
756 let output = quote! { ::proto_vulcan::compound::CompoundTerm::new_wildcard() };
757 output.to_tokens(tokens);
758 }
759 term if term.is_empty() => {
760 let output = quote! { ::proto_vulcan::compound::CompoundTerm::new_none() };
761 output.to_tokens(tokens);
762 }
763 _ => treeterm.to_tokens(tokens),
764 },
765 _ => self.pattern.to_tokens(tokens),
766 }
767 }
768}
769
770#[derive(Clone, Debug)]
771struct NamedCompoundArgument {
772 ident: Ident,
773 colon_token: Token![:],
774 pattern: Pattern,
775}
776
777impl NamedCompoundArgument {
778 fn get_vars(&self, vars: &mut PatternVariableSet) {
779 self.pattern.get_vars(vars);
780 if let Pattern::Term(TreeTerm::Var(ref x)) = self.pattern {
781 vars.set_compound(x);
782 }
783 }
784}
785
786impl Parse for NamedCompoundArgument {
787 fn parse(input: ParseStream) -> Result<Self> {
788 let ident;
789 let colon_token;
790 let pattern;
791 if input.peek(Ident) && input.peek2(Token![:]) {
792 ident = input.parse()?;
793 colon_token = input.parse()?;
794 pattern = input.parse()?;
795 } else {
796 pattern = input.parse()?;
797 match pattern {
798 Pattern::Term(TreeTerm::Var(ref var_ident)) => {
799 ident = var_ident.clone();
800 colon_token = syn::parse_quote!(:);
801 }
802 _ => return Err(input.error("Expected variable identifier for unnamed field.")),
803 }
804 }
805
806 Ok(NamedCompoundArgument {
807 ident,
808 colon_token,
809 pattern,
810 })
811 }
812}
813
814impl ToTokens for NamedCompoundArgument {
815 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
816 let ident = &self.ident;
817 let colon_token = &self.colon_token;
818 match &self.pattern {
819 Pattern::Term(treeterm) => match treeterm {
820 TreeTerm::Var(x) => {
821 let output = quote! { #ident #colon_token ::std::clone::Clone::clone(&#x) };
823 output.to_tokens(tokens);
824 }
825 TreeTerm::Any(_) => {
826 let output = quote! { #ident #colon_token ::proto_vulcan::compound::CompoundTerm::new_wildcard() };
827 output.to_tokens(tokens);
828 }
829 term if term.is_empty() => {
830 let output = quote! { #ident #colon_token ::proto_vulcan::compound::CompoundTerm::new_none() };
831 output.to_tokens(tokens);
832 }
833 _ => {
834 let output = quote! { #ident #colon_token #treeterm };
835 output.to_tokens(tokens);
836 }
837 },
838 _ => {
839 let pattern = &self.pattern;
840 let output = quote! { #ident #colon_token #pattern };
841 output.to_tokens(tokens);
842 }
843 }
844 }
845}
846
847#[derive(Clone, Debug)]
848struct CompoundPath {
849 leading_colon: Option<Token![::]>,
850 path: Punctuated<Ident, Token![::]>,
851 num_snake_case: usize,
852 prefix: Punctuated<Ident, Token![::]>,
853 typename: Ident,
854 variant: Option<Ident>,
855}
856
857impl Parse for CompoundPath {
858 fn parse(input: ParseStream) -> Result<Self> {
859 let leading_colon = if input.peek(syn::token::Colon2) {
860 Some(input.parse()?)
861 } else {
862 None
863 };
864
865 let mut num_snake_case: usize = 0;
866
867 let mut path: Punctuated<Ident, syn::token::Colon2> = Punctuated::new();
868 loop {
869 let ident: Ident;
870 if input.peek(Token![crate]) {
871 let _: Token![crate] = input.parse()?;
872 ident = quote::format_ident!("crate");
873 } else {
874 ident = input.parse()?;
875 }
876
877 if ident.to_string().chars().any(|c| c.is_uppercase()) {
878 num_snake_case += 1;
879 }
880 path.push_value(ident);
881
882 if !input.peek(Token![::]) {
883 break;
884 }
885
886 let punct = input.parse()?;
887 path.push_punct(punct);
888 }
889
890 let mut prefix = path.clone();
891 let typename;
892 let mut variant = None;
893 match num_snake_case {
894 0 => return Err(input.error("Type patterns must have snake-case names.")),
895 1 => {
896 typename = prefix.pop().unwrap().into_value();
897 }
898 2 => {
899 variant = Some(prefix.pop().unwrap().into_value());
900 typename = prefix.pop().unwrap().into_value();
901 }
902 _ => return Err(input.error("Ambiguous path with more than two snake-case segments")),
903 }
904
905 Ok(CompoundPath {
906 leading_colon,
907 path,
908 num_snake_case,
909 prefix,
910 typename,
911 variant,
912 })
913 }
914}
915
916impl ToTokens for CompoundPath {
917 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
918 let leading_colon = &self.leading_colon;
919 let prefix = &self.prefix;
920 let typename = &self.typename;
921 let variant = &self.variant;
922
923 let mut new_path = prefix.clone();
924 if typename == "Some" {
925 new_path.push(typename.clone());
926 } else {
927 let compound_mod_name = quote::format_ident!("{}_compound", typename);
928 let object_typename = quote::format_ident!("_Inner{}", typename);
929
930 if variant.is_some() {
931 new_path.push(compound_mod_name);
932 new_path.push(variant.clone().unwrap());
933 } else {
934 new_path.push(compound_mod_name);
935 new_path.push(object_typename);
936 }
937 }
938
939 let output = quote!(#leading_colon #new_path);
940 output.to_tokens(tokens);
941 }
942}
943
944#[derive(Clone, Debug)]
945struct UnnamedCompoundPattern {
946 compound_path: CompoundPath,
947 paren_token: Option<Paren>,
948 arguments: Option<Punctuated<CompoundArgument, Token![,]>>,
949}
950
951impl UnnamedCompoundPattern {
952 fn get_vars(&self, vars: &mut PatternVariableSet) {
953 if self.arguments.is_some() {
954 for pattern in self.arguments.as_ref().unwrap().iter() {
955 pattern.get_vars(vars);
956 }
957 }
958 }
959}
960
961impl ToTokens for UnnamedCompoundPattern {
962 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
963 let compound_path = &self.compound_path;
964 if self.arguments.is_some() {
965 let arguments: Vec<&CompoundArgument> =
966 self.arguments.as_ref().unwrap().iter().collect();
967 let output = quote! { ::proto_vulcan::Upcast::into_super(::proto_vulcan::Downcast::into_sub( #compound_path ( #( #arguments ),* ) )) };
968 output.to_tokens(tokens);
969 } else {
970 let output = quote! { ::proto_vulcan::Upcast::into_super(::proto_vulcan::Downcast::into_sub( #compound_path )) };
971 output.to_tokens(tokens);
972 }
973 }
974}
975
976#[derive(Clone, Debug)]
977struct NamedCompoundPattern {
978 compound_path: CompoundPath,
979 brace_token: Option<Brace>,
980 arguments: Option<Punctuated<NamedCompoundArgument, Token![,]>>,
981}
982
983impl NamedCompoundPattern {
984 fn get_vars(&self, vars: &mut PatternVariableSet) {
985 if self.arguments.is_some() {
986 for pattern in self.arguments.as_ref().unwrap().iter() {
987 pattern.get_vars(vars);
988 }
989 }
990 }
991}
992
993impl ToTokens for NamedCompoundPattern {
994 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
995 let compound_path = &self.compound_path;
996 if self.arguments.is_some() {
997 let arguments: Vec<NamedCompoundArgument> =
998 self.arguments.as_ref().unwrap().iter().cloned().collect();
999
1000 let output = quote! { ::proto_vulcan::Upcast::into_super(::proto_vulcan::Downcast::into_sub( #compound_path { #( #arguments ),* } )) };
1001 output.to_tokens(tokens);
1002 } else {
1003 let output = quote! { ::proto_vulcan::Upcast::into_super(::proto_vulcan::Downcast::into_sub( #compound_path { } )) };
1004 output.to_tokens(tokens);
1005 }
1006 }
1007}
1008
1009#[derive(Clone, Debug)]
1010enum CompoundPattern {
1011 Unnamed(UnnamedCompoundPattern),
1012 Named(NamedCompoundPattern),
1013 }
1015
1016impl CompoundPattern {
1017 fn is_next_compound(input: ParseStream) -> bool {
1018 if input.peek(Token![::])
1019 || input.peek2(Token![::])
1020 || input.peek2(Paren)
1021 || input.peek2(Brace)
1022 {
1023 true
1024 } else {
1025 false
1026 }
1027 }
1028
1029 fn get_vars(&self, vars: &mut PatternVariableSet) {
1030 match self {
1031 CompoundPattern::Unnamed(pattern) => pattern.get_vars(vars),
1032 CompoundPattern::Named(pattern) => pattern.get_vars(vars),
1033 }
1034 }
1035}
1036
1037impl Parse for CompoundPattern {
1038 fn parse(input: ParseStream) -> Result<Self> {
1039 let compound_path: CompoundPath = input.parse()?;
1040
1041 if input.peek(Brace) {
1042 let content;
1043 Ok(CompoundPattern::Named(NamedCompoundPattern {
1044 compound_path,
1045 brace_token: Some(braced!(content in input)),
1046 arguments: Some(content.parse_terminated(NamedCompoundArgument::parse)?),
1047 }))
1048 } else if input.peek(Paren) {
1049 let content;
1050 Ok(CompoundPattern::Unnamed(UnnamedCompoundPattern {
1051 compound_path,
1052 paren_token: Some(parenthesized!(content in input)),
1053 arguments: Some(content.parse_terminated(CompoundArgument::parse)?),
1054 }))
1055 } else {
1056 Ok(CompoundPattern::Unnamed(UnnamedCompoundPattern {
1057 compound_path,
1058 paren_token: None,
1059 arguments: None,
1060 }))
1061 }
1062 }
1063}
1064
1065impl ToTokens for CompoundPattern {
1066 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1067 match self {
1068 CompoundPattern::Unnamed(pattern) => pattern.to_tokens(tokens),
1069 CompoundPattern::Named(pattern) => pattern.to_tokens(tokens),
1070 }
1071 }
1072}
1073
1074#[derive(Clone, Debug)]
1075enum Pattern {
1076 Term(TreeTerm),
1077 Compound(CompoundPattern),
1078}
1079
1080impl Pattern {
1081 fn get_vars(&self, vars: &mut PatternVariableSet) {
1082 match self {
1083 Pattern::Term(term) => term.get_vars(vars),
1084 Pattern::Compound(compound) => compound.get_vars(vars),
1085 }
1086 }
1087}
1088
1089impl Parse for Pattern {
1090 fn parse(input: ParseStream) -> Result<Self> {
1091 if CompoundPattern::is_next_compound(input) {
1092 Ok(Pattern::Compound(CompoundPattern::parse(input)?))
1093 } else {
1094 Ok(Pattern::Term(TreeTerm::parse(input)?))
1095 }
1096 }
1097}
1098
1099impl ToTokens for Pattern {
1100 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1101 match self {
1102 Pattern::Term(treeterm) => treeterm.to_tokens(tokens),
1103 Pattern::Compound(compound) => compound.to_tokens(tokens),
1104 }
1105 }
1106}
1107
1108#[derive(Clone)]
1109struct PatternArm {
1110 patterns: Vec<Pattern>,
1111 arrow: Token![=>],
1112 brace_token: Option<Brace>,
1113 body: Punctuated<Clause, Token![,]>,
1114}
1115
1116impl Parse for PatternArm {
1117 fn parse(input: ParseStream) -> Result<Self> {
1118 let mut patterns = vec![];
1119 loop {
1120 let pattern: Pattern = input.parse()?;
1121 patterns.push(pattern);
1122
1123 if input.peek(Token![|]) {
1124 let _: Token![|] = input.parse()?;
1125 } else if input.peek(Token![=>]) {
1126 break;
1127 }
1128 }
1129
1130 for pattern in patterns.iter() {
1131 let mut pattern_vars = PatternVariableSet::new();
1132 pattern.get_vars(&mut pattern_vars);
1133 for var_ident in pattern_vars.iter() {
1134 if var_ident.to_string() == "__term__" {
1135 return Err(Error::new(
1136 var_ident.span(),
1137 "A pattern variable cannot be named '__term__'",
1138 ));
1139 }
1140 }
1141 }
1142
1143 let arrow: Token![=>] = input.parse()?;
1144
1145 if input.peek(Brace) {
1146 let content;
1147 let brace_token = braced!(content in input);
1148 let body = content.parse_terminated(Clause::parse)?;
1149 Ok(PatternArm {
1150 patterns,
1151 arrow,
1152 brace_token: Some(brace_token),
1153 body,
1154 })
1155 } else if input.peek(Token![,]) {
1156 Ok(PatternArm {
1157 patterns,
1158 arrow,
1159 brace_token: None,
1160 body: Punctuated::new(),
1161 })
1162 } else {
1163 let mut body: Punctuated<Clause, Token![,]> = Punctuated::new();
1164 body.push(input.parse()?);
1165 Ok(PatternArm {
1166 patterns,
1167 arrow,
1168 brace_token: None,
1169 body,
1170 })
1171 }
1172 }
1173}
1174
1175#[allow(dead_code)]
1176#[derive(Clone)]
1177struct PatternMatchOperator {
1178 name: Ident,
1179 term: TreeTerm,
1180 brace_token: Brace,
1181 arms: Punctuated<PatternArm, Token![,]>,
1182}
1183
1184impl Parse for PatternMatchOperator {
1185 fn parse(input: ParseStream) -> Result<Self> {
1186 let name: Ident;
1187 if input.peek(Ident) {
1188 name = input.parse()?;
1189 } else {
1190 let token: Token![match] = input.parse()?;
1191 name = Ident::new("match", token.span);
1192 };
1193 let content;
1194 Ok(PatternMatchOperator {
1195 name,
1196 term: input.parse()?,
1197 brace_token: braced!(content in input),
1198 arms: content.parse_terminated(PatternArm::parse)?,
1199 })
1200 }
1201}
1202
1203impl ToTokens for PatternMatchOperator {
1204 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1205 let name = &self.name;
1206 let term = &self.term;
1207
1208 let mut patterns: Vec<Pattern> = vec![];
1209 let mut vars: Vec<Vec<Ident>> = vec![];
1210 let mut compounds: Vec<Vec<Ident>> = vec![];
1211 let mut clauses: Vec<Punctuated<proc_macro2::TokenStream, Token![,]>> = vec![];
1212 for arm in self.arms.iter() {
1213 for pattern in arm.patterns.iter() {
1215 patterns.push(pattern.clone());
1216 let mut pattern_vars = PatternVariableSet::new();
1217 pattern.get_vars(&mut pattern_vars);
1218 let mut treeterm_pattern_vars = vec![];
1219 let mut compound_pattern_vars = vec![];
1220 pattern_vars.iter().for_each(|x| {
1221 if pattern_vars.is_compound(x) {
1222 compound_pattern_vars.push(x.clone());
1223 } else {
1224 treeterm_pattern_vars.push(x.clone());
1225 }
1226 });
1227 vars.push(treeterm_pattern_vars);
1228 compounds.push(compound_pattern_vars);
1229 let mut arm_clauses: Punctuated<proc_macro2::TokenStream, Token![,]> =
1230 Punctuated::new();
1231 for clause in arm.body.iter() {
1232 let tokens = quote! {
1233 ::proto_vulcan::GoalCast::cast_into( #clause )
1234 };
1235 arm_clauses.push(tokens);
1236 }
1237 clauses.push(arm_clauses);
1238 }
1239 }
1240
1241 let output = if name.to_string() == "match" {
1242 quote! {
1243 ::proto_vulcan::operator::conde::Conde::from_conjunctions (
1244 &[ #( &{
1245 let __term__ = #term;
1248 #( let #vars = ::proto_vulcan::lterm::LTerm::var(stringify!(#vars)); )*
1250 #( let #compounds = ::proto_vulcan::compound::CompoundTerm::new_var(stringify!(#compounds)); )*
1251 let __pattern__ = #patterns;
1252 [::proto_vulcan::GoalCast::cast_into(
1253 ::proto_vulcan::relation::eq(__term__, __pattern__)),
1254 #clauses]
1255 } ),* ],
1256 )
1257 }
1258 } else {
1259 quote! {
1260 #name ( ::proto_vulcan::operator::PatternMatchOperatorParam::new(
1261 &[ #( &{
1262 let __term__ = #term;
1265 #( let #vars = ::proto_vulcan::lterm::LTerm::var(stringify!(#vars)); )*
1267 #( let #compounds = ::proto_vulcan::compound::CompoundTerm::new_var(stringify!(#compounds)); )*
1268 let __pattern__ = #patterns;
1269 [::proto_vulcan::GoalCast::cast_into(
1270 ::proto_vulcan::relation::eq(__term__, __pattern__)),
1271 #clauses]
1272 } ),* ],
1273 ))
1274 }
1275 };
1276 output.to_tokens(tokens);
1277 }
1278}
1279
1280#[derive(Clone)]
1281struct For {
1282 for_token: Token![for],
1283 pattern: Ident,
1284 in_token: Token![in],
1285 coll: syn::Expr,
1286 brace_token: Brace,
1287 body: Punctuated<ClauseInOperator, Token![,]>,
1288}
1289
1290impl Parse for For {
1291 fn parse(input: ParseStream) -> Result<Self> {
1292 let for_token: Token![for] = input.parse()?;
1293 let pattern = input.parse()?;
1294 let in_token: Token![in] = input.parse()?;
1295 let coll = input.call(syn::Expr::parse_without_eager_brace)?;
1296 let content;
1297 let brace_token = braced!(content in input);
1298 let body = content.parse_terminated(ClauseInOperator::parse)?;
1299 Ok(For {
1300 for_token,
1301 pattern,
1302 in_token,
1303 coll,
1304 brace_token,
1305 body,
1306 })
1307 }
1308}
1309
1310impl ToTokens for For {
1311 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1312 let pattern = &self.pattern;
1313 let coll = &self.coll;
1314 let body: Vec<&ClauseInOperator> = self.body.iter().collect();
1315 let output = quote!({
1316 ::proto_vulcan::operator::everyg(::proto_vulcan::operator::ForOperatorParam::new(
1317 ::std::clone::Clone::clone(#coll),
1318 Box::new(|#pattern| ::proto_vulcan::GoalCast::cast_into(::proto_vulcan::operator::conj::InferredConj::from_conjunctions(&[ #( #body ),* ]))),
1319 ))
1320 });
1321 output.to_tokens(tokens);
1322 }
1323}
1324
1325#[derive(Clone, Debug)]
1326enum Value {
1327 Bool(syn::LitBool),
1328 Number(syn::LitInt),
1329 Char(syn::LitChar),
1330 String(syn::LitStr),
1331}
1332
1333impl Parse for Value {
1334 fn parse(input: ParseStream) -> Result<Self> {
1335 let lit: syn::Lit = input.parse()?;
1336 match lit {
1337 syn::Lit::Str(s) => Ok(Value::String(s)),
1338 syn::Lit::Char(c) => Ok(Value::Char(c)),
1339 syn::Lit::Int(n) => Ok(Value::Number(n)),
1340 syn::Lit::Bool(b) => Ok(Value::Bool(b)),
1341 _ => Err(Error::new(lit.span(), "Invalid literal")),
1342 }
1343 }
1344}
1345
1346impl ToTokens for Value {
1347 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1348 match self {
1349 Value::Bool(b) => b.to_tokens(tokens),
1350 Value::Number(n) => n.to_tokens(tokens),
1351 Value::Char(c) => c.to_tokens(tokens),
1352 Value::String(s) => s.to_tokens(tokens),
1353 }
1354 }
1355}
1356
1357#[derive(Clone, Debug)]
1358struct FieldAccess {
1359 field: Punctuated<Ident, Token![.]>,
1360}
1361
1362impl Parse for FieldAccess {
1363 fn parse(input: ParseStream) -> Result<Self> {
1364 let mut field = Punctuated::new();
1365 loop {
1366 if let Ok(p) = input.parse() {
1367 field.push_value(p);
1368 } else {
1369 let p: Token![self] = input.parse()?;
1370 field.push_value(Ident::new("self", p.span))
1371 }
1372
1373 if !input.peek(Token![.]) {
1374 break;
1375 }
1376 let punct: Token![.] = input.parse()?;
1377 field.push_punct(punct);
1378 }
1379
1380 Ok(FieldAccess { field })
1381 }
1382}
1383
1384#[derive(Clone, Debug)]
1386struct InnerTreeTerm(TreeTerm);
1387
1388impl InnerTreeTerm {
1389 fn get_vars(&self, vars: &mut PatternVariableSet) {
1390 self.0.get_vars(vars)
1391 }
1392}
1393
1394impl Parse for InnerTreeTerm {
1395 fn parse(input: ParseStream) -> Result<Self> {
1396 let term: TreeTerm = input.parse()?;
1397 Ok(InnerTreeTerm(term))
1398 }
1399}
1400
1401impl From<TreeTerm> for InnerTreeTerm {
1402 fn from(u: TreeTerm) -> InnerTreeTerm {
1403 InnerTreeTerm(u)
1404 }
1405}
1406
1407impl ToTokens for InnerTreeTerm {
1408 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1409 match &self.0 {
1410 TreeTerm::Value(value) => {
1411 let output = quote! { ::proto_vulcan::lterm::LTerm::from(#value) };
1412 output.to_tokens(tokens);
1413 }
1414 TreeTerm::Var(ident) => {
1415 let output = quote! { ::std::clone::Clone::clone(&#ident) };
1416 output.to_tokens(tokens);
1417 }
1418 TreeTerm::Field(field_access) => {
1419 let field = &field_access.field;
1420 let output = quote! { ::std::clone::Clone::clone(&#field) };
1421 output.to_tokens(tokens);
1422 }
1423 TreeTerm::Any(_) => {
1424 let output = quote! { ::proto_vulcan::lterm::LTerm::any() };
1425 output.to_tokens(tokens);
1426 }
1427 TreeTerm::ImproperList { items } => {
1428 let items: Vec<&InnerTreeTerm> = items.iter().collect();
1429 let output = quote! { ::proto_vulcan::lterm::LTerm::improper_from_array( &[ #(#items),* ] ) };
1430 output.to_tokens(tokens);
1431 }
1432 TreeTerm::ProperList { items } => {
1433 let items: Vec<&InnerTreeTerm> = items.iter().collect();
1434 let output =
1435 quote! { ::proto_vulcan::lterm::LTerm::from_array( &[ #(#items),* ] ) };
1436 output.to_tokens(tokens);
1437 }
1438 }
1439 }
1440}
1441
1442#[allow(dead_code)]
1443#[derive(Clone, Debug)]
1444enum TreeTerm {
1445 Value(Value),
1446 Var(Ident),
1447 Field(FieldAccess),
1448 Any(Token![_]),
1449 ImproperList { items: Vec<InnerTreeTerm> },
1450 ProperList { items: Vec<InnerTreeTerm> },
1451}
1452
1453impl TreeTerm {
1454 fn is_empty(&self) -> bool {
1455 match self {
1456 TreeTerm::ProperList { items } => items.len() == 0,
1457 _ => false,
1458 }
1459 }
1460}
1461
1462impl TreeTerm {
1463 fn get_vars(&self, vars: &mut PatternVariableSet) {
1464 match self {
1465 TreeTerm::Value(_) => (),
1466 TreeTerm::Var(ident) => {
1467 vars.insert(ident.clone());
1468 }
1469 TreeTerm::Field(_) => (),
1470 TreeTerm::Any(_) => (),
1471 TreeTerm::ImproperList { items } => {
1472 for item in items {
1473 item.get_vars(vars);
1474 }
1475 }
1476 TreeTerm::ProperList { items } => {
1477 for item in items {
1478 item.get_vars(vars);
1479 }
1480 }
1481 }
1482 }
1483}
1484
1485impl Parse for TreeTerm {
1486 fn parse(input: ParseStream) -> Result<Self> {
1487 if input.peek(Token![_]) {
1488 let us: Token![_] = input.parse()?;
1489 Ok(TreeTerm::Any(us))
1490 } else if (input.peek(Token![self]) || input.peek(Ident)) && input.peek2(Token![.]) {
1491 let field_access: FieldAccess = input.parse()?;
1492 Ok(TreeTerm::Field(field_access))
1493 } else if input.peek(Ident) {
1494 let id: Ident = input.parse()?;
1495 Ok(TreeTerm::Var(id))
1496 } else if input.peek(syn::Lit) {
1497 let value: Value = input.parse()?;
1498 Ok(TreeTerm::Value(value))
1499 } else if input.peek(Bracket) {
1500 let content;
1501 let _ = bracketed!(content in input);
1502
1503 let mut items: Vec<InnerTreeTerm> = vec![];
1504 let mut is_proper = true;
1505 while !content.is_empty() {
1506 let term: InnerTreeTerm = content.parse()?;
1507 items.push(term);
1508 if content.peek(Token![,]) {
1509 let _: Token![,] = content.parse()?;
1510 } else if content.peek(Token![|]) {
1511 let _: Token![|] = content.parse()?;
1512 let rest: InnerTreeTerm = content.parse()?;
1513 items.push(rest);
1514 is_proper = false;
1515 break;
1516 }
1517 }
1518
1519 if !content.is_empty() {
1520 return Err(content.error("Trailing characters"));
1521 }
1522
1523 if is_proper {
1524 Ok(TreeTerm::ProperList { items })
1525 } else {
1526 Ok(TreeTerm::ImproperList { items })
1527 }
1528 } else {
1529 Err(input.error("Invalid tree-term."))
1530 }
1531 }
1532}
1533
1534impl ToTokens for TreeTerm {
1535 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1536 match self {
1537 TreeTerm::Value(value) => {
1538 let output = quote! { ::proto_vulcan::lterm::LTerm::from(#value) };
1539 output.to_tokens(tokens);
1540 }
1541 TreeTerm::Var(ident) => {
1542 let output = quote! { ::proto_vulcan::Upcast::to_super(&#ident) };
1543 output.to_tokens(tokens);
1544 }
1545 TreeTerm::Field(field_access) => {
1546 let field = &field_access.field;
1547 let output = quote! { ::proto_vulcan::Upcast::to_super(&#field) };
1548 output.to_tokens(tokens);
1549 }
1550 TreeTerm::Any(_) => {
1551 let output = quote! { ::proto_vulcan::lterm::LTerm::any() };
1552 output.to_tokens(tokens);
1553 }
1554 TreeTerm::ImproperList { items } => {
1555 let items: Vec<&InnerTreeTerm> = items.iter().collect();
1556 let output = quote! { ::proto_vulcan::lterm::LTerm::improper_from_array( &[ #(#items),* ] ) };
1557 output.to_tokens(tokens);
1558 }
1559 TreeTerm::ProperList { items } => {
1560 let items: Vec<&InnerTreeTerm> = items.iter().collect();
1561 let output;
1562 if items.is_empty() {
1563 output = quote! { ::proto_vulcan::lterm::LTerm::empty_list() };
1564 } else {
1565 output =
1566 quote! { ::proto_vulcan::lterm::LTerm::from_array( &[ #(#items),* ] ) };
1567 }
1568 output.to_tokens(tokens);
1569 }
1570 }
1571 }
1572}
1573
1574#[allow(dead_code)]
1575#[derive(Clone)]
1576struct Eq {
1577 left: Argument,
1578 eqeq: Token![==],
1579 right: Argument,
1580}
1581
1582impl Parse for Eq {
1583 fn parse(input: ParseStream) -> Result<Self> {
1584 Ok(Eq {
1585 left: input.parse()?,
1586 eqeq: input.parse()?,
1587 right: input.parse()?,
1588 })
1589 }
1590}
1591
1592impl ToTokens for Eq {
1593 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1594 let left = &self.left;
1595 let right = &self.right;
1596 let output = quote! { ::proto_vulcan::relation::eq::eq ( #left, #right ) };
1597 output.to_tokens(tokens)
1598 }
1599}
1600
1601#[allow(dead_code)]
1602#[derive(Clone)]
1603struct Diseq {
1604 left: Argument,
1605 ne: Token![!=],
1606 right: Argument,
1607}
1608
1609impl Parse for Diseq {
1610 fn parse(input: ParseStream) -> Result<Self> {
1611 Ok(Diseq {
1612 left: input.parse()?,
1613 ne: input.parse()?,
1614 right: input.parse()?,
1615 })
1616 }
1617}
1618
1619impl ToTokens for Diseq {
1620 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1621 let left = &self.left;
1622 let right = &self.right;
1623 let output = quote! { ::proto_vulcan::relation::diseq::diseq ( #left, #right ) };
1624 output.to_tokens(tokens)
1625 }
1626}
1627
1628#[derive(Clone)]
1629enum Clause {
1630 For(For),
1632 Project(Project),
1634 FnGoal(FnGoal),
1636 Fresh(Fresh),
1638 Eq(Eq),
1640 Diseq(Diseq),
1642 Succeed(syn::LitBool),
1644 Fail(syn::LitBool),
1646 Conjunction(Conjunction),
1648 Relation(Relation),
1650 Closure(Closure),
1652 Loop(Loop),
1654 Operator(Operator),
1656 PatternMatchOperator(PatternMatchOperator),
1658 Expression(syn::Expr),
1660}
1661
1662impl Parse for Clause {
1663 fn parse(input: ParseStream) -> Result<Self> {
1664 let maybe_ident = input.cursor().ident().map(|x| x.0.to_string());
1665
1666 if input.peek(Ident)
1667 && input.peek2(Token![|])
1668 && maybe_ident == Some(String::from("project"))
1669 {
1670 let project: Project = input.parse()?;
1671 Ok(Clause::Project(project))
1672 } else if input.peek(Ident)
1673 && (input.peek2(Token![|]) || (input.peek2(Token![move]) && input.peek3(Token![|])))
1674 && maybe_ident == Some(String::from("fngoal"))
1675 {
1676 let fngoal: FnGoal = input.parse()?;
1677 Ok(Clause::FnGoal(fngoal))
1678 } else if input.peek(Ident)
1679 && input.peek2(Brace)
1680 && maybe_ident == Some(String::from("closure"))
1681 {
1682 let closure: Closure = input.parse()?;
1683 Ok(Clause::Closure(closure))
1684 } else if input.peek(Token![for]) {
1685 let for_clause: For = input.parse()?;
1686 Ok(Clause::For(for_clause))
1687 } else if input.peek(Token![loop]) && input.peek2(Brace) {
1688 let l: Loop = input.parse()?;
1689 Ok(Clause::Loop(l))
1690 } else if input.peek(Token![|]) {
1691 let fresh: Fresh = input.parse()?;
1692 Ok(Clause::Fresh(fresh))
1693 } else if let Ok(_) = Eq::parse(&input.fork()) {
1694 let eq: Eq = input.parse()?;
1695 Ok(Clause::Eq(eq))
1696 } else if let Ok(_) = Diseq::parse(&input.fork()) {
1697 let diseq: Diseq = input.parse()?;
1698 Ok(Clause::Diseq(diseq))
1699 } else if input.peek(syn::LitBool) {
1700 let b: syn::LitBool = input.parse()?;
1701 if b.value {
1702 Ok(Clause::Succeed(b))
1703 } else {
1704 Ok(Clause::Fail(b))
1705 }
1706 } else if input.peek(Bracket) {
1707 let conjunction: Conjunction = input.parse()?;
1708 Ok(Clause::Conjunction(conjunction))
1709 } else if input.peek(Ident) && input.peek2(Paren) {
1710 let relation: Relation = input.parse()?;
1711 Ok(Clause::Relation(relation))
1712 } else if input.peek(Ident) && input.peek2(Brace) {
1713 let operator: Operator = input.parse()?;
1714 Ok(Clause::Operator(operator))
1715 } else {
1716 if (input.peek(Ident) || input.peek(Token![match])) && input.peek3(Brace) {
1717 return Ok(PatternMatchOperator::parse(input)
1718 .and_then(|operator| Ok(Clause::PatternMatchOperator(operator)))?);
1719 }
1720 let expr: syn::Expr = input.parse()?;
1721 Ok(Clause::Expression(expr))
1722 }
1723 }
1724}
1725
1726impl ToTokens for Clause {
1727 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1728 match self {
1729 Clause::For(for_clause) => {
1730 for_clause.to_tokens(tokens);
1731 }
1732 Clause::Project(project) => {
1733 project.to_tokens(tokens);
1734 }
1735 Clause::FnGoal(fngoal) => {
1736 fngoal.to_tokens(tokens);
1737 }
1738 Clause::Fresh(fresh) => {
1739 fresh.to_tokens(tokens);
1740 }
1741 Clause::Eq(eq) => {
1742 eq.to_tokens(tokens);
1743 }
1744 Clause::Diseq(diseq) => {
1745 diseq.to_tokens(tokens);
1746 }
1747 Clause::Succeed(_) => {
1748 let output = quote! { ::proto_vulcan::relation::succeed() };
1749 output.to_tokens(tokens);
1750 }
1751 Clause::Fail(_) => {
1752 let output = quote! { ::proto_vulcan::relation::fail() };
1753 output.to_tokens(tokens);
1754 }
1755 Clause::Conjunction(conjunction) => {
1756 let output = quote! { ::proto_vulcan::operator::conj::InferredConj::from_array( #conjunction ) };
1759 output.to_tokens(tokens);
1760 }
1761 Clause::Relation(relation) => {
1762 relation.to_tokens(tokens);
1763 }
1764 Clause::Closure(closure) => {
1765 closure.to_tokens(tokens);
1766 }
1767 Clause::Loop(l) => {
1768 l.to_tokens(tokens);
1769 }
1770 Clause::Operator(operator) => {
1771 operator.to_tokens(tokens);
1772 }
1773 Clause::PatternMatchOperator(operator) => {
1774 operator.to_tokens(tokens);
1775 }
1776 Clause::Expression(expr) => {
1777 expr.to_tokens(tokens);
1778 }
1779 }
1780 }
1781}
1782
1783#[derive(Clone)]
1784struct ClauseInOperator(Clause);
1785
1786impl Parse for ClauseInOperator {
1787 fn parse(input: ParseStream) -> Result<Self> {
1788 let clause: Clause = input.parse()?;
1789 Ok(ClauseInOperator(clause))
1790 }
1791}
1792
1793impl ToTokens for ClauseInOperator {
1794 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1795 match &self.0 {
1796 Clause::For(for_clause) => {
1797 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(#for_clause) ] };
1798 output.to_tokens(tokens);
1799 }
1800 Clause::Project(project) => {
1801 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(#project) ] };
1802 output.to_tokens(tokens);
1803 }
1804 Clause::FnGoal(fngoal) => {
1805 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(#fngoal) ] };
1806 output.to_tokens(tokens);
1807 }
1808 Clause::Fresh(fresh) => {
1809 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(#fresh) ] };
1810 output.to_tokens(tokens);
1811 }
1812 Clause::Eq(eq) => {
1813 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(#eq) ] };
1814 output.to_tokens(tokens);
1815 }
1816 Clause::Diseq(diseq) => {
1817 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(#diseq) ] };
1818 output.to_tokens(tokens);
1819 }
1820 Clause::Succeed(_) => {
1821 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(::proto_vulcan::relation::succeed()) ] };
1822 output.to_tokens(tokens);
1823 }
1824 Clause::Fail(_) => {
1825 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(::proto_vulcan::relation::fail()) ] };
1826 output.to_tokens(tokens);
1827 }
1828 Clause::Conjunction(conjunction) => {
1829 conjunction.to_tokens(tokens);
1832 }
1833 Clause::Relation(relation) => {
1834 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(#relation) ] };
1835 output.to_tokens(tokens);
1836 }
1837 Clause::Closure(closure) => {
1838 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(#closure) ] };
1839 output.to_tokens(tokens);
1840 }
1841 Clause::Loop(l) => {
1842 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(#l) ] };
1843 output.to_tokens(tokens);
1844 }
1845 Clause::Operator(operator) => {
1846 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(#operator) ] };
1847 output.to_tokens(tokens);
1848 }
1849 Clause::PatternMatchOperator(operator) => {
1850 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(#operator) ] };
1851 output.to_tokens(tokens);
1852 }
1853 Clause::Expression(expr) => {
1854 let output = quote! { &[ ::proto_vulcan::GoalCast::cast_into(#expr) ]};
1855 output.to_tokens(tokens);
1856 }
1857 }
1858 }
1859}
1860
1861#[proc_macro]
1862pub fn proto_vulcan(input: TokenStream) -> TokenStream {
1863 let clause = parse_macro_input!(input as Clause);
1864
1865 let output = quote! {
1866 ::proto_vulcan::GoalCast::cast_into(#clause)
1867 };
1868 output.into()
1869}
1870
1871#[proc_macro]
1872pub fn proto_vulcan_closure(input: TokenStream) -> TokenStream {
1873 let clause = parse_macro_input!(input as Clause);
1874 let closure = Closure::new(vec![clause]);
1875
1876 let output = quote! {
1877 ::proto_vulcan::GoalCast::cast_into(#closure)
1878 };
1879 output.into()
1880}
1881
1882#[proc_macro]
1883pub fn lterm(input: TokenStream) -> TokenStream {
1884 let term = parse_macro_input!(input as TreeTerm);
1885
1886 let output = quote! {
1887 #term
1888 };
1889 output.into()
1890}
1891
1892#[allow(dead_code)]
1893#[derive(Clone)]
1894struct Query {
1895 or1_token: Token![|],
1896 variables: Punctuated<TypedVariable, Token![,]>,
1897 or2_token: Token![|],
1898 brace_token: Brace,
1899 body: Punctuated<Clause, Token![,]>,
1900}
1901
1902impl Parse for Query {
1903 fn parse(input: ParseStream) -> Result<Self> {
1904 let or1_token: Token![|] = input.parse()?;
1905 let mut variables = Punctuated::new();
1906 loop {
1907 if input.peek(Token![|]) {
1908 break;
1909 }
1910 let var: TypedVariable = input.parse()?;
1911 variables.push_value(var);
1912 if input.peek(Token![|]) {
1913 break;
1914 }
1915 let punct: Token![,] = input.parse()?;
1916 variables.push_punct(punct);
1917 }
1918
1919 let or2_token: Token![|] = input.parse()?;
1920
1921 let content;
1922 Ok(Query {
1923 or1_token,
1924 variables,
1925 or2_token,
1926 brace_token: braced!(content in input),
1927 body: content.parse_terminated(Clause::parse)?,
1928 })
1929 }
1930}
1931
1932impl ToTokens for Query {
1933 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1934 let query: Vec<Ident> = self.variables.iter().map(|x| &x.name).cloned().collect();
1935 let query_types: Vec<syn::Path> = self.variables.iter().map(|x| &x.path).cloned().collect();
1936 let body: Vec<&Clause> = self.body.iter().collect();
1937
1938 let output = quote! {
1939 #(let #query: #query_types <_, _> = ::proto_vulcan::compound::CompoundTerm::new_var(stringify!(#query)); )*
1940
1941 let __vars__ = vec![ #( ::proto_vulcan::Upcast::into_super(#query.clone()) ),* ];
1942
1943 let goal = {
1944 let __query__ = ::proto_vulcan::lterm::LTerm::var("__query__");
1945 ::proto_vulcan::GoalCast::cast_into(
1946 ::proto_vulcan::operator::fresh::Fresh::new(
1947 vec![::std::clone::Clone::clone(&__query__)],
1948 ::proto_vulcan::GoalCast::cast_into(
1949 ::proto_vulcan::operator::conj::InferredConj::from_array(&[
1950 ::proto_vulcan::GoalCast::cast_into(
1951 ::proto_vulcan::relation::eq::eq(
1952 ::std::clone::Clone::clone(&__query__),
1953 ::proto_vulcan::lterm::LTerm::from_array(&[#(::proto_vulcan::Upcast::to_super(&#query)),*]),
1954
1955 )
1956 ),
1957 ::proto_vulcan::operator::conj::Conj::from_array(&[
1958 #( ::proto_vulcan::GoalCast::cast_into( #body ) ),*
1959 ]),
1960 ::proto_vulcan::state::reify(::std::clone::Clone::clone(&__query__)),
1961 ]),
1962 )
1963 )
1964 )
1965 };
1966
1967 use std::fmt;
1968
1969 #[derive(Clone, Debug)]
1970 struct QResult<U: ::proto_vulcan::user::User, E: ::proto_vulcan::engine::Engine<U>> {
1971 #( #query: ::proto_vulcan::lresult::LResult<U, E>, )*
1972 }
1973
1974 impl<U: ::proto_vulcan::user::User, E: ::proto_vulcan::engine::Engine<U>> ::proto_vulcan::query::QueryResult<U, E> for QResult<U, E> {
1975 fn from_vec(v: Vec<::proto_vulcan::lresult::LResult<U, E>>) -> QResult<U, E> {
1976 let mut vi = v.into_iter();
1977 QResult {
1978 #( #query: vi.next().unwrap(), )*
1979 }
1980 }
1981 }
1982
1983 impl<U: ::proto_vulcan::user::User, E: ::proto_vulcan::engine::Engine<U>> fmt::Display for QResult<U, E> {
1984 #[allow(unused_variables, unused_assignments)]
1985 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1986 let mut count = 0;
1987 #( if count > 0 { writeln!(f, "")?; } write!(f, "{}: {}", stringify!(#query), self.#query)?; count += 1; )*
1988 write!(f, "")
1989 }
1990 }
1991
1992 ::proto_vulcan::query::Query::<QResult<_, _>>::new(__vars__, goal)
1993 };
1994
1995 output.to_tokens(tokens);
1996 }
1997}
1998
1999#[proc_macro]
2000pub fn proto_vulcan_query(input: TokenStream) -> TokenStream {
2001 let query = parse_macro_input!(input as Query);
2002 let output = quote! {{
2003 #query
2004 }};
2005 output.into()
2006}
2007
2008fn make_compound_modifications_to_path(path: &mut syn::Path) -> std::result::Result<(), Error> {
2009 match path.segments.iter_mut().last() {
2010 Some(last_segment) => match last_segment.arguments {
2011 syn::PathArguments::AngleBracketed(ref mut generic_arguments) => {
2012 for argument in generic_arguments.args.iter_mut() {
2013 match argument {
2014 syn::GenericArgument::Type(ty) => {
2015 make_compound_modifications_to_type(ty)?;
2016 }
2017 _ => {
2018 return Err(Error::new(argument.span(), "Invalid generic argument"));
2019 }
2020 }
2021 }
2022
2023 return Ok(());
2024 }
2025 syn::PathArguments::None => {
2026 last_segment.arguments =
2027 syn::PathArguments::AngleBracketed(syn::parse_quote! {<U, E>});
2028 }
2029 _ => {
2030 return Err(Error::new(
2031 last_segment.arguments.span(),
2032 "Invalid type argument",
2033 ));
2034 }
2035 },
2036 None => {
2037 return Err(Error::new(path.span(), "Invalid type argument"));
2038 }
2039 }
2040 Ok(())
2041}
2042
2043fn make_compound_modifications_to_type(ty: &mut syn::Type) -> std::result::Result<(), Error> {
2044 match ty {
2045 syn::Type::Path(typepath) => {
2046 make_compound_modifications_to_path(&mut typepath.path)?;
2048 *ty = syn::parse_quote! { #typepath };
2049 }
2050 _ => return Err(Error::new(ty.span(), "Invalid compound type")),
2051 }
2052 Ok(())
2053}
2054
2055fn make_compound_modifications_to_itemstruct(
2056 itemstruct: &mut syn::ItemStruct,
2057) -> std::result::Result<(), Error> {
2058 if itemstruct.generics.params.is_empty() {
2059 let new_generics: syn::Generics = syn::parse_quote! {<U: ::proto_vulcan::user::User, E: ::proto_vulcan::engine::Engine<U>>};
2060 itemstruct.generics = new_generics;
2061 }
2062 for field in itemstruct.fields.iter_mut() {
2063 field.vis = syn::Visibility::Public(syn::VisPublic {
2064 pub_token: syn::parse_quote!(pub),
2065 });
2066 make_compound_modifications_to_type(&mut field.ty)?;
2067 }
2068 itemstruct.vis = syn::parse_quote!(pub);
2069 Ok(())
2070}
2071
2072fn make_compound_unnamed_struct(itemstruct: syn::ItemStruct) -> TokenStream {
2073 let mut inner = itemstruct.clone();
2074 inner.ident = quote::format_ident!("_Inner{}", itemstruct.ident);
2075
2076 let vis = &itemstruct.vis;
2077 let struct_name = itemstruct.ident.clone();
2078 let inner_ident = &inner.ident;
2079 let mod_name = quote::format_ident!("{}_compound", struct_name);
2080 let (impl_generics, type_generics, where_clause) = itemstruct.generics.split_for_impl();
2081
2082 let field_indices: Vec<syn::Index> = itemstruct
2083 .fields
2084 .iter()
2085 .enumerate()
2086 .map(|(n, _)| syn::Index::from(n))
2087 .collect();
2088
2089 let output = quote!(
2090 #[allow(non_snake_case)]
2091 #vis mod #mod_name {
2092 use super::*;
2093 #[derive(Eq)]
2094 #inner
2095
2096 impl #impl_generics ::std::clone::Clone for #inner_ident #type_generics #where_clause {
2097 fn clone(&self) -> #inner_ident #type_generics {
2098 #inner_ident(#( ::std::clone::Clone::clone(&self.#field_indices) ),* )
2099 }
2100 }
2101
2102 impl #impl_generics ::proto_vulcan::compound::CompoundObject #type_generics for #inner_ident #type_generics #where_clause {
2103 fn type_name(&self) -> &'static str {
2104 stringify!(#struct_name)
2105 }
2106
2107 fn children<'a>(&'a self) -> Box<dyn Iterator<Item = &'a dyn ::proto_vulcan::compound::CompoundObject #type_generics> + 'a> {
2108 Box::new(vec![#(&self.#field_indices as &dyn ::proto_vulcan::compound::CompoundObject #type_generics),*].into_iter())
2109 }
2110 }
2111
2112 impl #impl_generics ::proto_vulcan::compound::CompoundWalkStar #type_generics for #inner_ident #type_generics #where_clause {
2113 fn compound_walk_star(&self, smap: &::proto_vulcan::state::SMap #type_generics) -> Self {
2114 #inner_ident(#(self.#field_indices.compound_walk_star(smap)),*)
2115 }
2116 }
2117
2118 impl #impl_generics Into<#struct_name #type_generics> for #inner_ident #type_generics #where_clause {
2119 fn into(self) -> #struct_name #type_generics {
2120 #struct_name {
2121 inner: Into::<LTerm #type_generics>::into(self),
2122 }
2123 }
2124 }
2125
2126 impl #impl_generics Into<::proto_vulcan::lterm::LTerm #type_generics> for #inner_ident #type_generics #where_clause {
2127 fn into(self) -> ::proto_vulcan::lterm::LTerm #type_generics {
2128 ::proto_vulcan::lterm::LTerm::from(::std::rc::Rc::new(self) as ::std::rc::Rc<dyn ::proto_vulcan::compound::CompoundObject #type_generics>)
2129 }
2130 }
2131
2132 impl #impl_generics ::proto_vulcan::Downcast #type_generics for #inner_ident #type_generics #where_clause {
2133 type SubType = #struct_name #type_generics;
2134 fn into_sub(self) -> Self::SubType {
2135 self.into()
2136 }
2137 }
2138
2139 impl #impl_generics ::core::fmt::Debug for #inner_ident #type_generics #where_clause {
2140 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
2141 let debug_trait_builder = &mut ::core::fmt::Formatter::debug_tuple(f, stringify!(#struct_name));
2142 #( let _ = ::core::fmt::DebugTuple::field(debug_trait_builder, &self.#field_indices); )*
2143 ::core::fmt::DebugTuple::finish(debug_trait_builder)
2144 }
2145 }
2146
2147 impl #impl_generics ::std::hash::Hash for #inner_ident #type_generics #where_clause {
2148 fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
2149 #( ::std::hash::Hash::hash(&self.#field_indices, state); )*
2150 }
2151 }
2152
2153 impl #impl_generics ::std::cmp::PartialEq for #inner_ident #type_generics #where_clause {
2154 fn eq(&self, other: &Self) -> bool {
2155 #( ::std::cmp::PartialEq::eq(&self.#field_indices, &other.#field_indices) &&)* true
2156 }
2157 }
2158 }
2159
2160 #[derive(Eq)]
2161 #vis struct #struct_name #impl_generics {
2162 inner: LTerm #type_generics,
2163 }
2164
2165 impl #impl_generics ::std::clone::Clone for #struct_name #type_generics #where_clause {
2166 fn clone(&self) -> #struct_name #type_generics {
2167 #struct_name {
2168 inner: ::std::clone::Clone::clone(&self.inner),
2169 }
2170 }
2171 }
2172
2173 impl #impl_generics ::std::fmt::Debug for #struct_name #type_generics #where_clause {
2174 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
2175 self.inner.fmt(f)
2176 }
2177 }
2178
2179 impl #impl_generics ::std::hash::Hash for #struct_name #type_generics #where_clause {
2180 fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
2181 ::std::hash::Hash::hash(&self.inner, state);
2182 }
2183 }
2184
2185 impl #impl_generics ::std::cmp::PartialEq for #struct_name #type_generics #where_clause {
2186 fn eq(&self, other: &Self) -> bool {
2187 ::std::cmp::PartialEq::eq(&self.inner, &other.inner)
2188 }
2189 }
2190
2191 #[automatically_derived]
2192 impl #impl_generics ::proto_vulcan::compound::CompoundTerm #type_generics for #struct_name #type_generics #where_clause {
2193 fn new_var(name: &'static str) -> #struct_name #type_generics {
2194 #struct_name {
2195 inner: LTerm::var(name),
2196 }
2197 }
2198
2199 fn new_wildcard() -> #struct_name #type_generics {
2200 #struct_name {
2201 inner: LTerm::any(),
2202 }
2203 }
2204
2205 fn new_none() -> #struct_name #type_generics {
2206 #struct_name {
2207 inner: LTerm::empty_list(),
2208 }
2209 }
2210 }
2211
2212 impl #impl_generics ::proto_vulcan::compound::CompoundObject #type_generics for #struct_name #type_generics #where_clause {
2213 fn type_name(&self) -> &'static str {
2214 stringify!(#struct_name)
2215 }
2216
2217 fn children<'a>(&'a self) -> Box<dyn Iterator<Item = &'a dyn ::proto_vulcan::compound::CompoundObject #type_generics> + 'a> {
2218 self.inner.children()
2219 }
2220
2221 fn as_term(&self) -> Option<<erm<U, E>> {
2222 Some(&self.inner)
2223 }
2224 }
2225
2226 impl #impl_generics ::proto_vulcan::compound::CompoundWalkStar #type_generics for #struct_name #type_generics #where_clause {
2227 fn compound_walk_star(&self, smap: &::proto_vulcan::state::SMap #type_generics) -> Self {
2228 #struct_name {
2229 inner: self.inner.compound_walk_star(smap),
2230 }
2231 }
2232 }
2233
2234 #[automatically_derived]
2235 impl #impl_generics Into<::proto_vulcan::lterm::LTerm #type_generics> for #struct_name #type_generics #where_clause {
2236 fn into(self) -> LTerm #type_generics {
2237 self.inner
2238 }
2239 }
2240
2241 impl #impl_generics ::proto_vulcan::Upcast<U, E, ::proto_vulcan::lterm::LTerm #type_generics> for #struct_name #type_generics #where_clause {
2242 #[inline]
2243 fn to_super<K: ::std::borrow::Borrow<Self>>(k: &K) -> ::proto_vulcan::lterm::LTerm #type_generics {
2244 Into::into(::std::clone::Clone::clone(k.borrow()))
2245 }
2246
2247 #[inline]
2248 fn into_super(self) -> ::proto_vulcan::lterm::LTerm #type_generics {
2249 Into::into(self)
2250 }
2251 }
2252
2253 impl #impl_generics ::proto_vulcan::Downcast #type_generics for #struct_name #type_generics #where_clause {
2254 type SubType = Self;
2255 fn into_sub(self) -> Self::SubType {
2256 self.into()
2257 }
2258 }
2259 );
2260 output.into()
2261}
2262
2263fn make_compound_named_struct(itemstruct: syn::ItemStruct) -> TokenStream {
2264 let mut inner = itemstruct.clone();
2265 inner.ident = quote::format_ident!("_Inner{}", itemstruct.ident);
2266
2267 let vis = &itemstruct.vis;
2268 let struct_name = itemstruct.ident.clone();
2269 let inner_ident = &inner.ident;
2270 let mod_name = quote::format_ident!("{}_compound", struct_name);
2271 let (impl_generics, type_generics, where_clause) = itemstruct.generics.split_for_impl();
2272
2273 let field_names: Vec<syn::Ident> = itemstruct
2274 .fields
2275 .iter()
2276 .map(|field| field.ident.as_ref().unwrap().clone())
2277 .collect();
2278
2279 let output = quote!(
2280 #[allow(non_snake_case)]
2281 #vis mod #mod_name {
2282 use super::*;
2283 #[derive(Eq)]
2284 #inner
2285
2286 impl #impl_generics ::std::clone::Clone for #inner_ident #type_generics #where_clause {
2287 fn clone(&self) -> #inner_ident #type_generics {
2288 #inner_ident {
2289 #( #field_names: ::std::clone::Clone::clone(&self.#field_names) ),*
2290 }
2291 }
2292 }
2293
2294 impl #impl_generics ::proto_vulcan::compound::CompoundObject #type_generics for #inner_ident #type_generics #where_clause {
2295 fn type_name(&self) -> &'static str {
2296 stringify!(#struct_name)
2297 }
2298
2299 fn children<'a>(&'a self) -> Box<dyn Iterator<Item = &'a dyn ::proto_vulcan::compound::CompoundObject #type_generics> + 'a> {
2300 Box::new(vec![#(&self.#field_names as &dyn ::proto_vulcan::compound::CompoundObject #type_generics),*].into_iter())
2301 }
2302 }
2303
2304 impl #impl_generics ::proto_vulcan::compound::CompoundWalkStar #type_generics for #inner_ident #type_generics #where_clause {
2305 fn compound_walk_star(&self, smap: &::proto_vulcan::state::SMap #type_generics) -> Self {
2306 #inner_ident { #( #field_names: self.#field_names.compound_walk_star(smap)),* }
2307 }
2308 }
2309
2310 impl #impl_generics Into<#struct_name #type_generics> for #inner_ident #type_generics #where_clause {
2311 fn into(self) -> #struct_name #type_generics {
2312 #struct_name {
2313 inner: Into::<LTerm #type_generics>::into(self),
2314 }
2315 }
2316 }
2317
2318 impl #impl_generics Into<::proto_vulcan::lterm::LTerm #type_generics> for #inner_ident #type_generics #where_clause {
2319 fn into(self) -> ::proto_vulcan::lterm::LTerm #type_generics {
2320 ::proto_vulcan::lterm::LTerm::from(::std::rc::Rc::new(self) as ::std::rc::Rc<dyn ::proto_vulcan::compound::CompoundObject #type_generics>)
2321 }
2322 }
2323
2324 impl #impl_generics ::proto_vulcan::Downcast #type_generics for #inner_ident #type_generics #where_clause {
2325 type SubType = #struct_name #type_generics;
2326 fn into_sub(self) -> Self::SubType {
2327 self.into()
2328 }
2329 }
2330
2331 impl #impl_generics ::core::fmt::Debug for #inner_ident #type_generics #where_clause {
2332 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
2333 let debug_trait_builder = &mut ::core::fmt::Formatter::debug_struct(f, stringify!(#struct_name));
2334 #(
2335 let _= ::core::fmt::DebugStruct::field(
2336 debug_trait_builder,
2337 stringify!(#field_names),
2338 &self.#field_names,
2339 );
2340 )*
2341 ::core::fmt::DebugStruct::finish(debug_trait_builder)
2342 }
2343 }
2344
2345 impl #impl_generics ::std::hash::Hash for #inner_ident #type_generics #where_clause {
2346 fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
2347 #( ::std::hash::Hash::hash(&self.#field_names, state); )*
2348 }
2349 }
2350
2351 impl #impl_generics ::std::cmp::PartialEq for #inner_ident #type_generics #where_clause {
2352 fn eq(&self, other: &Self) -> bool {
2353 #( ::std::cmp::PartialEq::eq(&self.#field_names, &other.#field_names) &&)* true
2354 }
2355 }
2356 }
2357
2358 #[derive(Eq)]
2359 #vis struct #struct_name #impl_generics {
2360 inner: LTerm #type_generics,
2361 }
2362
2363 impl #impl_generics ::std::clone::Clone for #struct_name #type_generics #where_clause {
2364 fn clone(&self) -> #struct_name #type_generics {
2365 #struct_name {
2366 inner: ::std::clone::Clone::clone(&self.inner),
2367 }
2368 }
2369 }
2370
2371 impl #impl_generics ::std::fmt::Debug for #struct_name #type_generics #where_clause {
2372 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
2373 self.inner.fmt(f)
2374 }
2375 }
2376
2377 impl #impl_generics ::std::hash::Hash for #struct_name #type_generics #where_clause {
2378 fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
2379 ::std::hash::Hash::hash(&self.inner, state);
2380 }
2381 }
2382
2383 impl #impl_generics ::std::cmp::PartialEq for #struct_name #type_generics #where_clause {
2384 fn eq(&self, other: &Self) -> bool {
2385 ::std::cmp::PartialEq::eq(&self.inner, &other.inner)
2386 }
2387 }
2388
2389 #[automatically_derived]
2390 impl #impl_generics ::proto_vulcan::compound::CompoundTerm #type_generics for #struct_name #type_generics #where_clause {
2391 fn new_var(name: &'static str) -> #struct_name #type_generics {
2392 #struct_name {
2393 inner: LTerm::var(name),
2394 }
2395 }
2396
2397 fn new_wildcard() -> #struct_name #type_generics {
2398 #struct_name {
2399 inner: LTerm::any(),
2400 }
2401 }
2402
2403 fn new_none() -> #struct_name #type_generics {
2404 #struct_name {
2405 inner: LTerm::empty_list(),
2406 }
2407 }
2408 }
2409
2410 impl #impl_generics ::proto_vulcan::compound::CompoundObject #type_generics for #struct_name #type_generics #where_clause {
2411 fn type_name(&self) -> &'static str {
2412 stringify!(#struct_name)
2413 }
2414
2415 fn children<'a>(&'a self) -> Box<dyn Iterator<Item = &'a dyn ::proto_vulcan::compound::CompoundObject #type_generics> + 'a> {
2416 self.inner.children()
2417 }
2418
2419 fn as_term(&self) -> Option<<erm #type_generics> {
2420 Some(&self.inner)
2421 }
2422 }
2423
2424 impl #impl_generics ::proto_vulcan::compound::CompoundWalkStar #type_generics for #struct_name #type_generics #where_clause {
2425 fn compound_walk_star(&self, smap: &::proto_vulcan::state::SMap #type_generics) -> Self {
2426 #struct_name {
2427 inner: self.inner.compound_walk_star(smap),
2428 }
2429 }
2430 }
2431
2432 #[automatically_derived]
2433 impl #impl_generics Into<::proto_vulcan::lterm::LTerm #type_generics> for #struct_name #type_generics #where_clause {
2434 fn into(self) -> LTerm #type_generics {
2435 self.inner
2436 }
2437 }
2438
2439 impl #impl_generics ::proto_vulcan::Upcast<U, E, ::proto_vulcan::lterm::LTerm #type_generics> for #struct_name #type_generics #where_clause {
2440 #[inline]
2441 fn to_super<K: ::std::borrow::Borrow<Self>>(k: &K) -> ::proto_vulcan::lterm::LTerm #type_generics {
2442 Into::into(::std::clone::Clone::clone(k.borrow()))
2443 }
2444
2445 #[inline]
2446 fn into_super(self) -> ::proto_vulcan::lterm::LTerm #type_generics {
2447 Into::into(self)
2448 }
2449 }
2450
2451 impl #impl_generics ::proto_vulcan::Downcast #type_generics for #struct_name #type_generics #where_clause {
2452 type SubType = Self;
2453 fn into_sub(self) -> Self::SubType {
2454 self.into()
2455 }
2456 }
2457 );
2458 output.into()
2459}
2460
2461fn make_compound_struct(mut itemstruct: syn::ItemStruct) -> TokenStream {
2462 match make_compound_modifications_to_itemstruct(&mut itemstruct) {
2464 Ok(()) => (),
2465 Err(error) => return error.to_compile_error().into(),
2466 }
2467
2468 match itemstruct.fields {
2469 syn::Fields::Unnamed(_) => make_compound_unnamed_struct(itemstruct),
2470 syn::Fields::Named(_) => make_compound_named_struct(itemstruct),
2471 syn::Fields::Unit => make_compound_named_struct(itemstruct),
2472 }
2473}
2474
2475#[proc_macro_attribute]
2476pub fn compound(_metadata: TokenStream, input: TokenStream) -> TokenStream {
2477 let item = parse_macro_input!(input as syn::Item);
2478
2479 match item {
2480 syn::Item::Struct(item_struct) => return make_compound_struct(item_struct),
2482 _ => {
2483 return syn::Error::new(item.span(), "Compound attribute requires struct or enum.")
2484 .to_compile_error()
2485 .into();
2486 }
2487 }
2488}