df_ls_derive 0.3.0-rc.1

A language server for Dwarf Fortress RAW files
Documentation
use crate::common;
use quote::{quote, quote_spanned};
use std::collections::HashMap;

#[derive(Clone, Debug, Default)]
pub struct TokenDeInfo {
    pub token: Option<String>,
    pub on_duplicate_to_parent: bool,
    pub on_duplicate_error: bool,
    pub primary_token: bool,
    pub alias: Option<String>, // TODO make Vec
}

pub fn get_token_de_info(field: &syn::Field) -> (TokenDeInfo, proc_macro2::TokenStream) {
    let mut token_info = TokenDeInfo::default();
    let mut errors = quote! {};
    for (_i, attr) in field.attrs.iter().enumerate() {
        let token_attrs = get_token_attrs_variables(attr);
        for (key, val) in token_attrs {
            let mut string_quote = "".to_string();
            if let Some(val) = val {
                if let syn::Lit::Str(string_lit) = val.clone() {
                    string_quote = string_lit.value();
                }
                if string_quote.is_empty() {
                    continue;
                }
                if string_quote.contains(' ') {
                    let error = quote_spanned! {
                        val.span() =>
                        compile_error!(
                            "String contains spaces."
                        );
                    };
                    errors = quote! {
                        #errors
                        #error
                    };
                }
            }
            match key.as_ref() {
                "token" => token_info.token = Some(string_quote),
                "on_duplicate_to_parent" => token_info.on_duplicate_to_parent = true,
                "on_duplicate_error" => token_info.on_duplicate_error = true,
                "primary_token" => token_info.primary_token = true,
                "alias" => token_info.alias = Some(string_quote),
                _ => {}
            }
        }
    }
    (token_info, errors)
}

fn get_token_attrs_variables(attr: &syn::Attribute) -> HashMap<String, Option<syn::Lit>> {
    let meta_items = common::get_meta_items(attr, "token_de").unwrap();
    let mut lit_list: HashMap<String, Option<syn::Lit>> = HashMap::new();
    for meta_item in meta_items {
        match meta_item {
            // Parse `#[token_de(token = "foo")]`
            syn::NestedMeta::Meta(syn::Meta::NameValue(m)) if m.path.is_ident("token") => {
                lit_list.insert("token".to_owned(), Some(m.lit));
            }
            // Parse `#[token_de(on_duplicate_to_parent)]`
            syn::NestedMeta::Meta(syn::Meta::Path(m)) if m.is_ident("on_duplicate_to_parent") => {
                lit_list.insert("on_duplicate_to_parent".to_owned(), None);
            }
            // Parse `#[token_de(on_duplicate_error)]`
            syn::NestedMeta::Meta(syn::Meta::Path(m)) if m.is_ident("on_duplicate_error") => {
                lit_list.insert("on_duplicate_error".to_owned(), None);
            }
            // Parse `#[token_de(primary_token)]`
            syn::NestedMeta::Meta(syn::Meta::Path(m)) if m.is_ident("primary_token") => {
                lit_list.insert("primary_token".to_owned(), None);
            }
            // Parse `#[token_de(alias = "bar")]`
            syn::NestedMeta::Meta(syn::Meta::NameValue(m)) if m.path.is_ident("alias") => {
                lit_list.insert("alias".to_owned(), Some(m.lit));
            }
            _ => (),
        };
    }
    lit_list
}