diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/slang-check-modifier.cpp | 163 |
1 files changed, 102 insertions, 61 deletions
diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp index 169b4696e..473b5e5da 100644 --- a/source/slang/slang-check-modifier.cpp +++ b/source/slang/slang-check-modifier.cpp @@ -80,84 +80,125 @@ namespace Slang AttributeDecl* SemanticsVisitor::lookUpAttributeDecl(Name* attributeName, Scope* scope) { - // Look up the name and see what we find. - // - // TODO: This needs to have some special filtering or naming - // rules to keep us from seeing shadowing variable declarations. - auto lookupResult = lookUp(getSession(), this, attributeName, scope, LookupMask::Attribute); - - // If the result was overloaded, - // then we aren't going to be able to extract a single decl. - if(lookupResult.isOverloaded()) - return nullptr; + auto session = getSession(); - if (lookupResult.isValid()) + // We start by looking for an existing attribute matching + // the name `attributeName`. + // { - auto decl = lookupResult.item.declRef.getDecl(); - if (auto attributeDecl = as<AttributeDecl>(decl)) - { - return attributeDecl; - } - else - { + // Look up the name and see what attributes we find. + // + auto lookupResult = lookUp(session, this, attributeName, scope, LookupMask::Attribute); + + // If the result was overloaded, then that means there + // are multiple attributes matching the name, and we + // aren't going to be able to narrow it down. + // + if(lookupResult.isOverloaded()) return nullptr; - } - } - // If we couldn't find a system attribute, try looking up as a user defined attribute - // A user defined attribute class is defined as a struct type with a "UserDefinedAttributeAttribute" modifier - lookupResult = lookUp(getSession(), this, getSession()->getNameObj(attributeName->text + "Attribute"), scope, LookupMask::type); - if (lookupResult.isOverloaded()) - { - // see if we have already created an AttributeDecl for this attribute struct - for (auto alt : lookupResult.items) + // If there is a single valid result, and it names + // an existing attribute declaration, then we can + // use it as the result. + // + if (lookupResult.isValid()) { - if (auto adecl = alt.declRef.as<AttributeDecl>()) - return adecl.getDecl(); + auto decl = lookupResult.item.declRef.getDecl(); + if (auto attributeDecl = as<AttributeDecl>(decl)) + { + return attributeDecl; + } } } - // If we still cannot find any thing, quit + + // If there wasn't already an attribute matching the + // given name, then we will look for a `struct` type + // matching the name scheme for user-defined attributes. + // + // If the attribute was `[Something(...)]` then we will + // look for a `struct` named `SomethingAttribute`. + // + LookupResult lookupResult = lookUp(session, this, session->getNameObj(attributeName->text + "Attribute"), scope, LookupMask::type); + // + // If we didn't find a matching type name, then we give up. + // if (!lookupResult.isValid() || lookupResult.isOverloaded()) return nullptr; - // Now construct an AttributeDecl for this user defined attribute class for future lookup - auto userDefAttribAttrib = lookupResult.item.declRef.decl->FindModifier<AttributeUsageAttribute>(); - if (!userDefAttribAttrib) + + + // We only allow a `struct` type to be used as an attribute + // if the type itself has an `[AttributeUsage(...)]` attribute + // attached to it. + // + auto structDecl = lookupResult.item.declRef.as<StructDecl>().getDecl(); + if(!structDecl) return nullptr; - // create an AttributeDecl for the user defined attribute - auto structAttribDef = lookupResult.item.declRef.as<StructDecl>().getDecl(); - RefPtr<AttributeDecl> attribDecl = new AttributeDecl(); - attribDecl->nameAndLoc = structAttribDef->nameAndLoc; - attribDecl->loc = structAttribDef->loc; - attribDecl->nextInContainerWithSameName = structAttribDef->nextInContainerWithSameName; - // create a __attributeTarget modifier for the attribute class definition + auto attrUsageAttr = structDecl->FindModifier<AttributeUsageAttribute>(); + if (!attrUsageAttr) + return nullptr; + + // We will now synthesize a new `AttributeDecl` to mirror + // what was declared on the `struct` type. + // + RefPtr<AttributeDecl> attrDecl = new AttributeDecl(); + attrDecl->nameAndLoc.name = attributeName; + attrDecl->nameAndLoc.loc = structDecl->nameAndLoc.loc; + attrDecl->loc = structDecl->loc; + RefPtr<AttributeTargetModifier> targetModifier = new AttributeTargetModifier(); - targetModifier->syntaxClass = userDefAttribAttrib->targetSyntaxClass; - targetModifier->loc = structAttribDef->loc; - targetModifier->next = attribDecl->modifiers.first; - attribDecl->modifiers.first = targetModifier; - structAttribDef->nextInContainerWithSameName = attribDecl.Ptr(); - // we should create UserDefinedAttribute nodes for all user defined attribute instances - attribDecl->syntaxClass = getSession()->findSyntaxClass(getSession()->getNameObj("UserDefinedAttribute")); - for (auto member : structAttribDef->Members) - { - if (auto varMember = as<VarDecl>(member)) + targetModifier->syntaxClass = attrUsageAttr->targetSyntaxClass; + targetModifier->loc = attrUsageAttr->loc; + addModifier(attrDecl, targetModifier); + + // Every attribute declaration is associated with the type + // of syntax nodes it constructs (via reflection/RTTI). + // + // User-defined attributes create instances of + // `UserDefinedAttribute`. + // + attrDecl->syntaxClass = session->findSyntaxClass(session->getNameObj("UserDefinedAttribute")); + + // The fields of the user-defined `struct` type become + // the parameters of the new attribute. + // + // TODO: This step should skip `static` fields. + // + for(auto member : structDecl->Members) + { + if(auto varMember = as<VarDecl>(member)) { - RefPtr<ParamDecl> param = new ParamDecl(); - param->nameAndLoc = member->nameAndLoc; - param->type = varMember->type; - param->loc = member->loc; - attribDecl->Members.add(param); + ensureDecl(varMember, DeclCheckState::CanUseTypeOfValueDecl); + + RefPtr<ParamDecl> paramDecl = new ParamDecl(); + paramDecl->nameAndLoc = member->nameAndLoc; + paramDecl->type = varMember->type; + paramDecl->loc = member->loc; + paramDecl->SetCheckState(DeclCheckState::Checked); + + paramDecl->ParentDecl = attrDecl; + attrDecl->Members.add(paramDecl); } } - // add the attribute class definition to the syntax tree, so it can be found - structAttribDef->ParentDecl->Members.add(attribDecl.Ptr()); - structAttribDef->ParentDecl->memberDictionaryIsValid = false; - // do necessary checks on this newly constructed node + // We need to end by putting the new attribute declaration + // into the AST, so that it can be found via lookup. + // + auto parentDecl = structDecl->ParentDecl; + // + // TODO: handle the case where `parentDecl` is generic? + // + attrDecl->ParentDecl = parentDecl; + parentDecl->Members.add(attrDecl); + parentDecl->memberDictionaryIsValid = false; + + // Finally, we perform any required semantic checks on + // the newly constructed attribute decl. + // // TODO: what check state is relevant here? - ensureDecl(attribDecl, DeclCheckState::Checked); + // + ensureDecl(attrDecl, DeclCheckState::Checked); - return attribDecl.Ptr(); + return attrDecl; } bool SemanticsVisitor::hasIntArgs(Attribute* attr, int numArgs) |
