smd_macro 0.0.7

A crate for the smd! macro
use super::{
  event_names::UI_EVENT_NAMES,
  util,
};
use crate::types::{
  AttributeOrEventHandler,
  TokenTreeSlice,
};

#[allow(unused_imports)]
use nom::{
  error_position,
  tuple_parser,
};

use nom::{
  alt,
  apply,
  call,
  map,
  named,
  tuple,
};
use proc_macro2::{
  Delimiter,
  TokenStream,
};

// N.B. there are three types of attributes values supported:
// groups, empty and literals. Obviously, only groups can hold event handlers
// (callbacks), so we either call assert_is_not_event_handler or we
// switch on whether it is an event handler.
//
// In the EventHandler case, the string *is changed to upper camel case*
// to match the Event type! Beware!
// (Should we use a newtype?)

fn assert_is_not_event_handler(string: &String) {
  assert!(
    !UI_EVENT_NAMES.contains_key(string),
    format!(
      "attribute {} is an event name, but was not followed by curly braces",
      string
    )
  );
}

impl AttributeOrEventHandler {
  fn create_from_string(string: String, t: TokenStream) -> AttributeOrEventHandler {
    match UI_EVENT_NAMES.get(&string) {
      Some((event_name, _should_include_rest_param)) => {
        AttributeOrEventHandler::EventHandler((event_name.to_string(), t))
      },
      None => {
        // TODO make this less awkward
        if string == "ref" {
          AttributeOrEventHandler::DomRef(t)
        } else {
          AttributeOrEventHandler::Attribute((string, t))
        }
      },
    }
  }
}

named!(
  pub match_attribute <TokenTreeSlice, AttributeOrEventHandler>,
  alt!(
    alt!(
      map!(
        tuple!(
          apply!(util::match_ident, None, false),
          apply!(util::match_punct, Some('='), None, vec![]),
          map!(apply!(util::match_group, Some(Delimiter::Brace)), super::util::enquote)
        ),
        |val| {
          AttributeOrEventHandler::create_from_string(val.0, val.2)
        }
      )
        | map!(
          tuple!(
            apply!(util::match_ident, None, false),
            apply!(util::match_punct, Some('='), None, vec![]),
            map!(call!(util::match_literal), super::util::enquote)
          ),
          |val| {
            assert_is_not_event_handler(&val.0);
            AttributeOrEventHandler::Attribute((val.0, val.2))
          }
        )
        | map!(
          apply!(util::match_ident, None, false),
          |attr_name| {
            assert_is_not_event_handler(&attr_name);
            AttributeOrEventHandler::Attribute((attr_name, quote::quote!("")))
          }
        )
    )
  )
);