code-product-lib 0.4.1

macro producing multiple expansions
Documentation
use syn::parse::{Parse, ParseStream};

// start = { product_entity | rust } ;
enum Start {
    ProductEntity(ProductEntity),
    Rust(RustCode),
}

impl Parse for Start {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        if input.peek(syn::token::Dollar) {
            input.parse().map(Start::ProductEntity)
        } else {
            input.parse().map(Start::Rust)
        }
    }
}

#[test]
fn test_start() {
    let input = quote! {
        $ { }
        $ ( )
        $ [ ]
        $ rust ;
    };
    let start: Start = syn::parse2(input).unwrap();
    match start {
        Start::ProductEntity(_) => {}
        Start::Rust(_) => {}
    }
}

// rust = ?any_valid_rust_token? ;
struct RustCode {
    code: Vec<Token>,
}

impl Parse for RustCode {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        input.parse().map(|code| RustCode { code })
    }
}

// product_entity = "$" ( scope | definition | reference ) ;
enum ProductEntity {
    Scope(Scope),
    Definition(Definition),
    Reference(Reference),
}

impl Parse for ProductEntity {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        input.parse::<syn::token::Dollar>()?;
        if input.peek(syn::token::Brace) {
            input.parse().map(ProductEntity::Scope)
        } else if input.peek(syn::token::Paren) {
            input.parse().map(ProductEntity::Definition)
        } else {
            input.parse().map(ProductEntity::Reference)
        }
    }
}


// scope = product_scope | linear_scope ;
// product_scope = "{" { product_entity | rust } "}" ;
// linear_scope = "[" { product_entity | rust } "]" ;
// definition = "(" ( table_definition | normal_definition ) ")" ;
// normal_definition = [ "$"? name ":" ] ( items | item );
// table_definition = "[" headers items "]" ;
// headers = ( name ":" )+ ;
// items = ( "(" { rust } ")" )+ ;
// item = { rust } ;
// name = ?identifier? ;
// reference = ( ?number? | ?identifier? ) ;


/*
    // product_entity = "$" ( scope | definition | product_reference | rust ) ;
    // the last 'rust' catches the escaped '$$' as '$'.
    fn parse_product_entity(&self) -> bool {
        self.parse_product_char()
            && (self.parse_scope()
                || self.parse_definition()
                || self.parse_product_reference()
                || self.parse_rust())
    }
*/