diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index 177af086..0edcd2ec 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -346,6 +346,11 @@ void BfStructuralVisitor::Visit(BfStrideOfExpression* strideOfExpr) Visit(strideOfExpr->ToBase()); } +void BfStructuralVisitor::Visit(BfOffsetOfExpression* offsetOfExpr) +{ + Visit(offsetOfExpr->ToBase()); +} + void BfStructuralVisitor::Visit(BfDefaultExpression* defaultExpr) { Visit(defaultExpr->ToBase()); @@ -1398,6 +1403,8 @@ const char* Beefy::BfTokenToString(BfToken token) return "null"; case BfToken_Nullable: return "nullable"; + case BfToken_OffsetOf: + return "offsetof"; case BfToken_Operator: return "operator"; case BfToken_Out: diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index 9b0e24c5..5758ee14 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -158,6 +158,7 @@ enum BfToken : uint8 BfToken_New, BfToken_Null, BfToken_Nullable, + BfToken_OffsetOf, BfToken_Operator, BfToken_Out, BfToken_Override, @@ -367,6 +368,7 @@ class BfTypedValueExpression; class BfTypeAttrExpression; class BfSizeOfExpression; class BfAlignOfExpression; +class BfOffsetOfExpression; class BfStrideOfExpression; class BfDefaultExpression; class BfUninitializedExpression; @@ -490,6 +492,7 @@ public: virtual void Visit(BfSizeOfExpression* sizeOfExpr); virtual void Visit(BfAlignOfExpression* alignOfExpr); virtual void Visit(BfStrideOfExpression* strideOfExpr); + virtual void Visit(BfOffsetOfExpression* offsetOfExpr); virtual void Visit(BfDefaultExpression* defaultExpr); virtual void Visit(BfUninitializedExpression* uninitializedExpr); virtual void Visit(BfCheckTypeExpression* checkTypeExpr); @@ -2652,7 +2655,7 @@ public: class BfAlignOfExpression : public BfTypeAttrExpression { public: - BF_AST_TYPE(BfAlignOfExpression, BfTypeAttrExpression); + BF_AST_TYPE(BfAlignOfExpression, BfTypeAttrExpression); }; BF_AST_DECL(BfAlignOfExpression, BfTypeAttrExpression); class BfStrideOfExpression : public BfTypeAttrExpression @@ -2661,6 +2664,15 @@ public: BF_AST_TYPE(BfStrideOfExpression, BfTypeAttrExpression); }; BF_AST_DECL(BfStrideOfExpression, BfTypeAttrExpression); +class BfOffsetOfExpression : public BfTypeAttrExpression +{ +public: + BF_AST_TYPE(BfOffsetOfExpression, BfTypeAttrExpression); + + BfTokenNode* mCommaToken; + BfIdentifierNode* mMemberName; +}; BF_AST_DECL(BfOffsetOfExpression, BfTypeAttrExpression); + class BfDefaultExpression : public BfExpression { public: diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index 9785316e..5561e8ce 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -987,11 +987,12 @@ void BfAutoComplete::AddSelfResultTypeMembers(BfTypeInstance* typeInst, BfTypeIn bool BfAutoComplete::InitAutocomplete(BfAstNode* dotNode, BfAstNode* nameNode, String& filter) { + bool isDot = (dotNode != NULL) && (dotNode->mToken == BfToken_Dot); if (IsAutocompleteNode(nameNode)) { auto bfParser = nameNode->GetSourceData()->ToParser(); - if (mIsGetDefinition) + if ((mIsGetDefinition) || (!isDot)) { mInsertStartIdx = nameNode->GetSrcStart(); mInsertEndIdx = nameNode->GetSrcEnd(); @@ -1002,11 +1003,15 @@ bool BfAutoComplete::InitAutocomplete(BfAstNode* dotNode, BfAstNode* nameNode, S mInsertEndIdx = std::min(bfParser->mCursorIdx + 1, nameNode->GetSrcEnd()); } - filter.Append(bfParser->mSrc + mInsertStartIdx, mInsertEndIdx - mInsertStartIdx); + filter.Append(bfParser->mSrc + nameNode->GetSrcStart(), mInsertEndIdx - nameNode->GetSrcStart()); return true; } - if ((dotNode != NULL) && (IsAutocompleteNode(dotNode, 0, 1))) + int lenAdd = 0; + if (!isDot) + lenAdd++; + + if ((dotNode != NULL) && (IsAutocompleteNode(dotNode, lenAdd, 1))) { mInsertStartIdx = dotNode->GetSrcEnd(); mInsertEndIdx = dotNode->GetSrcEnd(); @@ -1558,7 +1563,7 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress "alignof", "as", "asm", "base", "break", "case", "catch", "checked", "continue", "default", "defer", "delegate", "delete", "do", "else", "false", "finally", "fixed", "for", "function", "if", "implicit", "in", "internal", "is", "new", "mixin", "null", - "out", "params", "ref", "rettype", "return", + "offsetof", "out", "params", "ref", "rettype", "return", "sealed", "sizeof", "scope", "static", "strideof", "struct", "switch", /*"this",*/ "try", "true", "typeof", "unchecked", "using", "var", "virtual", "volatile", "where", "while", "alloctype", "comptype", "decltype", "nullable", diff --git a/IDEHelper/Compiler/BfElementVisitor.cpp b/IDEHelper/Compiler/BfElementVisitor.cpp index bd0da9e9..5deb47ad 100644 --- a/IDEHelper/Compiler/BfElementVisitor.cpp +++ b/IDEHelper/Compiler/BfElementVisitor.cpp @@ -492,6 +492,16 @@ void BfElementVisitor::Visit(BfTypeAttrExpression* typeAttrExpr) VisitChild(typeAttrExpr->mCloseParen); } +void BfElementVisitor::Visit(BfOffsetOfExpression* offsetOfExpr) +{ + VisitChild(offsetOfExpr->mToken); + VisitChild(offsetOfExpr->mOpenParen); + VisitChild(offsetOfExpr->mTypeRef); + VisitChild(offsetOfExpr->mCommaToken); + VisitChild(offsetOfExpr->mMemberName); + VisitChild(offsetOfExpr->mCloseParen); +} + void BfElementVisitor::Visit(BfDefaultExpression* defaultExpr) { Visit(defaultExpr->ToBase()); diff --git a/IDEHelper/Compiler/BfElementVisitor.h b/IDEHelper/Compiler/BfElementVisitor.h index a72f3cd7..60e07b09 100644 --- a/IDEHelper/Compiler/BfElementVisitor.h +++ b/IDEHelper/Compiler/BfElementVisitor.h @@ -69,6 +69,7 @@ public: virtual void Visit(BfLocalMethodDeclaration* methodDecl); virtual void Visit(BfParameterDeclaration* paramDecl); virtual void Visit(BfTypeAttrExpression* typeAttrExpr); + virtual void Visit(BfOffsetOfExpression* offsetOfExpr); virtual void Visit(BfDefaultExpression* defaultExpr); virtual void Visit(BfUninitializedExpression* uninitializedExpr); virtual void Visit(BfCheckTypeExpression* checkTypeExpr); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index d4087ffb..ea4de760 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -10409,8 +10409,11 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie return true; } -void BfExprEvaluator::DoTypeIntAttr(BfTypeReference* typeRef, BfToken token) +void BfExprEvaluator::DoTypeIntAttr(BfTypeReference* typeRef, BfTokenNode* commaToken, BfIdentifierNode* memberName, BfToken token) { + auto autoComplete = GetAutoComplete(); + + auto type = mModule->ResolveTypeRef(typeRef, BfPopulateType_Data, BfResolveTypeRefFlag_AutoComplete); if (type == NULL) return; @@ -10433,6 +10436,72 @@ void BfExprEvaluator::DoTypeIntAttr(BfTypeReference* typeRef, BfToken token) default: break; } + if (token == BfToken_OffsetOf) + { + bool found = false; + String findName; + if (memberName != NULL) + findName = memberName->ToString(); + + BfAstNode* refNode = typeRef; + if (memberName != NULL) + refNode = memberName; + + auto checkTypeInst = typeInst; + while (checkTypeInst != NULL) + { + checkTypeInst->mTypeDef->PopulateMemberSets(); + + String filter; + if ((autoComplete != NULL) && (autoComplete->InitAutocomplete(commaToken, memberName, filter))) + { + auto activeTypeDef = mModule->GetActiveTypeDef(); + mModule->PopulateType(checkTypeInst); + + BfProtectionCheckFlags protectionCheckFlags = BfProtectionCheckFlag_None; + for (auto fieldDef : checkTypeInst->mTypeDef->mFields) + { + if (fieldDef->mIsStatic) + continue; + + if (!mModule->CheckProtection(protectionCheckFlags, typeInst, fieldDef->mDeclaringType->mProject, fieldDef->mProtection, typeInst)) + continue; + + if ((!typeInst->IsTypeMemberIncluded(fieldDef->mDeclaringType, activeTypeDef, mModule)) || + (!typeInst->IsTypeMemberAccessible(fieldDef->mDeclaringType, activeTypeDef))) + continue; + + auto& fieldInst = checkTypeInst->mFieldInstances[fieldDef->mIdx]; + autoComplete->AddField(checkTypeInst, fieldDef, &fieldInst, filter); + } + } + + BfMemberSetEntry* memberSetEntry = NULL; + if (checkTypeInst->mTypeDef->mFieldSet.TryGetWith(findName, &memberSetEntry)) + { + auto fieldDef = (BfFieldDef*)memberSetEntry->mMemberDef; + if (fieldDef != NULL) + { + if (fieldDef->mIsStatic) + mModule->Fail(StrFormat("Cannot generate an offset from static field '%s.%s'", mModule->TypeToString(type).c_str(), fieldDef->mName.c_str()), refNode); + + mModule->PopulateType(checkTypeInst); + auto& fieldInst = checkTypeInst->mFieldInstances[fieldDef->mIdx]; + attrVal = fieldInst.mDataOffset; + found = true; + break; + } + } + + checkTypeInst = checkTypeInst->mBaseType; + } + + if (!found) + { + mModule->Fail(StrFormat("Unable to locate field '%s.%s'", mModule->TypeToString(type).c_str(), findName.c_str()), refNode); + } + } + bool isUndefVal = false; if (type->IsGenericParam()) @@ -10458,17 +10527,22 @@ void BfExprEvaluator::DoTypeIntAttr(BfTypeReference* typeRef, BfToken token) void BfExprEvaluator::Visit(BfSizeOfExpression* sizeOfExpr) { - DoTypeIntAttr(sizeOfExpr->mTypeRef, BfToken_SizeOf); + DoTypeIntAttr(sizeOfExpr->mTypeRef, NULL, NULL, BfToken_SizeOf); } void BfExprEvaluator::Visit(BfAlignOfExpression* alignOfExpr) { - DoTypeIntAttr(alignOfExpr->mTypeRef, BfToken_AlignOf); + DoTypeIntAttr(alignOfExpr->mTypeRef, NULL, NULL, BfToken_AlignOf); } void BfExprEvaluator::Visit(BfStrideOfExpression* strideOfExpr) { - DoTypeIntAttr(strideOfExpr->mTypeRef, BfToken_StrideOf); + DoTypeIntAttr(strideOfExpr->mTypeRef, NULL, NULL, BfToken_StrideOf); +} + +void BfExprEvaluator::Visit(BfOffsetOfExpression* offsetOfExpr) +{ + DoTypeIntAttr(offsetOfExpr->mTypeRef, offsetOfExpr->mCommaToken, offsetOfExpr->mMemberName, BfToken_OffsetOf); } void BfExprEvaluator::Visit(BfDefaultExpression* defaultExpr) diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index df6a3121..5f2739ea 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -487,7 +487,7 @@ public: void FinishDeferredEvals(SizedArrayImpl& argValues); void FinishDeferredEvals(BfResolvedArgs& argValues); bool LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifierNode* propName); - void DoTypeIntAttr(BfTypeReference* typeRef, BfToken token); + void DoTypeIntAttr(BfTypeReference* typeRef, BfTokenNode* commaToken, BfIdentifierNode* memberName, BfToken token); //void InitializedSizedArray(BfTupleExpression* createExpr, BfSizedArrayType* arrayType); void InitializedSizedArray(BfSizedArrayType* sizedArrayType, BfTokenNode* openToken, const BfSizedArray& values, const BfSizedArray& commas, BfTokenNode* closeToken, BfTypedValue* receivingValue = NULL); void CheckDotToken(BfTokenNode* tokenNode); @@ -518,6 +518,7 @@ public: virtual void Visit(BfSizeOfExpression* sizeOfExpr) override; virtual void Visit(BfAlignOfExpression* alignOfExpr) override; virtual void Visit(BfStrideOfExpression* strideOfExpr) override; + virtual void Visit(BfOffsetOfExpression* offsetOfExpr) override; virtual void Visit(BfDefaultExpression* defaultExpr) override; virtual void Visit(BfUninitializedExpression* uninitialziedExpr) override; virtual void Visit(BfCheckTypeExpression* checkTypeExpr) override; diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index 8db3a7e4..de367db2 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -3058,6 +3058,10 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) else if (SrcPtrHasToken("nullable")) mToken = BfToken_Nullable; break; + case TOKEN_HASH('o', 'f', 'f', 's'): + if (SrcPtrHasToken("offsetof")) + mToken = BfToken_OffsetOf; + break; case TOKEN_HASH('o', 'p', 'e', 'r'): if (SrcPtrHasToken("operator")) mToken = BfToken_Operator; diff --git a/IDEHelper/Compiler/BfPrinter.cpp b/IDEHelper/Compiler/BfPrinter.cpp index f63b7877..8a772451 100644 --- a/IDEHelper/Compiler/BfPrinter.cpp +++ b/IDEHelper/Compiler/BfPrinter.cpp @@ -1653,6 +1653,17 @@ void BfPrinter::Visit(BfSizeOfExpression* sizeOfExpr) VisitChild(sizeOfExpr->mCloseParen); } +void BfPrinter::Visit(BfOffsetOfExpression* offsetOfExpr) +{ + VisitChild(offsetOfExpr->mToken); + VisitChild(offsetOfExpr->mOpenParen); + VisitChild(offsetOfExpr->mTypeRef); + VisitChild(offsetOfExpr->mCommaToken); + ExpectSpace(); + VisitChild(offsetOfExpr->mMemberName); + VisitChild(offsetOfExpr->mCloseParen); +} + void BfPrinter::Visit(BfDefaultExpression* defaultExpr) { Visit(defaultExpr->ToBase()); diff --git a/IDEHelper/Compiler/BfPrinter.h b/IDEHelper/Compiler/BfPrinter.h index 7b270b1a..815222c5 100644 --- a/IDEHelper/Compiler/BfPrinter.h +++ b/IDEHelper/Compiler/BfPrinter.h @@ -168,6 +168,7 @@ public: virtual void Visit(BfParameterDeclaration* paramDecl) override; virtual void Visit(BfTypeOfExpression* typeOfExpr) override; virtual void Visit(BfSizeOfExpression* sizeOfExpr) override; + virtual void Visit(BfOffsetOfExpression* offsetOfExpr) override; virtual void Visit(BfDefaultExpression* defaultExpr) override; virtual void Visit(BfCheckTypeExpression* checkTypeExpr) override; virtual void Visit(BfDynamicCastExpression* dynCastExpr) override; diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index c997f52b..888118bb 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -1871,6 +1871,26 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat MEMBER_SET_CHECKED(typeAttrExpr, mCloseParen, tokenNode); exprLeft = typeAttrExpr; } + else if (token == BfToken_OffsetOf) + { + BfOffsetOfExpression* typeAttrExpr = mAlloc->Alloc(); + ReplaceNode(tokenNode, typeAttrExpr); + typeAttrExpr->mToken = tokenNode; + tokenNode = ExpectTokenAfter(typeAttrExpr, BfToken_LParen); + MEMBER_SET_CHECKED(typeAttrExpr, mOpenParen, tokenNode); + auto typeRef = CreateTypeRefAfter(typeAttrExpr); + MEMBER_SET_CHECKED(typeAttrExpr, mTypeRef, typeRef); + + tokenNode = ExpectTokenAfter(typeAttrExpr, BfToken_Comma); + MEMBER_SET_CHECKED(typeAttrExpr, mCommaToken, tokenNode); + + auto nameNode = ExpectIdentifierAfter(typeAttrExpr); + MEMBER_SET_CHECKED(typeAttrExpr, mMemberName, nameNode); + + tokenNode = ExpectTokenAfter(typeAttrExpr, BfToken_RParen); + MEMBER_SET_CHECKED(typeAttrExpr, mCloseParen, tokenNode); + exprLeft = typeAttrExpr; + } else if (token == BfToken_Default) { auto defaultExpr = mAlloc->Alloc();