1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 03:28:20 +02:00

Added [IgnoreErrors] block attribute

This commit is contained in:
Brian Fiete 2020-08-16 08:33:51 -07:00
parent 65d960a6e6
commit 99419097c5
16 changed files with 307 additions and 79 deletions

View file

@ -28,11 +28,12 @@ namespace System
Alloc = 0x40000,
Delete = 0x80000,
Alias = 0x100000,
Block = 0x200000,
All = Assembly | Module | Class | Struct | Enum | Constructor |
Method | Property | Field | StaticField | Interface | Parameter |
Delegate | Function | ReturnValue | GenericParameter | Invocation | MemberAccess |
Alloc | Delete | Alias,
Alloc | Delete | Alias | Block,
}
public enum ReflectKind
@ -137,6 +138,14 @@ namespace System
}
[AttributeUsage(.Block)]
public struct IgnoreErrorsAttribute : Attribute
{
public this(bool stopOnErrors = false)
{
}
}
[AttributeUsage(.Method | .Class | .Struct | .Enum)]
public struct OptimizeAttribute : Attribute
{

View file

@ -5,7 +5,7 @@ namespace System
}
public enum AttributeTargets
{
{
Assembly = 0x0001,
Module = 0x0002,
Class = 0x0004,
@ -28,11 +28,12 @@ namespace System
Alloc = 0x40000,
Delete = 0x80000,
Alias = 0x100000,
Block = 0x200000,
All = Assembly | Module | Class | Struct | Enum | Constructor |
Method | Property | Field | StaticField | Interface | Parameter |
Delegate | Function | ReturnValue | GenericParameter | Invocation | MemberAccess |
Alloc | Delete | Alias,
Alloc | Delete | Alias | Block,
}
public enum ReflectKind
@ -120,33 +121,43 @@ namespace System
[AttributeUsage(.Class | .Struct | .Interface | .Method | .Constructor)]
public struct AlwaysIncludeAttribute : Attribute
{
bool mAssumeInstantiated;
public bool AssumeInstantiated
{
get { return mAssumeInstantiated; }
set mut { mAssumeInstantiated = value; }
set { }
}
public bool IncludeAllMethods
{
set { }
}
}
[AttributeUsage(.MemberAccess | .Alloc | .Delete)]
[AttributeUsage(.MemberAccess | .Alloc)]
public struct FriendAttribute : Attribute
{
}
[AttributeUsage(.Block)]
public struct IgnoreErrorsAttribute : Attribute
{
public this(bool stopOnErrors = false)
{
}
}
[AttributeUsage(.Method | .Class | .Struct | .Enum)]
public struct OptimizeAttribute : Attribute
{
}
[AttributeUsage(.Method | .Class | .Struct | .Enum)]
public struct UseLLVMAttribute : Attribute
{
}
[AttributeUsage(.Method | .Class | .Struct | .Enum)]
public struct OptimizeAttribute : Attribute
{
}
[AttributeUsage(.Method /*2*/ | .StaticField)]
public struct CLinkAttribute : Attribute
{
@ -165,7 +176,6 @@ namespace System
public this(String linkName)
{
}
public this(MangleKind mangleKind)
@ -190,7 +200,7 @@ namespace System
}
}
[Obsolete("Use [CallingConvention(.Stdcall)]", false)]
[AttributeUsage(.Method | .Delegate | .Function)]
public struct StdCallAttribute : Attribute
{
@ -222,21 +232,6 @@ namespace System
{
}
public this(String intrinName, Type t0)
{
}
public this(String intrinName, Type t0, Type t1)
{
}
public this(String intrinName, Type t0, Type t1, Type t2)
{
}
}
[AttributeUsage(.Class | .Struct /*2*/)]
@ -268,6 +263,7 @@ namespace System
}
/// This attribute is required on constructors that include 'append' allocations.
[AttributeUsage(.Constructor)]
public struct AllowAppendAttribute : Attribute
{
@ -348,7 +344,7 @@ namespace System
public struct ExportAttribute : Attribute
{
}
[AttributeUsage(.StaticField | .Field, .NotInherited)]
@ -359,28 +355,36 @@ namespace System
}
}
/// The [Checked] attribute is used to mark a method or a method invocation as being "checked", meaning
/// that the method applies extra runtime checks such as bounds checking or other parameter or state validation.
[AttributeUsage(.Invocation | .Method | .Property)]
public struct CheckedAttribute : Attribute
{
}
/// The [Unchecked] attribute is used to mark a method or a method invocation as being "unchecked", meaning
/// that the method omits runtime checks such as bounds checking or other parameter or state validation.
[AttributeUsage(.Invocation | .Method | .Property)]
public struct UncheckedAttribute : Attribute
{
}
/// Generally used as a per-method optimization, [DisableChecks] will cause calls within this method to
/// call the unchecked version of methods. By default, only debug builds perform checked calls.
[AttributeUsage(.Method | .Constructor)]
public struct DisableChecksAttribute : Attribute
{
}
/// Generally used as a per-method optimization, [DisableObjectAccessChecks] will avoid the runtime per-object-access
/// checks which by default are only applied in debug builds anyway.
[AttributeUsage(.Method | .MemberAccess)]
public struct DisableObjectAccessChecksAttribute : Attribute
{
}
[AttributeUsage(.Method | .Constructor | .Class | .Struct | .Alias)]
[AttributeUsage(.Method | .Constructor | .Class | .Struct | .Alias | .Interface)]
public struct ObsoleteAttribute : Attribute
{
public this(bool isError)
@ -418,17 +422,17 @@ namespace System
}
}
/// If [NoDiscard] is used on a method, the the compiler will show a warning if the result is discarded.
/// If used on a type, the compiler will show an warning if any method returns that type and the caller discards the result.
[AttributeUsage(.Method | .Class | .Struct)]
public struct NoDiscardAttribute : Attribute
{
public this()
{
}
public this(String message)
{
}
}
}
}

View file

@ -121,6 +121,11 @@ void BfStructuralVisitor::Visit(BfStatement* stmt)
Visit(stmt->ToBase());
}
void BfStructuralVisitor::Visit(BfAttributedStatement* attribStmt)
{
Visit(attribStmt->ToBase());
}
void BfStructuralVisitor::Visit(BfLabelableStatement* labelableStmt)
{
Visit(labelableStmt->ToBase());
@ -753,8 +758,11 @@ bool BfAstNode::IsMissingSemicolon()
else
return false;
}
if (auto attribExpr = BfNodeDynCastExact<BfAttributedStatement>(this))
return (attribExpr->mStatement == NULL) || (attribExpr->mStatement->IsMissingSemicolon());
if (auto stmt = BfNodeDynCast<BfStatement>(this))
return stmt->mTrailingSemicolon == NULL;
return stmt->mTrailingSemicolon == NULL;
return false;
}
@ -769,6 +777,7 @@ bool BfAstNode::IsExpression()
return false;
return block->mChildArr.GetLast()->IsExpression();
}
return IsA<BfExpression>();
}

View file

@ -255,6 +255,7 @@ class BfLabelableStatement;
class BfExpression;
class BfExpressionStatement;
class BfAttributedExpression;
class BfAttributedStatement;
class BfLiteralExpression;
class BfBlock;
class BfBlockExtension;
@ -410,8 +411,9 @@ public:
virtual void Visit(BfLabeledBlock* labeledBlock);
virtual void Visit(BfExpression* expr);
virtual void Visit(BfExpressionStatement* exprStmt);
virtual void Visit(BfAttributedExpression* attribExpr);
virtual void Visit(BfAttributedExpression* attribExpr);
virtual void Visit(BfStatement* stmt);
virtual void Visit(BfAttributedStatement* attribStmt);
virtual void Visit(BfLabelableStatement* labelableStmt);
virtual void Visit(BfTypedValueExpression* typedValueExpr);
@ -2612,6 +2614,15 @@ public:
BfExpression* mExpression;
}; BF_AST_DECL(BfAttributedExpression, BfExpression);
class BfAttributedStatement : public BfStatement
{
public:
BF_AST_TYPE(BfAttributedStatement, BfStatement);
BfAttributeDirective* mAttributes;
BfAstNode* mStatement;
}; BF_AST_DECL(BfAttributedStatement, BfStatement);
class BfObjectCreateExpression : public BfMethodBoundExpression
{
public:

View file

@ -1499,7 +1499,11 @@ bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken
BfAttributeState attributeState;
attributeState.mTarget = (BfAttributeTargets)(BfAttributeTargets_MemberAccess);
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget);
isFriend = (attributeState.mCustomAttributes != NULL) && (attributeState.mCustomAttributes->Contains(mModule->mCompiler->mFriendAttributeTypeDef));
if ((attributeState.mCustomAttributes != NULL) && (attributeState.mCustomAttributes->Contains(mModule->mCompiler->mFriendAttributeTypeDef)))
{
isFriend = true;
attributeState.mUsed = true;
}
mInsertStartIdx = attrIdentifier->mAttributes->GetSrcEnd();
}

View file

@ -435,6 +435,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
mObsoleteAttributeTypeDef = NULL;
mErrorAttributeTypeDef = NULL;
mWarnAttributeTypeDef = NULL;
mIgnoreErrorsAttributeTypeDef = NULL;
mLastAutocompleteModule = NULL;
}
@ -6309,6 +6310,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
mObsoleteAttributeTypeDef = _GetRequiredType("System.ObsoleteAttribute");
mErrorAttributeTypeDef = _GetRequiredType("System.ErrorAttribute");
mWarnAttributeTypeDef = _GetRequiredType("System.WarnAttribute");
mIgnoreErrorsAttributeTypeDef = _GetRequiredType("System.IgnoreErrorsAttribute");
for (int i = 0; i < BfTypeCode_Length; i++)
mContext->mPrimitiveStructTypes[i] = NULL;

View file

@ -401,6 +401,7 @@ public:
BfTypeDef* mObsoleteAttributeTypeDef;
BfTypeDef* mErrorAttributeTypeDef;
BfTypeDef* mWarnAttributeTypeDef;
BfTypeDef* mIgnoreErrorsAttributeTypeDef;
int mCurTypeId;

View file

@ -114,6 +114,14 @@ void BfElementVisitor::Visit(BfStatement* stmt)
VisitChild(stmt->mTrailingSemicolon);
}
void BfElementVisitor::Visit(BfAttributedStatement* attribStmt)
{
Visit(attribStmt->ToBase());
VisitChild(attribStmt->mAttributes);
VisitChild(attribStmt->mStatement);
}
void BfElementVisitor::Visit(BfLabelableStatement* labelableStmt)
{
Visit(labelableStmt->ToBase());

View file

@ -18,6 +18,7 @@ public:
virtual void Visit(BfExpressionStatement* exprStmt);
virtual void Visit(BfAttributedExpression* attribExpr);
virtual void Visit(BfStatement* stmt);
virtual void Visit(BfAttributedStatement* attribStmt);
virtual void Visit(BfLabelableStatement* labelableStmt);
virtual void Visit(BfTypedValueExpression* typedValueExpr);

View file

@ -213,16 +213,16 @@ bool BfMethodMatcher::IsMemberAccessible(BfTypeInstance* typeInst, BfTypeDef* de
if (mActiveTypeDef == NULL)
mActiveTypeDef = mModule->GetActiveTypeDef();
// This needs to be outside the `IsInSpecializedSection`. Note that mActiveTypeDef does not pose a constraint here
// Note that mActiveTypeDef does not pose a constraint here
if (!typeInst->IsTypeMemberIncluded(declaringType, mActiveTypeDef, mModule))
return false;
// This may not be completely correct - BUT if we don't have this then even Dictionary TKey's operator == won't be considered accessible
if ((!mModule->IsInSpecializedSection()) && (mActiveTypeDef->mTypeDeclaration != NULL))
{
if (!typeInst->IsTypeMemberAccessible(declaringType, mActiveTypeDef))
return false;
auto visibleProjectSet = mModule->GetVisibleProjectSet();
if ((visibleProjectSet != NULL) && (!typeInst->IsTypeMemberAccessible(declaringType, visibleProjectSet)))
{
return false;
}
return true;
}
@ -2582,15 +2582,34 @@ void BfExprEvaluator::Visit(BfTypeReference* typeRef)
void BfExprEvaluator::Visit(BfAttributedExpression* attribExpr)
{
BfAttributeState attributeState;
attributeState.mTarget = (BfAttributeTargets)(BfAttributeTargets_Invocation | BfAttributeTargets_MemberAccess);
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attribExpr->mAttributes, attributeState.mTarget);
attributeState.mTarget = (BfAttributeTargets)(BfAttributeTargets_Invocation | BfAttributeTargets_MemberAccess);
if (auto block = BfNodeDynCast<BfBlock>(attribExpr->mExpression))
attributeState.mTarget = BfAttributeTargets_Block;
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attribExpr->mAttributes, attributeState.mTarget);
SetAndRestoreValue<BfAttributeState*> prevAttributeState(mModule->mAttributeState, &attributeState);
VisitChild(attribExpr->mExpression);
if (auto ignoreErrorsAttrib = attributeState.mCustomAttributes->Get(mModule->mCompiler->mIgnoreErrorsAttributeTypeDef))
{
SetAndRestoreValue<bool> ignoreErrors(mModule->mIgnoreErrors, true);
if (!ignoreErrorsAttrib->mCtorArgs.IsEmpty())
{
auto constant = mModule->mCurTypeInstance->mConstHolder->GetConstant(ignoreErrorsAttrib->mCtorArgs[0]);
if (constant->mBool)
attributeState.mFlags = BfAttributeState::Flag_StopOnError;
}
VisitChild(attribExpr->mExpression);
attributeState.mUsed = true;
}
else
{
VisitChild(attribExpr->mExpression);
}
if (!attributeState.mUsed)
{
mModule->Fail("Unused attributes", attribExpr->mAttributes);
}
}
}
void BfExprEvaluator::Visit(BfBlock* blockExpr)
@ -4106,9 +4125,15 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL))
{
if (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mFriendAttributeTypeDef))
{
mPropGetMethodFlags = (BfGetMethodInstanceFlags)(mPropGetMethodFlags | BfGetMethodInstanceFlag_Friend);
mModule->mAttributeState->mUsed = true;
}
if (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mDisableObjectAccessChecksAttributeTypeDef))
{
mPropGetMethodFlags = (BfGetMethodInstanceFlags)(mPropGetMethodFlags | BfGetMethodInstanceFlag_DisableObjectAccessChecks);
mModule->mAttributeState->mUsed = true;
}
}
if (mPropDef->mIsStatic)
@ -12740,8 +12765,8 @@ BfAllocTarget BfExprEvaluator::ResolveAllocTarget(BfAstNode* allocNode, BfTokenN
}
}
}
else if (attrib.mType->mTypeDef == mModule->mCompiler->mFriendAttributeTypeDef)
allocTarget.mIsFriend = true;
else if (attrib.mType->mTypeDef == mModule->mCompiler->mFriendAttributeTypeDef)
allocTarget.mIsFriend = true;
}
if (outCustomAttributes != NULL)
@ -14059,7 +14084,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
bool allowImplicitThis = false;
BfAstNode* methodNodeSrc = target;
BfAttributeState attributeState;
attributeState.mTarget = (BfAttributeTargets)(BfAttributeTargets_Invocation | BfAttributeTargets_MemberAccess);
@ -14194,7 +14219,8 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
{
if (attrIdentifier->mIdentifier != NULL)
methodNodeSrc = attrIdentifier->mIdentifier;
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget);
attributeState.mSrc = attrIdentifier->mAttributes;
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget);
if (attrIdentifier->mIdentifier != NULL)
targetFunctionName = attrIdentifier->mIdentifier->ToString();
}
@ -14370,7 +14396,8 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
{
if (attrIdentifier->mIdentifier != NULL)
methodNodeSrc = attrIdentifier->mIdentifier;
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget);
attributeState.mSrc = attrIdentifier->mAttributes;
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget);
targetFunctionName = attrIdentifier->mIdentifier->ToString();
}
else
@ -14476,7 +14503,8 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
{
if (attrIdentifier->mIdentifier != NULL)
methodNodeSrc = attrIdentifier->mIdentifier;
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget);
attributeState.mSrc = attrIdentifier->mAttributes;
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget);
}
allowImplicitThis = true;
@ -14635,12 +14663,18 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
}
BfCheckedKind checkedKind = BfCheckedKind_NotSet;
if (attributeState.mCustomAttributes != NULL)
if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL))
{
if (attributeState.mCustomAttributes->Contains(mModule->mCompiler->mCheckedAttributeTypeDef))
if (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mCheckedAttributeTypeDef))
{
checkedKind = BfCheckedKind_Checked;
if (attributeState.mCustomAttributes->Contains(mModule->mCompiler->mUncheckedAttributeTypeDef))
mModule->mAttributeState->mUsed = true;
}
if (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mUncheckedAttributeTypeDef))
{
checkedKind = BfCheckedKind_Unchecked;
mModule->mAttributeState->mUsed = true;
}
}
SetAndRestoreValue<bool> prevUsedAsStatement(mUsedAsStatement, mUsedAsStatement || isCascade);
@ -14648,6 +14682,11 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
mResult = MatchMethod(methodNodeSrc, methodBoundExpr, thisValue, allowImplicitThis, bypassVirtual, targetFunctionName, argValues, methodGenericArguments, checkedKind);
argValues.HandleFixits(mModule);
if ((mModule->mAttributeState == &attributeState) && (!attributeState.mUsed))
{
mModule->Fail("Unused attributes", attributeState.mSrc);
}
if (isCascade)
{
if (outCascadeValue != NULL)
@ -16910,7 +16949,7 @@ void BfExprEvaluator::DoMemberReference(BfMemberReferenceExpression* memberRefEx
BfAutoComplete* autoComplete = GetAutoComplete();
if (autoComplete != NULL)
{
{
SetAndRestoreValue<bool> prevFriendSet(autoComplete->mHasFriendSet, (attributeState.mCustomAttributes != NULL) && (attributeState.mCustomAttributes->Contains(mModule->mCompiler->mFriendAttributeTypeDef)));
if (memberRefExpr->mTarget == NULL)
@ -19260,7 +19299,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
{
auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox);
if (!convertedValue)
return;
return;
if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality))
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
else

View file

@ -2226,15 +2226,27 @@ BfProjectSet* BfModule::GetVisibleProjectSet()
{
auto typeInstance = type->ToTypeInstance();
if (typeInstance == NULL)
{
if (type->IsSizedArray())
_AddType(type->GetUnderlyingType());
return;
}
if (typeInstance->IsTuple())
{
for (auto& fieldInst : typeInstance->mFieldInstances)
{
if (fieldInst.mDataIdx != -1)
_AddType(fieldInst.mResolvedType);
}
}
_AddProject(typeInstance->mTypeDef->mProject);
if (typeInstance->mGenericTypeInfo == NULL)
return;
for (auto type : typeInstance->mGenericTypeInfo->mTypeGenericArguments)
{
if (seenTypes.Add(type))
_AddType(type);
}
_AddType(type);
}
};
if (mCurTypeInstance != NULL)
@ -2460,7 +2472,10 @@ bool BfModule::CheckProtection(BfProtection protection, bool allowProtected, boo
((protection == BfProtection_Private) && (allowPrivate)))
return true;
if ((mAttributeState != NULL) && (mAttributeState->mCustomAttributes != NULL) && (mAttributeState->mCustomAttributes->Contains(mCompiler->mFriendAttributeTypeDef)))
return true;
{
mAttributeState->mUsed = true;
return true;
}
return false;
}
@ -2564,7 +2579,10 @@ bool BfModule::CheckProtection(BfProtectionCheckFlags& flags, BfTypeInstance* me
}
if ((mAttributeState != NULL) && (mAttributeState->mCustomAttributes != NULL) && (mAttributeState->mCustomAttributes->Contains(mCompiler->mFriendAttributeTypeDef)))
{
mAttributeState->mUsed = true;
return true;
}
return false;
}
@ -2584,7 +2602,9 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
BP_ZONE("BfModule::Fail");
if (mIgnoreErrors)
{
{
if (mAttributeState != NULL)
mAttributeState->mFlags = (BfAttributeState::Flags)(mAttributeState->mFlags | BfAttributeState::Flag_HadError);
return NULL;
}
@ -4167,19 +4187,25 @@ void BfModule::CreateValueTypeEqualsMethod(bool strictEquals)
auto _SizedIndex = [&](BfIRValue target, BfIRValue index)
{
BfTypedValue result;
if (sizedArrayType->mElementType->IsSizeAligned())
{
auto ptrType = CreatePointerType(sizedArrayType->mElementType);
auto ptrValue = mBfIRBuilder->CreateBitCast(target, mBfIRBuilder->MapType(ptrType));
auto gepResult = mBfIRBuilder->CreateInBoundsGEP(ptrValue, index);
return BfTypedValue(gepResult, sizedArrayType->mElementType, BfTypedValueKind_Addr);
result = BfTypedValue(gepResult, sizedArrayType->mElementType, BfTypedValueKind_Addr);
}
else
{
auto indexResult = CreateIndexedValue(sizedArrayType->mElementType, target, index);
return BfTypedValue(indexResult, sizedArrayType->mElementType, BfTypedValueKind_Addr);
result = BfTypedValue(indexResult, sizedArrayType->mElementType, BfTypedValueKind_Addr);
}
if (!result.mType->IsValueType())
result = LoadValue(result);
return result;
};
if (sizedArrayType->mElementCount > 6)
@ -9874,6 +9900,7 @@ static String GetAttributesTargetListString(BfAttributeTargets attrTarget)
AddAttributeTargetName(flagsLeft, BfAttributeTargets_MemberAccess, resultStr, "member access");
AddAttributeTargetName(flagsLeft, BfAttributeTargets_Alloc, resultStr, "allocations");
AddAttributeTargetName(flagsLeft, BfAttributeTargets_Alias, resultStr, "aliases");
AddAttributeTargetName(flagsLeft, BfAttributeTargets_Block, resultStr, "blocks");
if (resultStr.IsEmpty())
return "<nothing>";
return resultStr;

View file

@ -660,13 +660,25 @@ public:
class BfAttributeState
{
public:
enum Flags
{
Flag_None,
Flag_StopOnError = 1,
Flag_HadError = 2
};
public:
Flags mFlags;
BfAstNode* mSrc;
BfAttributeTargets mTarget;
BfCustomAttributes* mCustomAttributes;
BfCustomAttributes* mCustomAttributes;
bool mUsed;
BfAttributeState()
{
mSrc = NULL;
mFlags = Flag_None;
mTarget = BfAttributeTargets_None;
mCustomAttributes = NULL;
mUsed = false;
@ -1553,6 +1565,7 @@ public:
virtual void Visit(BfExpressionStatement* expressionStmt) override;
virtual void Visit(BfVariableDeclaration* varDecl) override;
virtual void Visit(BfLocalMethodDeclaration* methodDecl) override;
virtual void Visit(BfAttributedStatement* attribStmt) override;
virtual void Visit(BfThrowStatement* throwStmt) override;
virtual void Visit(BfDeleteStatement* deleteStmt) override;
virtual void Visit(BfSwitchStatement* switchStmt) override;

View file

@ -3866,6 +3866,10 @@ BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createS
return localMethodDecl;
}
else if (token == BfToken_LBracket)
{
return CreateAttributedStatement(tokenNode);
}
}
if (auto identifier = BfNodeDynCast<BfIdentifierNode>(node))
@ -5311,7 +5315,10 @@ BfAttributeDirective* BfReducer::CreateAttributeDirective(BfTokenNode* startToke
auto nextNode = mVisitorPos.GetNext();
tokenNode = BfNodeDynCast<BfTokenNode>(nextNode);
if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_RBracket))
{
mVisitorPos.MoveNext();
goto Do_RBracket;
}
return attributeDirective;
}
MEMBER_SET(attributeDirective, mCtorCloseParen, tokenNode);
@ -5340,6 +5347,44 @@ Do_RBracket:
return attributeDirective;
}
BfStatement* BfReducer::CreateAttributedStatement(BfTokenNode* tokenNode)
{
auto attrib = CreateAttributeDirective(tokenNode);
if (attrib == NULL)
return NULL;
BfAstNode* stmt = CreateStatementAfter(attrib);
if (stmt != NULL)
{
bool isValid = true;
auto checkNode = stmt;
if (auto exprStatement = BfNodeDynCast<BfExpressionStatement>(checkNode))
checkNode = exprStatement->mExpression;
if ((checkNode->IsA<BfObjectCreateExpression>()) ||
(checkNode->IsA<BfInvocationExpression>()) ||
(checkNode->IsA<BfVariableDeclaration>()) ||
(checkNode->IsA<BfBlock>()))
{
BfAttributedStatement* attribStmt = mAlloc->Alloc<BfAttributedStatement>();
ReplaceNode(attrib, attribStmt);
attribStmt->mAttributes = attrib;
MEMBER_SET(attribStmt, mStatement, stmt);
return attribStmt;
}
}
Fail("Prefixed attributes can only be used on allocations, invocations, blocks, or variable declarations", attrib);
BfAttributedStatement* attribStmt = mAlloc->Alloc<BfAttributedStatement>();
ReplaceNode(attrib, attribStmt);
attribStmt->mAttributes = attrib;
if (stmt != NULL)
MEMBER_SET(attribStmt, mStatement, stmt);
return attribStmt;
}
BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool onlyAllowIdentifier)
{
auto attrib = CreateAttributeDirective(tokenNode);
@ -5347,8 +5392,8 @@ BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool
return NULL;
if (!onlyAllowIdentifier)
{
auto expr = CreateExpressionAfter(attrib);
{
BfExpression* expr = CreateExpressionAfter(attrib);
if (expr != NULL)
{
if (auto identifier = BfNodeDynCast<BfIdentifierNode>(expr))
@ -5362,7 +5407,8 @@ BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool
if ((expr->IsA<BfObjectCreateExpression>()) ||
(expr->IsA<BfInvocationExpression>()) ||
(expr->IsA<BfVariableDeclaration>()))
(expr->IsA<BfVariableDeclaration>()) ||
(expr->IsA<BfBlock>()))
{
BfAttributedExpression* attribExpr = mAlloc->Alloc<BfAttributedExpression>();
ReplaceNode(attrib, attribExpr);
@ -5370,9 +5416,9 @@ BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool
MEMBER_SET(attribExpr, mExpression, expr);
return attribExpr;
}
}
}
Fail("Prefixed attributes can only be used on constructor calls, invocations, or variable declarations", attrib);
Fail("Prefixed attributes can only be used on allocations, invocations, blocks, or variable declarations", attrib);
BfAttributedExpression* attribExpr = mAlloc->Alloc<BfAttributedExpression>();
ReplaceNode(attrib, attribExpr);

View file

@ -192,6 +192,7 @@ public:
BfFieldDtorDeclaration* CreateFieldDtorDeclaration(BfAstNode* srcNode);
BfFieldDeclaration* CreateFieldDeclaration(BfTokenNode* tokenNode, BfTypeReference* typeRef, BfIdentifierNode* nameIdentifier, BfFieldDeclaration* prevFieldDeclaration);
BfAttributeDirective* CreateAttributeDirective(BfTokenNode* startToken);
BfStatement* CreateAttributedStatement(BfTokenNode* tokenNode);
BfExpression* CreateAttributedExpression(BfTokenNode* tokenNode, bool onlyAllowIdentifier);
BfDelegateBindExpression* CreateDelegateBindExpression(BfAstNode* allocNode);
BfLambdaBindExpression* CreateLambdaBindExpression(BfAstNode* allocNode, BfTokenNode* parenToken = NULL);

View file

@ -1492,7 +1492,8 @@ enum BfAttributeTargets : int32
BfAttributeTargets_Alloc = 0x40000,
BfAttributeTargets_Delete = 0x80000,
BfAttributeTargets_Alias = 0x100000,
BfAttributeTargets_All = 0x1FFFFF
BfAttributeTargets_Block = 0x200000,
BfAttributeTargets_All = 0x3FFFFF
};
class BfAttributeData

View file

@ -3394,9 +3394,19 @@ void BfModule::VisitCodeBlock(BfBlock* block)
{
if (mCurMethodState->mCurScope->mExprEvaluator != NULL)
{
// Evaluate last child as an expression
mCurMethodState->mCurScope->mExprEvaluator->VisitChild(expr);
mCurMethodState->mCurScope->mExprEvaluator->FinishExpressionResult();
if ((mAttributeState != NULL) &&
((mAttributeState->mFlags & (BfAttributeState::Flag_StopOnError | BfAttributeState::Flag_HadError)) == (BfAttributeState::Flag_StopOnError | BfAttributeState::Flag_HadError)))
{
// Resolve as just 'false'
mCurMethodState->mCurScope->mExprEvaluator->mResult = GetDefaultTypedValue(GetPrimitiveType(BfTypeCode_Boolean));
}
else
{
// Evaluate last child as an expression
mCurMethodState->mCurScope->mExprEvaluator->VisitChild(expr);
mCurMethodState->mCurScope->mExprEvaluator->FinishExpressionResult();
}
break;
}
else if (mCurMethodState->InMainMixinScope())
@ -3416,10 +3426,17 @@ void BfModule::VisitCodeBlock(BfBlock* block)
}
}
}
UpdateSrcPos(child);
BfAutoParentNodeEntry autoParentNode(this, child);
child->Accept(this);
if ((mAttributeState != NULL) &&
((mAttributeState->mFlags & (BfAttributeState::Flag_StopOnError | BfAttributeState::Flag_HadError)) == (BfAttributeState::Flag_StopOnError | BfAttributeState::Flag_HadError)))
{
// Ignore child
}
else
child->Accept(this);
mSystem->CheckLockYield();
@ -3740,6 +3757,41 @@ void BfModule::Visit(BfLocalMethodDeclaration* methodDecl)
Fail("Local method declarations must be wrapped in a block statement", methodDecl->mMethodDeclaration->mNameNode);
}
void BfModule::Visit(BfAttributedStatement* attribStmt)
{
BfAttributeState attributeState;
attributeState.mTarget = (BfAttributeTargets)(BfAttributeTargets_Invocation | BfAttributeTargets_MemberAccess);
if (auto block = BfNodeDynCast<BfBlock>(attribStmt->mStatement))
attributeState.mTarget = BfAttributeTargets_Block;
attributeState.mCustomAttributes = GetCustomAttributes(attribStmt->mAttributes, attributeState.mTarget);
SetAndRestoreValue<BfAttributeState*> prevAttributeState(mAttributeState, &attributeState);
if (auto ignoreErrorsAttrib = attributeState.mCustomAttributes->Get(mCompiler->mIgnoreErrorsAttributeTypeDef))
{
SetAndRestoreValue<bool> ignoreErrors(mIgnoreErrors, true);
if (!ignoreErrorsAttrib->mCtorArgs.IsEmpty())
{
auto constant = mCurTypeInstance->mConstHolder->GetConstant(ignoreErrorsAttrib->mCtorArgs[0]);
if (constant->mBool)
attributeState.mFlags = BfAttributeState::Flag_StopOnError;
}
VisitChild(attribStmt->mStatement);
attributeState.mUsed = true;
}
else
{
VisitChild(attribStmt->mStatement);
}
if (!attributeState.mUsed)
{
Fail("Unused attributes", attribStmt->mAttributes);
}
}
void BfModule::Visit(BfExpression* expression)
{
UpdateSrcPos(expression);