/**
 * 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 = UdaOptional;
    version = UdaSelector;
}

version (Posix)
    version = UdaGNUAbiTag;

version (CoreDdoc)
{
    version = UdaGNUAbiTag;
    version = UdaOptional;
    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 make an Objective-C interface method optional.
 *
 * An optional method is a method that does **not** have to be implemented in
 * the class that implements the interface. To safely call an optional method,
 * a runtime check should be performed to make sure the receiver implements the
 * method.
 *
 * This is a special compiler recognized attribute, it has several
 * requirements, which all will be enforced by the compiler:
 *
 * * The attribute can only be attached to methods which have Objective-C
 *   linkage. That is, a method inside an interface declared as `extern (Objective-C)`
 *
 * * It can only be used for methods that are declared inside an interface
 * * It can only be used once in a method declaration
 * * It cannot be attached to a method that is a template
 *
 * Examples:
 * ---
 * import core.attribute : optional, selector;
 *
 * extern (Objective-C):
 *
 * struct objc_selector;
 * alias SEL = objc_selector*;
 *
 * SEL sel_registerName(in char* str);
 *
 * extern class NSObject
 * {
 *     bool respondsToSelector(SEL sel) @selector("respondsToSelector:");
 * }
 *
 * interface Foo
 * {
 *     @optional void foo() @selector("foo");
 *     @optional void bar() @selector("bar");
 * }
 *
 * class Bar : NSObject
 * {
 *     static Bar alloc() @selector("alloc");
 *     Bar init() @selector("init");
 *
 *     void bar() @selector("bar")
 *     {
 *     }
 * }
 *
 * extern (D) void main()
 * {
 *     auto bar = Bar.alloc.init;
 *
 *     if (bar.respondsToSelector(sel_registerName("bar")))
 *         bar.bar();
 * }
 * ---
 */
version (UdaOptional)
    enum optional;

/**
 * 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;
    }
}
