Skip to content

Commit

Permalink
Support 'package(ident)' syntax (parser/AST)
Browse files Browse the repository at this point in the history
This commit adds capability of parsing and resolving
explicit package defined for package protection attribute. Adjusting
acess checks to use it will be done in separate commit.
  • Loading branch information
Dicebot committed Aug 24, 2014
1 parent d6c770a commit c595ba4
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/attrib.h
Expand Up @@ -102,6 +102,11 @@ class ProtDeclaration : public AttribDeclaration
public:
Prot protection;

/**
* Params:
* p = protection attribute data
* decl = declarations which are affected by this protection attribute
*/
ProtDeclaration(Prot p, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
Expand Down
2 changes: 2 additions & 0 deletions src/dsymbol.c
Expand Up @@ -1552,8 +1552,10 @@ Dsymbol *DsymbolTable::update(Dsymbol *s)
Prot::Prot(PROTKIND kind)
{
this->kind = kind;
this->pkg = NULL;
}


bool Prot::isMoreRestrictiveThan(Prot other)
{
return this->kind < other.kind;
Expand Down
1 change: 1 addition & 0 deletions src/dsymbol.h
Expand Up @@ -106,6 +106,7 @@ enum PROTKIND
struct Prot
{
PROTKIND kind;
Package* pkg;

Prot(PROTKIND kind = PROTundefined);

Expand Down
20 changes: 19 additions & 1 deletion src/hdrgen.c
Expand Up @@ -2994,10 +2994,28 @@ const char *linkageToChars(LINK linkage)
void protectionToBuffer(OutBuffer *buf, Prot prot)
{
const char *p = protectionToChars(prot);

if (p)
buf->writestring(p);
}

if ((prot.kind == PROTpackage) && (prot.pkg))
{
Package* ppkg = prot.pkg;

if (ppkg)
{
buf->writeByte('(');
while (ppkg)
{
buf->writestring(ppkg->ident->string);
ppkg = ppkg->parent ? ppkg->parent->isPackage() : NULL;
if (ppkg)
buf->writeByte('.');
}
buf->writeByte(')');
}
}
}

const char *protectionToChars(Prot prot)
{
Expand Down
15 changes: 15 additions & 0 deletions src/module.c
Expand Up @@ -1051,6 +1051,21 @@ Module *Package::isPackageMod()
return NULL;
}

bool Package::isAncestorPackageOf(Package* pkg)
{
if (!pkg)
return false;

while (pkg)
{
if (this == pkg)
return true;
pkg = pkg->parent ? pkg->parent->isPackage() : NULL;
}

return false;
}

/****************************************************
* Input:
* packages[] the pkg1.pkg2 of pkg1.pkg2.mod
Expand Down
15 changes: 15 additions & 0 deletions src/module.h
Expand Up @@ -53,6 +53,21 @@ class Package : public ScopeDsymbol

Package *isPackage() { return this; }

/**
* Checks if pkg is a sub-package of this
*
* For example, if this qualifies to 'a1.a2' and pkg - to 'a1.a2.a3',
* this function returns 'true'. If it is other way around or qualified
* package paths conflict function returns 'false'.
*
* Params:
* pkg = possible subpackage
*
* Returns:
* see description
*/
bool isAncestorPackageOf(Package* pkg);

void semantic(Scope *sc) { }
Dsymbol *search(Loc loc, Identifier *ident, int flags = IgnoreNone);
void accept(Visitor *v) { v->visit(this); }
Expand Down
61 changes: 59 additions & 2 deletions src/parse.c
Expand Up @@ -218,6 +218,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes
pAttrs->comment = token.blockComment;
}
PROTKIND prot;
Identifiers* pkg_prot_idents = NULL;
StorageClass stc;
Condition *condition;

Expand Down Expand Up @@ -648,7 +649,6 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes
case TOKpublic: prot = PROTpublic; goto Lprot;
case TOKexport: prot = PROTexport; goto Lprot;
Lprot:
nextToken();
if (pAttrs->protection.kind != PROTundefined)
{
if (pAttrs->protection.kind != prot)
Expand All @@ -658,11 +658,32 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes
error("redundant protection attribute '%s'", protectionToChars(prot));
}
pAttrs->protection.kind = prot;

nextToken();

if (pAttrs->protection.kind == PROTpackage)
{
// optional qualified package identifier to bind
// protection to
if ((pAttrs->protection.kind == PROTpackage) && (token.value == TOKlparen))
{
pkg_prot_idents = parseQualifiedIdentifier("protection package");
check(TOKrparen);
}
}

a = parseBlock(pLastDecl, pAttrs);
if (pAttrs->protection.kind != PROTundefined)
{
if ((pAttrs->protection.kind == PROTpackage) && pkg_prot_idents)
{
Dsymbol* tmp;
Package::resolve(pkg_prot_idents, &tmp, NULL);
pAttrs->protection.pkg = tmp ? tmp->isPackage() : NULL;
}

s = new ProtDeclaration(pAttrs->protection, a);
pAttrs->protection.kind = PROTundefined;
pAttrs->protection = Prot();
}
break;

Expand Down Expand Up @@ -1199,6 +1220,42 @@ LINK Parser::parseLinkage(Identifiers **pidents)
return link;
}

/***********************************
* Parse ident1.ident2.ident3
*
* Params:
* entity = what qualified identifier is expected to resolve into.
* Used only for better error message
*
* Returns:
* array of identifiers with actual qualified one stored last
*/
Identifiers* Parser::parseQualifiedIdentifier(const char* entity)
{
Identifiers *qualified = new Identifiers();

do
{
nextToken();

if (token.value != TOKidentifier)
{
error(
"%s expected as dot-separated identifiers, got '%s'",
entity,
token.toChars()
);
}

Identifier *id = token.ident;
qualified->push(id);

nextToken();
} while (token.value == TOKdot);

return qualified;
}

/**************************************
* Parse a debug conditional
*/
Expand Down
1 change: 1 addition & 0 deletions src/parse.h
Expand Up @@ -93,6 +93,7 @@ class Parser : public Lexer
TypeQualified *parseTypeof();
Type *parseVector();
LINK parseLinkage(Identifiers **);
Identifiers* parseQualifiedIdentifier(const char* entity);
Condition *parseDebugCondition();
Condition *parseVersionCondition();
Condition *parseStaticIfCondition();
Expand Down

0 comments on commit c595ba4

Please sign in to comment.