From a02639a44a25005046140d20e8b5ef042dd6a418 Mon Sep 17 00:00:00 2001 From: Jan Jurzitza Date: Sat, 24 Mar 2018 05:24:29 +0100 Subject: [PATCH] auto generate documentation in constants.d from dd files (#430) * make constant.d auto generate from .dd files (fix #428) * added isDeprecated to constants.d * add isDeprecated to expected keywords in traits test * make traits message BARELY FIT into the response buffer because who wants to increase the message buffer anyway? I certainly don't and this seems like a much better solution long term /s * undo apply dfmt on constants.d * use startsWith & canFind with multiple needles * made completion have dynamic ddoc as input * Remove debug pragma msg from constants.d * Move message buffer to heap, increase size to 1MB * made traits & pragma ddoc generation separate tool --- constants-gen/generator.d | 223 ++++++ constants-gen/pragma.dd | 190 +++++ constants-gen/traits.dd | 1127 +++++++++++++++++++++++++++++ constants-gen/update-constants.sh | 4 + src/dcd/common/constants.d | 877 +--------------------- src/dcd/common/constants2.d | 1072 +++++++++++++++++++++++++++ tests/tc_traits/expected.txt | 1 + 7 files changed, 2620 insertions(+), 874 deletions(-) create mode 100755 constants-gen/generator.d create mode 100644 constants-gen/pragma.dd create mode 100644 constants-gen/traits.dd create mode 100755 constants-gen/update-constants.sh create mode 100644 src/dcd/common/constants2.d diff --git a/constants-gen/generator.d b/constants-gen/generator.d new file mode 100755 index 0000000..20d185d --- /dev/null +++ b/constants-gen/generator.d @@ -0,0 +1,223 @@ +#!/usr/bin/env rdmd + +import std.algorithm; +import std.ascii; +import std.file; +import std.regex; +import std.stdio; +import std.string; + +struct ConstantCompletion +{ + string[] identifiers; + string ddoc; +} + +struct SingleConstantCompletion +{ + string identifier; + string ddoc; + + string toString() const + { + return "ConstantCompletion(\"" ~ identifier ~ "\", `" ~ ddoc.replaceAll(ctRegex!"`+", + "` ~ \"$0\" ~ `") ~ "`)"; + } +} + +unittest +{ + ConstantCompletion completion; + completion.ddoc = "'abc``def'"; + assert(completion.toString == q{ConstantCompletion("", `'abc` ~ "``" ~ `def'`)}); +} + +ConstantCompletion[] parsePragmas(string ddoc) +{ + ConstantCompletion[] completions; + + bool foundTerminator; + + ConstantCompletion current; + bool inInlineCode; + bool seekingToFirst = true; + string indent; + + void addCurrent() + { + if (seekingToFirst) + { + current = ConstantCompletion.init; + return; + } + // ret still has `$(DD content)` around it, strip that + if (current.ddoc.startsWith("$(DD")) + { + current.ddoc = current.ddoc["$(DD".length .. $].strip; + if (current.ddoc.endsWith(")")) + current.ddoc = current.ddoc[0 .. $ - 1].stripRight; + } + completions ~= current; + current = ConstantCompletion.init; + } + + foreach (line; ddoc.lineSplitter!(KeepTerminator.yes)) + { + auto strippedLine = line.stripLeft; + if (strippedLine.startsWith("$(SPEC_SUBNAV_PREV_NEXT")) + { + addCurrent(); + // end of macros + foundTerminator = true; + break; + } + else if (strippedLine.startsWith("$(DT $(LNAME2 ")) + { + addCurrent(); + seekingToFirst = false; + indent = line[0 .. $ - strippedLine.length]; + string identifierLine = strippedLine.stripRight; // fully stripped + auto closing = identifierLine.indexOfAny("),"); + if (closing == -1) + closing = identifierLine.length; + current.identifiers = [identifierLine["$(DT $(LNAME2".length .. closing].strip]; + } + else if (!seekingToFirst) + { + if (line.startsWith("---")) // code blocks aren't indented + inInlineCode = !inInlineCode; + + if (inInlineCode) + current.ddoc ~= line; + else + { + if (line.startsWith(indent)) // strip indentation equal to DT (section header) + current.ddoc ~= line[indent.length .. $]; + else + current.ddoc ~= line; + } + } + } + if (!foundTerminator) + throw new Exception("Could not find '$(SPEC_SUBNAV_PREV_NEXT' line in pragma.dd, format of the file has changed and code needs to be adjusted."); + + return completions; +} + +ConstantCompletion[] parseTraits(string ddoc) +{ + ConstantCompletion[] completions; + + bool foundTerminator; + + ConstantCompletion current; + bool inInlineCode; + bool seekingToFirst = true; + string indent; + + void addCurrent() + { + current.ddoc = current.ddoc.strip; + if (seekingToFirst || current == ConstantCompletion.init) + { + current = ConstantCompletion.init; + return; + } + completions ~= current; + current = ConstantCompletion.init; + } + + foreach (line; ddoc.lineSplitter!(KeepTerminator.yes)) + { + if (line.stripLeft.startsWith("$(SPEC_SUBNAV_PREV_NEXT")) + { + addCurrent(); + foundTerminator = true; + break; + } + else if (line.canFind("$(GNAME ")) + { + addCurrent(); + ptrdiff_t i = line.indexOf("$(GNAME "); + while (i != -1) + { + auto closing = line.indexOfAny("),", i); + current.identifiers ~= line[i + "$(GNAME ".length .. closing].strip; + i = line.indexOf("$(GNAME ", closing); + } + seekingToFirst = false; + + if (current.identifiers.length == 1 && current.identifiers[0][0].isUpper) + seekingToFirst = true; // not considering capitalized identifiers traits (TraitsKeyword, TraitsExpression, etc.) + } + else if (!seekingToFirst) + { + if (line.startsWith("---")) + inInlineCode = !inInlineCode; + if (inInlineCode) + current.ddoc ~= line; + else + { + if (!current.ddoc.length) + indent = line[0 .. $ - line.stripLeft.length]; + if (line.startsWith(indent)) + current.ddoc ~= line[indent.length .. $]; + else + current.ddoc ~= line; + } + } + } + if (!foundTerminator) + throw new Exception("Could not find '$(SPEC_SUBNAV_PREV_NEXT' line in traits.dd, format of the file has changed and code needs to be adjusted."); + + return completions; +} + +void main() +{ + immutable pragmaDDoc = readText("pragma.dd"); + immutable traitsDDoc = readText("traits.dd"); + + auto pragmas = parsePragmas(pragmaDDoc); + auto traits = parseTraits(traitsDDoc); + + string part1 = `// +// +// this file is auto generated by constants-gen/generator.d, do not edit manually. +// +// + +module dcd.common.constants2; + +import dcd.common.constants : ConstantCompletion; + +/** + * Pragma arguments + */ +immutable ConstantCompletion[] pragmas = [ + // generated from pragma.dd`; + string part2 = `]; + +/** + * Traits arguments + */ +immutable ConstantCompletion[] traits = [ + // generated from traits.dd`; + + string part3 = "];"; + + auto file = File("../src/dcd/common/constants2.d", "w"); + file.writeln(part1); + foreach (pragma_; pragmas.sorted) + file.writeln('\t', pragma_, ","); + file.writeln(part2); + foreach (trait; traits.sorted) + file.writeln('\t', trait, ","); + file.writeln(part3); +} + +auto sorted(T)(T range) +{ + return range.map!(a => a.identifiers.map!(identifier => SingleConstantCompletion(identifier, + a.ddoc))).join.sort!"a.identifier < b.identifier"; +} diff --git a/constants-gen/pragma.dd b/constants-gen/pragma.dd new file mode 100644 index 0000000..f90dd74 --- /dev/null +++ b/constants-gen/pragma.dd @@ -0,0 +1,190 @@ +Ddoc + +$(SPEC_S Pragmas, + +$(HEADERNAV_TOC) + +$(GRAMMAR +$(GNAME Pragma): + $(D pragma) $(D $(LPAREN)) $(I Identifier) $(D $(RPAREN)) + $(D pragma) $(D $(LPAREN)) $(I Identifier) $(D ,) $(GLINK2 expression, ArgumentList) $(D $(RPAREN)) +) + + + $(P Pragmas are a way to pass special information to the compiler + and to add vendor specific extensions to D. + Pragmas can be used by themselves terminated with a $(SINGLEQUOTE ;), + they can influence a statement, a block of statements, a declaration, or + a block of declarations. + ) + + $(P Pragmas can appear as either declarations, + $(I Pragma) $(GLINK2 attribute, DeclarationBlock), + or as statements, + $(GLINK2 statement, PragmaStatement). + ) + +----------------- +pragma(ident); // just by itself + +pragma(ident) declaration; // influence one declaration + +pragma(ident): // influence subsequent declarations + declaration; + declaration; + +pragma(ident) // influence block of declarations +{ + declaration; + declaration; +} + +pragma(ident) statement; // influence one statement + +pragma(ident) // influence block of statements +{ + statement; + statement; +} +----------------- + + $(P The kind of pragma it is determined by the $(I Identifier). + $(I ExpressionList) is a comma-separated list of + $(ASSIGNEXPRESSION)s. The $(ASSIGNEXPRESSION)s must be + parsable as expressions, but what they mean semantically + is up to the individual pragma semantics. + ) + +$(H2 $(LEGACY_LNAME2 Predefined-Pragmas, predefined-pragmas, Predefined Pragmas)) + +$(P All implementations must support these, even if by just ignoring them:) + +$(UL + $(LI $(LINK2 #inline, pragma inline)) + $(LI $(LINK2 #lib, pragma lib)) + $(LI $(LINK2 #mangle, pragma mangle)) + $(LI $(LINK2 #msg, pragma msg)) + $(LI $(LINK2 #startaddress, pragma startaddress)) +) + + $(DL + + $(DT $(LNAME2 inline, $(D inline))) + $(DD $(P Affects whether functions are inlined or not. If at the declaration level, it + affects the functions declared in the block it controls. If inside a function, it + affects the function it is enclosed by. If there are multiple pragma inlines in a function, + the lexically last one takes effect.) + + $(P It takes three forms:) + $(OL + $(LI +--- +pragma(inline) +--- + Sets the behavior to match the default behavior set by the compiler switch + $(DDSUBLINK dmd, switch-inline, $(TT -inline)). + ) + $(LI +--- +pragma(inline, false) +--- + Functions are never inlined. + ) + $(LI +--- +pragma(inline, true) +--- + If a function cannot be inlined with the $(DDSUBLINK dmd, switch-inline, $(TT -inline)) + switch, an error message is issued. This is expected to be improved in the future to causing + functions to always be inlined regardless of compiler switch settings. Whether a compiler can + inline a particular function or not is implementation defined. + ) + ) +--- +pragma(inline): +int foo(int x) // foo() is never inlined +{ + pragma(inline, true); + ++x; + pragma(inline, false); // supercedes the others + return x + 3; +} +--- + ) + + + $(DT $(LNAME2 lib, $(D lib))) + $(DD Inserts a directive in the object file to link in the library + specified by the $(ASSIGNEXPRESSION). + The $(ASSIGNEXPRESSION)s must be a string literal: +----------------- +pragma(lib, "foo.lib"); +----------------- + ) + + + $(DT $(LNAME2 mangle, $(D mangle))) + $(DD Overrides the default mangling for a symbol. It's only effective + when the symbol is a function declaration or a variable declaration. + For example this allows linking to a symbol which is a D keyword, which would normally + be disallowed as a symbol name: +----------------- +pragma(mangle, "body") +extern(C) void body_func(); +----------------- + ) + + + $(DT $(LNAME2 msg, $(D msg))) + $(DD Constructs a message from the arguments and prints to the standard error stream while compiling: +----------------- +pragma(msg, "compiling...", 1, 1.0); +----------------- + ) + + + $(DT $(LNAME2 startaddress, $(D startaddress))) + $(DD Puts a directive into the object file saying that the + function specified in the first argument will be the + start address for the program: +----------------- +void foo() { ... } +pragma(startaddress, foo); +----------------- + This is not normally used for application level programming, + but is for specialized systems work. + For applications code, the start address is taken care of + by the runtime library. + ) + ) + +$(H2 $(LNAME2 vendor_specific_pragmas, Vendor Specific Pragmas)) + + $(P Vendor specific pragma $(I Identifier)s can be defined if they + are prefixed by the vendor's trademarked name, in a similar manner + to version identifiers: + ) + +----------------- +pragma(DigitalMars_funky_extension) { ... } +----------------- + + $(P Compilers must diagnose an error for unrecognized $(I Pragma)s, + even if they are vendor specific ones. This implies that vendor + specific pragmas should be wrapped in version statements: + ) + +----------------- +version (DigitalMars) +{ + pragma(DigitalMars_funky_extension) + { ... } +} +----------------- + +$(SPEC_SUBNAV_PREV_NEXT attribute, Attributes, expression, Expressions) +) + +Macros: + CHAPTER=9 + TITLE=Pragmas diff --git a/constants-gen/traits.dd b/constants-gen/traits.dd new file mode 100644 index 0000000..6357f1b --- /dev/null +++ b/constants-gen/traits.dd @@ -0,0 +1,1127 @@ +Ddoc + +$(SPEC_S Traits, + +$(HEADERNAV_TOC) + + $(P Traits are extensions to the language to enable + programs, at compile time, to get at information + internal to the compiler. This is also known as + compile time reflection. + It is done as a special, easily extended syntax (similar + to Pragmas) so that new capabilities can be added + as required. + ) + +$(GRAMMAR +$(GNAME TraitsExpression): + $(D __traits) $(D $(LPAREN)) $(GLINK TraitsKeyword) $(D ,) $(GLINK TraitsArguments) $(D $(RPAREN)) + +$(GNAME TraitsKeyword): + $(GBLINK isAbstractClass) + $(GBLINK isArithmetic) + $(GBLINK isAssociativeArray) + $(GBLINK isFinalClass) + $(GBLINK isPOD) + $(GBLINK isNested) + $(GBLINK isFuture) + $(GBLINK isDeprecated) + $(GBLINK isFloating) + $(GBLINK isIntegral) + $(GBLINK isScalar) + $(GBLINK isStaticArray) + $(GBLINK isUnsigned) + $(GBLINK isDisabled) + $(GBLINK isVirtualFunction) + $(GBLINK isVirtualMethod) + $(GBLINK isAbstractFunction) + $(GBLINK isFinalFunction) + $(GBLINK isStaticFunction) + $(GBLINK isOverrideFunction) + $(GBLINK isTemplate) + $(GBLINK isRef) + $(GBLINK isOut) + $(GBLINK isLazy) + $(GBLINK hasMember) + $(GBLINK identifier) + $(GBLINK getAliasThis) + $(GBLINK getAttributes) + $(GBLINK getFunctionAttributes) + $(GBLINK getFunctionVariadicStyle) + $(GBLINK getLinkage) + $(GBLINK getMember) + $(GBLINK getOverloads) + $(GBLINK getParameterStorageClasses) + $(GBLINK getPointerBitmap) + $(GBLINK getProtection) + $(GBLINK getVirtualFunctions) + $(GBLINK getVirtualMethods) + $(GBLINK getUnitTests) + $(GBLINK parent) + $(GBLINK classInstanceSize) + $(GBLINK getVirtualIndex) + $(GBLINK allMembers) + $(GBLINK derivedMembers) + $(GBLINK isSame) + $(GBLINK compiles) + +$(GNAME TraitsArguments): + $(GLINK TraitsArgument) + $(GLINK TraitsArgument) $(D ,) $(I TraitsArguments) + +$(GNAME TraitsArgument): + $(GLINK2 expression, AssignExpression) + $(GLINK2 declaration, Type) +) + +$(P Additionally special keywords are provided for debugging purposes:) + +$(GRAMMAR +$(GNAME SpecialKeyword): + $(D $(RELATIVE_LINK2 specialkeywords, __FILE__)) + $(D $(RELATIVE_LINK2 specialkeywords, __FILE_FULL_PATH__)) + $(D $(RELATIVE_LINK2 specialkeywords, __MODULE__)) + $(D $(RELATIVE_LINK2 specialkeywords, __LINE__)) + $(D $(RELATIVE_LINK2 specialkeywords, __FUNCTION__)) + $(D $(RELATIVE_LINK2 specialkeywords, __PRETTY_FUNCTION__)) +) + +$(H2 $(GNAME isArithmetic)) + + $(P If the arguments are all either types that are arithmetic types, + or expressions that are typed as arithmetic types, then $(D true) + is returned. + Otherwise, $(D false) is returned. + If there are no arguments, $(D false) is returned.) + +--- +import std.stdio; + +void main() +{ + int i; + writeln(__traits(isArithmetic, int)); + writeln(__traits(isArithmetic, i, i+1, int)); + writeln(__traits(isArithmetic)); + writeln(__traits(isArithmetic, int*)); +} +--- + + Prints: + +$(CONSOLE +true +true +false +false +) + +$(H2 $(GNAME isFloating)) + + $(P Works like $(D isArithmetic), except it's for floating + point types (including imaginary and complex types).) + +$(H2 $(GNAME isIntegral)) + + $(P Works like $(D isArithmetic), except it's for integral + types (including character types).) + +$(H2 $(GNAME isScalar)) + + $(P Works like $(D isArithmetic), except it's for scalar + types.) + +$(H2 $(GNAME isUnsigned)) + + $(P Works like $(D isArithmetic), except it's for unsigned + types.) + +$(H2 $(GNAME isStaticArray)) + + $(P Works like $(D isArithmetic), except it's for static array + types.) + +$(H2 $(GNAME isAssociativeArray)) + + $(P Works like $(D isArithmetic), except it's for associative array + types.) + +$(H2 $(GNAME isAbstractClass)) + + $(P If the arguments are all either types that are abstract classes, + or expressions that are typed as abstract classes, then $(D true) + is returned. + Otherwise, $(D false) is returned. + If there are no arguments, $(D false) is returned.) + +--- +import std.stdio; + +abstract class C { int foo(); } + +void main() +{ + C c; + writeln(__traits(isAbstractClass, C)); + writeln(__traits(isAbstractClass, c, C)); + writeln(__traits(isAbstractClass)); + writeln(__traits(isAbstractClass, int*)); +} +--- + + Prints: + +$(CONSOLE +true +true +false +false +) + +$(H2 $(GNAME isFinalClass)) + + $(P Works like $(D isAbstractClass), except it's for final + classes.) + +$(H2 $(GNAME isPOD)) + + $(P Takes one argument, which must be a type. It returns + $(D true) if the type is a $(DDSUBLINK glossary, pod, POD) type, otherwise $(D false).) + +$(H2 $(GNAME isNested)) + + $(P Takes one argument. + It returns $(D true) if the argument is a nested type which internally + stores a context pointer, otherwise it returns $(D false). + Nested types can be $(DDSUBLINK spec/class, nested, classes), + $(DDSUBLINK spec/struct, nested, structs), and + $(DDSUBLINK spec/function, variadicnested, functions).) + +$(H2 $(GNAME isFuture)) + + $(P Takes one argument. It returns `true` if the argument is a symbol + marked with the `@future` keyword, otherwise `false`. Currently, only + functions and variable declarations have support for the `@future` keyword.) + +$(H2 $(GNAME isDeprecated)) + + $(P Takes one argument. It returns `true` if the argument is a symbol + marked with the `deprecated` keyword, otherwise `false`.) + +$(H2 $(GNAME isDisabled)) + + $(P Takes one argument and returns `true` if it's a function declaration + marked with `@disable`.) + +--- +struct Foo +{ + @disable void foo(); + void bar(){} +} + +static assert(__traits(isDisabled, Foo.foo)); +static assert(!__traits(isDisabled, Foo.bar)); +--- + + $(P For any other declaration even if `@disable` is a syntactically valid + attribute `false` is returned because the annotation has no effect.) + +--- +@disable struct Bar{} + +static assert(!__traits(isDisabled, Bar)); +--- + +$(H2 $(GNAME isVirtualFunction)) + + $(P The same as $(GLINK isVirtualMethod), except + that final functions that don't override anything return true. + ) + +$(H2 $(GNAME isVirtualMethod)) + + $(P Takes one argument. If that argument is a virtual function, + $(D true) is returned, otherwise $(D false). + Final functions that don't override anything return false. + ) + +--- +import std.stdio; + +struct S +{ + void bar() { } +} + +class C +{ + void bar() { } +} + +void main() +{ + writeln(__traits(isVirtualMethod, C.bar)); // true + writeln(__traits(isVirtualMethod, S.bar)); // false +} +--- + +$(H2 $(GNAME isAbstractFunction)) + + $(P Takes one argument. If that argument is an abstract function, + $(D true) is returned, otherwise $(D false). + ) + +--- +import std.stdio; + +struct S +{ + void bar() { } +} + +class C +{ + void bar() { } +} + +class AC +{ + abstract void foo(); +} + +void main() +{ + writeln(__traits(isAbstractFunction, C.bar)); // false + writeln(__traits(isAbstractFunction, S.bar)); // false + writeln(__traits(isAbstractFunction, AC.foo)); // true +} +--- + +$(H2 $(GNAME isFinalFunction)) + + $(P Takes one argument. If that argument is a final function, + $(D true) is returned, otherwise $(D false). + ) + +--- +import std.stdio; + +struct S +{ + void bar() { } +} + +class C +{ + void bar() { } + final void foo(); +} + +final class FC +{ + void foo(); +} + +void main() +{ + writeln(__traits(isFinalFunction, C.bar)); // false + writeln(__traits(isFinalFunction, S.bar)); // false + writeln(__traits(isFinalFunction, C.foo)); // true + writeln(__traits(isFinalFunction, FC.foo)); // true +} +--- + +$(H2 $(GNAME isOverrideFunction)) + + $(P Takes one argument. If that argument is a function marked with + $(D_KEYWORD override), $(D true) is returned, otherwise $(D false). + ) + +--- +import std.stdio; + +class Base +{ + void foo() { } +} + +class Foo : Base +{ + override void foo() { } + void bar() { } +} + +void main() +{ + writeln(__traits(isOverrideFunction, Base.foo)); // false + writeln(__traits(isOverrideFunction, Foo.foo)); // true + writeln(__traits(isOverrideFunction, Foo.bar)); // false +} +--- + +$(H2 $(GNAME isStaticFunction)) + + $(P Takes one argument. If that argument is a static function, + meaning it has no context pointer, + $(D true) is returned, otherwise $(D false). + ) + + +$(H2 $(GNAME isRef), $(GNAME isOut), $(GNAME isLazy)) + + $(P Takes one argument. If that argument is a declaration, + $(D true) is returned if it is $(D_KEYWORD ref), $(D_KEYWORD out), + or $(D_KEYWORD lazy), otherwise $(D false). + ) + +--- +void fooref(ref int x) +{ + static assert(__traits(isRef, x)); + static assert(!__traits(isOut, x)); + static assert(!__traits(isLazy, x)); +} + +void fooout(out int x) +{ + static assert(!__traits(isRef, x)); + static assert(__traits(isOut, x)); + static assert(!__traits(isLazy, x)); +} + +void foolazy(lazy int x) +{ + static assert(!__traits(isRef, x)); + static assert(!__traits(isOut, x)); + static assert(__traits(isLazy, x)); +} +--- + +$(H2 $(GNAME isTemplate)) + + $(P Takes one argument. If that argument is a template then $(D true) is returned, + otherwise $(D false). + ) + +--- +void foo(T)(){} +static assert(__traits(isTemplate,foo)); +static assert(!__traits(isTemplate,foo!int())); +static assert(!__traits(isTemplate,"string")); +--- + +$(H2 $(GNAME hasMember)) + + $(P The first argument is a type that has members, or + is an expression of a type that has members. + The second argument is a string. + If the string is a valid property of the type, + $(D true) is returned, otherwise $(D false). + ) + +--- +import std.stdio; + +struct S +{ + int m; +} + +void main() +{ + S s; + + writeln(__traits(hasMember, S, "m")); // true + writeln(__traits(hasMember, s, "m")); // true + writeln(__traits(hasMember, S, "y")); // false + writeln(__traits(hasMember, int, "sizeof")); // true +} +--- + +$(H2 $(GNAME identifier)) + + $(P Takes one argument, a symbol. Returns the identifier + for that symbol as a string literal. + ) +--- +import std.stdio; + +int var = 123; +pragma(msg, typeof(var)); // int +pragma(msg, typeof(__traits(identifier, var))); // string +writeln(var); // 123 +writeln(__traits(identifier, var)); // "var" +--- + +$(H2 $(GNAME getAliasThis)) + + $(P Takes one argument, a symbol of aggregate type. + If the given aggregate type has $(D alias this), returns a list of + $(D alias this) names, by a tuple of $(D string)s. + Otherwise returns an empty tuple. + ) + +$(SECTION2 $(GNAME getAttributes), + $(P + Takes one argument, a symbol. Returns a tuple of all attached user-defined attributes. + If no UDA's exist it will return an empty tuple. + ) + + $(P + For more information, see: $(DDSUBLINK spec/attribute, uda, User-Defined Attributes) + ) + +--- +@(3) int a; +@("string", 7) int b; + +enum Foo; +@Foo int c; + +pragma(msg, __traits(getAttributes, a)); +pragma(msg, __traits(getAttributes, b)); +pragma(msg, __traits(getAttributes, c)); +--- + + Prints: + +$(CONSOLE +tuple(3) +tuple("string", 7) +tuple((Foo)) +) +) + +$(SECTION2 $(GNAME getFunctionVariadicStyle), + $(P + Takes one argument which must either be a function symbol, or a type + that is a function, delegate or a function pointer. + It returns a string identifying the kind of + $(LINK2 function.html#variadic, variadic arguments) that are supported. + ) + + $(TABLE2 getFunctionVariadicStyle, + $(THEAD result, kind, access, example) + $(TROW $(D "none"), not a variadic function, $(NBSP), $(D void foo();)) + $(TROW $(D "argptr"), D style variadic function, $(D _argptr) and $(D _arguments), $(D void bar(...))) + $(TROW $(D "stdarg"), C style variadic function, $(LINK2 $(ROOT_DIR)phobos/core_stdc_stdarg.html, $(D core.stdc.stdarg)), $(D extern (C) void abc(int, ...))) + $(TROW $(D "typesafe"), typesafe variadic function, array on stack, $(D void def(int[] ...))) + ) + +--- +import core.stdc.stdarg; + +void novar() {} +extern(C) void cstyle(int, ...) {} +extern(C++) void cppstyle(int, ...) {} +void dstyle(...) {} +void typesafe(int[]...) {} + +static assert(__traits(getFunctionVariadicStyle, novar) == "none"); +static assert(__traits(getFunctionVariadicStyle, cstyle) == "stdarg"); +static assert(__traits(getFunctionVariadicStyle, cppstyle) == "stdarg"); +static assert(__traits(getFunctionVariadicStyle, dstyle) == "argptr"); +static assert(__traits(getFunctionVariadicStyle, typesafe) == "typesafe"); + +static assert(__traits(getFunctionVariadicStyle, (int[] a...) {}) == "typesafe"); +static assert(__traits(getFunctionVariadicStyle, typeof(cstyle)) == "stdarg"); +--- +) + +$(SECTION2 $(GNAME getFunctionAttributes), + $(P + Takes one argument which must either be a function symbol, function literal, + or a function pointer. It returns a string tuple of all the attributes of + that function $(B excluding) any user-defined attributes (UDAs can be + retrieved with the $(RELATIVE_LINK2 get-attributes, getAttributes) trait). + If no attributes exist it will return an empty tuple. + ) + + + $(B Note:) The order of the attributes in the returned tuple is + implementation-defined and should not be relied upon. + + $(P + A list of currently supported attributes are:) + $(UL $(LI $(D pure), $(D nothrow), $(D @nogc), $(D @property), $(D @system), $(D @trusted), $(D @safe), and $(D ref))) + $(B Note:) $(D ref) is a function attribute even though it applies to the return type. + + $(P + Additionally the following attributes are only valid for non-static member functions:) + $(UL $(LI $(D const), $(D immutable), $(D inout), $(D shared))) + + For example: + +--- +int sum(int x, int y) pure nothrow { return x + y; } + +// prints ("pure", "nothrow", "@system") +pragma(msg, __traits(getFunctionAttributes, sum)); + +struct S +{ + void test() const @system { } +} + +// prints ("const", "@system") +pragma(msg, __traits(getFunctionAttributes, S.test)); +--- + + $(P Note that some attributes can be inferred. For example:) + +--- +// prints ("pure", "nothrow", "@nogc", "@trusted") +pragma(msg, __traits(getFunctionAttributes, (int x) @trusted { return x * 2; })); +--- +) + +$(H2 $(GNAME getLinkage)) + + $(P Takes one argument, which is a declaration symbol, or the type of a function, + delegate, or pointer to function. + Returns a string representing the $(LINK2 attribute.html#LinkageAttribute, LinkageAttribute) + of the declaration. + The string is one of: + ) + + $(UL + $(LI $(D "D")) + $(LI $(D "C")) + $(LI $(D "C++")) + $(LI $(D "Windows")) + $(LI $(D "Pascal")) + $(LI $(D "Objective-C")) + $(LI $(D "System")) + ) + +--- +extern (C) int fooc(); +alias aliasc = fooc; + +static assert(__traits(getLinkage, fooc) == "C"); +static assert(__traits(getLinkage, aliasc) == "C"); +--- + +$(H2 $(GNAME getMember)) + + $(P Takes two arguments, the second must be a string. + The result is an expression formed from the first + argument, followed by a $(SINGLEQUOTE .), followed by the second + argument as an identifier. + ) + +--- +import std.stdio; + +struct S +{ + int mx; + static int my; +} + +void main() +{ + S s; + + __traits(getMember, s, "mx") = 1; // same as s.mx=1; + writeln(__traits(getMember, s, "m" ~ "x")); // 1 + + __traits(getMember, S, "mx") = 1; // error, no this for S.mx + __traits(getMember, S, "my") = 2; // ok +} +--- + +$(H2 $(GNAME getOverloads)) + + $(P The first argument is an aggregate (e.g. struct/class/module). + The second argument is a string that matches the name of + one of the functions in that aggregate. + The result is a tuple of all the overloads of that function. + ) + +--- +import std.stdio; + +class D +{ + this() { } + ~this() { } + void foo() { } + int foo(int) { return 2; } +} + +void main() +{ + D d = new D(); + + foreach (t; __traits(getOverloads, D, "foo")) + writeln(typeid(typeof(t))); + + alias b = typeof(__traits(getOverloads, D, "foo")); + foreach (t; b) + writeln(typeid(t)); + + auto i = __traits(getOverloads, d, "foo")[1](1); + writeln(i); +} +--- + + Prints: + +$(CONSOLE +void() +int() +void() +int() +2 +) + +$(H2 $(GNAME getParameterStorageClasses)) + + $(P + Takes two arguments. + The first must either be a function symbol, or a type + that is a function, delegate or a function pointer. + The second is an integer identifying which parameter, where the first parameter is + 0. + It returns a tuple of strings representing the storage classes of that parameter. + ) + +--- +ref int foo(return ref const int* p, scope int* a, out int b, lazy int c); + +static assert(__traits(getParameterStorageClasses, foo, 0)[0] == "return"); +static assert(__traits(getParameterStorageClasses, foo, 0)[1] == "ref"); + +static assert(__traits(getParameterStorageClasses, foo, 1)[0] == "scope"); +static assert(__traits(getParameterStorageClasses, foo, 2)[0] == "out"); +static assert(__traits(getParameterStorageClasses, typeof(&foo), 3)[0] == "lazy"); +--- + +$(H2 $(GNAME getPointerBitmap)) + + $(P The argument is a type. + The result is an array of $(D size_t) describing the memory used by an instance of the given type. + ) + $(P The first element of the array is the size of the type (for classes it is + the $(GBLINK classInstanceSize)).) + $(P The following elements describe the locations of GC managed pointers within the + memory occupied by an instance of the type. + For type T, there are $(D T.sizeof / size_t.sizeof) possible pointers represented + by the bits of the array values.) + $(P This array can be used by a precise GC to avoid false pointers.) +--- +class C +{ + // implicit virtual function table pointer not marked + // implicit monitor field not marked, usually managed manually + C next; + size_t sz; + void* p; + void function () fn; // not a GC managed pointer +} + +struct S +{ + size_t val1; + void* p; + C c; + byte[] arr; // { length, ptr } + void delegate () dg; // { context, func } +} + +static assert (__traits(getPointerBitmap, C) == [6*size_t.sizeof, 0b010100]); +static assert (__traits(getPointerBitmap, S) == [7*size_t.sizeof, 0b0110110]); +--- + + +$(H2 $(GNAME getProtection)) + + $(P The argument is a symbol. + The result is a string giving its protection level: "public", "private", "protected", "export", or "package". + ) + +--- +import std.stdio; + +class D +{ + export void foo() { } + public int bar; +} + +void main() +{ + D d = new D(); + + auto i = __traits(getProtection, d.foo); + writeln(i); + + auto j = __traits(getProtection, d.bar); + writeln(j); +} +--- + + Prints: + +$(CONSOLE +export +public +) + + +$(H2 $(GNAME getVirtualFunctions)) + + $(P The same as $(GLINK getVirtualMethods), except that + final functions that do not override anything are included. + ) + +$(H2 $(GNAME getVirtualMethods)) + + $(P The first argument is a class type or an expression of + class type. + The second argument is a string that matches the name of + one of the functions of that class. + The result is a tuple of the virtual overloads of that function. + It does not include final functions that do not override anything. + ) + +--- +import std.stdio; + +class D +{ + this() { } + ~this() { } + void foo() { } + int foo(int) { return 2; } +} + +void main() +{ + D d = new D(); + + foreach (t; __traits(getVirtualMethods, D, "foo")) + writeln(typeid(typeof(t))); + + alias b = typeof(__traits(getVirtualMethods, D, "foo")); + foreach (t; b) + writeln(typeid(t)); + + auto i = __traits(getVirtualMethods, d, "foo")[1](1); + writeln(i); +} +--- + + Prints: + +$(CONSOLE +void() +int() +void() +int() +2 +) + +$(H2 $(GNAME getUnitTests)) + + $(P + Takes one argument, a symbol of an aggregate (e.g. struct/class/module). + The result is a tuple of all the unit test functions of that aggregate. + The functions returned are like normal nested static functions, + $(DDSUBLINK glossary, ctfe, CTFE) will work and + $(DDSUBLINK spec/attribute, uda, UDA's) will be accessible. + ) + + $(H3 Note:) + + $(P + The -unittest flag needs to be passed to the compiler. If the flag + is not passed $(CODE __traits(getUnitTests)) will always return an + empty tuple. + ) + +--- +module foo; + +import core.runtime; +import std.stdio; + +struct name { string name; } + +class Foo +{ + unittest + { + writeln("foo.Foo.unittest"); + } +} + +@name("foo") unittest +{ + writeln("foo.unittest"); +} + +template Tuple (T...) +{ + alias Tuple = T; +} + +shared static this() +{ + // Override the default unit test runner to do nothing. After that, "main" will + // be called. + Runtime.moduleUnitTester = { return true; }; +} + +void main() +{ + writeln("start main"); + + alias tests = Tuple!(__traits(getUnitTests, foo)); + static assert(tests.length == 1); + + alias attributes = Tuple!(__traits(getAttributes, tests[0])); + static assert(attributes.length == 1); + + foreach (test; tests) + test(); + + foreach (test; __traits(getUnitTests, Foo)) + test(); +} +--- + + $(P By default, the above will print:) + +$(CONSOLE +start main +foo.unittest +foo.Foo.unittest +) + +$(H2 $(GNAME parent)) + + $(P Takes a single argument which must evaluate to a symbol. + The result is the symbol that is the parent of it. + ) + +$(H2 $(GNAME classInstanceSize)) + + $(P Takes a single argument, which must evaluate to either + a class type or an expression of class type. + The result + is of type $(CODE size_t), and the value is the number of + bytes in the runtime instance of the class type. + It is based on the static type of a class, not the + polymorphic type. + ) + +$(H2 $(GNAME getVirtualIndex)) + + $(P Takes a single argument which must evaluate to a function. + The result is a $(CODE ptrdiff_t) containing the index + of that function within the vtable of the parent type. + If the function passed in is final and does not override + a virtual function, $(D -1) is returned instead. + ) + +$(H2 $(GNAME allMembers)) + + $(P Takes a single argument, which must evaluate to either + a type or an expression of type. + A tuple of string literals is returned, each of which + is the name of a member of that type combined with all + of the members of the base classes (if the type is a class). + No name is repeated. + Builtin properties are not included. + ) + +--- +import std.stdio; + +class D +{ + this() { } + ~this() { } + void foo() { } + int foo(int) { return 0; } +} + +void main() +{ + auto b = [ __traits(allMembers, D) ]; + writeln(b); + // ["__ctor", "__dtor", "foo", "toString", "toHash", "opCmp", "opEquals", + // "Monitor", "factory"] +} +--- + + $(P The order in which the strings appear in the result + is not defined.) + +$(H2 $(GNAME derivedMembers)) + + $(P Takes a single argument, which must evaluate to either + a type or an expression of type. + A tuple of string literals is returned, each of which + is the name of a member of that type. + No name is repeated. + Base class member names are not included. + Builtin properties are not included. + ) + +--- +import std.stdio; + +class D +{ + this() { } + ~this() { } + void foo() { } + int foo(int) { return 0; } +} + +void main() +{ + auto a = [__traits(derivedMembers, D)]; + writeln(a); // ["__ctor", "__dtor", "foo"] +} +--- + + $(P The order in which the strings appear in the result + is not defined.) + +$(H2 $(GNAME isSame)) + + $(P Takes two arguments and returns bool $(D true) if they + are the same symbol, $(D false) if not.) + +--- +import std.stdio; + +struct S { } + +int foo(); +int bar(); + +void main() +{ + writeln(__traits(isSame, foo, foo)); // true + writeln(__traits(isSame, foo, bar)); // false + writeln(__traits(isSame, foo, S)); // false + writeln(__traits(isSame, S, S)); // true + writeln(__traits(isSame, std, S)); // false + writeln(__traits(isSame, std, std)); // true +} +--- + + $(P If the two arguments are expressions made up of literals + or enums that evaluate to the same value, true is returned.) + +$(H2 $(GNAME compiles)) + + $(P Returns a bool $(D true) if all of the arguments + compile (are semantically correct). + The arguments can be symbols, types, or expressions that + are syntactically correct. + The arguments cannot be statements or declarations. + ) + + $(P If there are no arguments, the result is $(D false).) + +--- +import std.stdio; + +struct S +{ + static int s1; + int s2; +} + +int foo(); +int bar(); + +void main() +{ + writeln(__traits(compiles)); // false + writeln(__traits(compiles, foo)); // true + writeln(__traits(compiles, foo + 1)); // true + writeln(__traits(compiles, &foo + 1)); // false + writeln(__traits(compiles, typeof(1))); // true + writeln(__traits(compiles, S.s1)); // true + writeln(__traits(compiles, S.s3)); // false + writeln(__traits(compiles, 1,2,3,int,long,std)); // true + writeln(__traits(compiles, 3[1])); // false + writeln(__traits(compiles, 1,2,3,int,long,3[1])); // false +} +--- + + $(P This is useful for:) + + $(UL + $(LI Giving better error messages inside generic code than + the sometimes hard to follow compiler ones.) + $(LI Doing a finer grained specialization than template + partial specialization allows for.) + ) + + +$(H2 $(LNAME2 specialkeywords, Special Keywords)) + + $(P $(CODE __FILE__) and $(CODE __LINE__) expand to the source + file name and line number at the point of instantiation. The path of + the source file is left up to the compiler. ) + + $(P $(CODE __FILE_FULL_PATH__) expands to the absolute source + file name at the point of instantiation.) + + $(P $(CODE __MODULE__) expands to the module name at the point of + instantiation.) + + $(P $(CODE __FUNCTION__) expands to the fully qualified name of the + function at the point of instantiation.) + + $(P $(CODE __PRETTY_FUNCTION__) is similar to $(CODE __FUNCTION__), + but also expands the function return type, its parameter types, + and its attributes.) + + $(P Example usage:) + +----- +module test; +import std.stdio; + +void test(string file = __FILE__, size_t line = __LINE__, + string mod = __MODULE__, string func = __FUNCTION__, + string pretty = __PRETTY_FUNCTION__, + string fileFullPath = __FILE_FULL_PATH__) +{ + writefln("file: '%s', line: '%s', module: '%s',\nfunction: '%s', " ~ + "pretty function: '%s',\nfile full path: '%s'", + file, line, mod, func, pretty, fileFullPath); +} + +int main(string[] args) +{ + test(); + return 0; +} +----- + + $(P Assuming the file was at /example/test.d, this will output:) + +$(CONSOLE +file: 'test.d', line: '13', module: 'test', +function: 'test.main', pretty function: 'int test.main(string[] args)', +file full path: '/example/test.d' +) + +$(SPEC_SUBNAV_PREV_NEXT version, Conditional Compilation, errors, Error Handling) +) + +Macros: + CHAPTER=25 + TITLE=Traits + GBLINK=$(RELATIVE_LINK2 $0, $(D $0)) diff --git a/constants-gen/update-constants.sh b/constants-gen/update-constants.sh new file mode 100755 index 0000000..d2caf75 --- /dev/null +++ b/constants-gen/update-constants.sh @@ -0,0 +1,4 @@ +#!/bin/sh +wget https://raw.githubusercontent.com/dlang/dlang.org/master/spec/pragma.dd -O pragma.dd +wget https://raw.githubusercontent.com/dlang/dlang.org/master/spec/traits.dd -O traits.dd +rdmd generator.d diff --git a/src/dcd/common/constants.d b/src/dcd/common/constants.d index 446f164..0d01c0f 100644 --- a/src/dcd/common/constants.d +++ b/src/dcd/common/constants.d @@ -18,6 +18,8 @@ module dcd.common.constants; +public import dcd.common.constants2; + // The lists in this module should be kept sorted. struct ConstantCompletion @@ -26,87 +28,12 @@ struct ConstantCompletion string ddoc; } -/** - * Pragma arguments - */ -immutable ConstantCompletion[] pragmas = [ - // docs from https://github.com/dlang/dlang.org/blob/master/spec/pragma.dd - ConstantCompletion("inline", `$(P Affects whether functions are inlined or not. If at the declaration level, it -affects the functions declared in the block it controls. If inside a function, it -affects the function it is enclosed by. If there are multiple pragma inlines in a function, -the lexically last one takes effect.) - -$(P It takes three forms:) -$(OL - $(LI ---- -pragma(inline) ---- - Sets the behavior to match the default behavior set by the compiler switch - $(DDSUBLINK dmd, switch-inline, $(TT -inline)). - ) - $(LI ---- -pragma(inline, false) ---- - Functions are never inlined. - ) - $(LI ---- -pragma(inline, true) ---- - If a function cannot be inlined with the $(DDSUBLINK dmd, switch-inline, $(TT -inline)) - switch, an error message is issued. This is expected to be improved in the future to causing - functions to always be inlined regardless of compiler switch settings. Whether a compiler can - inline a particular function or not is implementation defined. - ) -) ---- -pragma(inline): -int foo(int x) // foo() is never inlined -{ - pragma(inline, true); - ++x; - pragma(inline, false); // supercedes the others - return x + 3; -} ----`), - ConstantCompletion("lib", `Inserts a directive in the object file to link in the library -specified by the $(ASSIGNEXPRESSION). -The $(ASSIGNEXPRESSION)s must be a string literal: ------------------ -pragma(lib, "foo.lib"); ------------------`), - ConstantCompletion("mangle", `Overrides the default mangling for a symbol. It's only effective -when the symbol is a function declaration or a variable declaration. -For example this allows linking to a symbol which is a D keyword, which would normally -be disallowed as a symbol name: ------------------ -pragma(mangle, "body") -extern(C) void body_func(); ------------------`), - ConstantCompletion("msg", `Constructs a message from the arguments and prints to the standard error stream while compiling: ------------------ -pragma(msg, "compiling...", 1, 1.0); ------------------`), - ConstantCompletion("startaddress", `Puts a directive into the object file saying that the -function specified in the first argument will be the -start address for the program: ------------------ -void foo() { ... } -pragma(startaddress, foo); ------------------ -This is not normally used for application level programming, -but is for specialized systems work. -For applications code, the start address is taken care of -by the runtime library.`) -]; - /** * Linkage types */ immutable ConstantCompletion[] linkages = [ // https://dlang.org/spec/attribute.html#linkage + // custom typed instead of copied from the docs to fit completions better ConstantCompletion("C", "Enforces C calling conventions for the function, no mangling."), ConstantCompletion("C++", "Offers limited compatibility with C++."), ConstantCompletion("D", "Default D mangling and calling conventions."), @@ -117,804 +44,6 @@ immutable ConstantCompletion[] linkages = [ ConstantCompletion("Windows", "Enforces Win32/`__stdcall` conventions for the function.") ]; -private immutable string isLazyDoc = `$(P Takes one argument. If that argument is a declaration, - $(D true) is returned if it is $(D_KEYWORD ref), $(D_KEYWORD out), - or $(D_KEYWORD lazy), otherwise $(D false). -) - ---- -void fooref(ref int x) -{ - static assert(__traits(isRef, x)); - static assert(!__traits(isOut, x)); - static assert(!__traits(isLazy, x)); -} - -void fooout(out int x) -{ - static assert(!__traits(isRef, x)); - static assert(__traits(isOut, x)); - static assert(!__traits(isLazy, x)); -} - -void foolazy(lazy int x) -{ - static assert(!__traits(isRef, x)); - static assert(!__traits(isOut, x)); - static assert(__traits(isLazy, x)); -} ----`; - -/** - * Traits arguments - */ -immutable ConstantCompletion[] traits = [ - // https://github.com/dlang/dlang.org/blob/master/spec/traits.dd - ConstantCompletion("allMembers", `Takes a single argument, which must evaluate to either -a type or an expression of type. -A tuple of string literals is returned, each of which -is the name of a member of that type combined with all -of the members of the base classes (if the type is a class). -No name is repeated. -Builtin properties are not included.`), - ConstantCompletion("classInstanceSize", `Takes a single argument, which must evaluate to either -a class type or an expression of class type. -The result -is of type $(CODE size_t), and the value is the number of -bytes in the runtime instance of the class type. -It is based on the static type of a class, not the -polymorphic type.`), - ConstantCompletion("compiles", `$(P Returns a bool $(D true) if all of the arguments -compile (are semantically correct). -The arguments can be symbols, types, or expressions that -are syntactically correct. -The arguments cannot be statements or declarations. -) - -$(P If there are no arguments, the result is $(D false).) - ---- -import std.stdio; - -struct S -{ - static int s1; - int s2; -} - -int foo(); -int bar(); - -void main() -{ - writeln(__traits(compiles)); // false - writeln(__traits(compiles, foo)); // true - writeln(__traits(compiles, foo + 1)); // true - writeln(__traits(compiles, &foo + 1)); // false - writeln(__traits(compiles, typeof(1))); // true - writeln(__traits(compiles, S.s1)); // true - writeln(__traits(compiles, S.s3)); // false - writeln(__traits(compiles, 1,2,3,int,long,std)); // true - writeln(__traits(compiles, 3[1])); // false - writeln(__traits(compiles, 1,2,3,int,long,3[1])); // false -} ---- - -$(P This is useful for:) - -$(UL -$(LI Giving better error messages inside generic code than -the sometimes hard to follow compiler ones.) -$(LI Doing a finer grained specialization than template -partial specialization allows for.) -)`), - ConstantCompletion("derivedMembers", `$(P Takes a single argument, which must evaluate to either -a type or an expression of type. -A tuple of string literals is returned, each of which -is the name of a member of that type. -No name is repeated. -Base class member names are not included. -Builtin properties are not included. -) - ---- -import std.stdio; - -class D -{ - this() { } - ~this() { } - void foo() { } - int foo(int) { return 0; } -} - -void main() -{ - auto a = [__traits(derivedMembers, D)]; - writeln(a); // ["__ctor", "__dtor", "foo"] -} ---- - -$(P The order in which the strings appear in the result -is not defined.)`), - ConstantCompletion("getAliasThis", `Takes one argument, a symbol of aggregate type. -If the given aggregate type has $(D alias this), returns a list of -$(D alias this) names, by a tuple of $(D string)s. -Otherwise returns an empty tuple.`), - ConstantCompletion("getAttributes", `$(P -Takes one argument, a symbol. Returns a tuple of all attached user defined attributes. -If no UDA's exist it will return an empty tuple. -) - -$(P - For more information, see: $(DDSUBLINK spec/attribute, uda, User Defined Attributes) -) - ---- -@(3) int a; -@("string", 7) int b; - -enum Foo; -@Foo int c; - -pragma(msg, __traits(getAttributes, a)); -pragma(msg, __traits(getAttributes, b)); -pragma(msg, __traits(getAttributes, c)); ---- - -Prints: - -$(CONSOLE -tuple(3) -tuple("string", 7) -tuple((Foo)) -)`), - ConstantCompletion("getFunctionAttributes", `$(P - Takes one argument which must either be a function symbol, function literal, - or a function pointer. It returns a string tuple of all the attributes of - that function $(B excluding) any user defined attributes (UDAs can be - retrieved with the $(RELATIVE_LINK2 get-attributes, getAttributes) trait). - If no attributes exist it will return an empty tuple. -) - -$(B Note:) The order of the attributes in the returned tuple is -implementation-defined and should not be relied upon. - -$(P - A list of currently supported attributes are:) - $(UL $(LI $(D pure), $(D nothrow), $(D @nogc), $(D @property), $(D @system), $(D @trusted), $(D @safe), and $(D ref))) - $(B Note:) $(D ref) is a function attribute even though it applies to the return type. - -$(P - Additionally the following attributes are only valid for non-static member functions:) - $(UL $(LI $(D const), $(D immutable), $(D inout), $(D shared))) - -For example: - ---- -int sum(int x, int y) pure nothrow { return x + y; } - -// prints ("pure", "nothrow", "@system") -pragma(msg, __traits(getFunctionAttributes, sum)); - -struct S -{ -void test() const @system { } -} - -// prints ("const", "@system") -pragma(msg, __traits(getFunctionAttributes, S.test)); ---- - -$(P Note that some attributes can be inferred. For example:) - ---- -// prints ("pure", "nothrow", "@nogc", "@trusted") -pragma(msg, __traits(getFunctionAttributes, (int x) @trusted { return x * 2; })); ----`), - ConstantCompletion("getFunctionVariadicStyle", `$(P -Takes one argument which must either be a function symbol, or a type -that is a function, delegate or a function pointer. -It returns a string identifying the kind of -$(LINK2 function.html#variadic, variadic arguments) that are supported. -) - -$(TABLE2 getFunctionVariadicStyle, -$(THEAD string returned, kind, access, example) -$(TROW $(D "none"), not a variadic function,  , $(D void foo();)) -$(TROW $(D "argptr"), D style variadic function, $(D _argptr) and $(D _arguments), $(D void bar(...))) -$(TROW $(D "stdarg"), C style variadic function, $(LINK2 $(ROOT_DIR)phobos/core_stdc_stdarg.html, $(D core.stdc.stdarg)), $(D extern (C) void abc(int, ...))) -$(TROW $(D "typesafe"), typesafe variadic function, array on stack, $(D void def(int[] ...))) -) - ---- -import core.stdc.stdarg; - -void novar() {} -extern(C) void cstyle(int, ...) {} -extern(C++) void cppstyle(int, ...) {} -void dstyle(...) {} -void typesafe(int[]...) {} - -static assert(__traits(getFunctionVariadicStyle, novar) == "none"); -static assert(__traits(getFunctionVariadicStyle, cstyle) == "stdarg"); -static assert(__traits(getFunctionVariadicStyle, cppstyle) == "stdarg"); -static assert(__traits(getFunctionVariadicStyle, dstyle) == "argptr"); -static assert(__traits(getFunctionVariadicStyle, typesafe) == "typesafe"); - -static assert(__traits(getFunctionVariadicStyle, (int[] a...) {}) == "typesafe"); -static assert(__traits(getFunctionVariadicStyle, typeof(cstyle)) == "stdarg"); ----`), - ConstantCompletion("getLinkage", `$(P Takes one argument, which is a declaration symbol, or the type of a function, -delegate, or pointer to function. -Returns a string representing the $(LINK2 attribute.html#LinkageAttribute, LinkageAttribute) -of the declaration. -The string is one of: -) - -$(UL -$(LI $(D "D")) -$(LI $(D "C")) -$(LI $(D "C++")) -$(LI $(D "Windows")) -$(LI $(D "Pascal")) -$(LI $(D "Objective-C")) -$(LI $(D "System")) -) - ---- -extern (C) int fooc(); -alias aliasc = fooc; - -static assert(__traits(getLinkage, fooc) == "C"); -static assert(__traits(getLinkage, aliasc) == "C"); ----`), - ConstantCompletion("getMember", `$(P Takes two arguments, the second must be a string. -The result is an expression formed from the first -argument, followed by a $(SINGLEQUOTE .), followed by the second -argument as an identifier. -) - ---- -import std.stdio; - -struct S -{ - int mx; - static int my; -} - -void main() -{ - S s; - - __traits(getMember, s, "mx") = 1; // same as s.mx=1; - writeln(__traits(getMember, s, "m" ~ "x")); // 1 - - __traits(getMember, S, "mx") = 1; // error, no this for S.mx - __traits(getMember, S, "my") = 2; // ok -} ----`), - ConstantCompletion("getOverloads", `$(P The first argument is an aggregate (e.g. struct/class/module). -The second argument is a string that matches the name of -one of the functions in that aggregate. -The result is a tuple of all the overloads of that function. -) - ---- -import std.stdio; - -class D -{ - this() { } - ~this() { } - void foo() { } - int foo(int) { return 2; } -} - -void main() -{ - D d = new D(); - - foreach (t; __traits(getOverloads, D, "foo")) - writeln(typeid(typeof(t))); - - alias b = typeof(__traits(getOverloads, D, "foo")); - foreach (t; b) - writeln(typeid(t)); - - auto i = __traits(getOverloads, d, "foo")[1](1); - writeln(i); -} ---- - -Prints: - -$(CONSOLE -void() -int() -void() -int() -2 -)`), - ConstantCompletion("getParameterStorageClasses", `$(P - Takes two arguments. - The first must either be a function symbol, or a type - that is a function, delegate or a function pointer. - The second is an integer identifying which parameter, where the first parameter is - 0. - It returns a tuple of strings representing the storage classes of that parameter. -) - ---- -ref int foo(return ref const int* p, scope int* a, out int b, lazy int c); - -static assert(__traits(getParameterStorageClasses, foo, 0)[0] == "return"); -static assert(__traits(getParameterStorageClasses, foo, 0)[1] == "ref"); - -static assert(__traits(getParameterStorageClasses, foo, 1)[0] == "scope"); -static assert(__traits(getParameterStorageClasses, foo, 2)[0] == "out"); -static assert(__traits(getParameterStorageClasses, typeof(&foo), 3)[0] == "lazy"); ----`), - ConstantCompletion("getPointerBitmap", `$(P The argument is a type. - The result is an array of $(D size_t) describing the memory used by an instance of the given type. -) -$(P The first element of the array is the size of the type (for classes it is - the $(GBLINK classInstanceSize)).) -$(P The following elements describe the locations of GC managed pointers within the - memory occupied by an instance of the type. - For type T, there are $(D T.sizeof / size_t.sizeof) possible pointers represented - by the bits of the array values.) -$(P This array can be used by a precise GC to avoid false pointers.) ---- -class C -{ - // implicit virtual function table pointer not marked - // implicit monitor field not marked, usually managed manually - C next; - size_t sz; - void* p; - void function () fn; // not a GC managed pointer -} - -struct S -{ - size_t val1; - void* p; - C c; - byte[] arr; // { length, ptr } - void delegate () dg; // { context, func } -} - -static assert (__traits(getPointerBitmap, C) == [6*size_t.sizeof, 0b010100]); -static assert (__traits(getPointerBitmap, S) == [7*size_t.sizeof, 0b0110110]); ----`), - ConstantCompletion("getProtection", `$(P The argument is a symbol. - The result is a string giving its protection level: "public", "private", "protected", "export", or "package". -) - ---- -import std.stdio; - -class D -{ - export void foo() { } - public int bar; -} - -void main() -{ - D d = new D(); - - auto i = __traits(getProtection, d.foo); - writeln(i); - - auto j = __traits(getProtection, d.bar); - writeln(j); -} ---- - -Prints: - -$(CONSOLE -export -public -)`), - ConstantCompletion("getUnitTests", `$(P - Takes one argument, a symbol of an aggregate (e.g. struct/class/module). - The result is a tuple of all the unit test functions of that aggregate. - The functions returned are like normal nested static functions, - $(DDSUBLINK glossary, ctfe, CTFE) will work and - $(DDSUBLINK spec/attribute, uda, UDA's) will be accessible. -) - -$(H3 Note:) - -$(P - The -unittest flag needs to be passed to the compiler. If the flag - is not passed $(CODE __traits(getUnitTests)) will always return an - empty tuple. -) - ---- -module foo; - -import core.runtime; -import std.stdio; - -struct name { string name; } - -class Foo -{ - unittest - { - writeln("foo.Foo.unittest"); - } -} - -@name("foo") unittest -{ - writeln("foo.unittest"); -} - -template Tuple (T...) -{ - alias Tuple = T; -} - -shared static this() -{ - // Override the default unit test runner to do nothing. After that, "main" will - // be called. - Runtime.moduleUnitTester = { return true; }; -} - -void main() -{ - writeln("start main"); - - alias tests = Tuple!(__traits(getUnitTests, foo)); - static assert(tests.length == 1); - - alias attributes = Tuple!(__traits(getAttributes, tests[0])); - static assert(attributes.length == 1); - - foreach (test; tests) - test(); - - foreach (test; __traits(getUnitTests, Foo)) - test(); -} ---- - -$(P By default, the above will print:) - -$(CONSOLE -start main -foo.unittest -foo.Foo.unittest -)`), - ConstantCompletion("getVirtualFunctions", `The same as $(GLINK getVirtualMethods), except that -final functions that do not override anything are included.`), - ConstantCompletion("getVirtualIndex", `Takes a single argument which must evaluate to a function. -The result is a $(CODE ptrdiff_t) containing the index -of that function within the vtable of the parent type. -If the function passed in is final and does not override -a virtual function, $(D -1) is returned instead.`), - ConstantCompletion("getVirtualMethods", `$(P The first argument is a class type or an expression of - class type. - The second argument is a string that matches the name of - one of the functions of that class. - The result is a tuple of the virtual overloads of that function. - It does not include final functions that do not override anything. -) - ---- -import std.stdio; - -class D -{ - this() { } - ~this() { } - void foo() { } - int foo(int) { return 2; } -} - -void main() -{ - D d = new D(); - - foreach (t; __traits(getVirtualMethods, D, "foo")) - writeln(typeid(typeof(t))); - - alias b = typeof(__traits(getVirtualMethods, D, "foo")); - foreach (t; b) - writeln(typeid(t)); - - auto i = __traits(getVirtualMethods, d, "foo")[1](1); - writeln(i); -} ---- - -Prints: - -$(CONSOLE -void() -int() -void() -int() -2 -)`), - ConstantCompletion("hasMember", `$(P The first argument is a type that has members, or - is an expression of a type that has members. - The second argument is a string. - If the string is a valid property of the type, - $(D true) is returned, otherwise $(D false). -) - ---- -import std.stdio; - -struct S -{ - int m; -} - -void main() -{ - S s; - - writeln(__traits(hasMember, S, "m")); // true - writeln(__traits(hasMember, s, "m")); // true - writeln(__traits(hasMember, S, "y")); // false - writeln(__traits(hasMember, int, "sizeof")); // true -} ----`), - ConstantCompletion("identifier", `$(P Takes one argument, a symbol. Returns the identifier - for that symbol as a string literal. -) ---- -import std.stdio; - -int var = 123; -pragma(msg, typeof(var)); // int -pragma(msg, typeof(__traits(identifier, var))); // string -writeln(var); // 123 -writeln(__traits(identifier, var)); // "var" ----`), - ConstantCompletion("isAbstractClass", `$(P If the arguments are all either types that are abstract classes, - or expressions that are typed as abstract classes, then $(D true) - is returned. - Otherwise, $(D false) is returned. - If there are no arguments, $(D false) is returned.) - ---- -import std.stdio; - -abstract class C { int foo(); } - -void main() -{ - C c; - writeln(__traits(isAbstractClass, C)); - writeln(__traits(isAbstractClass, c, C)); - writeln(__traits(isAbstractClass)); - writeln(__traits(isAbstractClass, int*)); -} ---- - -Prints: - -$(CONSOLE -true -true -false -false -)`), - ConstantCompletion("isAbstractFunction", `$(P Takes one argument. If that argument is an abstract function, - $(D true) is returned, otherwise $(D false). -) - ---- -import std.stdio; - -struct S -{ - void bar() { } -} - -class C -{ - void bar() { } -} - -class AC -{ - abstract void foo(); -} - -void main() -{ - writeln(__traits(isAbstractFunction, C.bar)); // false - writeln(__traits(isAbstractFunction, S.bar)); // false - writeln(__traits(isAbstractFunction, AC.foo)); // true -} ----`), - ConstantCompletion("isArithmetic", `$(P If the arguments are all either types that are arithmetic types, - or expressions that are typed as arithmetic types, then $(D true) - is returned. - Otherwise, $(D false) is returned. - If there are no arguments, $(D false) is returned.) - ---- -import std.stdio; - -void main() -{ - int i; - writeln(__traits(isArithmetic, int)); - writeln(__traits(isArithmetic, i, i+1, int)); - writeln(__traits(isArithmetic)); - writeln(__traits(isArithmetic, int*)); -} ---- - -Prints: - -$(CONSOLE -true -true -false -false -)`), - ConstantCompletion("isAssociativeArray", `Works like $(D isArithmetic), except it's for associative array types.`), - - ConstantCompletion("isDisabled", r"$(P Takes one argument and returns `true` if it's a function declaration - marked with `@disable`.) - ---- -struct Foo -{ - @disable void foo(); - void bar(){} -} - -static assert(__traits(isDisabled, Foo.foo)); -static assert(!__traits(isDisabled, Foo.bar)); ---- - - $(P For any other declaration even if `@disable` is a syntactically valid - attribute `false` is returned because the annotation has no effect.) - ---- -@disable struct Bar{} - -static assert(!__traits(isDisabled, Bar)); ----"), - ConstantCompletion("isFinalClass", `Works like $(D isAbstractClass), except it's for final classes.`), - ConstantCompletion("isFinalFunction", `$(P Takes one argument. If that argument is a final function, - $(D true) is returned, otherwise $(D false). -) - ---- -import std.stdio; - -struct S -{ - void bar() { } -} - -class C -{ - void bar() { } - final void foo(); -} - -final class FC -{ - void foo(); -} - -void main() -{ - writeln(__traits(isFinalFunction, C.bar)); // false - writeln(__traits(isFinalFunction, S.bar)); // false - writeln(__traits(isFinalFunction, C.foo)); // true - writeln(__traits(isFinalFunction, FC.foo)); // true -} ----`), - ConstantCompletion("isFloating", `Works like $(D isArithmetic), except it's for floating -point types (including imaginary and complex types).`), - ConstantCompletion("isFuture", "Takes one argument. It returns `true` if the argument is a symbol -marked with the `@future` keyword, otherwise `false`. Currently, only -functions and variable declarations have support for the `@future` keyword."), - ConstantCompletion("isIntegral", `Works like $(D isArithmetic), except it's for integral -types (including character types).`), - ConstantCompletion("isLazy", isLazyDoc), - ConstantCompletion("isNested", `Takes one argument. -It returns $(D true) if the argument is a nested type which internally -stores a context pointer, otherwise it returns $(D false). -Nested types can be $(DDSUBLINK spec/class, nested, classes), -$(DDSUBLINK spec/struct, nested, structs), and -$(DDSUBLINK spec/function, variadicnested, functions).`), - ConstantCompletion("isOut", isLazyDoc), - ConstantCompletion("isOverrideFunction", `$(P Takes one argument. If that argument is a function marked with - $(D_KEYWORD override), $(D true) is returned, otherwise $(D false). -) - ---- -import std.stdio; - -class Base -{ - void foo() { } -} - -class Foo : Base -{ - override void foo() { } - void bar() { } -} - -void main() -{ - writeln(__traits(isOverrideFunction, Base.foo)); // false - writeln(__traits(isOverrideFunction, Foo.foo)); // true - writeln(__traits(isOverrideFunction, Foo.bar)); // false -} ----`), - ConstantCompletion("isPOD", `$(P Takes one argument, which must be a type. It returns -$(D true) if the type is a $(DDSUBLINK glossary, pod, POD) type, otherwise $(D false).)`), - ConstantCompletion("isRef", isLazyDoc), - ConstantCompletion("isSame", `$(P Takes two arguments and returns bool $(D true) if they - are the same symbol, $(D false) if not.) - ---- -import std.stdio; - -struct S { } - -int foo(); -int bar(); - -void main() -{ - writeln(__traits(isSame, foo, foo)); // true - writeln(__traits(isSame, foo, bar)); // false - writeln(__traits(isSame, foo, S)); // false - writeln(__traits(isSame, S, S)); // true - writeln(__traits(isSame, std, S)); // false - writeln(__traits(isSame, std, std)); // true -} ---- - -$(P If the two arguments are expressions made up of literals -or enums that evaluate to the same value, true is returned.)`), - ConstantCompletion("isScalar", `Works like $(D isArithmetic), except it's for scalar types.`), - ConstantCompletion("isStaticArray", `Works like $(D isArithmetic), except it's for static array types.`), - ConstantCompletion("isStaticFunction", `Takes one argument. If that argument is a static function, -meaning it has no context pointer, -$(D true) is returned, otherwise $(D false).`), - ConstantCompletion("isTemplate", `$(P Takes one argument. If that argument is a template then $(D true) is returned, - otherwise $(D false). -) - ---- -void foo(T)(){} -static assert(__traits(isTemplate,foo)); -static assert(!__traits(isTemplate,foo!int())); -static assert(!__traits(isTemplate,"string")); ----`), - ConstantCompletion("isUnsigned", `Works like $(D isArithmetic), except it's for unsigned types.`), - ConstantCompletion("isVirtualFunction", `The same as $(GLINK isVirtualMethod), except -that final functions that don't override anything return true.`), - ConstantCompletion("isVirtualMethod", `Takes one argument. If that argument is a virtual function, -$(D true) is returned, otherwise $(D false). -Final functions that don't override anything return false.`), - ConstantCompletion("parent", `Takes a single argument which must evaluate to a symbol. -The result is the symbol that is the parent of it.`) -]; - /** * Scope conditions */ diff --git a/src/dcd/common/constants2.d b/src/dcd/common/constants2.d new file mode 100644 index 0000000..6779053 --- /dev/null +++ b/src/dcd/common/constants2.d @@ -0,0 +1,1072 @@ +// +// +// this file is auto generated by constants-gen/generator.d, do not edit manually. +// +// + +module dcd.common.constants2; + +import dcd.common.constants : ConstantCompletion; + +/** + * Pragma arguments + */ +immutable ConstantCompletion[] pragmas = [ + // generated from pragma.dd + ConstantCompletion("inline", `$(P Affects whether functions are inlined or not. If at the declaration level, it + affects the functions declared in the block it controls. If inside a function, it + affects the function it is enclosed by. If there are multiple pragma inlines in a function, + the lexically last one takes effect.) + + $(P It takes three forms:) + $(OL + $(LI +--- +pragma(inline) +--- + Sets the behavior to match the default behavior set by the compiler switch + $(DDSUBLINK dmd, switch-inline, $(TT -inline)). + ) + $(LI +--- +pragma(inline, false) +--- + Functions are never inlined. + ) + $(LI +--- +pragma(inline, true) +--- + If a function cannot be inlined with the $(DDSUBLINK dmd, switch-inline, $(TT -inline)) + switch, an error message is issued. This is expected to be improved in the future to causing + functions to always be inlined regardless of compiler switch settings. Whether a compiler can + inline a particular function or not is implementation defined. + ) + ) +--- +pragma(inline): +int foo(int x) // foo() is never inlined +{ + pragma(inline, true); + ++x; + pragma(inline, false); // supercedes the others + return x + 3; +} +---`), + ConstantCompletion("lib", `Inserts a directive in the object file to link in the library + specified by the $(ASSIGNEXPRESSION). + The $(ASSIGNEXPRESSION)s must be a string literal: +----------------- +pragma(lib, "foo.lib"); +-----------------`), + ConstantCompletion("mangle", `Overrides the default mangling for a symbol. It's only effective + when the symbol is a function declaration or a variable declaration. + For example this allows linking to a symbol which is a D keyword, which would normally + be disallowed as a symbol name: +----------------- +pragma(mangle, "body") +extern(C) void body_func(); +-----------------`), + ConstantCompletion("msg", `Constructs a message from the arguments and prints to the standard error stream while compiling: +----------------- +pragma(msg, "compiling...", 1, 1.0); +-----------------`), + ConstantCompletion("startaddress", `Puts a directive into the object file saying that the + function specified in the first argument will be the + start address for the program: +----------------- +void foo() { ... } +pragma(startaddress, foo); +----------------- + This is not normally used for application level programming, + but is for specialized systems work. + For applications code, the start address is taken care of + by the runtime library. +) +) + +$(H2 $(LNAME2 vendor_specific_pragmas, Vendor Specific Pragmas)) + + $(P Vendor specific pragma $(I Identifier)s can be defined if they + are prefixed by the vendor's trademarked name, in a similar manner + to version identifiers: + ) + +----------------- +pragma(DigitalMars_funky_extension) { ... } +----------------- + + $(P Compilers must diagnose an error for unrecognized $(I Pragma)s, + even if they are vendor specific ones. This implies that vendor + specific pragmas should be wrapped in version statements: + ) + +----------------- +version (DigitalMars) +{ + pragma(DigitalMars_funky_extension) + { ... } +} +-----------------`), +]; + +/** + * Traits arguments + */ +immutable ConstantCompletion[] traits = [ + // generated from traits.dd + ConstantCompletion("allMembers", `$(P Takes a single argument, which must evaluate to either +a type or an expression of type. +A tuple of string literals is returned, each of which +is the name of a member of that type combined with all +of the members of the base classes (if the type is a class). +No name is repeated. +Builtin properties are not included. +) + +--- +import std.stdio; + +class D +{ + this() { } + ~this() { } + void foo() { } + int foo(int) { return 0; } +} + +void main() +{ + auto b = [ __traits(allMembers, D) ]; + writeln(b); + // ["__ctor", "__dtor", "foo", "toString", "toHash", "opCmp", "opEquals", + // "Monitor", "factory"] +} +--- + +$(P The order in which the strings appear in the result +is not defined.)`), + ConstantCompletion("classInstanceSize", `$(P Takes a single argument, which must evaluate to either +a class type or an expression of class type. +The result +is of type $(CODE size_t), and the value is the number of +bytes in the runtime instance of the class type. +It is based on the static type of a class, not the +polymorphic type. +)`), + ConstantCompletion("compiles", `$(P Returns a bool $(D true) if all of the arguments +compile (are semantically correct). +The arguments can be symbols, types, or expressions that +are syntactically correct. +The arguments cannot be statements or declarations. +) + +$(P If there are no arguments, the result is $(D false).) + +--- +import std.stdio; + +struct S +{ + static int s1; + int s2; +} + +int foo(); +int bar(); + +void main() +{ + writeln(__traits(compiles)); // false + writeln(__traits(compiles, foo)); // true + writeln(__traits(compiles, foo + 1)); // true + writeln(__traits(compiles, &foo + 1)); // false + writeln(__traits(compiles, typeof(1))); // true + writeln(__traits(compiles, S.s1)); // true + writeln(__traits(compiles, S.s3)); // false + writeln(__traits(compiles, 1,2,3,int,long,std)); // true + writeln(__traits(compiles, 3[1])); // false + writeln(__traits(compiles, 1,2,3,int,long,3[1])); // false +} +--- + +$(P This is useful for:) + +$(UL +$(LI Giving better error messages inside generic code than +the sometimes hard to follow compiler ones.) +$(LI Doing a finer grained specialization than template +partial specialization allows for.) +) + + +$(H2 $(LNAME2 specialkeywords, Special Keywords)) + + $(P $(CODE __FILE__) and $(CODE __LINE__) expand to the source + file name and line number at the point of instantiation. The path of + the source file is left up to the compiler. ) + + $(P $(CODE __FILE_FULL_PATH__) expands to the absolute source + file name at the point of instantiation.) + + $(P $(CODE __MODULE__) expands to the module name at the point of + instantiation.) + + $(P $(CODE __FUNCTION__) expands to the fully qualified name of the + function at the point of instantiation.) + + $(P $(CODE __PRETTY_FUNCTION__) is similar to $(CODE __FUNCTION__), + but also expands the function return type, its parameter types, + and its attributes.) + + $(P Example usage:) + +----- +module test; +import std.stdio; + +void test(string file = __FILE__, size_t line = __LINE__, + string mod = __MODULE__, string func = __FUNCTION__, + string pretty = __PRETTY_FUNCTION__, + string fileFullPath = __FILE_FULL_PATH__) +{ + writefln("file: '%s', line: '%s', module: '%s',\nfunction: '%s', " ~ + "pretty function: '%s',\nfile full path: '%s'", + file, line, mod, func, pretty, fileFullPath); +} + +int main(string[] args) +{ + test(); + return 0; +} +----- + +$(P Assuming the file was at /example/test.d, this will output:) + +$(CONSOLE +file: 'test.d', line: '13', module: 'test', +function: 'test.main', pretty function: 'int test.main(string[] args)', +file full path: '/example/test.d' +)`), + ConstantCompletion("derivedMembers", `$(P Takes a single argument, which must evaluate to either +a type or an expression of type. +A tuple of string literals is returned, each of which +is the name of a member of that type. +No name is repeated. +Base class member names are not included. +Builtin properties are not included. +) + +--- +import std.stdio; + +class D +{ + this() { } + ~this() { } + void foo() { } + int foo(int) { return 0; } +} + +void main() +{ + auto a = [__traits(derivedMembers, D)]; + writeln(a); // ["__ctor", "__dtor", "foo"] +} +--- + +$(P The order in which the strings appear in the result +is not defined.)`), + ConstantCompletion("getAliasThis", `$(P Takes one argument, a symbol of aggregate type. + If the given aggregate type has $(D alias this), returns a list of + $(D alias this) names, by a tuple of $(D string)s. + Otherwise returns an empty tuple. +)`), + ConstantCompletion("getAttributes", `$(P + Takes one argument, a symbol. Returns a tuple of all attached user-defined attributes. + If no UDA's exist it will return an empty tuple. +) + +$(P + For more information, see: $(DDSUBLINK spec/attribute, uda, User-Defined Attributes) +) + +--- +@(3) int a; +@("string", 7) int b; + +enum Foo; +@Foo int c; + +pragma(msg, __traits(getAttributes, a)); +pragma(msg, __traits(getAttributes, b)); +pragma(msg, __traits(getAttributes, c)); +--- + + Prints: + +$(CONSOLE +tuple(3) +tuple("string", 7) +tuple((Foo)) +) +)`), + ConstantCompletion("getFunctionAttributes", `$(P + Takes one argument which must either be a function symbol, function literal, + or a function pointer. It returns a string tuple of all the attributes of + that function $(B excluding) any user-defined attributes (UDAs can be + retrieved with the $(RELATIVE_LINK2 get-attributes, getAttributes) trait). + If no attributes exist it will return an empty tuple. +) + + + $(B Note:) The order of the attributes in the returned tuple is + implementation-defined and should not be relied upon. + + $(P + A list of currently supported attributes are:) + $(UL $(LI $(D pure), $(D nothrow), $(D @nogc), $(D @property), $(D @system), $(D @trusted), $(D @safe), and $(D ref))) + $(B Note:) $(D ref) is a function attribute even though it applies to the return type. + + $(P + Additionally the following attributes are only valid for non-static member functions:) + $(UL $(LI $(D const), $(D immutable), $(D inout), $(D shared))) + +For example: + +--- +int sum(int x, int y) pure nothrow { return x + y; } + +// prints ("pure", "nothrow", "@system") +pragma(msg, __traits(getFunctionAttributes, sum)); + +struct S +{ + void test() const @system { } +} + +// prints ("const", "@system") +pragma(msg, __traits(getFunctionAttributes, S.test)); +--- + +$(P Note that some attributes can be inferred. For example:) + +--- +// prints ("pure", "nothrow", "@nogc", "@trusted") +pragma(msg, __traits(getFunctionAttributes, (int x) @trusted { return x * 2; })); +--- +)`), + ConstantCompletion("getFunctionVariadicStyle", `$(P + Takes one argument which must either be a function symbol, or a type + that is a function, delegate or a function pointer. + It returns a string identifying the kind of + $(LINK2 function.html#variadic, variadic arguments) that are supported. +) + +$(TABLE2 getFunctionVariadicStyle, + $(THEAD result, kind, access, example) + $(TROW $(D "none"), not a variadic function, $(NBSP), $(D void foo();)) + $(TROW $(D "argptr"), D style variadic function, $(D _argptr) and $(D _arguments), $(D void bar(...))) + $(TROW $(D "stdarg"), C style variadic function, $(LINK2 $(ROOT_DIR)phobos/core_stdc_stdarg.html, $(D core.stdc.stdarg)), $(D extern (C) void abc(int, ...))) + $(TROW $(D "typesafe"), typesafe variadic function, array on stack, $(D void def(int[] ...))) +) + +--- +import core.stdc.stdarg; + +void novar() {} +extern(C) void cstyle(int, ...) {} +extern(C++) void cppstyle(int, ...) {} +void dstyle(...) {} +void typesafe(int[]...) {} + +static assert(__traits(getFunctionVariadicStyle, novar) == "none"); +static assert(__traits(getFunctionVariadicStyle, cstyle) == "stdarg"); +static assert(__traits(getFunctionVariadicStyle, cppstyle) == "stdarg"); +static assert(__traits(getFunctionVariadicStyle, dstyle) == "argptr"); +static assert(__traits(getFunctionVariadicStyle, typesafe) == "typesafe"); + +static assert(__traits(getFunctionVariadicStyle, (int[] a...) {}) == "typesafe"); +static assert(__traits(getFunctionVariadicStyle, typeof(cstyle)) == "stdarg"); +--- +)`), + ConstantCompletion("getLinkage", `$(P Takes one argument, which is a declaration symbol, or the type of a function, +delegate, or pointer to function. +Returns a string representing the $(LINK2 attribute.html#LinkageAttribute, LinkageAttribute) +of the declaration. +The string is one of: +) + +$(UL +$(LI $(D "D")) +$(LI $(D "C")) +$(LI $(D "C++")) +$(LI $(D "Windows")) +$(LI $(D "Pascal")) +$(LI $(D "Objective-C")) +$(LI $(D "System")) +) + +--- +extern (C) int fooc(); +alias aliasc = fooc; + +static assert(__traits(getLinkage, fooc) == "C"); +static assert(__traits(getLinkage, aliasc) == "C"); +---`), + ConstantCompletion("getMember", `$(P Takes two arguments, the second must be a string. +The result is an expression formed from the first +argument, followed by a $(SINGLEQUOTE .), followed by the second +argument as an identifier. +) + +--- +import std.stdio; + +struct S +{ + int mx; + static int my; +} + +void main() +{ + S s; + + __traits(getMember, s, "mx") = 1; // same as s.mx=1; + writeln(__traits(getMember, s, "m" ~ "x")); // 1 + + __traits(getMember, S, "mx") = 1; // error, no this for S.mx + __traits(getMember, S, "my") = 2; // ok +} +---`), + ConstantCompletion("getOverloads", `$(P The first argument is an aggregate (e.g. struct/class/module). +The second argument is a string that matches the name of +one of the functions in that aggregate. +The result is a tuple of all the overloads of that function. +) + +--- +import std.stdio; + +class D +{ + this() { } + ~this() { } + void foo() { } + int foo(int) { return 2; } +} + +void main() +{ + D d = new D(); + + foreach (t; __traits(getOverloads, D, "foo")) + writeln(typeid(typeof(t))); + + alias b = typeof(__traits(getOverloads, D, "foo")); + foreach (t; b) + writeln(typeid(t)); + + auto i = __traits(getOverloads, d, "foo")[1](1); + writeln(i); +} +--- + +Prints: + +$(CONSOLE +void() +int() +void() +int() +2 +)`), + ConstantCompletion("getParameterStorageClasses", `$(P + Takes two arguments. + The first must either be a function symbol, or a type + that is a function, delegate or a function pointer. + The second is an integer identifying which parameter, where the first parameter is + 0. + It returns a tuple of strings representing the storage classes of that parameter. +) + +--- +ref int foo(return ref const int* p, scope int* a, out int b, lazy int c); + +static assert(__traits(getParameterStorageClasses, foo, 0)[0] == "return"); +static assert(__traits(getParameterStorageClasses, foo, 0)[1] == "ref"); + +static assert(__traits(getParameterStorageClasses, foo, 1)[0] == "scope"); +static assert(__traits(getParameterStorageClasses, foo, 2)[0] == "out"); +static assert(__traits(getParameterStorageClasses, typeof(&foo), 3)[0] == "lazy"); +---`), + ConstantCompletion("getPointerBitmap", `$(P The argument is a type. +The result is an array of $(D size_t) describing the memory used by an instance of the given type. +) +$(P The first element of the array is the size of the type (for classes it is +the $(GBLINK classInstanceSize)).) +$(P The following elements describe the locations of GC managed pointers within the +memory occupied by an instance of the type. +For type T, there are $(D T.sizeof / size_t.sizeof) possible pointers represented +by the bits of the array values.) +$(P This array can be used by a precise GC to avoid false pointers.) +--- +class C +{ + // implicit virtual function table pointer not marked + // implicit monitor field not marked, usually managed manually + C next; + size_t sz; + void* p; + void function () fn; // not a GC managed pointer +} + +struct S +{ + size_t val1; + void* p; + C c; + byte[] arr; // { length, ptr } + void delegate () dg; // { context, func } +} + +static assert (__traits(getPointerBitmap, C) == [6*size_t.sizeof, 0b010100]); +static assert (__traits(getPointerBitmap, S) == [7*size_t.sizeof, 0b0110110]); +---`), + ConstantCompletion("getProtection", `$(P The argument is a symbol. +The result is a string giving its protection level: "public", "private", "protected", "export", or "package". +) + +--- +import std.stdio; + +class D +{ + export void foo() { } + public int bar; +} + +void main() +{ + D d = new D(); + + auto i = __traits(getProtection, d.foo); + writeln(i); + + auto j = __traits(getProtection, d.bar); + writeln(j); +} +--- + +Prints: + +$(CONSOLE +export +public +)`), + ConstantCompletion("getUnitTests", `$(P + Takes one argument, a symbol of an aggregate (e.g. struct/class/module). + The result is a tuple of all the unit test functions of that aggregate. + The functions returned are like normal nested static functions, + $(DDSUBLINK glossary, ctfe, CTFE) will work and + $(DDSUBLINK spec/attribute, uda, UDA's) will be accessible. +) + +$(H3 Note:) + +$(P + The -unittest flag needs to be passed to the compiler. If the flag + is not passed $(CODE __traits(getUnitTests)) will always return an + empty tuple. +) + +--- +module foo; + +import core.runtime; +import std.stdio; + +struct name { string name; } + +class Foo +{ + unittest + { + writeln("foo.Foo.unittest"); + } +} + +@name("foo") unittest +{ + writeln("foo.unittest"); +} + +template Tuple (T...) +{ + alias Tuple = T; +} + +shared static this() +{ + // Override the default unit test runner to do nothing. After that, "main" will + // be called. + Runtime.moduleUnitTester = { return true; }; +} + +void main() +{ + writeln("start main"); + + alias tests = Tuple!(__traits(getUnitTests, foo)); + static assert(tests.length == 1); + + alias attributes = Tuple!(__traits(getAttributes, tests[0])); + static assert(attributes.length == 1); + + foreach (test; tests) + test(); + + foreach (test; __traits(getUnitTests, Foo)) + test(); +} +--- + +$(P By default, the above will print:) + +$(CONSOLE +start main +foo.unittest +foo.Foo.unittest +)`), + ConstantCompletion("getVirtualFunctions", `$(P The same as $(GLINK getVirtualMethods), except that +final functions that do not override anything are included. +)`), + ConstantCompletion("getVirtualIndex", `$(P Takes a single argument which must evaluate to a function. +The result is a $(CODE ptrdiff_t) containing the index +of that function within the vtable of the parent type. +If the function passed in is final and does not override +a virtual function, $(D -1) is returned instead. +)`), + ConstantCompletion("getVirtualMethods", `$(P The first argument is a class type or an expression of +class type. +The second argument is a string that matches the name of +one of the functions of that class. +The result is a tuple of the virtual overloads of that function. +It does not include final functions that do not override anything. +) + +--- +import std.stdio; + +class D +{ + this() { } + ~this() { } + void foo() { } + int foo(int) { return 2; } +} + +void main() +{ + D d = new D(); + + foreach (t; __traits(getVirtualMethods, D, "foo")) + writeln(typeid(typeof(t))); + + alias b = typeof(__traits(getVirtualMethods, D, "foo")); + foreach (t; b) + writeln(typeid(t)); + + auto i = __traits(getVirtualMethods, d, "foo")[1](1); + writeln(i); +} +--- + +Prints: + +$(CONSOLE +void() +int() +void() +int() +2 +)`), + ConstantCompletion("hasMember", `$(P The first argument is a type that has members, or +is an expression of a type that has members. +The second argument is a string. +If the string is a valid property of the type, +$(D true) is returned, otherwise $(D false). +) + +--- +import std.stdio; + +struct S +{ + int m; +} + +void main() +{ + S s; + + writeln(__traits(hasMember, S, "m")); // true + writeln(__traits(hasMember, s, "m")); // true + writeln(__traits(hasMember, S, "y")); // false + writeln(__traits(hasMember, int, "sizeof")); // true +} +---`), + ConstantCompletion("identifier", `$(P Takes one argument, a symbol. Returns the identifier +for that symbol as a string literal. +) +--- +import std.stdio; + +int var = 123; +pragma(msg, typeof(var)); // int +pragma(msg, typeof(__traits(identifier, var))); // string +writeln(var); // 123 +writeln(__traits(identifier, var)); // "var" +---`), + ConstantCompletion("isAbstractClass", `$(P If the arguments are all either types that are abstract classes, +or expressions that are typed as abstract classes, then $(D true) +is returned. +Otherwise, $(D false) is returned. +If there are no arguments, $(D false) is returned.) + +--- +import std.stdio; + +abstract class C { int foo(); } + +void main() +{ + C c; + writeln(__traits(isAbstractClass, C)); + writeln(__traits(isAbstractClass, c, C)); + writeln(__traits(isAbstractClass)); + writeln(__traits(isAbstractClass, int*)); +} +--- + +Prints: + +$(CONSOLE +true +true +false +false +)`), + ConstantCompletion("isAbstractFunction", `$(P Takes one argument. If that argument is an abstract function, +$(D true) is returned, otherwise $(D false). +) + +--- +import std.stdio; + +struct S +{ + void bar() { } +} + +class C +{ + void bar() { } +} + +class AC +{ + abstract void foo(); +} + +void main() +{ + writeln(__traits(isAbstractFunction, C.bar)); // false + writeln(__traits(isAbstractFunction, S.bar)); // false + writeln(__traits(isAbstractFunction, AC.foo)); // true +} +---`), + ConstantCompletion("isArithmetic", `$(P If the arguments are all either types that are arithmetic types, +or expressions that are typed as arithmetic types, then $(D true) +is returned. +Otherwise, $(D false) is returned. +If there are no arguments, $(D false) is returned.) + +--- +import std.stdio; + +void main() +{ + int i; + writeln(__traits(isArithmetic, int)); + writeln(__traits(isArithmetic, i, i+1, int)); + writeln(__traits(isArithmetic)); + writeln(__traits(isArithmetic, int*)); +} +--- + +Prints: + +$(CONSOLE +true +true +false +false +)`), + ConstantCompletion("isAssociativeArray", `$(P Works like $(D isArithmetic), except it's for associative array +types.)`), + ConstantCompletion("isDeprecated", `$(P Takes one argument. It returns ` ~ "`" ~ `true` ~ "`" ~ ` if the argument is a symbol +marked with the ` ~ "`" ~ `deprecated` ~ "`" ~ ` keyword, otherwise ` ~ "`" ~ `false` ~ "`" ~ `.)`), + ConstantCompletion("isDisabled", `$(P Takes one argument and returns ` ~ "`" ~ `true` ~ "`" ~ ` if it's a function declaration +marked with ` ~ "`" ~ `@disable` ~ "`" ~ `.) + +--- +struct Foo +{ + @disable void foo(); + void bar(){} +} + +static assert(__traits(isDisabled, Foo.foo)); +static assert(!__traits(isDisabled, Foo.bar)); +--- + +$(P For any other declaration even if ` ~ "`" ~ `@disable` ~ "`" ~ ` is a syntactically valid +attribute ` ~ "`" ~ `false` ~ "`" ~ ` is returned because the annotation has no effect.) + +--- +@disable struct Bar{} + +static assert(!__traits(isDisabled, Bar)); +---`), + ConstantCompletion("isFinalClass", `$(P Works like $(D isAbstractClass), except it's for final +classes.)`), + ConstantCompletion("isFinalFunction", `$(P Takes one argument. If that argument is a final function, +$(D true) is returned, otherwise $(D false). +) + +--- +import std.stdio; + +struct S +{ + void bar() { } +} + +class C +{ + void bar() { } + final void foo(); +} + +final class FC +{ + void foo(); +} + +void main() +{ + writeln(__traits(isFinalFunction, C.bar)); // false + writeln(__traits(isFinalFunction, S.bar)); // false + writeln(__traits(isFinalFunction, C.foo)); // true + writeln(__traits(isFinalFunction, FC.foo)); // true +} +---`), + ConstantCompletion("isFloating", `$(P Works like $(D isArithmetic), except it's for floating +point types (including imaginary and complex types).)`), + ConstantCompletion("isFuture", `$(P Takes one argument. It returns ` ~ "`" ~ `true` ~ "`" ~ ` if the argument is a symbol +marked with the ` ~ "`" ~ `@future` ~ "`" ~ ` keyword, otherwise ` ~ "`" ~ `false` ~ "`" ~ `. Currently, only +functions and variable declarations have support for the ` ~ "`" ~ `@future` ~ "`" ~ ` keyword.)`), + ConstantCompletion("isIntegral", `$(P Works like $(D isArithmetic), except it's for integral +types (including character types).)`), + ConstantCompletion("isLazy", `$(P Takes one argument. If that argument is a declaration, +$(D true) is returned if it is $(D_KEYWORD ref), $(D_KEYWORD out), +or $(D_KEYWORD lazy), otherwise $(D false). +) + +--- +void fooref(ref int x) +{ + static assert(__traits(isRef, x)); + static assert(!__traits(isOut, x)); + static assert(!__traits(isLazy, x)); +} + +void fooout(out int x) +{ + static assert(!__traits(isRef, x)); + static assert(__traits(isOut, x)); + static assert(!__traits(isLazy, x)); +} + +void foolazy(lazy int x) +{ + static assert(!__traits(isRef, x)); + static assert(!__traits(isOut, x)); + static assert(__traits(isLazy, x)); +} +---`), + ConstantCompletion("isNested", `$(P Takes one argument. +It returns $(D true) if the argument is a nested type which internally +stores a context pointer, otherwise it returns $(D false). +Nested types can be $(DDSUBLINK spec/class, nested, classes), +$(DDSUBLINK spec/struct, nested, structs), and +$(DDSUBLINK spec/function, variadicnested, functions).)`), + ConstantCompletion("isOut", `$(P Takes one argument. If that argument is a declaration, +$(D true) is returned if it is $(D_KEYWORD ref), $(D_KEYWORD out), +or $(D_KEYWORD lazy), otherwise $(D false). +) + +--- +void fooref(ref int x) +{ + static assert(__traits(isRef, x)); + static assert(!__traits(isOut, x)); + static assert(!__traits(isLazy, x)); +} + +void fooout(out int x) +{ + static assert(!__traits(isRef, x)); + static assert(__traits(isOut, x)); + static assert(!__traits(isLazy, x)); +} + +void foolazy(lazy int x) +{ + static assert(!__traits(isRef, x)); + static assert(!__traits(isOut, x)); + static assert(__traits(isLazy, x)); +} +---`), + ConstantCompletion("isOverrideFunction", `$(P Takes one argument. If that argument is a function marked with +$(D_KEYWORD override), $(D true) is returned, otherwise $(D false). +) + +--- +import std.stdio; + +class Base +{ + void foo() { } +} + +class Foo : Base +{ + override void foo() { } + void bar() { } +} + +void main() +{ + writeln(__traits(isOverrideFunction, Base.foo)); // false + writeln(__traits(isOverrideFunction, Foo.foo)); // true + writeln(__traits(isOverrideFunction, Foo.bar)); // false +} +---`), + ConstantCompletion("isPOD", `$(P Takes one argument, which must be a type. It returns +$(D true) if the type is a $(DDSUBLINK glossary, pod, POD) type, otherwise $(D false).)`), + ConstantCompletion("isRef", `$(P Takes one argument. If that argument is a declaration, +$(D true) is returned if it is $(D_KEYWORD ref), $(D_KEYWORD out), +or $(D_KEYWORD lazy), otherwise $(D false). +) + +--- +void fooref(ref int x) +{ + static assert(__traits(isRef, x)); + static assert(!__traits(isOut, x)); + static assert(!__traits(isLazy, x)); +} + +void fooout(out int x) +{ + static assert(!__traits(isRef, x)); + static assert(__traits(isOut, x)); + static assert(!__traits(isLazy, x)); +} + +void foolazy(lazy int x) +{ + static assert(!__traits(isRef, x)); + static assert(!__traits(isOut, x)); + static assert(__traits(isLazy, x)); +} +---`), + ConstantCompletion("isSame", `$(P Takes two arguments and returns bool $(D true) if they +are the same symbol, $(D false) if not.) + +--- +import std.stdio; + +struct S { } + +int foo(); +int bar(); + +void main() +{ + writeln(__traits(isSame, foo, foo)); // true + writeln(__traits(isSame, foo, bar)); // false + writeln(__traits(isSame, foo, S)); // false + writeln(__traits(isSame, S, S)); // true + writeln(__traits(isSame, std, S)); // false + writeln(__traits(isSame, std, std)); // true +} +--- + +$(P If the two arguments are expressions made up of literals +or enums that evaluate to the same value, true is returned.)`), + ConstantCompletion("isScalar", `$(P Works like $(D isArithmetic), except it's for scalar +types.)`), + ConstantCompletion("isStaticArray", `$(P Works like $(D isArithmetic), except it's for static array +types.)`), + ConstantCompletion("isStaticFunction", `$(P Takes one argument. If that argument is a static function, +meaning it has no context pointer, +$(D true) is returned, otherwise $(D false). +)`), + ConstantCompletion("isTemplate", `$(P Takes one argument. If that argument is a template then $(D true) is returned, +otherwise $(D false). +) + +--- +void foo(T)(){} +static assert(__traits(isTemplate,foo)); +static assert(!__traits(isTemplate,foo!int())); +static assert(!__traits(isTemplate,"string")); +---`), + ConstantCompletion("isUnsigned", `$(P Works like $(D isArithmetic), except it's for unsigned +types.)`), + ConstantCompletion("isVirtualFunction", `$(P The same as $(GLINK isVirtualMethod), except +that final functions that don't override anything return true. +)`), + ConstantCompletion("isVirtualMethod", `$(P Takes one argument. If that argument is a virtual function, +$(D true) is returned, otherwise $(D false). +Final functions that don't override anything return false. +) + +--- +import std.stdio; + +struct S +{ + void bar() { } +} + +class C +{ + void bar() { } +} + +void main() +{ + writeln(__traits(isVirtualMethod, C.bar)); // true + writeln(__traits(isVirtualMethod, S.bar)); // false +} +---`), + ConstantCompletion("parent", `$(P Takes a single argument which must evaluate to a symbol. +The result is the symbol that is the parent of it. +)`), +]; diff --git a/tests/tc_traits/expected.txt b/tests/tc_traits/expected.txt index e5c14cf..88b5010 100644 --- a/tests/tc_traits/expected.txt +++ b/tests/tc_traits/expected.txt @@ -23,6 +23,7 @@ isAbstractClass k isAbstractFunction k isArithmetic k isAssociativeArray k +isDeprecated k isDisabled k isFinalClass k isFinalFunction k