diff --git a/src/attrib.c b/src/attrib.c index 0b1be25f896f..a456013a2c1e 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -1586,3 +1586,101 @@ const char *CompileDeclaration::kind() } +/***************************** UserAttributeDeclaration *****************************/ + +UserAttributeDeclaration::UserAttributeDeclaration(Expressions *atts, Dsymbols *decl) + : AttribDeclaration(decl) +{ + //printf("UserAttributeDeclaration()\n"); + this->atts = atts; +} + +Dsymbol *UserAttributeDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars()); + assert(!s); + Expressions *atts = Expression::arraySyntaxCopy(this->atts); + return new UserAttributeDeclaration(atts, Dsymbol::arraySyntaxCopy(decl)); +} + +void UserAttributeDeclaration::semantic(Scope *sc) +{ + //printf("UserAttributeDeclaration::semantic() %p\n", this); + atts = arrayExpressionSemantic(atts, sc); + + if (decl) + { + Scope *newsc = sc; +#if 0 + if (atts && atts->dim) + { + // create new one for changes + newsc = new Scope(*sc); + newsc->flags &= ~SCOPEfree; + + // Append new atts to old one + if (!newsc->userAttributes) + newsc->userAttributes = atts; + else + newsc->userAttributes->append(atts); + } +#endif + for (size_t i = 0; i < decl->dim; i++) + { Dsymbol *s = (*decl)[i]; + + s->semantic(newsc); + } + if (newsc != sc) + { + sc->offset = newsc->offset; + newsc->pop(); + } + } +} + +void UserAttributeDeclaration::setScope(Scope *sc) +{ + //printf("UserAttributeDeclaration::setScope() %p\n", this); + if (decl) + { + Scope *newsc = sc; +#if 1 + if (atts && atts->dim) + { + // create new one for changes + newsc = new Scope(*sc); + newsc->flags &= ~SCOPEfree; + + // Append new atts to old one + if (!newsc->userAttributes) + newsc->userAttributes = atts; + else + newsc->userAttributes->append(atts); + } +#endif + for (size_t i = 0; i < decl->dim; i++) + { Dsymbol *s = (*decl)[i]; + + s->setScope(newsc); // yes, the only difference from semantic() + } + if (newsc != sc) + { + sc->offset = newsc->offset; + newsc->pop(); + } + } +} + +void UserAttributeDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('['); + argsToCBuffer(buf, atts, hgs); + AttribDeclaration::toCBuffer(buf, hgs); +} + +const char *UserAttributeDeclaration::kind() +{ + return "UserAttribute"; +} + + diff --git a/src/attrib.h b/src/attrib.h index e180ec95e648..0c3dea713c2d 100644 --- a/src/attrib.h +++ b/src/attrib.h @@ -201,4 +201,20 @@ struct CompileDeclaration : AttribDeclaration const char *kind(); }; +/** + * User defined attributes look like: + * [ args, ... ] + */ +struct UserAttributeDeclaration : AttribDeclaration +{ + Expressions *atts; + + UserAttributeDeclaration(Expressions *atts, Dsymbols *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + void setScope(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); +}; + #endif /* DMD_ATTRIB_H */ diff --git a/src/class.c b/src/class.c index 095d148017c6..12f2dbe348be 100644 --- a/src/class.c +++ b/src/class.c @@ -302,6 +302,7 @@ void ClassDeclaration::semantic(Scope *sc) { isdeprecated = true; } + userAttributes = sc->userAttributes; if (sc->linkage == LINKcpp) error("cannot create C++ classes"); @@ -1294,6 +1295,7 @@ void InterfaceDeclaration::semantic(Scope *sc) { isdeprecated = true; } + userAttributes = sc->userAttributes; // Expand any tuples in baseclasses[] for (size_t i = 0; i < baseclasses->dim; ) diff --git a/src/declaration.c b/src/declaration.c index a900f5f65278..2020c5492fd6 100644 --- a/src/declaration.c +++ b/src/declaration.c @@ -314,6 +314,7 @@ Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) void TypedefDeclaration::semantic(Scope *sc) { //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); + userAttributes = sc->userAttributes; if (sem == SemanticStart) { sem = SemanticIn; parent = sc->parent; @@ -342,6 +343,7 @@ void TypedefDeclaration::semantic(Scope *sc) return; } storage_class |= sc->stc & STCdeprecated; + userAttributes = sc->userAttributes; } else if (sem == SemanticIn) { @@ -479,6 +481,7 @@ void AliasDeclaration::semantic(Scope *sc) storage_class |= sc->stc & STCdeprecated; protection = sc->protection; + userAttributes = sc->userAttributes; // Given: // alias foo.bar.abc def; @@ -808,6 +811,8 @@ void VarDeclaration::semantic(Scope *sc) if (storage_class & STCextern && init) error("extern symbols cannot have initializers"); + userAttributes = sc->userAttributes; + AggregateDeclaration *ad = isThis(); if (ad) storage_class |= ad->storage_class & STC_TYPECTOR; diff --git a/src/dsymbol.c b/src/dsymbol.c index 72d7d6778aba..e3618d625f52 100644 --- a/src/dsymbol.c +++ b/src/dsymbol.c @@ -47,6 +47,7 @@ Dsymbol::Dsymbol() this->comment = NULL; this->scope = NULL; this->errors = false; + this->userAttributes = NULL; } Dsymbol::Dsymbol(Identifier *ident) @@ -62,6 +63,7 @@ Dsymbol::Dsymbol(Identifier *ident) this->scope = NULL; this->errors = false; this->depmsg = NULL; + this->userAttributes = NULL; } int Dsymbol::equals(Object *o) diff --git a/src/dsymbol.h b/src/dsymbol.h index 605ef1feb073..06f5066a6254 100644 --- a/src/dsymbol.h +++ b/src/dsymbol.h @@ -123,6 +123,7 @@ struct Dsymbol : Object Scope *scope; // !=NULL means context to use for semantic() bool errors; // this symbol failed to pass semantic() char *depmsg; // customized deprecation message + Expressions *userAttributes; // user defined attributes from UserAttributeDeclaration Dsymbol(); Dsymbol(Identifier *); diff --git a/src/enum.c b/src/enum.c index a12fd9a5f350..dd7bc2a0f909 100644 --- a/src/enum.c +++ b/src/enum.c @@ -113,6 +113,7 @@ void EnumDeclaration::semantic(Scope *sc) if (sc->stc & STCdeprecated) isdeprecated = 1; + userAttributes = sc->userAttributes; parent = sc->parent; protection = sc->protection; diff --git a/src/expression.h b/src/expression.h index 3c4f9f9f9ac7..6723b7a1f7f0 100644 --- a/src/expression.h +++ b/src/expression.h @@ -87,6 +87,7 @@ int checkPostblit(Loc loc, Type *t); #endif struct ArrayExp *resolveOpDollar(Scope *sc, struct ArrayExp *ae); struct SliceExp *resolveOpDollar(Scope *sc, struct SliceExp *se); +Expressions *arrayExpressionSemantic(Expressions *exps, Scope *sc); /* Interpreter: what form of return value expression is required? */ diff --git a/src/func.c b/src/func.c index be0aaf219cf2..39a0cd3f7709 100644 --- a/src/func.c +++ b/src/func.c @@ -181,6 +181,7 @@ void FuncDeclaration::semantic(Scope *sc) else linkage = sc->linkage; protection = sc->protection; + userAttributes = sc->userAttributes; if (!originalType) originalType = type; diff --git a/src/idgen.c b/src/idgen.c index 97d2a8467176..4b401d4aa91b 100644 --- a/src/idgen.c +++ b/src/idgen.c @@ -334,6 +334,7 @@ Msgtable msgtable[] = { "isSame" }, { "compiles" }, { "parameters" }, + { "getAttributes" }, }; diff --git a/src/parse.c b/src/parse.c index bf09ec5595fb..8c6940f3ee0b 100644 --- a/src/parse.c +++ b/src/parse.c @@ -481,6 +481,14 @@ Dsymbols *Parser::parseDeclDefs(int once) break; } + case TOKlbracket: + { + Expressions *exps = parseArguments(); + a = parseBlock(); + s = new UserAttributeDeclaration(exps, a); + break; + } + case TOKextern: if (peek(&token)->value != TOKlparen) { stc = STCextern; diff --git a/src/scope.c b/src/scope.c index d71fe42d30e6..d28eaf646450 100644 --- a/src/scope.c +++ b/src/scope.c @@ -82,6 +82,7 @@ Scope::Scope() this->lastdc = NULL; this->lastoffset = 0; this->docbuf = NULL; + this->userAttributes = NULL; } Scope::Scope(Scope *enclosing) @@ -130,6 +131,7 @@ Scope::Scope(Scope *enclosing) this->lastdc = NULL; this->lastoffset = 0; this->docbuf = enclosing->docbuf; + this->userAttributes = enclosing->userAttributes; assert(this != enclosing); } diff --git a/src/scope.h b/src/scope.h index 7814d54b92d5..1daa11fac8a5 100644 --- a/src/scope.h +++ b/src/scope.h @@ -103,6 +103,7 @@ struct Scope #ifdef IN_GCC Expressions *attributes; // GCC decl/type attributes #endif + Expressions *userAttributes; // user defined attributes DocComment *lastdc; // documentation comment for last symbol at this scope unsigned lastoffset; // offset in docbuf of where to insert next dec diff --git a/src/struct.c b/src/struct.c index 80305a7ec841..f755325c2bf8 100644 --- a/src/struct.c +++ b/src/struct.c @@ -418,6 +418,7 @@ void StructDeclaration::semantic(Scope *sc) assert(!isAnonymous()); if (sc->stc & STCabstract) error("structs, unions cannot be abstract"); + userAttributes = sc->userAttributes; if (sizeok == SIZEOKnone) // if not already done the addMember step { diff --git a/src/traits.c b/src/traits.c index 0260c897fa4f..d6a6a6fa5f64 100644 --- a/src/traits.c +++ b/src/traits.c @@ -358,6 +358,23 @@ Expression *TraitsExp::semantic(Scope *sc) } return new IntegerExp(loc, cd->structsize, Type::tsize_t); } + else if (ident == Id::getAttributes) + { + if (dim != 1) + goto Ldimerror; + Object *o = (*args)[0]; + Dsymbol *s = getDsymbol(o); + if (!s) + { + error("first argument is not a symbol"); + goto Lfalse; + } + //printf("getAttributes %s, %p\n", s->toChars(), s->userAttributes); + if (!s->userAttributes) + s->userAttributes = new Expressions(); + TupleExp *tup = new TupleExp(loc, s->userAttributes); + return tup->semantic(sc); + } else if (ident == Id::allMembers || ident == Id::derivedMembers) { if (dim != 1)