proto_vulcan_macros/
lib.rs

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                    // No Into::into() for compound pattern arguments to constrain type.
312                    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        // Handle Tuple-constructor first
435        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        // No parsing for quoted input
492        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                // Try parsing TreeTerm
508                Ok(Argument::TreeTerm(term))
509            } else {
510                // By parsing parenthesises away if any, we avoid unused parenthesis warnings
511                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    // The `compound` flags affects the variable builder selection and how the
680    // variable is accessed in the compound pattern arguments.
681    //
682    //  * When variable is at compound pattern argument position, then the type
683    //    of the argument is derived from the compound term builder. Therefore,
684    //    at compound argument position the variable is accessed by only cloning
685    //    a reference, without the enclosing Into::into()-call.
686    //
687    // Compound flag      let #x =                      Access
688    //     true           CompoundTerm::new_wildcard()  Clone::clone(&#x)
689    //     false          LTerm::var(#x)                Into::into(Clone::clone(&#x))
690    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                    // No Into::into() for compound pattern arguments to constrain type.
752                    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                    // No Into::into() for compound pattern arguments to constrain type.
822                    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    //Tuple
1014}
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            // Repeat |-expression patterns with multiple single pattern entries
1214            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                        // Define alias for the `term` so that pattern-variables do not redefine it
1246                        // before the equality-relation with pattern is created.
1247                        let __term__ = #term;
1248                        // Define new variables found in the pattern
1249                        #( 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                        // Define alias for the `term` so that pattern-variables do not redefine it
1263                        // before the equality-relation with pattern is created.
1264                        let __term__ = #term;
1265                        // Define new variables found in the pattern
1266                        #( 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/// TreeTerm within a TreeTerm
1385#[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 x in coll { }
1631    For(For),
1632    /// project |x, y, z| { }
1633    Project(Project),
1634    // fngoal |state| { }
1635    FnGoal(FnGoal),
1636    /// |x, y, z| { }
1637    Fresh(Fresh),
1638    // x == y
1639    Eq(Eq),
1640    // x != y
1641    Diseq(Diseq),
1642    // true
1643    Succeed(syn::LitBool),
1644    // false
1645    Fail(syn::LitBool),
1646    // [ ]
1647    Conjunction(Conjunction),
1648    // $relation (param1, param2, ...)
1649    Relation(Relation),
1650    // closure { }
1651    Closure(Closure),
1652    // loop { }
1653    Loop(Loop),
1654    // $operator { }
1655    Operator(Operator),
1656    // $operator $term { pattern0 => body0, ...}
1657    PatternMatchOperator(PatternMatchOperator),
1658    // Expression that evaluates to Goal
1659    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                // When conjunction is not inside a non-conjunction an operator we can construct
1757                // an Conj-goal from it.
1758                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                // When conjunction is inside an operator, we do not create Conj-goal, and instead
1830                // let the conjunction be represented as an array of goals.
1831                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            //let has_generic_args = has_generic_arguments(&typepath.path)?;
2047            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<&LTerm<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<&LTerm #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    // Add generics and where necessary
2463    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::Enum(item_enum) => return make_compound_enum(item_enum),
2481        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}