Skip to content

Commit

Permalink
Merge pull request #3947 from IgorStepanov/module-attributes
Browse files Browse the repository at this point in the history
[enh] implement UDA for module declaration
  • Loading branch information
9rnsr committed Oct 5, 2014
2 parents b7ace0b + 0bbdedf commit 2efa27a
Show file tree
Hide file tree
Showing 13 changed files with 185 additions and 34 deletions.
2 changes: 1 addition & 1 deletion src/attrib.h
Expand Up @@ -208,7 +208,7 @@ class CompileDeclaration : public AttribDeclaration

/**
* User defined attributes look like:
* [ args, ... ]
* @(args, ...)
*/
class UserAttributeDeclaration : public AttribDeclaration
{
Expand Down
59 changes: 36 additions & 23 deletions src/hdrgen.c
Expand Up @@ -62,29 +62,7 @@ void genhdrfile(Module *m)
HdrGenState hgs;
hgs.hdrgen = true;

if (m->md)
{
if (m->md->isdeprecated)
{
if (m->md->msg)
{
buf.writestring("deprecated(");
toCBuffer(m->md->msg, &buf, &hgs);
buf.writestring(") ");
}
else
buf.writestring("deprecated ");
}
buf.writestring("module ");
buf.writestring(m->md->toChars());
buf.writeByte(';');
buf.writenl();
}
for (size_t i = 0; i < m->members->dim; i++)
{
Dsymbol *s = (*m->members)[i];
toCBuffer(s, &buf, &hgs);
}
toCBuffer(m, &buf, &hgs);

// Transfer image to file
m->hdrfile->setbuffer(buf.data, buf.offset);
Expand Down Expand Up @@ -2927,6 +2905,41 @@ class PrettyPrintVisitor : public Visitor
}
buf->writeByte(')');
}

void visit(Module *m)
{
if (m->md)
{
if (m->userAttribDecl)
{
buf->writestring("@(");
argsToBuffer(m->userAttribDecl->atts);
buf->writeByte(')');
buf->writenl();
}
if (m->md->isdeprecated)
{
if (m->md->msg)
{
buf->writestring("deprecated(");
m->md->msg->accept(this);
buf->writestring(") ");
}
else
buf->writestring("deprecated ");
}

buf->writestring("module ");
buf->writestring(m->md->toChars());
buf->writeByte(';');
buf->writenl();
}
for (size_t i = 0; i < m->members->dim; i++)
{
Dsymbol *s = (*m->members)[i];
s->accept(this);
}
}
};

void toCBuffer(Statement *s, OutBuffer *buf, HdrGenState *hgs)
Expand Down
16 changes: 16 additions & 0 deletions src/module.c
Expand Up @@ -23,6 +23,7 @@
#include "dsymbol.h"
#include "expression.h"
#include "lexer.h"
#include "attrib.h"

#ifdef IN_GCC
#include "d-dmd-gcc.h"
Expand Down Expand Up @@ -727,6 +728,11 @@ void Module::semantic()
runDeferredSemantic();
}

if (userAttribDecl)
{
userAttribDecl->semantic(sc);
}

if (!scope)
{
sc = sc->pop();
Expand Down Expand Up @@ -756,6 +762,11 @@ void Module::semantic2()
s->semantic2(sc);
}

if (userAttribDecl)
{
userAttribDecl->semantic2(sc);
}

sc = sc->pop();
sc->pop();
semanticRun = PASSsemantic2done;
Expand Down Expand Up @@ -783,6 +794,11 @@ void Module::semantic3()
s->semantic3(sc);
}

if (userAttribDecl)
{
userAttribDecl->semantic3(sc);
}

sc = sc->pop();
sc->pop();
semanticRun = PASSsemantic3done;
Expand Down
77 changes: 67 additions & 10 deletions src/parse.c
Expand Up @@ -101,24 +101,71 @@ Dsymbols *Parser::parseModule()
Dsymbols *decldefs;
bool isdeprecated = false;
Expression *msg = NULL;
Token *tk;
Expressions *udas = NULL;
StorageClass stc;

if (token.value == TOKdeprecated)
if (skipAttributes(&token, &tk) && tk->value == TOKmodule)
{
Token *tk;
if (skipParensIf(peek(&token), &tk) && tk->value == TOKmodule)
while (token.value != TOKmodule)
{
// deprecated (...) module ...
isdeprecated = true;
nextToken();
if (token.value == TOKlparen)
switch (token.value)
{
check(TOKlparen);
msg = parseAssignExp();
check(TOKrparen);
case TOKdeprecated:
{
// deprecated (...) module ...
if (isdeprecated)
{
error("there is only one deprecation attribute allowed for module declaration");
}
else
{
isdeprecated = true;
}
nextToken();
if (token.value == TOKlparen)
{
check(TOKlparen);
msg = parseAssignExp();
check(TOKrparen);
}
break;
}
case TOKat:
{
Expressions *exps = NULL;
stc = parseAttribute(&exps);

if (stc == STCproperty || stc == STCnogc || stc == STCdisable ||
stc == STCsafe || stc == STCtrusted || stc == STCsystem)
{
error("@%s attribute for module declaration is not supported", token.toChars());
}
else
{
udas = UserAttributeDeclaration::concat(udas, exps);
}
if (stc)
nextToken();
break;
}
default:
{
error("'module' expected instead of %s", token.toChars());
nextToken();
break;
}
}
}
}

if (udas)
{
Dsymbols *a = new Dsymbols();
UserAttributeDeclaration *udad = new UserAttributeDeclaration(udas, a);
mod->userAttribDecl = udad;
}

// ModuleDeclation leads off
if (token.value == TOKmodule)
{
Expand Down Expand Up @@ -6044,7 +6091,17 @@ int Parser::skipAttributes(Token *t, Token **pt)
case TOKoverride:
case TOKabstract:
case TOKsynchronized:
break;
case TOKdeprecated:
if (peek(t)->value == TOKlparen)
{
t = peek(t);
if (!skipParens(t, &t))
goto Lerror;
// t is on the next of closing parenthesis
continue;
}
break;
case TOKnothrow:
case TOKpure:
case TOKref:
Expand Down
4 changes: 4 additions & 0 deletions src/traits.c
Expand Up @@ -735,6 +735,10 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
e->error("first argument is not a symbol");
goto Lfalse;
}
if (s->isImport())
{
s = s->isImport()->mod;
}
//printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->scope);
UserAttributeDeclaration *udad = s->userAttribDecl;
TupleExp *tup = new TupleExp(e->loc, udad ? udad->getAttributes() : new Expressions());
Expand Down
7 changes: 7 additions & 0 deletions test/compilable/extra-files/testheaderudamodule.di
@@ -0,0 +1,7 @@
@(1, UDA(2))
module testheaderudamodule;
struct UDA
{
int a;
}
void main();
5 changes: 5 additions & 0 deletions test/compilable/imports/udamodule1.d
@@ -0,0 +1,5 @@
@(1) deprecated("This module will be removed.") @(2) module imports.udamodule1;

void foo()
{
}
7 changes: 7 additions & 0 deletions test/compilable/imports/udamodule2.d
@@ -0,0 +1,7 @@
@UDA(1) @UDA(2) module imports.udamodule2;

import imports.udamodule2a;

void foo()
{
}
6 changes: 6 additions & 0 deletions test/compilable/imports/udamodule2a.d
@@ -0,0 +1,6 @@
module imports.udamodule2a;

struct UDA
{
int a;
}
13 changes: 13 additions & 0 deletions test/compilable/testheaderudamodule.d
@@ -0,0 +1,13 @@
// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheaderudamodule.di
// PERMUTE_ARGS:
// POST_SCRIPT: compilable/extra-files/header-postscript.sh testheaderudamodule

@(1, UDA(2))
module testheaderudamodule;

struct UDA
{
int a;
}

void main() {}
11 changes: 11 additions & 0 deletions test/compilable/udamodule1.d
@@ -0,0 +1,11 @@
// REQUIRED_ARGS:
// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
compilable/udamodule1.d(9): Deprecation: module imports.udamodule1 is deprecated - This module will be removed.
---
*/
import imports.udamodule1;

void main() { foo(); }
5 changes: 5 additions & 0 deletions test/compilable/udamodule2.d
@@ -0,0 +1,5 @@
import imports.udamodule2;
import imports.udamodule2a;

enum Attrib = __traits(getAttributes, imports.udamodule2);
static assert(Attrib[0] == UDA(1) && Attrib[1] == UDA(2));
7 changes: 7 additions & 0 deletions test/fail_compilation/moduleundefuda.d
@@ -0,0 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/moduleundefuda.d(7): Error: undefined identifier undef
---
*/
@undef module moduleundefuda;

0 comments on commit 2efa27a

Please sign in to comment.