/**
 * This module contains UDA's (User Defined Attributes) either used in
 * the runtime or special UDA's recognized by compiler.
 *
 * Copyright: Copyright Jacob Carlborg 2015.
 * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
 * Authors:   Jacob Carlborg
 * Source:    $(DRUNTIMESRC core/_attribute.d)
 */

/*          Copyright Jacob Carlborg 2015.
 * Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 */
module core.attribute;

version (D_ObjectiveC)
    version = UdaSelector;

version (Posix)
    version = UdaGNUAbiTag;

version (CoreDdoc)
{
    version = UdaGNUAbiTag;
    version = UdaSelector;
}

/**
 * Use this attribute to attach an Objective-C selector to a method.
 *
 * This is a special compiler recognized attribute, it has several
 * requirements, which all will be enforced by the compiler:
 *
 * $(UL
 *  $(LI
 *      The attribute can only be attached to methods or constructors which
 *      have Objective-C linkage. That is, a method or a constructor in a
 *      class or interface declared as $(D_CODE extern(Objective-C)).
 *  ),
 *
 *  $(LI It cannot be attached to a method or constructor that is a template),
 *
 *  $(LI
 *      The number of colons in the string need to match the number of
 *      arguments the method accept.
 *  ),
 *
 *  $(LI It can only be used once in a method declaration)
 * )
 *
 * Examples:
 * ---
 * extern (Objective-C)
 * class NSObject
 * {
 *  this() @selector("init");
 *  static NSObject alloc() @selector("alloc");
 *  NSObject initWithUTF8String(in char* str) @selector("initWithUTF8String:");
 *  ObjcObject copyScriptingValue(ObjcObject value, NSString key, NSDictionary properties)
 *      @selector("copyScriptingValue:forKey:withProperties:");
 * }
 * ---
 */
version (UdaSelector) struct selector
{
    string selector;
}

/**
 * Use this attribute to declare an ABI tag on a C++ symbol.
 *
 * ABI tag is an attribute introduced by the GNU C++ compiler.
 * It modifies the mangled name of the symbol to incorporate the tag name,
 * in order to distinguish from an earlier version with a different ABI.
 *
 * This is a special compiler recognized attribute, it has a few
 * requirements, which all will be enforced by the compiler:
 *
 * $(UL
 *  $(LI
 *      There can only be one such attribute per symbol.
 *  ),
 *  $(LI
 *      The attribute can only be attached to an `extern(C++)` symbol
 *      (`struct`, `class`, `enum`, function, and their templated counterparts).
 *  ),
 *  $(LI
 *      The attribute cannot be applied to C++ namespaces.
 *      This is to prevent confusion with the C++ semantic, which allows it to
 *      be applied to namespaces.
 *  ),
 *  $(LI
 *      The string arguments must only contain valid characters
 *      for C++ name mangling which currently include alphanumerics
 *      and the underscore character.
 *  ),
 * )
 *
 * This UDA is not transitive, and inner scope do not inherit outer scopes'
 * ABI tag. See examples below for how to translate a C++ declaration to D.
 * Also note that entries in this UDA will be automatically sorted
 * alphabetically, hence `gnuAbiTag("c", "b", "a")` will appear as
 * `@gnuAbiTag("a", "b", "c")`.
 *
 * See_Also:
 * $(LINK2 https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.abi-tag, Itanium ABI spec)
 * $(LINK2 https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html, GCC attributes documentation).
 *
 * Examples:
 * ---
 * // ---- foo.cpp
 * struct [[gnu::abi_tag ("tag1", "tag2")]] Tagged1_2
 * {
 *     struct [[gnu::abi_tag ("tag3")]] Tagged3
 *     {
 *         [[gnu::abi_tag ("tag4")]]
 *         int Tagged4 () { return 42; }
 *     }
 * }
 * Tagged1_2 inst1;
 * // ---- foo.d
 * @gnuAbiTag("tag1", "tag2") struct Tagged1_2
 * {
 *     // Notice the repetition
 *     @gnuAbiTag("tag1", "tag2", "tag3") struct Tagged3
 *     {
 *         @gnuAbiTag("tag1", "tag2", "tag3", "tag4") int Tagged4 ();
 *     }
 * }
 * extern __gshared Tagged1_2 inst1;
 * ---
 */
version (UdaGNUAbiTag) struct gnuAbiTag
{
    string[] tags;

    this(string[] tags...)
    {
        this.tags = tags;
    }
}
