1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Added support for global:: lookups

This commit is contained in:
Brian Fiete 2025-05-18 12:13:15 +02:00
parent ee50457885
commit 958a1630aa
13 changed files with 202 additions and 28 deletions

View file

@ -1611,6 +1611,8 @@ const char* Beefy::BfTokenToString(BfToken token)
return ";"; return ";";
case BfToken_Colon: case BfToken_Colon:
return ":"; return ":";
case BfToken_ColonColon:
return "::";
case BfToken_Comma: case BfToken_Comma:
return ","; return ",";
case BfToken_Dot: case BfToken_Dot:

View file

@ -304,6 +304,7 @@ enum BfToken : uint8
BfToken_RDblChevron, BfToken_RDblChevron,
BfToken_Semicolon, BfToken_Semicolon,
BfToken_Colon, BfToken_Colon,
BfToken_ColonColon,
BfToken_Comma, BfToken_Comma,
BfToken_Dot, BfToken_Dot,
BfToken_DotDot, BfToken_DotDot,
@ -2014,6 +2015,13 @@ public:
BfTokenNode* mColonToken; BfTokenNode* mColonToken;
BfAstNode* mTargetNode; // . : or identifier BfAstNode* mTargetNode; // . : or identifier
BfAttributeDirective* mAttributes; BfAttributeDirective* mAttributes;
BfAstNode* GetTargetNode()
{
if ((mColonToken != NULL) && (mColonToken->mToken == BfToken_ColonColon))
return mColonToken;
return mTargetNode;
}
}; BF_AST_DECL(BfScopeNode, BfAstNode); }; BF_AST_DECL(BfScopeNode, BfAstNode);
class BfNewNode : public BfAstNode class BfNewNode : public BfAstNode
@ -2108,6 +2116,12 @@ public:
ASTREF(BfIdentifierNode*) mLeft; ASTREF(BfIdentifierNode*) mLeft;
ASTREF(BfTokenNode*) mDot; ASTREF(BfTokenNode*) mDot;
ASTREF(BfIdentifierNode*) mRight; ASTREF(BfIdentifierNode*) mRight;
bool IsGlobalLookup()
{
return (mDot != NULL) && (mDot->mToken == BfToken_ColonColon);
}
}; BF_AST_DECL(BfQualifiedNameNode, BfIdentifierNode); }; BF_AST_DECL(BfQualifiedNameNode, BfIdentifierNode);
class BfUsingDirective : public BfStatement class BfUsingDirective : public BfStatement
@ -2599,6 +2613,12 @@ public:
ASTREF(BfTypeReference*) mLeft; ASTREF(BfTypeReference*) mLeft;
ASTREF(BfTokenNode*) mDot; ASTREF(BfTokenNode*) mDot;
ASTREF(BfTypeReference*) mRight; ASTREF(BfTypeReference*) mRight;
bool IsGlobalLookup()
{
return (mDot != NULL) && (mDot->mToken == BfToken_ColonColon);
}
}; BF_AST_DECL(BfQualifiedTypeReference, BfTypeReference); }; BF_AST_DECL(BfQualifiedTypeReference, BfTypeReference);
class BfResolvedTypeReference : public BfTypeReference class BfResolvedTypeReference : public BfTypeReference
@ -3036,6 +3056,13 @@ public:
BfAstNode* mTargetNode; BfAstNode* mTargetNode;
BfAstNode* GetScopeNameNode()
{
if ((mColonToken != NULL) && (mColonToken->mToken == BfToken_ColonColon))
return mColonToken;
return mScopeName;
}
// virtual bool IsMissingSemicolon() override // virtual bool IsMissingSemicolon() override
// { // {
// return BfNodeDynCastExact<BfBlock>(mTargetNode) == NULL; // return BfNodeDynCastExact<BfBlock>(mTargetNode) == NULL;
@ -3059,6 +3086,13 @@ public:
BfAstNode* mTarget; BfAstNode* mTarget;
BfTokenNode* mColonToken; BfTokenNode* mColonToken;
BfAstNode* mScopeName; // :, mixin, or identifier BfAstNode* mScopeName; // :, mixin, or identifier
BfAstNode* GetScopeNameNode()
{
if ((mColonToken != NULL) && (mColonToken->mToken == BfToken_ColonColon))
return mColonToken;
return mScopeName;
}
}; BF_AST_DECL(BfScopedInvocationTarget, BfAstNode); }; BF_AST_DECL(BfScopedInvocationTarget, BfAstNode);
class BfInvocationExpression : public BfMethodBoundExpression class BfInvocationExpression : public BfMethodBoundExpression

View file

@ -1853,7 +1853,7 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress
{ {
"alignof", "append", "as", "asm", "base", "break", "case", "catch", "checked", "continue", "const", "default", "defer", "alignof", "append", "as", "asm", "base", "break", "case", "catch", "checked", "continue", "const", "default", "defer",
"delegate", "delete", "do", "else", "false", "finally", "delegate", "delete", "do", "else", "false", "finally",
"fixed", "for", "function", "if", "implicit", "in", "internal", "is", "isconst", "new", "mixin", "not", "null", "fixed", "for", "function", "global", "if", "implicit", "in", "internal", "is", "isconst", "new", "mixin", "not", "null",
"offsetof", "out", "params", "readonly", "ref", "rettype", "return", "offsetof", "out", "params", "readonly", "ref", "rettype", "return",
"sealed", "sizeof", "scope", "static", "strideof", "struct", "switch", /*"this",*/ "try", "true", "typeof", "unchecked", "sealed", "sizeof", "scope", "static", "strideof", "struct", "switch", /*"this",*/ "try", "true", "typeof", "unchecked",
"using", "var", "virtual", "volatile", "where", "while", "using", "var", "virtual", "volatile", "where", "while",
@ -1873,7 +1873,7 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress
const char* tokens[] = const char* tokens[] =
{ {
"abstract", "append", "base", "class", "concrete", "const", "abstract", "append", "base", "class", "concrete", "const",
"delegate", "extern", "enum", "explicit", "extension", "function", "delegate", "extern", "enum", "explicit", "extension", "function", "global",
"interface", "in", "implicit", "internal", "mixin", "namespace", "new", "interface", "in", "implicit", "internal", "mixin", "namespace", "new",
"operator", "out", "override", "params", "private", "protected", "public", "readonly", "ref", "rettype", "return", "operator", "out", "override", "params", "private", "protected", "public", "readonly", "ref", "rettype", "return",
"scope", "sealed", "static", "struct", "this", "typealias", "scope", "sealed", "static", "struct", "this", "typealias",
@ -1926,6 +1926,16 @@ bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken
if (!WantsEntries()) if (!WantsEntries())
return false; return false;
bool isGlobalLookup = true;
if (auto dotTokenNode = BfNodeDynCast<BfTokenNode>(dotToken))
{
if (dotTokenNode->mToken == BfToken_ColonColon)
{
CheckNode(memberName, false, false);
return false;
}
}
BfAttributedIdentifierNode* attrIdentifier = NULL; BfAttributedIdentifierNode* attrIdentifier = NULL;
bool isAutocompletingName = false; bool isAutocompletingName = false;
if ((attrIdentifier = BfNodeDynCast<BfAttributedIdentifierNode>(memberName))) if ((attrIdentifier = BfNodeDynCast<BfAttributedIdentifierNode>(memberName)))

View file

@ -17224,7 +17224,7 @@ void BfExprEvaluator::ResolveAllocTarget(BfAllocTarget& allocTarget, BfAstNode*
if (auto scopeNode = BfNodeDynCast<BfScopeNode>(allocNode)) if (auto scopeNode = BfNodeDynCast<BfScopeNode>(allocNode))
{ {
newToken = scopeNode->mScopeToken; newToken = scopeNode->mScopeToken;
allocTarget.mScopeData = mModule->FindScope(scopeNode->mTargetNode, true); allocTarget.mScopeData = mModule->FindScope(scopeNode->GetTargetNode(), true);
if (autoComplete != NULL) if (autoComplete != NULL)
{ {
@ -17799,7 +17799,9 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo
} }
auto targetNameNode = targetSrc; auto targetNameNode = targetSrc;
if (scopedInvocationTarget != NULL) if (scopedInvocationTarget != NULL)
targetNameNode = scopedInvocationTarget->mTarget; {
targetNameNode = scopedInvocationTarget->GetScopeNameNode();
}
while (true) while (true)
{ {
@ -18214,7 +18216,7 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo
auto checkNode = origTargetSrc; auto checkNode = origTargetSrc;
if (scopedInvocationTarget != NULL) if (scopedInvocationTarget != NULL)
{ {
auto targetScope = mModule->FindScope(scopedInvocationTarget->mScopeName, curMethodState->mMixinState); auto targetScope = mModule->FindScope(scopedInvocationTarget->GetScopeNameNode(), curMethodState->mMixinState);
if (targetScope != NULL) if (targetScope != NULL)
{ {
mixinState->mTargetScope = targetScope; mixinState->mTargetScope = targetScope;
@ -19106,7 +19108,20 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
if (GetAutoComplete() != NULL) if (GetAutoComplete() != NULL)
GetAutoComplete()->CheckMemberReference(qualifiedName->mLeft, qualifiedName->mDot, qualifiedName->mRight); GetAutoComplete()->CheckMemberReference(qualifiedName->mLeft, qualifiedName->mDot, qualifiedName->mRight);
if (qualifiedName->mLeft->GetSrcLength() == 4) bool isGlobalLookup = false;
if (auto qualifiedNameNode = BfNodeDynCast<BfQualifiedNameNode>(target))
{
if (qualifiedNameNode->IsGlobalLookup())
{
if (auto subQualifiedNameNode = BfNodeDynCast<BfQualifiedNameNode>(qualifiedNameNode->mRight))
{
qualifiedName = subQualifiedNameNode;
isGlobalLookup = true;
}
}
}
if ((!isGlobalLookup) && (qualifiedName->mLeft->GetSrcLength() == 4))
{ {
if (CheckIsBase(qualifiedName->mLeft)) if (CheckIsBase(qualifiedName->mLeft))
bypassVirtual = true; bypassVirtual = true;
@ -19127,6 +19142,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
targetFunctionName = qualifiedName->mRight->ToString(); targetFunctionName = qualifiedName->mRight->ToString();
bool hadError = false; bool hadError = false;
if (!isGlobalLookup)
thisValue = LookupIdentifier(qualifiedName->mLeft, true, &hadError); thisValue = LookupIdentifier(qualifiedName->mLeft, true, &hadError);
CheckResultForReading(thisValue); CheckResultForReading(thisValue);
@ -19141,18 +19157,22 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
if ((!thisValue) && (mPropDef == NULL)) if ((!thisValue) && (mPropDef == NULL))
{ {
auto typeLookupFlags = (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowGlobalContainer | BfResolveTypeRefFlag_IgnoreLookupError);
if (isGlobalLookup)
typeLookupFlags = (BfResolveTypeRefFlags)(typeLookupFlags | BfResolveTypeRefFlag_GlobalLookup);
// Identifier not found. Static method? Just check speculatively don't throw error // Identifier not found. Static method? Just check speculatively don't throw error
BfType* type; BfType* type;
{ {
//SetAndRestoreValue<bool> prevIgnoreErrors(mModule->mIgnoreErrors, true); //SetAndRestoreValue<bool> prevIgnoreErrors(mModule->mIgnoreErrors, true);
type = mModule->ResolveTypeRef(qualifiedName->mLeft, NULL, BfPopulateType_DataAndMethods, (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowGlobalContainer | BfResolveTypeRefFlag_IgnoreLookupError)); type = mModule->ResolveTypeRef(qualifiedName->mLeft, NULL, BfPopulateType_DataAndMethods, typeLookupFlags);
} }
if (type == NULL) if (type == NULL)
{ {
//SetAndRestoreValue<bool> prevIgnoreErrors(mModule->mIgnoreErrors, true); //SetAndRestoreValue<bool> prevIgnoreErrors(mModule->mIgnoreErrors, true);
type = mModule->ResolveTypeRef(qualifiedName, methodGenericArguments, BfPopulateType_DataAndMethods, (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowGlobalContainer | BfResolveTypeRefFlag_IgnoreLookupError)); type = mModule->ResolveTypeRef(qualifiedName, methodGenericArguments, BfPopulateType_DataAndMethods, typeLookupFlags);
if (type != NULL) if (type != NULL)
{ {
// This is a CTOR call, treat it as such // This is a CTOR call, treat it as such

View file

@ -16568,7 +16568,7 @@ BfScopeData* BfModule::FindScope(BfAstNode* scopeName, BfMixinState* fromMixinSt
if (auto tokenNode = BfNodeDynCast<BfTokenNode>(scopeName)) if (auto tokenNode = BfNodeDynCast<BfTokenNode>(scopeName))
{ {
if (tokenNode->GetToken() == BfToken_Colon) if ((tokenNode->GetToken() == BfToken_Colon) || (tokenNode->GetToken() == BfToken_ColonColon))
{ {
if ((!allowAcrossDeferredBlock) && (mCurMethodState->mInDeferredBlock)) if ((!allowAcrossDeferredBlock) && (mCurMethodState->mInDeferredBlock))
{ {

View file

@ -10519,6 +10519,8 @@ BfTypeDef* BfModule::FindTypeDefRaw(const BfAtomComposite& findName, int numGene
if (mSystem->mTypeDefs.TryGet(findName, NULL)) if (mSystem->mTypeDefs.TryGet(findName, NULL))
mSystem->FindTypeDef(findName, numGenericArgs, useProject, BfAtomComposite(), allowPrivate, &lookupCtx); mSystem->FindTypeDef(findName, numGenericArgs, useProject, BfAtomComposite(), allowPrivate, &lookupCtx);
if ((resolveFlags & BfResolveTypeRefFlag_GlobalLookup) == 0)
{
for (auto& checkNamespace : useTypeDef->mNamespaceSearch) for (auto& checkNamespace : useTypeDef->mNamespaceSearch)
{ {
BfAtom* atom = findName.mParts[0]; BfAtom* atom = findName.mParts[0];
@ -10527,6 +10529,7 @@ BfTypeDef* BfModule::FindTypeDefRaw(const BfAtomComposite& findName, int numGene
mSystem->FindTypeDef(findName, numGenericArgs, useProject, checkNamespace, allowPrivate, &lookupCtx); mSystem->FindTypeDef(findName, numGenericArgs, useProject, checkNamespace, allowPrivate, &lookupCtx);
} }
} }
}
if (!lookupCtx.HasValidMatch()) if (!lookupCtx.HasValidMatch())
{ {
@ -10550,7 +10553,7 @@ BfTypeDef* BfModule::FindTypeDefRaw(const BfAtomComposite& findName, int numGene
} }
} }
if ((!lookupCtx.HasValidMatch()) && (typeInstance == NULL)) if ((!lookupCtx.HasValidMatch()) && (typeInstance == NULL) && ((resolveFlags & BfResolveTypeRefFlag_GlobalLookup) == 0))
{ {
if (useTypeDef->mOuterType != NULL) if (useTypeDef->mOuterType != NULL)
return FindTypeDefRaw(findName, numGenericArgs, typeInstance, useTypeDef->mOuterType, error); return FindTypeDefRaw(findName, numGenericArgs, typeInstance, useTypeDef->mOuterType, error);
@ -10591,6 +10594,12 @@ BfTypeDef* BfModule::FindTypeDef(const BfAtomComposite& findName, int numGeneric
if (useTypeDef != NULL) if (useTypeDef != NULL)
useTypeDef = useTypeDef->GetDefinition(); useTypeDef = useTypeDef->GetDefinition();
if ((resolveFlags & BfResolveTypeRefFlag_GlobalLookup) != 0)
{
// No need to cache
return FindTypeDefRaw(findName, numGenericArgs, typeInstance, useTypeDef, error, NULL, resolveFlags);
}
if ((typeInstance == NULL) && (useTypeDef == NULL)) if ((typeInstance == NULL) && (useTypeDef == NULL))
{ {
BfProject* project = NULL; BfProject* project = NULL;
@ -11589,6 +11598,12 @@ BfType* BfModule::ResolveTypeRef_Ref(BfTypeReference* typeRef, BfPopulateType po
if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(typeRef)) if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(typeRef))
{ {
if (qualifiedTypeRef->IsGlobalLookup())
{
resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_GlobalLookup);
return ResolveTypeRef_Ref(qualifiedTypeRef->mRight, populateType, resolveFlags, numGenericArgs);
}
//TODO: Determine why we had this prevIgnoreErrors set here. It causes things like IEnumerator<Hey.Test<INVALIDNAME>> not fail //TODO: Determine why we had this prevIgnoreErrors set here. It causes things like IEnumerator<Hey.Test<INVALIDNAME>> not fail
// properly on INVALIDNAME // properly on INVALIDNAME
SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, /*true*/mIgnoreErrors); SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, /*true*/mIgnoreErrors);

View file

@ -2630,6 +2630,13 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate, bool disablePrepro
mToken = BfToken_Dot; mToken = BfToken_Dot;
mSyntaxToken = BfSyntaxToken_Token; mSyntaxToken = BfSyntaxToken_Token;
} }
else if (mSrc[mSrcIdx] == ':')
{
mSrcIdx++;
mTokenEnd = mSrcIdx;
mToken = BfToken_ColonColon;
mSyntaxToken = BfSyntaxToken_Token;
}
else else
{ {
mToken = BfToken_Colon; mToken = BfToken_Colon;

View file

@ -4248,6 +4248,11 @@ BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createS
FailAfter("Expected scope name", deferStmt); FailAfter("Expected scope name", deferStmt);
} }
} }
else if (nextTokenNode->GetToken() == BfToken_ColonColon)
{
MEMBER_SET(deferStmt, mColonToken, nextTokenNode);
mVisitorPos.MoveNext();
}
else if (nextTokenNode->GetToken() == BfToken_LParen) else if (nextTokenNode->GetToken() == BfToken_LParen)
{ {
mPassInstance->Warn(0, "Syntax deprecated", nextTokenNode); mPassInstance->Warn(0, "Syntax deprecated", nextTokenNode);
@ -5868,7 +5873,7 @@ BfTypeReference* BfReducer::CreateRefTypeRef(BfTypeReference* elementType, BfTok
return refTypeRef; return refTypeRef;
} }
BfIdentifierNode* BfReducer::CompactQualifiedName(BfAstNode* leftNode) BfIdentifierNode* BfReducer::CompactQualifiedName(BfAstNode* leftNode, bool allowGlobalLookup)
{ {
AssertCurrentNode(leftNode); AssertCurrentNode(leftNode);
@ -5879,9 +5884,15 @@ BfIdentifierNode* BfReducer::CompactQualifiedName(BfAstNode* leftNode)
auto leftIdentifier = (BfIdentifierNode*)leftNode; auto leftIdentifier = (BfIdentifierNode*)leftNode;
while (true) while (true)
{ {
bool isGlobalLookup = false;
auto nextToken = mVisitorPos.Get(mVisitorPos.mReadPos + 1); auto nextToken = mVisitorPos.Get(mVisitorPos.mReadPos + 1);
auto tokenNode = BfNodeDynCast<BfTokenNode>(nextToken); auto tokenNode = BfNodeDynCast<BfTokenNode>(nextToken);
if ((tokenNode == NULL) || ((tokenNode->GetToken() != BfToken_Dot) /*&& (tokenNode->GetToken() != BfToken_QuestionDot)*/)) if ((tokenNode != NULL) && (tokenNode->mToken == BfToken_ColonColon) && (leftNode->IsExact<BfIdentifierNode>()) && (leftNode->Equals("global")) && (allowGlobalLookup))
{
isGlobalLookup = true;
}
else if ((tokenNode == NULL) || ((tokenNode->GetToken() != BfToken_Dot) /*&& (tokenNode->GetToken() != BfToken_QuestionDot)*/))
return leftIdentifier; return leftIdentifier;
auto nextNextToken = mVisitorPos.Get(mVisitorPos.mReadPos + 2); auto nextNextToken = mVisitorPos.Get(mVisitorPos.mReadPos + 2);
@ -5906,6 +5917,22 @@ BfIdentifierNode* BfReducer::CompactQualifiedName(BfAstNode* leftNode)
return leftIdentifier; return leftIdentifier;
} }
if (isGlobalLookup)
{
// For 'global::', we put 'global' on the left and the rest on the right which is different from normal
mVisitorPos.MoveNext(); // past .
mVisitorPos.MoveNext(); // past right
auto rightSide = CompactQualifiedName(rightIdentifier, false);
auto qualifiedNameNode = mAlloc->Alloc<BfQualifiedNameNode>();
ReplaceNode(leftIdentifier, qualifiedNameNode);
qualifiedNameNode->mLeft = leftIdentifier;
MEMBER_SET(qualifiedNameNode, mDot, tokenNode);
MEMBER_SET(qualifiedNameNode, mRight, rightSide);
return qualifiedNameNode;
}
// If the previous dotted span failed (IE: had chevrons) then don't insert qualified names in the middle of it // If the previous dotted span failed (IE: had chevrons) then don't insert qualified names in the middle of it
auto prevNodeToken = BfNodeDynCast<BfTokenNode>(prevNode); auto prevNodeToken = BfNodeDynCast<BfTokenNode>(prevNode);
if ((prevNodeToken != NULL) && if ((prevNodeToken != NULL) &&
@ -7935,7 +7962,7 @@ BfInvocationExpression* BfReducer::CreateInvocationExpression(BfAstNode* target,
if (auto nextToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext())) if (auto nextToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()))
{ {
if (nextToken->GetToken() == BfToken_Colon) if ((nextToken->GetToken() == BfToken_Colon) || (nextToken->GetToken() == BfToken_ColonColon))
{ {
auto scopedInvocationTarget = CreateScopedInvocationTarget(invocationExpr->mTarget, nextToken); auto scopedInvocationTarget = CreateScopedInvocationTarget(invocationExpr->mTarget, nextToken);
invocationExpr->SetSrcEnd(scopedInvocationTarget->GetSrcEnd()); invocationExpr->SetSrcEnd(scopedInvocationTarget->GetSrcEnd());
@ -8317,6 +8344,10 @@ BfScopedInvocationTarget* BfReducer::CreateScopedInvocationTarget(BfAstNode*& ta
MEMBER_SET(scopedInvocationTarget, mColonToken, colonToken); MEMBER_SET(scopedInvocationTarget, mColonToken, colonToken);
mVisitorPos.MoveNext(); mVisitorPos.MoveNext();
if (colonToken->mToken == BfToken_ColonColon)
return scopedInvocationTarget;
if (auto nextToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext())) if (auto nextToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()))
{ {
if ((nextToken->GetToken() == BfToken_Colon) || (nextToken->GetToken() == BfToken_Mixin)) if ((nextToken->GetToken() == BfToken_Colon) || (nextToken->GetToken() == BfToken_Mixin))
@ -8473,7 +8504,7 @@ BfAstNode* BfReducer::CreateAllocNode(BfTokenNode* allocToken)
auto nextToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()); auto nextToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext());
if (nextToken == NULL) if (nextToken == NULL)
return allocToken; return allocToken;
if ((nextToken->mToken != BfToken_Colon) && (nextToken->mToken != BfToken_LBracket)) if ((nextToken->mToken != BfToken_Colon) && (nextToken->mToken != BfToken_ColonColon) && (nextToken->mToken != BfToken_LBracket))
return allocToken; return allocToken;
auto scopeNode = mAlloc->Alloc<BfScopeNode>(); auto scopeNode = mAlloc->Alloc<BfScopeNode>();
@ -8504,6 +8535,11 @@ BfAstNode* BfReducer::CreateAllocNode(BfTokenNode* allocToken)
FailAfter("Expected scope name", scopeNode); FailAfter("Expected scope name", scopeNode);
} }
} }
else if (nextToken->mToken == BfToken_ColonColon)
{
MEMBER_SET(scopeNode, mColonToken, nextToken);
mVisitorPos.MoveNext();
}
nextToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext()); nextToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.GetNext());
if (nextToken == NULL) if (nextToken == NULL)

View file

@ -231,7 +231,7 @@ public:
void ReadPropertyBlock(BfPropertyDeclaration* propertyDeclaration, BfBlock* block); void ReadPropertyBlock(BfPropertyDeclaration* propertyDeclaration, BfBlock* block);
BfAstNode* ReadTypeMember(BfTokenNode* node, bool declStarted = false, int depth = 0, BfAstNode* deferredHeadNode = NULL); BfAstNode* ReadTypeMember(BfTokenNode* node, bool declStarted = false, int depth = 0, BfAstNode* deferredHeadNode = NULL);
BfAstNode* ReadTypeMember(BfAstNode* node, bool declStarted = false, int depth = 0, BfAstNode* deferredHeadNode = NULL); BfAstNode* ReadTypeMember(BfAstNode* node, bool declStarted = false, int depth = 0, BfAstNode* deferredHeadNode = NULL);
BfIdentifierNode* CompactQualifiedName(BfAstNode* leftNode); BfIdentifierNode* CompactQualifiedName(BfAstNode* leftNode, bool allowGlobalLookup = true);
void TryIdentifierConvert(int readPos); void TryIdentifierConvert(int readPos);
void CreateQualifiedNames(BfAstNode* node); void CreateQualifiedNames(BfAstNode* node);
BfFieldDtorDeclaration* CreateFieldDtorDeclaration(BfAstNode* srcNode); BfFieldDtorDeclaration* CreateFieldDtorDeclaration(BfAstNode* srcNode);

View file

@ -42,7 +42,8 @@ enum BfResolveTypeRefFlags
BfResolveTypeRefFlag_AllowUnboundGeneric = 0x40000, BfResolveTypeRefFlag_AllowUnboundGeneric = 0x40000,
BfResolveTypeRefFlag_ForceUnboundGeneric = 0x80000, BfResolveTypeRefFlag_ForceUnboundGeneric = 0x80000,
BfResolveTypeRefFlag_IgnoreProtection = 0x100000, BfResolveTypeRefFlag_IgnoreProtection = 0x100000,
BfResolveTypeRefFlag_SpecializedProject = 0x200000 BfResolveTypeRefFlag_SpecializedProject = 0x200000,
BfResolveTypeRefFlag_GlobalLookup = 0x400000
}; };
enum BfTypeNameFlags : uint16 enum BfTypeNameFlags : uint16
@ -1735,7 +1736,7 @@ struct BfTypeLookupEntry
enum Flags : uint8 enum Flags : uint8
{ {
Flags_None, Flags_None,
Flags_SpecializedProject Flags_SpecializedProject,
}; };
BfAtomComposite mName; BfAtomComposite mName;

View file

@ -285,6 +285,8 @@ void BfSourceClassifier::Visit(BfQualifiedNameNode* qualifiedName)
Visit((BfAstNode*)qualifiedName); Visit((BfAstNode*)qualifiedName);
VisitChild(qualifiedName->mLeft); VisitChild(qualifiedName->mLeft);
if (qualifiedName->IsGlobalLookup())
SetElementType(qualifiedName->mLeft, BfSourceElementType_Namespace);
VisitChild(qualifiedName->mDot); VisitChild(qualifiedName->mDot);
VisitChild(qualifiedName->mRight); VisitChild(qualifiedName->mRight);
if (BfNodeIsExact<BfIdentifierNode>(qualifiedName->mRight)) if (BfNodeIsExact<BfIdentifierNode>(qualifiedName->mRight))
@ -350,6 +352,8 @@ void BfSourceClassifier::Visit(BfQualifiedTypeReference* qualifiedType)
Visit((BfAstNode*)qualifiedType); Visit((BfAstNode*)qualifiedType);
VisitChild(qualifiedType->mLeft); VisitChild(qualifiedType->mLeft);
if (qualifiedType->IsGlobalLookup())
SetElementType(qualifiedType->mLeft, BfSourceElementType_Namespace);
VisitChild(qualifiedType->mDot); VisitChild(qualifiedType->mDot);
VisitChild(qualifiedType->mRight); VisitChild(qualifiedType->mRight);
} }
@ -495,6 +499,8 @@ void BfSourceClassifier::Visit(BfInvocationExpression* invocationExpr)
if (auto qualifiedName = BfNodeDynCast<BfQualifiedNameNode>(target)) if (auto qualifiedName = BfNodeDynCast<BfQualifiedNameNode>(target))
{ {
VisitChild(qualifiedName->mLeft); VisitChild(qualifiedName->mLeft);
if (qualifiedName->IsGlobalLookup())
SetElementType(qualifiedName->mLeft, BfSourceElementType_Namespace);
VisitChild(qualifiedName->mDot); VisitChild(qualifiedName->mDot);
VisitChild(qualifiedName->mRight); VisitChild(qualifiedName->mRight);
identifier = qualifiedName->mRight; identifier = qualifiedName->mRight;

View file

@ -7387,6 +7387,8 @@ void BfModule::Visit(BfDeferStatement* deferStmt)
BfScopeData* scope = NULL; BfScopeData* scope = NULL;
auto scopeNameNode = deferStmt->GetScopeNameNode();
if (deferStmt->mScopeToken != NULL) if (deferStmt->mScopeToken != NULL)
{ {
if (deferStmt->mScopeToken->GetToken() == BfToken_Scope) if (deferStmt->mScopeToken->GetToken() == BfToken_Scope)
@ -7394,9 +7396,9 @@ void BfModule::Visit(BfDeferStatement* deferStmt)
else else
scope = &mCurMethodState->mHeadScope; scope = &mCurMethodState->mHeadScope;
} }
else if (deferStmt->mScopeName != NULL) else if (scopeNameNode != NULL)
{ {
scope = FindScope(deferStmt->mScopeName, true); scope = FindScope(scopeNameNode, true);
if (scope == NULL) if (scope == NULL)
{ {

View file

@ -0,0 +1,41 @@
#pragma warning disable 168
namespace Tests;
namespace A.B
{
class Zonk<T>
{
public static int sVal = 123;
}
static
{
public static void Main()
{
global::B.Init();
global::A.B.Zonk<int>.sVal = 234;
global::B.MethodT<float>();
global::System.String str = null;
}
}
}
namespace B
{
static
{
public static void Init()
{
}
public static void MethodT<T>()
{
}
}
}
class Lookups
{
}