#include "BfAst.h" #include "BfReducer.h" #include "BfParser.h" #include "BfSystem.h" #include "BfUtil.h" #include "BeefySysLib/util/BeefPerf.h" #include "BeefySysLib/util/StackHelper.h" #include "BeefySysLib/util/AllocDebug.h" #include USING_NS_BF; #define MEMBER_SET(dest, member, src) \ { dest->member = src; \ MoveNode(src, dest); } #define MEMBER_SET_CHECKED(dest, member, src) \ { if (src == NULL) return dest; \ dest->member = src; \ MoveNode(src, dest); } #define MEMBER_SET_CHECKED_BOOL(dest, member, src) \ { if (src == NULL) return false; \ dest->member = src; \ MoveNode(src, dest); } static BfBinaryOp TokenToBinaryOp(BfToken token) { switch (token) { case BfToken_Plus: return BfBinaryOp_Add; case BfToken_Minus: return BfBinaryOp_Subtract; case BfToken_Star: return BfBinaryOp_Multiply; case BfToken_ForwardSlash: return BfBinaryOp_Divide; case BfToken_Modulus: return BfBinaryOp_Modulus; case BfToken_Ampersand: return BfBinaryOp_BitwiseAnd; case BfToken_Bar: return BfBinaryOp_BitwiseOr; case BfToken_Carat: return BfBinaryOp_ExclusiveOr; case BfToken_LDblChevron: return BfBinaryOp_LeftShift; case BfToken_RDblChevron: return BfBinaryOp_RightShift; case BfToken_CompareEquals: return BfBinaryOp_Equality; case BfToken_CompareNotEquals: return BfBinaryOp_InEquality; case BfToken_RChevron: return BfBinaryOp_GreaterThan; case BfToken_LChevron: return BfBinaryOp_LessThan; case BfToken_GreaterEquals: return BfBinaryOp_GreaterThanOrEqual; case BfToken_LessEquals: return BfBinaryOp_LessThanOrEqual; case BfToken_Spaceship: return BfBinaryOp_Compare; case BfToken_DblAmpersand: return BfBinaryOp_ConditionalAnd; case BfToken_DblBar: return BfBinaryOp_ConditionalOr; case BfToken_DblQuestion: return BfBinaryOp_NullCoalesce; default: return BfBinaryOp_None; } } static BfUnaryOp TokenToUnaryOp(BfToken token) { switch (token) { case BfToken_Star: return BfUnaryOp_Dereference; case BfToken_Ampersand: return BfUnaryOp_AddressOf; case BfToken_Minus: return BfUnaryOp_Negate; case BfToken_Bang: return BfUnaryOp_Not; case BfToken_Plus: return BfUnaryOp_Positive; case BfToken_Tilde: return BfUnaryOp_InvertBits; case BfToken_DblPlus: return BfUnaryOp_Increment; case BfToken_DblMinus: return BfUnaryOp_Decrement; case BfToken_Ref: return BfUnaryOp_Ref; case BfToken_Mut: return BfUnaryOp_Mut; case BfToken_Out: return BfUnaryOp_Out; case BfToken_Params: return BfUnaryOp_Params; default: return BfUnaryOp_None; } } static BfAssignmentOp TokenToAssignmentOp(BfToken token) { switch (token) { case BfToken_AssignEquals: return BfAssignmentOp_Assign; case BfToken_PlusEquals: return BfAssignmentOp_Add; case BfToken_MinusEquals: return BfAssignmentOp_Subtract; case BfToken_MultiplyEquals: return BfAssignmentOp_Multiply; case BfToken_DivideEquals: return BfAssignmentOp_Divide; case BfToken_ModulusEquals: return BfAssignmentOp_Modulus; case BfToken_ShiftLeftEquals: return BfAssignmentOp_ShiftLeft; case BfToken_ShiftRightEquals: return BfAssignmentOp_ShiftRight; case BfToken_AndEquals: return BfAssignmentOp_BitwiseAnd; case BfToken_OrEquals: return BfAssignmentOp_BitwiseOr; case BfToken_XorEquals: return BfAssignmentOp_ExclusiveOr; default: return BfAssignmentOp_None; } } BfReducer::BfReducer() { mCurTypeDecl = NULL; mLastTypeDecl = NULL; mCurMethodDecl = NULL; mSource = NULL; mClassDepth = 0; mAlloc = NULL; mStmtHasError = false; mPrevStmtHadError = false; mPassInstance = NULL; mCompatMode = false; mAllowTypeWildcard = false; mIsFieldInitializer = false; mInParenExpr = false; mSkipCurrentNodeAssert = false; mAssertCurrentNodeIdx = 0; mSystem = NULL; mResolvePassData = NULL; mMethodDepth = 0; mDocumentCheckIdx = 0; mTypeMemberNodeStart = NULL; } bool BfReducer::IsSemicolon(BfAstNode* node) { auto tokenNode = BfNodeDynCast(node); return (tokenNode != NULL) && (tokenNode->GetToken() == BfToken_Semicolon); } bool BfReducer::StringEquals(BfAstNode* node, BfAstNode* node2) { int len = node->GetSrcLength(); int len2 = node2->GetSrcLength(); if (len != len2) return false; int start = node->GetSrcStart(); int start2 = node2->GetSrcStart(); const char* srcStr = node->GetSourceData()->mSrc; for (int i = 0; i < len; i++) { if (srcStr[start + i] != srcStr[start2 + i]) return false; } return true; } int gAssertCurrentNodeIdx = 0; void BfReducer::AssertCurrentNode(BfAstNode* node) { if (mSkipCurrentNodeAssert) return; auto currentNode = mVisitorPos.GetCurrent(); if (currentNode == NULL) return; if (!node->LocationEndEquals(currentNode)) { const char* lastCPtr = &node->GetSourceData()->mSrc[node->GetSrcEnd() - 1]; // We have an "exceptional" case where breaking a double chevron will look like a position error if ((lastCPtr[0] != '>') || (lastCPtr[1] != '>')) { BF_FATAL("Internal parsing error"); } } gAssertCurrentNodeIdx++; mAssertCurrentNodeIdx++; } // For autocomplete we only do a reduce on nodes the cursor is in bool BfReducer::IsNodeRelevant(BfAstNode* astNode) { BfParser* bfParser = astNode->GetSourceData()->ToParser(); if (bfParser == NULL) return true; int cursorPos = bfParser->mCursorIdx; if ((cursorPos == -1) || (astNode->Contains(cursorPos, 1, 0))) return true; BF_ASSERT(bfParser->mParserData->mRefCount == -1); return false; } bool BfReducer::IsNodeRelevant(BfAstNode* startNode, BfAstNode* endNode) { BfParser* bfParser = startNode->GetSourceData()->ToParser(); if (bfParser == NULL) return true; int cursorPos = bfParser->mCursorIdx; int lenAdd = 1; if ((cursorPos == -1) || ((cursorPos >= startNode->GetSrcStart()) && (cursorPos < endNode->GetSrcEnd() + lenAdd))) return true; BF_ASSERT(bfParser->mParserData->mRefCount == -1); return false; } void BfReducer::MoveNode(BfAstNode* srcNode, BfAstNode* newOwner) { #ifdef BF_AST_HAS_PARENT_MEMBER srcNode->mParent = newOwner; #endif int srcStart = srcNode->GetSrcStart(); int srcEnd = srcNode->GetSrcEnd(); if (srcStart < newOwner->GetSrcStart()) newOwner->SetSrcStart(srcStart); if (srcEnd > newOwner->GetSrcEnd()) newOwner->SetSrcEnd(srcEnd); } // Replaces prevNode with new node and adds prevNode to newNode's childrenj // It can be considered that newNode encapsulated prevNode. void BfReducer::ReplaceNode(BfAstNode* prevNode, BfAstNode* newNode) { #ifdef BF_AST_HAS_PARENT_MEMBER newNode->mParent = prevNode->mParent; #endif if (!newNode->IsInitialized()) { #ifdef BF_AST_COMPACT if (prevNode->mIsCompact) { newNode->mIsCompact = prevNode->mIsCompact; newNode->mCompact_SrcStart = prevNode->mCompact_SrcStart; newNode->mCompact_SrcLen = prevNode->mCompact_SrcLen; newNode->mCompact_TriviaLen = prevNode->mCompact_TriviaLen; } else { int prevTriviaStart; int prevSrcStart; int prevSrcEnd; prevNode->GetSrcPositions(prevTriviaStart, prevSrcStart, prevSrcEnd); newNode->Init(prevTriviaStart, prevSrcStart, prevSrcEnd); } #else newNode->mTriviaStart = prevNode->mTriviaStart; newNode->mSrcStart = prevNode->mSrcStart; newNode->mSrcEnd = prevNode->mSrcEnd; #endif } else { int newTriviaStart; int newSrcStart; int newSrcEnd; newNode->GetSrcPositions(newTriviaStart, newSrcStart, newSrcEnd); int prevTriviaStart; int prevSrcStart; int prevSrcEnd; prevNode->GetSrcPositions(prevTriviaStart, prevSrcStart, prevSrcEnd); if (prevTriviaStart < newTriviaStart) newNode->SetTriviaStart(prevTriviaStart); if (prevSrcStart < newSrcStart) newNode->SetSrcStart(prevSrcStart); if (prevSrcEnd > newSrcEnd) newNode->SetSrcEnd(prevSrcEnd); } #ifdef BF_AST_HAS_PARENT_MEMBER prevNode->mParent = newNode; #endif } BfAstNode* BfReducer::Fail(const StringImpl& errorMsg, BfAstNode* refNode) { mStmtHasError = true; if (mPassInstance->HasLastFailedAt(refNode)) // No duplicate failures return NULL; mPassInstance->Fail(errorMsg, refNode); return NULL; } BfAstNode* BfReducer::FailAfter(const StringImpl& errorMsg, BfAstNode* prevNode) { mStmtHasError = true; mPassInstance->FailAfter(errorMsg, prevNode); return NULL; } void BfReducer::AddErrorNode(BfAstNode* astNode, bool removeNode) { if (mSource != NULL) mSource->AddErrorNode(astNode); if (removeNode) astNode->RemoveSelf(); } bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int* outEndNode, bool* couldBeExpr, bool* isGenericType, bool* isTuple) { AssertCurrentNode(checkNode); if (couldBeExpr != NULL) *couldBeExpr = true; if (outEndNode != NULL) *outEndNode = -1; auto firstNode = checkNode; if (checkNode == NULL) return false; int checkIdx = mVisitorPos.mReadPos; if ((!checkNode->IsA()) && (!checkNode->IsA())) { if (auto checkTokenNode = BfNodeDynCast(checkNode)) { BfToken checkToken = checkTokenNode->GetToken(); if ((checkToken == BfToken_Ref) || (checkToken == BfToken_Mut)) { checkIdx++; if (mVisitorPos.Get(checkIdx) == NULL) return false; } else if ((checkToken == BfToken_Var) || (checkToken == BfToken_Let)) { checkIdx++; checkNode = mVisitorPos.Get(checkIdx); checkTokenNode = BfNodeDynCast(checkNode); if (outEndNode) *outEndNode = checkIdx; if (successToken == BfToken_None) return true; return (checkToken == successToken); } else if (checkToken == BfToken_Unsigned) { // Unsigned val start } else if (checkToken == BfToken_LParen) { // Tuple start } else if (checkToken == BfToken_Decltype) { // Decltype start } else if ((checkToken == BfToken_Delegate) || (checkToken == BfToken_Function)) { int startNode = mVisitorPos.mReadPos; mVisitorPos.mReadPos++; int endNode = -1; // Return type auto checkNode = mVisitorPos.GetCurrent(); if ((checkNode == NULL) || (!IsTypeReference(checkNode, BfToken_LParen, &endNode, couldBeExpr, isGenericType, isTuple))) { if (outEndNode != NULL) *outEndNode = endNode; mVisitorPos.mReadPos = startNode; return false; } // Take in params as a tuple mVisitorPos.mReadPos = endNode; auto currentNode = mVisitorPos.GetCurrent(); bool hasParams = false; if (currentNode != NULL) { if (auto openToken = BfNodeDynCast(currentNode)) { if (openToken->GetToken() == BfToken_LParen) { int parenDepth = 1; // Do a smarter check? checkIdx = endNode + 1; while (true) { auto checkNode = mVisitorPos.Get(checkIdx); if (checkNode == NULL) break; if (auto tokenNode = BfNodeDynCast(checkNode)) { bool done = false; switch (tokenNode->GetToken()) { case BfToken_LParen: parenDepth++; break; case BfToken_RParen: parenDepth--; if (parenDepth == 0) { endNode = checkIdx + 1; done = true; } break; case BfToken_Semicolon: // Failed done = true; break; } if (done) break; } checkIdx++; } hasParams = parenDepth == 0; } } } if (!hasParams) { if (outEndNode != NULL) *outEndNode = endNode; mVisitorPos.mReadPos = startNode; return false; } if (outEndNode != NULL) *outEndNode = endNode; mVisitorPos.mReadPos = startNode; return true; } else return false; } else return false; } int chevronDepth = 0; bool identifierExpected = true; bool hadEndBracket = false; int bracketDepth = 0; int parenDepth = 0; bool hadTupleComma = false; bool hadIdentifier = false; bool foundSuccessToken = false; BfTokenNode* lastToken = NULL; //while (checkNode != NULL) SizedArray tokenStack; while (true) { auto checkNode = mVisitorPos.Get(checkIdx); if (checkNode == NULL) break; auto checkTokenNode = BfNodeDynCast(checkNode); if (checkTokenNode != NULL) { if (hadEndBracket) return false; BfToken checkToken = checkTokenNode->GetToken(); if (bracketDepth > 0) { if ((checkToken == BfToken_LBracket) || (checkToken == BfToken_QuestionLBracket)) { bracketDepth++; } else if (checkToken == BfToken_RBracket) { bracketDepth--; } } else { if ((checkToken == successToken) && (checkTokenNode != firstNode)) { bool doEnding = true; bool success = false; if ((lastToken != NULL) && ((lastToken->GetToken() == BfToken_RChevron) || (lastToken->GetToken() == BfToken_RDblChevron))) { if (couldBeExpr != NULL) *couldBeExpr = false; } if (successToken == BfToken_RParen) { success = (chevronDepth == 0) && (bracketDepth == 0) && (parenDepth == 1); if (success) { // Check identifierExpected - this catches (.) casts if ((identifierExpected) && (couldBeExpr != NULL)) *couldBeExpr = false; } } else if ((successToken == BfToken_Comma) || (successToken == BfToken_LBracket)) { success = (chevronDepth == 0) && (bracketDepth == 0) && (parenDepth == 0); } if (success) { if (outEndNode != NULL) *outEndNode = checkIdx; return true; } if (doEnding) { if (outEndNode != NULL) *outEndNode = checkIdx; return (chevronDepth == 0) && (bracketDepth == 0) && (parenDepth == 0); } } bool isDone = false; if (checkToken == BfToken_LParen) { if ((hadIdentifier) && (chevronDepth == 0) && (bracketDepth == 0) && (parenDepth == 0)) isDone = true; else { tokenStack.Add(BfToken_LParen); parenDepth++; } } else if (checkToken == BfToken_RParen) { if ((parenDepth == 0) || (tokenStack.back() != BfToken_LParen)) { if (outEndNode != NULL) *outEndNode = checkIdx; return false; } tokenStack.pop_back(); parenDepth--; if (parenDepth > 0) { // if we are embedded in a multi-tuple like (A, (B, C), D) then we expect a , or ) after // closing an inner tuple. Otherwise this is an expression like ((Type)a) auto nextNode = mVisitorPos.GetNext(); bool isOkay = false; if (auto nextToken = BfNodeDynCast(nextNode)) { isOkay = (nextToken->GetToken() == BfToken_Comma) || (nextToken->GetToken() == BfToken_RParen); } if (!isOkay) { if (outEndNode != NULL) *outEndNode = checkIdx; return false; } } if ((parenDepth < 0) || // Probably a cast ((successToken == BfToken_None) && (parenDepth == 0) && (!hadTupleComma))) { if (successToken == BfToken_RParen) { foundSuccessToken = true; break; } else { if (outEndNode != NULL) *outEndNode = checkIdx; return false; } } } else if ((checkToken == BfToken_Const) && (chevronDepth > 0)) { if (mCompatMode) { identifierExpected = true; } else { int prevReadPos = mVisitorPos.mReadPos; auto nextNode = mVisitorPos.Get(checkIdx + 1); if (nextNode != NULL) { mVisitorPos.mReadPos = checkIdx + 1; auto expr = CreateExpression(nextNode, BfReducer::CreateExprFlags_BreakOnRChevron); int endExprReadPos = mVisitorPos.mReadPos; mVisitorPos.mReadPos = prevReadPos; if (expr == NULL) { if (outEndNode != NULL) *outEndNode = checkIdx; return false; } checkIdx = endExprReadPos; } } } else if ((checkToken == BfToken_Minus) && (mCompatMode) && (chevronDepth > 0) && (parenDepth == 0) && (bracketDepth == 0)) { // Allow } else if (checkToken == BfToken_Unsigned) { identifierExpected = true; } else if ((checkToken == BfToken_Ref) || (checkToken == BfToken_Mut)) { identifierExpected = true; } else if (checkToken == BfToken_LChevron) { identifierExpected = true; chevronDepth++; tokenStack.Add(BfToken_LChevron); } else if ((checkToken == BfToken_RChevron) || (checkToken == BfToken_RDblChevron)) { for (int i = 0; i < ((checkToken == BfToken_RDblChevron) ? 2 : 1); i++) { if ((tokenStack.IsEmpty()) || (tokenStack.back() != BfToken_LChevron)) { if (outEndNode != NULL) *outEndNode = checkIdx; return false; } tokenStack.pop_back(); chevronDepth--; } identifierExpected = false; if (chevronDepth < 0) { if (outEndNode != NULL) *outEndNode = checkIdx; return false; } if (chevronDepth == 0) { if (isGenericType != NULL) *isGenericType = true; } } else if (checkToken == BfToken_RDblChevron) chevronDepth -= 2; else if (checkToken == BfToken_Comma) { if ((bracketDepth == 0) && (tokenStack.IsEmpty())) { if (outEndNode != NULL) *outEndNode = checkIdx; return false; } if ((!tokenStack.IsEmpty()) && (tokenStack.back() == BfToken_LParen)) { hadTupleComma = true; if (isTuple != NULL) { *isTuple = true; } } identifierExpected = true; } else if (checkToken == BfToken_Dot) { auto prevNode = mVisitorPos.Get(checkIdx - 1); if (auto prevToken = BfNodeDynCast(prevNode)) { if (couldBeExpr != NULL) { // UH- NO, it could be referencing a static member // a ">." can only be a reference to an inner type of a generic type //if ((prevToken->GetToken() == BfToken_RChevron) || (prevToken->GetToken() == BfToken_RDblChevron)) //*couldBeExpr = false; } // a ".[" can only be a member reference after an indexer expression if (prevToken->GetToken() == BfToken_RBracket) { if (outEndNode != NULL) *outEndNode = checkIdx; return false; } } identifierExpected = true; } else if (checkToken == BfToken_RBracket) { hadEndBracket = true; } else if ((checkToken == BfToken_Star) || (checkToken == BfToken_Question)) { if (checkToken == BfToken_Star) { auto prevNode = mVisitorPos.Get(checkIdx - 1); if (auto prevToken = BfNodeDynCast(prevNode)) { switch (prevToken->GetToken()) { case BfToken_RParen: case BfToken_RBracket: case BfToken_RChevron: case BfToken_RDblChevron: break; default: // These are definitely dereferences return false; } } while (true) { auto nextNode = mVisitorPos.Get(checkIdx + 1); auto nextToken = BfNodeDynCast(nextNode); if ((nextToken == NULL) || (nextToken->GetToken() != BfToken_Star)) break; checkTokenNode = nextToken; checkToken = checkTokenNode->GetToken(); checkIdx++; } } else { auto prevNode = mVisitorPos.Get(checkIdx - 1); if (auto prevToken = BfNodeDynCast(prevNode)) { // If this is just a 'loose' comma then it can't be part of a nullable if ((prevToken->GetToken() == BfToken_Comma) || (prevToken->GetToken() == BfToken_LParen)) { return false; } } } // Star or Question always end a TypeRef if ((chevronDepth == 0) && (parenDepth == 0) && (bracketDepth == 0)) { if (hadTupleComma) return false; if (couldBeExpr != NULL) *couldBeExpr = false; if (outEndNode != NULL) *outEndNode = checkIdx + 1; if (successToken == BfToken_None) return true; auto nextNode = mVisitorPos.Get(checkIdx + 1); if (auto nextToken = BfNodeDynCast(nextNode)) { if (nextToken->GetToken() == successToken) { if (outEndNode != NULL) *outEndNode = checkIdx + 1; return true; } if (nextToken->GetToken() == BfToken_LBracket) { // A rare case of something like "char*[...]", let the bracket information through } else break; } else return false; } } else if ((checkToken == BfToken_LBracket) || (checkToken == BfToken_QuestionLBracket)) { auto prevNode = mVisitorPos.Get(checkIdx - 1); if (auto prevToken = BfNodeDynCast(prevNode)) { // .[ - that's not a valid type, but could be an attributed member reference if ((prevToken->GetToken() == BfToken_Dot) || (prevToken->GetToken() == BfToken_DotDot)) { if (outEndNode != NULL) *outEndNode = checkIdx - 1; return false; } } bracketDepth++; } else if (checkToken == BfToken_This) { if ((parenDepth == 1) && (hadIdentifier)) { // If this looks like it's from a '( this ...)' then it could be part of a function declaration, so allow it } else { if (outEndNode != NULL) *outEndNode = checkIdx; return false; } } else if ((checkToken == BfToken_Delegate) || (checkToken == BfToken_Function)) { int funcEndNode = -1; int prevReadPos = mVisitorPos.mReadPos; mVisitorPos.mReadPos = checkIdx; bool isTypeRef = IsTypeReference(checkNode, BfToken_None, &funcEndNode); mVisitorPos.mReadPos = prevReadPos; if (!isTypeRef) { if (outEndNode != NULL) *outEndNode = checkIdx; return false; } checkIdx = funcEndNode; continue; } else if (checkToken == BfToken_Decltype) { int endNodeIdx = checkIdx + 1; auto nextNode = mVisitorPos.Get(checkIdx + 1); if (auto tokenNode = BfNodeDynCast(nextNode)) { int openCount = 1; while (true) { endNodeIdx++; auto checkNextNode = mVisitorPos.Get(endNodeIdx); if (checkNextNode == NULL) break; if (auto checkNextToken = BfNodeDynCast(checkNextNode)) { if (checkNextToken->GetToken() == BfToken_LParen) openCount++; else if (checkNextToken->GetToken() == BfToken_RParen) { openCount--; if (openCount == 0) break; } } } } checkIdx = endNodeIdx; /*if (outEndNode != NULL) *outEndNode = endNodeIdx + 1; return true;*/ } else if (checkToken != BfToken_LBracket) isDone = true; if (isDone) { if (outEndNode != NULL) *outEndNode = checkIdx; if (isGenericType != NULL) *isGenericType = false; return false; } } } else if (bracketDepth > 0) { // Ignore } else if ((checkNode->IsA()) || (checkNode->IsA())) { // Identifier is always allowed in tuple (parenDepth == 0), because it's potentially the field name // (successToken == BfToken_RParen) infers we are already checking inside parentheses, such as // when we see a potential cast expression if ((!identifierExpected) && (parenDepth == 0) && (successToken != BfToken_RParen)) { if (outEndNode != NULL) *outEndNode = checkIdx; if (successToken == BfToken_None) return chevronDepth == 0; return false; } hadIdentifier = true; identifierExpected = false; } else if (checkNode->IsA()) { if (successToken == BfToken_LBrace) { foundSuccessToken = true; } break; } else if ((mCompatMode) && (checkNode->IsExact()) && (chevronDepth > 0) && (identifierExpected)) { // Allow identifierExpected = false; } else { if (outEndNode != NULL) *outEndNode = checkIdx; return false; } lastToken = checkTokenNode; checkIdx++; } if (outEndNode != NULL) *outEndNode = checkIdx; return (hadIdentifier) && (chevronDepth == 0) && (bracketDepth == 0) && (parenDepth == 0) && ((successToken == BfToken_None) || (foundSuccessToken)); } bool BfReducer::IsLocalMethod(BfAstNode* nameNode) { AssertCurrentNode(nameNode); int parenDepth = 0; bool hadParens = false; int chevronDepth = 0; bool hadGenericParams = false; int checkIdx = mVisitorPos.mReadPos + 1; while (true) { auto checkNode = mVisitorPos.Get(checkIdx); if (checkNode == NULL) return false; if (auto tokenNode = BfNodeDynCast(checkNode)) { BfToken token = tokenNode->GetToken(); if (token == BfToken_LParen) { parenDepth++; hadParens = true; } else if (token == BfToken_RParen) { parenDepth--; if (parenDepth == 0) return true; } else { switch (token) { case BfToken_Semicolon: // Never can be a local method return false; case BfToken_Where: // Always denotes a local method return true; } } } else if (auto tokenNode = BfNodeDynCast(checkNode)) { //return (hadParens) && (parenDepth == 0); return false; } else { } checkIdx++; } return false; } int BfReducer::QualifiedBacktrack(BfAstNode* endNode, int checkIdx, bool* outHadChevrons) { auto checkNode = endNode; BF_ASSERT(checkNode == mVisitorPos.Get(checkIdx)); int chevronDepth = 0; bool identifierExpected = true; bool hadEndBracket = false; bool lastWasIdentifier = false; while (checkNode != NULL) { auto checkTokenNode = BfNodeDynCast(checkNode); if (checkTokenNode != NULL) { BfToken checkToken = checkTokenNode->GetToken(); if ((checkToken == BfToken_Dot) || (checkToken == BfToken_DotDot)) { if (chevronDepth == 0) return checkIdx; } else if (checkToken == BfToken_LChevron) { if (outHadChevrons != NULL) *outHadChevrons = true; chevronDepth++; } else if (checkToken == BfToken_RChevron) { // Was this a case like "Test MethodName"? Those are split. if (lastWasIdentifier) return -1; chevronDepth--; } else if (checkToken == BfToken_RDblChevron) { if (lastWasIdentifier) return -1; chevronDepth -= 2; } else if ((checkToken != BfToken_Comma) && (checkToken != BfToken_Dot) && (checkToken != BfToken_DotDot) && (checkToken != BfToken_RBracket) && (checkToken != BfToken_Star) && (checkToken != BfToken_Question) && (checkToken != BfToken_LBracket)) { return -1; } if (chevronDepth == 0) return -1; lastWasIdentifier = false; } else if (checkNode->IsA()) { // Two identifiers in a row denotes a break if (lastWasIdentifier) return -1; lastWasIdentifier = true; } else { return -1; } checkIdx--; checkNode = mVisitorPos.Get(checkIdx); } return -1; } BfExpression* BfReducer::ApplyToFirstExpression(BfUnaryOperatorExpression* unaryOp, BfExpression* target) { auto condExpression = BfNodeDynCast(target); if (condExpression != NULL) { auto result = ApplyToFirstExpression(unaryOp, condExpression->mConditionExpression); if (result == condExpression->mConditionExpression) { //TODO: Make sure this one works, check children and next's and such //ReplaceNode(unaryOp, binOpExpression); unaryOp->mExpression = condExpression->mConditionExpression; ReplaceNode(unaryOp, condExpression); unaryOp->SetSrcEnd(condExpression->mConditionExpression->GetSrcEnd()); condExpression->mConditionExpression = unaryOp; } condExpression->SetSrcStart(unaryOp->GetSrcStart()); return result; } auto binOpExpression = BfNodeDynCast(target); if (binOpExpression != NULL) { auto result = ApplyToFirstExpression(unaryOp, binOpExpression->mLeft); if (result == binOpExpression->mLeft) { unaryOp->mExpression = binOpExpression->mLeft; unaryOp->SetSrcEnd(binOpExpression->mLeft->GetSrcEnd()); binOpExpression->mLeft = unaryOp; } binOpExpression->SetSrcStart(unaryOp->GetSrcStart()); return result; } return target; } static String DbgNodeToString(BfAstNode* astNode) { if (auto binOpExpr = BfNodeDynCast(astNode)) { String str; str += "("; str += DbgNodeToString(binOpExpr->mLeft); str += " "; str += DbgNodeToString(binOpExpr->mOpToken); str += " "; str += DbgNodeToString(binOpExpr->mRight); str += ")"; return str; } else if (auto condExpr = BfNodeDynCast(astNode)) { String str; str += "("; str += DbgNodeToString(condExpr->mConditionExpression); str += ") ? ("; str += DbgNodeToString(condExpr->mTrueExpression); str += ") : ("; str += DbgNodeToString(condExpr->mFalseExpression); str += ")"; return str; } return astNode->ToString(); } BfExpression* BfReducer::CheckBinaryOperatorPrecedence(BfBinaryOperatorExpression* binOpExpression) { BfExpression* resultExpr = binOpExpression; bool dbg = false; #ifdef BF_AST_HAS_PARENT_MEMBER BF_ASSERT(BfNodeDynCast(binOpExpression->mParent) == NULL); #endif SizedArray binOpParents; SizedArray deferredChecks; BfBinaryOperatorExpression* checkBinOpExpression = binOpExpression; while (true) { if (checkBinOpExpression == NULL) { if (deferredChecks.size() == 0) break; checkBinOpExpression = deferredChecks.back(); deferredChecks.pop_back(); } if (dbg) OutputDebugStrF("Checking: %s\n", DbgNodeToString(checkBinOpExpression).c_str()); #ifdef BF_AST_HAS_PARENT_MEMBER BfBinaryOperatorExpression* prevBinOpExpression = BfNodeDynCast(checkBinOpExpression->mParent); if (prevBinOpExpression != NULL) { BF_ASSERT(binOpParents.back() == prevBinOpExpression); } #else BfBinaryOperatorExpression* prevBinOpExpression = NULL; #endif if (!binOpParents.IsEmpty()) { prevBinOpExpression = binOpParents.back(); } BfBinaryOperatorExpression* nextBinaryOperatorExpression = NULL; bool didCondSwap = false; while (auto rightCondExpression = BfNodeDynCast(checkBinOpExpression->mRight)) { // Turn (A || (B ? C : D)) into ((A || B) ? C : D) BfExpression* exprA = checkBinOpExpression->mLeft; BfExpression* exprB = rightCondExpression->mConditionExpression; BfExpression* exprC = rightCondExpression->mTrueExpression; checkBinOpExpression->SetSrcEnd(exprB->GetSrcEnd()); MEMBER_SET(rightCondExpression, mConditionExpression, checkBinOpExpression); MEMBER_SET(checkBinOpExpression, mLeft, exprA); MEMBER_SET(checkBinOpExpression, mRight, exprB); didCondSwap = true; if (dbg) { OutputDebugStrF("NewCond: %s\n", DbgNodeToString(rightCondExpression).c_str()); OutputDebugStrF("CheckAfterCond: %s\n", DbgNodeToString(checkBinOpExpression).c_str()); } if (prevBinOpExpression != NULL) { BF_ASSERT(checkBinOpExpression == prevBinOpExpression->mRight); MEMBER_SET(prevBinOpExpression, mRight, rightCondExpression); nextBinaryOperatorExpression = prevBinOpExpression; binOpParents.pop_back(); } else { BF_ASSERT(resultExpr == checkBinOpExpression); resultExpr = rightCondExpression; } } if (nextBinaryOperatorExpression != NULL) { checkBinOpExpression = nextBinaryOperatorExpression; continue; } /*auto _CheckLeftBinaryOpearator = [&](BfBinaryOperatorExpression* checkBinOpExpression) { while (auto leftBinOpExpression = BfNodeDynCast(checkBinOpExpression->mLeft)) { if (dbg) { OutputDebugStrF("CheckCur : %s\n", DbgNodeToString(checkBinOpExpression).c_str()); OutputDebugStrF("Left : %s\n", DbgNodeToString(leftBinOpExpression).c_str()); } if (leftBinOpExpression->mRight == NULL) { BF_ASSERT(mPassInstance->HasFailed()); return; } int leftPrecedence = BfGetBinaryOpPrecendence(leftBinOpExpression->mOp); int rightPrecedence = BfGetBinaryOpPrecendence(checkBinOpExpression->mOp); // Turn ((A + B) * C) into (A + (B * C)) if (leftPrecedence >= rightPrecedence) { break; } BfTokenNode* tokenNode = checkBinOpExpression->mOpToken; BfExpression* exprA = leftBinOpExpression->mLeft; BfExpression* exprB = leftBinOpExpression->mRight; BfExpression* exprC = checkBinOpExpression->mRight; auto rightBinOpExpression = leftBinOpExpression; // We reuse this memory for the right side now auto binOp = checkBinOpExpression->mOp; checkBinOpExpression->mLeft = exprA; checkBinOpExpression->mOp = leftBinOpExpression->mOp; checkBinOpExpression->mOpToken = leftBinOpExpression->mOpToken; checkBinOpExpression->mRight = rightBinOpExpression; rightBinOpExpression->mLeft = exprB; rightBinOpExpression->mOp = binOp; rightBinOpExpression->mOpToken = tokenNode; rightBinOpExpression->mRight = exprC; rightBinOpExpression->SetSrcStart(rightBinOpExpression->mLeft->GetSrcStart()); rightBinOpExpression->SetSrcEnd(rightBinOpExpression->mRight->GetSrcEnd()); if (dbg) { OutputDebugStrF("CheckAfter : %s\n", DbgNodeToString(checkBinOpExpression).c_str()); } } };*/ while (auto rightBinOpExpression = BfNodeDynCast(checkBinOpExpression->mRight)) { if (dbg) { OutputDebugStrF("CheckCur : %s\n", DbgNodeToString(checkBinOpExpression).c_str()); OutputDebugStrF("Right : %s\n", DbgNodeToString(rightBinOpExpression).c_str()); } if (rightBinOpExpression->mRight == NULL) { BF_ASSERT(mPassInstance->HasFailed()); return binOpExpression; } int leftPrecedence = BfGetBinaryOpPrecendence(checkBinOpExpression->mOp); int rightPrecedence = BfGetBinaryOpPrecendence(rightBinOpExpression->mOp); // Turn (A * (B + C)) into ((A * B) + C) // Note: this DOES need to be '<' in order to preserve left-to-right evaluation when precedence is equal if (leftPrecedence < rightPrecedence) { binOpParents.Add(checkBinOpExpression); nextBinaryOperatorExpression = rightBinOpExpression; break; } BfTokenNode* tokenNode = checkBinOpExpression->mOpToken; BfExpression* exprA = checkBinOpExpression->mLeft; BfExpression* exprB = rightBinOpExpression->mLeft; BfExpression* exprC = rightBinOpExpression->mRight; auto leftBinOpExpression = rightBinOpExpression; // We reuse this memory for the left side now auto binOp = checkBinOpExpression->mOp; checkBinOpExpression->mLeft = leftBinOpExpression; checkBinOpExpression->mOp = rightBinOpExpression->mOp; checkBinOpExpression->mOpToken = rightBinOpExpression->mOpToken; checkBinOpExpression->mRight = exprC; leftBinOpExpression->mLeft = exprA; leftBinOpExpression->mOp = binOp; leftBinOpExpression->mOpToken = tokenNode; leftBinOpExpression->mRight = exprB; leftBinOpExpression->SetSrcStart(leftBinOpExpression->mLeft->GetSrcStart()); leftBinOpExpression->SetSrcEnd(leftBinOpExpression->mRight->GetSrcEnd()); if (dbg) { OutputDebugStrF("CheckAfter: %s\n", DbgNodeToString(checkBinOpExpression).c_str()); } if ((leftPrecedence > rightPrecedence) && (prevBinOpExpression != NULL)) { // Backtrack nextBinaryOperatorExpression = prevBinOpExpression; binOpParents.pop_back(); break; } if (auto leftBinaryExpr = BfNodeDynCast(checkBinOpExpression->mLeft)) { deferredChecks.push_back(leftBinaryExpr); } } checkBinOpExpression = nextBinaryOperatorExpression; } if (dbg) OutputDebugStrF("NodeOut: %s\n", DbgNodeToString(resultExpr).c_str()); return resultExpr; } BfAstNode* BfReducer::ReplaceTokenStarter(BfAstNode* astNode, int idx) { if (auto tokenNode = BfNodeDynCast(astNode)) { if ((tokenNode->GetToken() == BfToken_As) || (tokenNode->GetToken() == BfToken_In)) { if (idx == -1) idx = mVisitorPos.mReadPos; BF_ASSERT(mVisitorPos.Get(idx) == astNode); auto identifierNode = mAlloc->Alloc(); ReplaceNode(tokenNode, identifierNode); mVisitorPos.Set(idx, identifierNode); return identifierNode; } } return astNode; } BfEnumCaseBindExpression* BfReducer::CreateEnumCaseBindExpression(BfTokenNode* bindToken) { auto bindExpr = mAlloc->Alloc(); MEMBER_SET(bindExpr, mBindToken, bindToken); mVisitorPos.MoveNext(); auto nextNode = mVisitorPos.GetNext(); if (auto nextToken = BfNodeDynCast(nextNode)) { if (nextToken->GetToken() == BfToken_Dot) { auto memberReferenceExpr = mAlloc->Alloc(); MEMBER_SET(memberReferenceExpr, mDotToken, nextToken); mVisitorPos.MoveNext(); auto memberName = ExpectIdentifierAfter(memberReferenceExpr); if (memberName != NULL) { MEMBER_SET(memberReferenceExpr, mMemberName, memberName); } MEMBER_SET(bindExpr, mEnumMemberExpr, memberReferenceExpr); } } if (bindExpr->mEnumMemberExpr == NULL) { auto typeRef = CreateTypeRefAfter(bindExpr); if (typeRef != NULL) { if (auto namedTypeRef = BfNodeDynCast(typeRef)) { MEMBER_SET(bindExpr, mEnumMemberExpr, namedTypeRef->mNameNode); } else { auto memberRefExpr = mAlloc->Alloc(); if (auto qualifiedTypeRef = BfNodeDynCast(typeRef)) { if (auto namedTypeRef = BfNodeDynCast(qualifiedTypeRef->mRight)) { MEMBER_SET(memberRefExpr, mTarget, qualifiedTypeRef->mLeft); MEMBER_SET(memberRefExpr, mDotToken, qualifiedTypeRef->mDot); MEMBER_SET(memberRefExpr, mMemberName, namedTypeRef->mNameNode); } } else { MEMBER_SET(memberRefExpr, mTarget, typeRef); } MEMBER_SET(bindExpr, mEnumMemberExpr, memberRefExpr); } } if (bindExpr->mEnumMemberExpr == NULL) { Fail("Expected enum case name", typeRef); } } if (bindExpr->mEnumMemberExpr != NULL) { auto openToken = ExpectTokenAfter(bindExpr->mEnumMemberExpr, BfToken_LParen); if (openToken != NULL) { auto tupleExpr = CreateTupleExpression(openToken, NULL); MEMBER_SET(bindExpr, mBindNames, tupleExpr); } } return bindExpr; } BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags createExprFlags) { if (node == NULL) return NULL; BP_ZONE("CreateExpression"); // { BP_ZONE("CreateExpression.CheckStack"); StackHelper stackHelper; if (!stackHelper.CanStackExpand(64 * 1024)) { BfExpression* result = NULL; if (!stackHelper.Execute([&]() { result = CreateExpression(node, createExprFlags); })) { Fail("Expression too complex to parse", node); } return result; } } AssertCurrentNode(node); /*if (auto block = BfNodeDynCast(node)) { HandleBlock(block, true); return block; }*/ auto rhsCreateExprFlags = (CreateExprFlags)(createExprFlags & CreateExprFlags_BreakOnRChevron); node = ReplaceTokenStarter(node); auto exprLeft = BfNodeDynCast(node); AssertCurrentNode(node); if ((createExprFlags & (CreateExprFlags_AllowVariableDecl | CreateExprFlags_PermissiveVariableDecl)) != 0) { bool isLocalVariable = false; auto nextNode = mVisitorPos.GetNext(); BfVariableDeclaration* continuingVariable = NULL; int outEndNode = -1; bool couldBeExpr = false; bool isTuple = false; if (IsTypeReference(node, BfToken_None, &outEndNode, &couldBeExpr, NULL, &isTuple)) { if ((createExprFlags & CreateExprFlags_PermissiveVariableDecl) != 0) isLocalVariable = true; else if (auto identifierNode = BfNodeDynCast(mVisitorPos.Get(outEndNode))) { if (auto equalsToken = BfNodeDynCast(mVisitorPos.Get(outEndNode + 1))) { if (equalsToken->GetToken() == BfToken_AssignEquals) isLocalVariable = true; } //if (!couldBeExpr) { auto endingTokenNode = BfNodeDynCast(mVisitorPos.Get(outEndNode - 1)); // If the type ends with a * or a ? then it could be an expression if (endingTokenNode == NULL) { isLocalVariable = true; } else { BfToken endingToken = endingTokenNode->GetToken(); if (endingToken == BfToken_RParen) { if (isTuple) isLocalVariable = true; } else if (endingToken == BfToken_Star) { // Check spacing for "a* b" to determine if it's a pointer definition or a multiply auto beforeStarNode = mVisitorPos.Get(outEndNode - 2); if ((endingTokenNode->GetSrcStart() == beforeStarNode->GetSrcEnd()) && (identifierNode->GetSrcStart() > endingTokenNode->GetSrcEnd())) isLocalVariable = true; } else if ((endingToken != BfToken_Star) && (endingToken != BfToken_Question)) isLocalVariable = true; } } } if (auto typeNameToken = BfNodeDynCast(node)) { if ((typeNameToken->GetToken() == BfToken_Var) || (typeNameToken->GetToken() == BfToken_Let)) isLocalVariable = true; } } if (nextNode == NULL) { // Treat ending identifier as just an identifier (could be block result) isLocalVariable = false; } if ((isLocalVariable) || (continuingVariable != NULL)) { auto variableDeclaration = mAlloc->Alloc(); BfTypeReference* typeRef = NULL; if (continuingVariable != NULL) { typeRef = continuingVariable->mTypeRef; variableDeclaration->mModSpecifier = continuingVariable->mModSpecifier; ReplaceNode(node, variableDeclaration); variableDeclaration->mPrecedingComma = (BfTokenNode*)node; } else { typeRef = CreateTypeRef(node); if (typeRef == NULL) return NULL; ReplaceNode(typeRef, variableDeclaration); } variableDeclaration->mTypeRef = typeRef; BfAstNode* variableNameNode = NULL; nextNode = mVisitorPos.GetNext(); if (auto tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_LParen) { mVisitorPos.mReadPos++; variableNameNode = CreateTupleExpression(tokenNode); } } if (variableNameNode == NULL) variableNameNode = ExpectIdentifierAfter(variableDeclaration, "variable name"); if (variableNameNode == NULL) return variableDeclaration; auto tokenNode = BfNodeDynCast(mVisitorPos.GetNext()); variableDeclaration->mNameNode = variableNameNode; MoveNode(variableNameNode, variableDeclaration); if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_AssignEquals)) { MEMBER_SET(variableDeclaration, mEqualsNode, tokenNode); mVisitorPos.MoveNext(); if (variableDeclaration->mInitializer == NULL) variableDeclaration->mInitializer = CreateExpressionAfter(variableDeclaration); if (variableDeclaration->mInitializer == NULL) return variableDeclaration; MoveNode(variableDeclaration->mInitializer, variableDeclaration); } exprLeft = variableDeclaration; } } if (auto block = BfNodeDynCast(node)) { HandleBlock(block, true); exprLeft = block; } if (auto identifierNode = BfNodeDynCast(exprLeft)) { identifierNode = CompactQualifiedName(identifierNode); exprLeft = identifierNode; if ((mCompatMode) && (exprLeft->ToString() == "defined")) { auto definedNodeExpr = mAlloc->Alloc(); ReplaceNode(identifierNode, definedNodeExpr); auto nextNode = mVisitorPos.GetNext(); bool hadParenToken = false; if (auto parenToken = BfNodeDynCast(nextNode)) { if (parenToken->GetToken() == BfToken_LParen) { MoveNode(parenToken, definedNodeExpr); hadParenToken = true; } } auto definedIdentifier = ExpectIdentifierAfter(definedNodeExpr); MEMBER_SET_CHECKED(definedNodeExpr, mIdentifier, definedIdentifier); if (hadParenToken) { auto parenToken = ExpectTokenAfter(definedNodeExpr, BfToken_RParen); if (parenToken != NULL) MoveNode(parenToken, definedNodeExpr); } exprLeft = definedNodeExpr; } int endNodeIdx = -1; if ((IsTypeReference(exprLeft, BfToken_LBracket, &endNodeIdx, NULL))) { if (IsTypeReference(exprLeft, BfToken_LBrace, NULL, NULL)) { BfSizedArrayCreateExpression* arrayCreateExpr = mAlloc->Alloc(); auto typeRef = CreateTypeRef(exprLeft); if (typeRef != NULL) { ReplaceNode(typeRef, arrayCreateExpr); auto arrayType = BfNodeDynCast(typeRef); if (arrayType != NULL) { arrayCreateExpr->mTypeRef = arrayType; auto nextNode = mVisitorPos.GetNext(); auto block = BfNodeDynCast(nextNode); if (block != NULL) { Fail("Brace initialization is not supported. Enclose initializer with parentheses.", block); auto initializerExpr = CreateCollectionInitializerExpression(block); MEMBER_SET(arrayCreateExpr, mInitializer, initializerExpr); mVisitorPos.MoveNext(); } exprLeft = arrayCreateExpr; } else { Fail("Sized array type expected", typeRef); } } } else if (IsTypeReference(exprLeft, BfToken_LParen, NULL, NULL)) { if (auto tokenNode = BfNodeDynCast(mVisitorPos.Get(endNodeIdx - 1))) { if ((tokenNode->mToken == BfToken_Star) || (tokenNode->mToken == BfToken_Question)) // Is it something that can ONLY be a sized type reference? { BfSizedArrayCreateExpression* arrayCreateExpr = mAlloc->Alloc(); auto typeRef = CreateTypeRef(exprLeft); if (typeRef != NULL) { ReplaceNode(typeRef, arrayCreateExpr); auto arrayType = BfNodeDynCast(typeRef); if (arrayType != NULL) { arrayCreateExpr->mTypeRef = arrayType; auto nextNode = mVisitorPos.GetNext(); if (auto nextToken = BfNodeDynCast(nextNode)) { mVisitorPos.MoveNext(); auto initializerExpr = CreateCollectionInitializerExpression(nextToken); MEMBER_SET(arrayCreateExpr, mInitializer, initializerExpr); } exprLeft = arrayCreateExpr; } else { Fail("Sized array type expected", typeRef); } } } } } /*else if (IsTypeReference(exprLeft, BfToken_LParen, NULL, NULL)) { BfSizedArrayCreateExpression* arrayCreateExpr = mAlloc->Alloc(); auto typeRef = CreateTypeRef(exprLeft); if (typeRef != NULL) { ReplaceNode(typeRef, arrayCreateExpr); auto arrayType = BfNodeDynCast(typeRef); if (arrayType != NULL) { mVisitorPos.MoveNext(); arrayCreateExpr->mTypeRef = arrayType; auto nextNode = mVisitorPos.GetCurrent(); auto openParen = BfNodeDynCast(nextNode); BF_ASSERT(openParen->GetToken() == BfToken_LParen); auto initializerExpr = CreateCollectionInitializerExpression(openParen); MEMBER_SET(arrayCreateExpr, mInitializer, initializerExpr); exprLeft = arrayCreateExpr; } else { Fail("Sized array type expected", typeRef); } } }*/ } } if (exprLeft == NULL) { if (auto tokenNode = BfNodeDynCast(node)) { BfToken token = tokenNode->GetToken(); auto nextNode = mVisitorPos.GetNext(); if ((nextNode != NULL) && ((token == BfToken_Checked) || (token == BfToken_Unchecked))) { mVisitorPos.MoveNext(); auto nextExpr = CreateExpression(nextNode); if (nextExpr == NULL) return NULL; return nextExpr; } else if ((token == BfToken_New) || (token == BfToken_Scope) || (token == BfToken_Stack) || (token == BfToken_Append)) { if (token == BfToken_Stack) Fail("'Stack' not supported. Use 'scope::' instead.", tokenNode); auto allocNode = CreateAllocNode(tokenNode); bool isDelegateBind = false; bool isLambdaBind = false; bool isBoxing = false; auto nextNode = mVisitorPos.GetNext(); if (auto nextTokenNode = BfNodeDynCast(nextNode)) { int nextToken = nextTokenNode->GetToken(); isBoxing = nextToken == BfToken_Box; isDelegateBind = nextToken == BfToken_FatArrow; isLambdaBind = (nextToken == BfToken_LBracket); // Either this is a lambda bind or a dynamic tuple allocation. // We assume it's a lambda bind unless theres a "()" afterward if (nextToken == BfToken_LParen) { int endNode = -1; mVisitorPos.mReadPos++; if (!IsTypeReference(nextTokenNode, BfToken_LParen, &endNode)) { isLambdaBind = true; } // if (IsTypeReference(nextToken, BfToken_FatArrow, &endNode)) // isLambdaBind = true; mVisitorPos.mReadPos--; } } if (isBoxing) { auto boxExpr = mAlloc->Alloc(); ReplaceNode(allocNode, boxExpr); boxExpr->mAllocNode = allocNode; tokenNode = ExpectTokenAfter(boxExpr, BfToken_Box); MEMBER_SET(boxExpr, mBoxToken, tokenNode); auto exprNode = CreateExpressionAfter(boxExpr); if (exprNode != NULL) { MEMBER_SET(boxExpr, mExpression, exprNode); } return boxExpr; } else if (isLambdaBind) exprLeft = CreateLambdaBindExpression(allocNode); else if (isDelegateBind) exprLeft = CreateDelegateBindExpression(allocNode); else exprLeft = CreateObjectCreateExpression(allocNode); if (token == BfToken_Append) { #ifdef BF_AST_HAS_PARENT_MEMBER auto ctorDeclP = exprLeft->FindParentOfType(); if (ctorDeclP != NULL) ctorDeclP->mHasAppend = true; #endif #ifdef BF_AST_HAS_PARENT_MEMBER BF_ASSERT(ctorDecl == ctorDeclP); #endif } } else if (token == BfToken_This) { auto thisExpr = mAlloc->Alloc(); ReplaceNode(tokenNode, thisExpr); thisExpr->SetTriviaStart(tokenNode->GetTriviaStart()); exprLeft = thisExpr; } else if (token == BfToken_Base) { auto baseExpr = mAlloc->Alloc(); ReplaceNode(tokenNode, baseExpr); baseExpr->SetTriviaStart(tokenNode->GetTriviaStart()); exprLeft = baseExpr; } else if (token == BfToken_Null) { BfVariant nullVariant; nullVariant.mTypeCode = BfTypeCode_NullPtr; auto bfLiteralExpression = mAlloc->Alloc(); bfLiteralExpression->mValue = nullVariant; ReplaceNode(tokenNode, bfLiteralExpression); bfLiteralExpression->SetTriviaStart(tokenNode->GetTriviaStart()); exprLeft = bfLiteralExpression; } else if ((token == BfToken_TypeOf) || (token == BfToken_SizeOf) || (token == BfToken_AlignOf) || (token == BfToken_StrideOf)) { BfTypeAttrExpression* typeAttrExpr = NULL; switch (tokenNode->GetToken()) { case BfToken_TypeOf: typeAttrExpr = mAlloc->Alloc(); break; case BfToken_SizeOf: typeAttrExpr = mAlloc->Alloc(); break; case BfToken_AlignOf: typeAttrExpr = mAlloc->Alloc(); break; case BfToken_StrideOf: typeAttrExpr = mAlloc->Alloc(); break; } 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_RParen); MEMBER_SET_CHECKED(typeAttrExpr, mCloseParen, tokenNode); exprLeft = typeAttrExpr; } else if (token == BfToken_Default) { auto defaultExpr = mAlloc->Alloc(); ReplaceNode(tokenNode, defaultExpr); defaultExpr->mDefaultToken = tokenNode; if ((tokenNode = BfNodeDynCast(mVisitorPos.GetNext())) && (tokenNode->GetToken() == BfToken_LParen)) { mVisitorPos.MoveNext(); //tokenNode = ExpectTokenAfter(defaultExpr, BfToken_LParen); MEMBER_SET_CHECKED(defaultExpr, mOpenParen, tokenNode); auto sizeRef = CreateTypeRefAfter(defaultExpr); MEMBER_SET_CHECKED(defaultExpr, mTypeRef, sizeRef); tokenNode = ExpectTokenAfter(defaultExpr, BfToken_RParen); MEMBER_SET_CHECKED(defaultExpr, mCloseParen, tokenNode); } exprLeft = defaultExpr; } else if (token == BfToken_Question) { auto uninitExpr = mAlloc->Alloc(); ReplaceNode(tokenNode, uninitExpr); uninitExpr->mQuestionToken = tokenNode; return uninitExpr; //MEMBER_SET(variableDeclaration, mInitializer, uninitExpr); } else if (token == BfToken_Case) { auto caseExpr = mAlloc->Alloc(); ReplaceNode(tokenNode, caseExpr); caseExpr->mCaseToken = tokenNode; if (auto bindToken = BfNodeDynCast(mVisitorPos.GetNext())) { if ((bindToken->GetToken() == BfToken_Var) || (bindToken->GetToken() == BfToken_Let)) { auto expr = CreateEnumCaseBindExpression(bindToken); if (expr == NULL) return caseExpr; MEMBER_SET(caseExpr, mCaseExpression, expr); } } if (caseExpr->mCaseExpression == NULL) { auto expr = CreateExpressionAfter(caseExpr, (CreateExprFlags)(CreateExprFlags_NoAssignment | CreateExprFlags_PermissiveVariableDecl)); if (expr == NULL) return caseExpr; MEMBER_SET(caseExpr, mCaseExpression, expr); } auto equalsNode = ExpectTokenAfter(caseExpr, BfToken_AssignEquals); if (equalsNode == NULL) return caseExpr; MEMBER_SET(caseExpr, mEqualsNode, equalsNode); auto expr = CreateExpressionAfter(caseExpr); if (expr == NULL) return caseExpr; MEMBER_SET(caseExpr, mValueExpression, expr); return caseExpr; } else if (token == BfToken_Dot) // Abbreviated dot syntax ".EnumVal" { auto memberReferenceExpr = mAlloc->Alloc(); ReplaceNode(tokenNode, memberReferenceExpr); MEMBER_SET(memberReferenceExpr, mDotToken, tokenNode); bool handled = false; if (auto nextToken = BfNodeDynCastExact(mVisitorPos.GetNext())) { if (nextToken->GetToken() == BfToken_LParen) { // It's an unnamed dot ctor handled = true; } } if (!handled) { auto memberName = ExpectIdentifierAfter(memberReferenceExpr); if (memberName != NULL) { MEMBER_SET(memberReferenceExpr, mMemberName, memberName); } } // We don't set exprLeft here because it's illegal to do ".EnumVal.SomethingElse". That wouldn't make // sense because the abbreviated syntax relies on type inference and the ".SomethingElse" wouldn't be // the right type (whatever it is), AND mostly importantly, it breaks autocomplete when we are typing // "KEnum val = ." above a line that starts with a something like a method call "OtherThing.MethodCall()" // The exception is if we're creating an enum val with a payload //auto nextToken = BfNodeDynCast(mVisitorPos.GetNext()); //if ((nextToken != NULL) && (nextToken->GetToken() == BfToken_LParen)) { exprLeft = memberReferenceExpr; } /*else { return memberReferenceExpr; }*/ } else if (token == BfToken_LBracket) { exprLeft = CreateAttributedExpression(tokenNode, false); } else if (token == BfToken_FatArrow) { auto delegateBindExpr = mAlloc->Alloc(); ReplaceNode(tokenNode, delegateBindExpr); MEMBER_SET_CHECKED(delegateBindExpr, mFatArrowToken, tokenNode); auto expr = CreateExpressionAfter(delegateBindExpr); MEMBER_SET_CHECKED(delegateBindExpr, mTarget, expr); auto nextNode = mVisitorPos.GetNext(); if (tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_LChevron) { auto genericParamsDecl = CreateGenericArguments(tokenNode); MEMBER_SET_CHECKED(delegateBindExpr, mGenericArgs, genericParamsDecl); } } return delegateBindExpr; } } } if (exprLeft == NULL) { if (auto tokenNode = BfNodeDynCast(node)) { BfUnaryOperatorExpression* unaryOpExpr = NULL; auto nextNode = mVisitorPos.GetNext(); if ((tokenNode->GetToken() == BfToken_LParen) && (nextNode != NULL)) { bool couldBeExpr = true; // Peek ahead int endNodeIdx = -1; BfAstNode* endNode = NULL; bool isTuple = false; bool outerIsTypeRef = IsTypeReference(tokenNode, BfToken_FatArrow, &endNodeIdx, &couldBeExpr, NULL, &isTuple); if (outerIsTypeRef) { if (endNodeIdx != -1) { endNode = mVisitorPos.Get(endNodeIdx); if (auto endToken = BfNodeDynCast(endNode)) { if (endToken->GetToken() == BfToken_FatArrow) { return CreateLambdaBindExpression(NULL, tokenNode); } } } } //mVisitorPos.mReadPos++; bool isCastExpr = false; couldBeExpr = false; isTuple = false; if ((createExprFlags & CreateExprFlags_NoCast) == 0) isCastExpr = IsTypeReference(node, BfToken_RParen, &endNodeIdx, &couldBeExpr, NULL, &isTuple); //mVisitorPos.mReadPos--; if (endNodeIdx != -1) endNode = mVisitorPos.Get(endNodeIdx); //TODO: Remove this for compat /*if (couldBeExpr) isCastExpr = false;*/ if (isCastExpr) { bool isValidTupleCast = false; auto tokenNextNode = mVisitorPos.Get(mVisitorPos.mReadPos + 1); if (auto startToken = BfNodeDynCast(tokenNextNode)) { if (startToken->GetToken() == BfToken_LParen) { if (endNode != NULL) { auto afterEndNode = mVisitorPos.Get(endNodeIdx + 1); if (auto afterEndToken = BfNodeDynCast(afterEndNode)) { if (afterEndToken->GetToken() == BfToken_RParen) { isValidTupleCast = true; endNode = afterEndToken; // Check this one now, instead... } } } if (!isValidTupleCast) isCastExpr = false; } } BfAstNode* beforeEndNode = mVisitorPos.Get(endNodeIdx - 1); if (auto prevTokenNode = BfNodeDynCast(beforeEndNode)) { int prevToken = prevTokenNode->GetToken(); // Ending in a "*" or a ">" means it's definitely a type reference if ((prevToken == BfToken_Star) || (prevToken == BfToken_RChevron) || (prevToken == BfToken_RDblChevron)) couldBeExpr = false; } // It's not a cast expression if a binary operator (like +) immediately follows if (couldBeExpr) { auto endNextNode = mVisitorPos.Get(endNodeIdx + 1); if (endNextNode == NULL) { isCastExpr = false; } else if (auto nextTokenNode = BfNodeDynCast(endNextNode)) { BfToken nextToken = nextTokenNode->GetToken(); //TODO: Hm. What other tokens make it into a cast expr? auto binaryOp = TokenToBinaryOp(nextToken); // When we have a binary operator token following, it COULD either be a "(double)-val" or it COULD be a "(val2)-val" // But we can't tell until we determine whether the thing inside the paren is a type name or a value name, so we // have special code in BfExprEvaluator that can fix those cases at evaluation time if (((binaryOp != BfBinaryOp_None) /*&& (nextToken != BfToken_Star) && (nextToken != BfToken_Ampersand)*/) || // Star could be dereference, not multiply (nextToken == BfToken_RParen) || (nextToken == BfToken_LBracket) || (nextToken == BfToken_Dot) || (nextToken == BfToken_DotDot) || (nextToken == BfToken_Comma) || (nextToken == BfToken_Colon) || (nextToken == BfToken_Question) || (nextToken == BfToken_Semicolon) || (nextToken == BfToken_AssignEquals) || (nextToken == BfToken_Case)) isCastExpr = false; } } } if (isCastExpr) { auto bfCastExpr = mAlloc->Alloc(); if (isTuple) { // Create typeRef including the parens (tuple type) auto castTypeRef = CreateTypeRef(tokenNode); ReplaceNode(castTypeRef, bfCastExpr); bfCastExpr->mTypeRef = castTypeRef; } else { ReplaceNode(tokenNode, bfCastExpr); bfCastExpr->mOpenParen = tokenNode; auto castTypeRef = CreateTypeRefAfter(bfCastExpr); MEMBER_SET_CHECKED(bfCastExpr, mTypeRef, castTypeRef); tokenNode = ExpectTokenAfter(bfCastExpr, BfToken_RParen); MEMBER_SET_CHECKED(bfCastExpr, mCloseParen, tokenNode); } auto expression = CreateExpressionAfter(bfCastExpr); if (expression == NULL) return bfCastExpr; MEMBER_SET(bfCastExpr, mExpression, expression); unaryOpExpr = bfCastExpr; } else { if (auto nextToken = BfNodeDynCast(mVisitorPos.GetNext())) { // Empty tuple? if (nextToken->GetToken() == BfToken_RParen) { auto tupleExpr = mAlloc->Alloc(); ReplaceNode(tokenNode, tupleExpr); tupleExpr->mOpenParen = tokenNode; MEMBER_SET(tupleExpr, mCloseParen, nextToken); mVisitorPos.MoveNext(); return tupleExpr; } } // static int sItrIdx = 0; // sItrIdx++; // int itrIdx = sItrIdx; // if (itrIdx == 197) // { // NOP; // } // BfParenthesizedExpression or BfTupleExpression SetAndRestoreValue prevInParenExpr(mInParenExpr, true); auto innerExpr = CreateExpressionAfter(tokenNode, CreateExprFlags_AllowVariableDecl); if (innerExpr == NULL) return NULL; BfTokenNode* closeParenToken; if (innerExpr->IsA()) closeParenToken = ExpectTokenAfter(innerExpr, BfToken_RParen, BfToken_Comma, BfToken_Colon); else closeParenToken = ExpectTokenAfter(innerExpr, BfToken_RParen, BfToken_Comma); if ((closeParenToken == NULL) || (closeParenToken->GetToken() == BfToken_RParen)) { auto parenExpr = mAlloc->Alloc(); parenExpr->mExpression = innerExpr; ReplaceNode(node, parenExpr); parenExpr->mOpenParen = tokenNode; MoveNode(innerExpr, parenExpr); if (closeParenToken == NULL) return parenExpr; MEMBER_SET(parenExpr, mCloseParen, closeParenToken); exprLeft = parenExpr; if ((createExprFlags & CreateExprFlags_ExitOnParenExpr) != 0) return exprLeft; } else { mVisitorPos.mReadPos--; // Backtrack to before token exprLeft = CreateTupleExpression(tokenNode, innerExpr); } } } if (exprLeft == NULL) { BfUnaryOp unaryOp = TokenToUnaryOp(tokenNode->GetToken()); if (unaryOp != BfUnaryOp_None) { if (unaryOp == BfUnaryOp_Positive) Fail("Unary operator '+' not allowed", tokenNode); unaryOpExpr = mAlloc->Alloc(); unaryOpExpr->mOp = unaryOp; unaryOpExpr->mOpToken = tokenNode; ReplaceNode(tokenNode, unaryOpExpr); unaryOpExpr->mExpression = CreateExpressionAfter(unaryOpExpr, rhsCreateExprFlags); if (unaryOpExpr->mExpression == NULL) return NULL; MoveNode(unaryOpExpr->mExpression, unaryOpExpr); } if (unaryOpExpr != NULL) { exprLeft = unaryOpExpr; if (auto binaryOpExpr = BfNodeDynCast(unaryOpExpr->mExpression)) { exprLeft = binaryOpExpr; ApplyToFirstExpression(unaryOpExpr, binaryOpExpr); } if (auto condExpr = BfNodeDynCast(unaryOpExpr->mExpression)) { exprLeft = condExpr; ApplyToFirstExpression(unaryOpExpr, condExpr); } if (auto assignmentExpr = BfNodeDynCast(unaryOpExpr->mExpression)) { // Apply unary operator (likely a dereference) to LHS assignmentExpr->RemoveSelf(); ReplaceNode(unaryOpExpr, assignmentExpr); if (assignmentExpr->mLeft != NULL) { MEMBER_SET(unaryOpExpr, mExpression, assignmentExpr->mLeft); unaryOpExpr->SetSrcEnd(assignmentExpr->mLeft->GetSrcEnd()); MEMBER_SET(assignmentExpr, mLeft, unaryOpExpr); exprLeft = assignmentExpr; } } if (auto dynCastExpr = BfNodeDynCast(unaryOpExpr->mExpression)) { // Apply unary operator (likely a dereference) to Expr dynCastExpr->RemoveSelf(); ReplaceNode(unaryOpExpr, dynCastExpr); if (dynCastExpr->mTarget != NULL) { MEMBER_SET(unaryOpExpr, mExpression, dynCastExpr->mTarget); unaryOpExpr->SetSrcEnd(dynCastExpr->mTarget->GetSrcEnd()); MEMBER_SET(dynCastExpr, mTarget, unaryOpExpr); exprLeft = dynCastExpr; } } if (auto caseExpr = BfNodeDynCast(unaryOpExpr->mExpression)) { // Apply unary operator (likely a dereference) to Expr caseExpr->RemoveSelf(); ReplaceNode(unaryOpExpr, caseExpr); if (caseExpr->mValueExpression != NULL) { MEMBER_SET(unaryOpExpr, mExpression, caseExpr->mValueExpression); unaryOpExpr->SetSrcEnd(caseExpr->mValueExpression->GetSrcEnd()); MEMBER_SET(caseExpr, mValueExpression, unaryOpExpr); exprLeft = caseExpr; } } } } } } if (exprLeft == NULL) { Fail("Expected expression", node); return NULL; } while (true) { auto nextNode = mVisitorPos.GetNext(); if (nextNode == NULL) break; if (auto tokenNode = BfNodeDynCast(nextNode)) { BfToken token = tokenNode->GetToken(); if (((createExprFlags & CreateExprFlags_BreakOnRChevron) != 0) && (token == BfToken_RChevron)) return exprLeft; if ((token == BfToken_DblPlus) || (token == BfToken_DblMinus)) { // Post-increment, post-decrement auto unaryOpExpr = mAlloc->Alloc(); ReplaceNode(exprLeft, unaryOpExpr); unaryOpExpr->mOp = (token == BfToken_DblPlus) ? BfUnaryOp_PostIncrement : BfUnaryOp_PostDecrement; MEMBER_SET(unaryOpExpr, mOpToken, tokenNode); MEMBER_SET(unaryOpExpr, mExpression, exprLeft); exprLeft = unaryOpExpr; mVisitorPos.MoveNext(); continue; } if (token == BfToken_As) { auto dynCastExpr = mAlloc->Alloc(); ReplaceNode(exprLeft, dynCastExpr); dynCastExpr->mTarget = exprLeft; MEMBER_SET(dynCastExpr, mAsToken, tokenNode); mVisitorPos.MoveNext(); auto typeRef = CreateTypeRefAfter(dynCastExpr); if (typeRef == NULL) return dynCastExpr; MEMBER_SET(dynCastExpr, mTypeRef, typeRef); return dynCastExpr; } if (token == BfToken_Is) { auto checkTypeExpr = mAlloc->Alloc(); ReplaceNode(exprLeft, checkTypeExpr); checkTypeExpr->mTarget = exprLeft; MEMBER_SET(checkTypeExpr, mIsToken, tokenNode); mVisitorPos.MoveNext(); auto typeRef = CreateTypeRefAfter(checkTypeExpr); if (typeRef == NULL) return checkTypeExpr; MEMBER_SET(checkTypeExpr, mTypeRef, typeRef); exprLeft = checkTypeExpr; continue; } if (token == BfToken_Question) { auto conditionExpr = mAlloc->Alloc(); ReplaceNode(exprLeft, conditionExpr); conditionExpr->mConditionExpression = exprLeft; MEMBER_SET(conditionExpr, mQuestionToken, tokenNode); mVisitorPos.MoveNext(); auto expr = CreateExpressionAfter(conditionExpr); if (expr != NULL) { MEMBER_SET(conditionExpr, mTrueExpression, expr); tokenNode = ExpectTokenAfter(conditionExpr, BfToken_Colon); if (tokenNode != NULL) { MEMBER_SET(conditionExpr, mColonToken, tokenNode); expr = CreateExpressionAfter(conditionExpr); if (expr != NULL) { MEMBER_SET(conditionExpr, mFalseExpression, expr); } } } exprLeft = conditionExpr; continue; } if ((token == BfToken_Case) && ((createExprFlags & CreateStmtFlags_NoCaseExpr) == 0)) { // If we have a ".Member case " expression, that is an invalid construct. We bail out here // because it allows the ".Member" to autocomplete because we will treat it as a full expression instead // of making it the target of an illegal expression if (auto memberRefLeft = BfNodeDynCast(exprLeft)) { if (memberRefLeft->mTarget == NULL) return exprLeft; } auto caseExpr = mAlloc->Alloc(); ReplaceNode(exprLeft, caseExpr); caseExpr->mValueExpression = exprLeft; MEMBER_SET(caseExpr, mCaseToken, tokenNode); mVisitorPos.MoveNext(); exprLeft = caseExpr; if (auto bindTokenNode = BfNodeDynCast(mVisitorPos.GetNext())) { BfToken bindToken = bindTokenNode->GetToken(); if ((bindToken == BfToken_Var) || (bindToken == BfToken_Let)) { auto expr = CreateEnumCaseBindExpression(bindTokenNode); if (expr == NULL) continue; MEMBER_SET(caseExpr, mCaseExpression, expr); } } if (caseExpr->mCaseExpression == NULL) { auto expr = CreateExpressionAfter(caseExpr, (CreateExprFlags)(CreateExprFlags_NoAssignment | CreateExprFlags_PermissiveVariableDecl)); if (expr == NULL) continue; MEMBER_SET(caseExpr, mCaseExpression, expr); } continue; } if (token == BfToken_LChevron) { bool hadEndingToken = false; // If this is a complex member reference (IE: GType.sVal) then condense in into a BfMemberReference. // We need to be conservative about typeRef names, so GType.A.B.C.D, we can only assume "GType.A" is a typeref // and the ".B.C.D" part is exposed as a MemberReference that may or may not include inner types int outNodeIdx = -1; bool isGenericType = false; bool isTypeRef = ((IsTypeReference(exprLeft, BfToken_None, &outNodeIdx, NULL, &isGenericType)) && (outNodeIdx != -1)); BfAstNode* outNode = mVisitorPos.Get(outNodeIdx); if ((!isTypeRef) && (outNodeIdx != -1)) { if ((isGenericType) && (outNode == NULL)) { for (int checkOutNodeIdx = outNodeIdx + 1; true; checkOutNodeIdx++) { BfAstNode* checkNode = mVisitorPos.Get(checkOutNodeIdx); if (checkNode == NULL) break; outNode = checkNode; } isTypeRef = true; } else if (auto outTokenNode = BfNodeDynCast(outNode)) { BfToken outToken = outTokenNode->GetToken(); if ((outToken == BfToken_Semicolon) || (outToken == BfToken_RParen) || (outToken == BfToken_Comma) || (outToken == BfToken_Let) || (outToken == BfToken_Var) || (outToken == BfToken_Const)) { auto prevNode = mVisitorPos.Get(outNodeIdx - 1); if (auto prevToken = BfNodeDynCast(prevNode)) { // This handles such as "dlg = stack => obj.method;" if (prevToken->GetToken() == BfToken_RChevron) hadEndingToken = true; } } //TODO: We had BfToken_Semicolon here, but it broke legitimate cases of "a.b.c < d.e.f;" expressions //if ((outToken == BfToken_Semicolon) || (isGenericType) || (outToken == BfToken_LParen) || (outToken == BfToken_Var) || (outToken == BfToken_Const)) { // Was just 'true' int newOutNodeIdx = -1; bool newIsTypeRef = IsTypeReference(exprLeft, outToken, &newOutNodeIdx, NULL, &isGenericType); BfAstNode* newOutNode = mVisitorPos.Get(newOutNodeIdx); if ((newIsTypeRef) && (newOutNode == outNode) && (isGenericType)) isTypeRef = true; } } } if (isTypeRef) { auto startIdentifier = exprLeft; int curNodeEndIdx = outNodeIdx - 1; BfAstNode* curNodeEnd = mVisitorPos.Get(curNodeEndIdx); bool isDotName = false; if (auto qualifiedIdentifierNode = BfNodeDynCast(startIdentifier)) { // Don't try to convert dot-name to a qualified type isDotName = qualifiedIdentifierNode->mTarget == NULL; } bool didSplit = false; for (int checkIdx = curNodeEndIdx; checkIdx >= mVisitorPos.mReadPos; checkIdx--) { if (isDotName) break; auto checkNode = mVisitorPos.Get(checkIdx); if (auto tokenNode = BfNodeDynCast(checkNode)) { BfToken token = tokenNode->GetToken(); if ((token == BfToken_RChevron) || (token == BfToken_RDblChevron)) { auto nextCheckNode = mVisitorPos.Get(checkIdx + 1); if (auto nextTokenNode = BfNodeDynCast(nextCheckNode)) { if (nextTokenNode->GetToken() == BfToken_Dot) { auto nextNextCheckNode = mVisitorPos.Get(checkIdx + 2); if (auto identifierNode = BfNodeDynCast(nextNextCheckNode)) { // Remove dot temporarily so we create a typedef up to that dot nextTokenNode->SetToken(BfToken_None); auto typeRef = CreateTypeRef(startIdentifier); if (typeRef == NULL) return NULL; nextTokenNode->SetToken(BfToken_Dot); auto memberRefExpr = mAlloc->Alloc(); ReplaceNode(identifierNode, memberRefExpr); MEMBER_SET(memberRefExpr, mDotToken, nextTokenNode); MEMBER_SET(memberRefExpr, mTarget, typeRef); MEMBER_SET(memberRefExpr, mMemberName, identifierNode); exprLeft = memberRefExpr; mVisitorPos.mReadPos = checkIdx + 2; didSplit = true; break; } else if (auto tokenNode = BfNodeDynCast(nextNextCheckNode)) { if (tokenNode->GetToken() == BfToken_LBracket) { // Remove dot temporarily so we create a typedef up to that dot nextTokenNode->SetToken(BfToken_None); auto typeRef = CreateTypeRef(startIdentifier); if (typeRef == NULL) return NULL; nextTokenNode->SetToken(BfToken_Dot); mVisitorPos.mReadPos = checkIdx + 0; exprLeft = CreateMemberReferenceExpression(typeRef); didSplit = true; } } } else if (nextTokenNode->GetToken() == BfToken_LBracket) { int endNodeIdx = -1; if (IsTypeReference(startIdentifier, BfToken_LParen, &endNodeIdx)) { if (endNodeIdx > checkIdx + 1) { auto typeRef = CreateTypeRef(startIdentifier); auto arrayType = BfNodeDynCast(typeRef); if (arrayType == NULL) return NULL; mVisitorPos.mReadPos = checkIdx + 0; auto arrayCreateExpr = mAlloc->Alloc(); ReplaceNode(typeRef, arrayCreateExpr); arrayCreateExpr->mTypeRef = arrayType; mVisitorPos.mReadPos = endNodeIdx; auto initializerExpr = CreateCollectionInitializerExpression(BfNodeDynCast(mVisitorPos.GetCurrent())); MEMBER_SET(arrayCreateExpr, mInitializer, initializerExpr); exprLeft = arrayCreateExpr; return arrayCreateExpr; } } } } } } } if (didSplit) continue; } // Could be a struct generic initializer, or a generic method invocation if (auto outToken = BfNodeDynCast(outNode)) { int endNodeIdx = -1; if ((outToken->GetToken() == BfToken_LParen) && (IsTypeReference(exprLeft, BfToken_LParen, &endNodeIdx))) { exprLeft = CreateInvocationExpression(exprLeft); if (exprLeft == NULL) return NULL; continue; } } if (hadEndingToken) return exprLeft; } if (token == BfToken_Star) { auto nextNode = mVisitorPos.GetNext(); if (auto nextToken = BfNodeDynCast(nextNode)) { if ((nextToken->mToken == BfToken_Star) || (nextToken->mToken == BfToken_LBracket)) { //if (IsTypeReference(tokenNode, BfToken_LBracket)) { /*auto typeRef = CreateTypeRef(tokenNode, true); exprLeft = CreateObjectCreateExpression(typeRef); return exprLeft;*/ } } } } BfBinaryOp binOp = TokenToBinaryOp(tokenNode->GetToken()); if (binOp != BfBinaryOp_None) { auto binOpExpression = mAlloc->Alloc(); ReplaceNode(exprLeft, binOpExpression); binOpExpression->mLeft = exprLeft; binOpExpression->mOp = binOp; MEMBER_SET(binOpExpression, mOpToken, tokenNode); mVisitorPos.MoveNext(); // We only need to check binary operator precedence at the "top level" binary operator rhsCreateExprFlags = (CreateExprFlags)(rhsCreateExprFlags | CreateExprFlags_NoCheckBinOpPrecedence); auto exprRight = CreateExpressionAfter(binOpExpression, rhsCreateExprFlags); if (exprRight == NULL) return binOpExpression; MEMBER_SET(binOpExpression, mRight, exprRight); if ((createExprFlags & CreateExprFlags_NoCheckBinOpPrecedence) != 0) return binOpExpression; return CheckBinaryOperatorPrecedence(binOpExpression); } auto assignmentOp = TokenToAssignmentOp(tokenNode->GetToken()); if (assignmentOp != BfAssignmentOp_None) { if ((createExprFlags & CreateExprFlags_NoAssignment) != 0) return exprLeft; auto assignmentExpression = mAlloc->Alloc(); ReplaceNode(exprLeft, assignmentExpression); mVisitorPos.MoveNext(); assignmentExpression->mOp = assignmentOp; assignmentExpression->mLeft = exprLeft; assignmentExpression->mOpToken = tokenNode; MoveNode(assignmentExpression->mOpToken, assignmentExpression); bool continueCascade = false; if (auto memberExpr = BfNodeDynCast(exprLeft)) { if (memberExpr->mDotToken->GetToken() == BfToken_DotDot) continueCascade = true; } CreateExprFlags flags = rhsCreateExprFlags; if (continueCascade) flags = (CreateExprFlags)(rhsCreateExprFlags | CreateExprFlags_BreakOnCascade); auto exprRight = CreateExpressionAfter(assignmentExpression, flags); if (exprRight == NULL) { FailAfter("Invalid expression", assignmentExpression); return assignmentExpression; } assignmentExpression->mRight = exprRight; MoveNode(assignmentExpression->mRight, assignmentExpression); if (continueCascade) { if (auto nextToken = BfNodeDynCast(mVisitorPos.GetNext())) { if (nextToken->GetToken() == BfToken_DotDot) { exprLeft = assignmentExpression; continue; } } } return assignmentExpression; } BF_ASSERT(tokenNode->GetToken() == token); // Not a binary op, it's a 'close' if (token == BfToken_Bang) { if ((createExprFlags & CreateExprFlags_ExitOnBang) != 0) return exprLeft; exprLeft = CreateInvocationExpression(exprLeft); } else if (token == BfToken_LParen) { exprLeft = CreateInvocationExpression(exprLeft, (CreateExprFlags)(createExprFlags & ~(CreateExprFlags_NoCast))); } else if ((token == BfToken_LBracket) || (token == BfToken_QuestionLBracket)) { exprLeft = CreateIndexerExpression(exprLeft); } else if ((token == BfToken_Dot) || (token == BfToken_DotDot) || (token == BfToken_QuestionDot)) { if ((token == BfToken_DotDot) && ((createExprFlags & CreateExprFlags_BreakOnCascade) != 0)) return exprLeft; if (auto memberExpr = BfNodeDynCastExact(exprLeft)) { if (memberExpr->mTarget == NULL) { // A dot syntax like ".A.B" is never valid - to help with autocomplete we stop the expr parsing here Fail("Unexpected '.' token", tokenNode); return exprLeft; } } exprLeft = CreateMemberReferenceExpression(exprLeft); } else { return exprLeft; } if (exprLeft == NULL) return NULL; } else break; } return exprLeft; } BfExpression* BfReducer::CreateExpressionAfter(BfAstNode* node, CreateExprFlags createExprFlags) { AssertCurrentNode(node); auto nextNode = mVisitorPos.GetNext(); bool isEmpty = false; if (auto tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_RParen) isEmpty = true; } if ((nextNode == NULL) || (isEmpty)) { FailAfter("Expression expected", node); return NULL; } int startReadPos = mVisitorPos.mReadPos; mVisitorPos.MoveNext(); auto result = CreateExpression(nextNode, createExprFlags); if (result == NULL) { // Nope, didn't handle it mVisitorPos.mReadPos = startReadPos; } return result; } BfForEachStatement* BfReducer::CreateForEachStatement(BfAstNode* node, bool hasTypeDecl) { auto forToken = BfNodeDynCast(node); auto parenToken = ExpectTokenAfter(forToken, BfToken_LParen); if (parenToken == NULL) return NULL; auto forEachStatement = mAlloc->Alloc(); ReplaceNode(forToken, forEachStatement); MEMBER_SET(forEachStatement, mForToken, forToken); MEMBER_SET(forEachStatement, mOpenParen, parenToken); if (hasTypeDecl) { if (auto tokenNode = BfNodeDynCast(mVisitorPos.GetNext())) { if (tokenNode->mToken == BfToken_ReadOnly) { MEMBER_SET_CHECKED(forEachStatement, mReadOnlyToken, tokenNode); mVisitorPos.MoveNext(); } } auto typeRef = CreateTypeRefAfter(forEachStatement); if (typeRef == NULL) return forEachStatement; MEMBER_SET_CHECKED(forEachStatement, mVariableTypeRef, typeRef); } if (auto nextNode = BfNodeDynCast(mVisitorPos.GetNext())) { if (nextNode->mToken == BfToken_LParen) { mVisitorPos.MoveNext(); auto tupleNode = CreateTupleExpression(nextNode); MEMBER_SET_CHECKED(forEachStatement, mVariableName, tupleNode); } } if (forEachStatement->mVariableName == NULL) { auto name = ExpectIdentifierAfter(forEachStatement, "variable name"); MEMBER_SET_CHECKED(forEachStatement, mVariableName, name); } auto inToken = ExpectTokenAfter(forEachStatement, BfToken_In, BfToken_LChevron); MEMBER_SET_CHECKED(forEachStatement, mInToken, inToken); auto expr = CreateExpressionAfter(forEachStatement); MEMBER_SET_CHECKED(forEachStatement, mCollectionExpression, expr); parenToken = ExpectTokenAfter(forEachStatement, BfToken_RParen); MEMBER_SET_CHECKED(forEachStatement, mCloseParen, parenToken); auto stmt = CreateStatementAfter(forEachStatement, CreateStmtFlags_FindTrailingSemicolon); if (stmt == NULL) return forEachStatement; MEMBER_SET(forEachStatement, mEmbeddedStatement, stmt); return forEachStatement; } BfStatement* BfReducer::CreateForStatement(BfAstNode* node) { int startReadIdx = mVisitorPos.mReadPos; auto forToken = BfNodeDynCast(node); auto parenToken = ExpectTokenAfter(forToken, BfToken_LParen); if (parenToken == NULL) return NULL; int outNodeIdx = -1; auto nextNode = mVisitorPos.GetNext(); if (auto tokenNode = BfNodeDynCast(nextNode)) { // Handle 'for (let (key, value) in dict)' if ((tokenNode->mToken == BfToken_Let) || (tokenNode->mToken == BfToken_Var)) { if (auto afterLet = BfNodeDynCast(mVisitorPos.Get(mVisitorPos.mReadPos + 2))) { if (afterLet->mToken == BfToken_LParen) { bool isTupleIn = true; int parenDepth = 1; for (int readPos = mVisitorPos.mReadPos + 3; true; readPos++) { auto checkNode = mVisitorPos.Get(readPos); if (auto tokenNode = BfNodeDynCast(checkNode)) { if (tokenNode->mToken == BfToken_RParen) { if (parenDepth != 1) { isTupleIn = false; break; } parenDepth--; } else if (tokenNode->mToken == BfToken_In) { if (parenDepth != 0) isTupleIn = false; break; } else if (tokenNode->mToken == BfToken_Comma) { // } else { isTupleIn = false; break; } } else if (auto identifierNode = BfNodeDynCast(checkNode)) { // } else { isTupleIn = false; break; } } if (isTupleIn) { mVisitorPos.mReadPos = startReadIdx; return CreateForEachStatement(node, true); } } } } } bool isTypeRef = false; if (auto nextToken = BfNodeDynCast(nextNode)) { if (nextNode->mToken == BfToken_ReadOnly) { mVisitorPos.mReadPos += 2; isTypeRef = IsTypeReference(mVisitorPos.Get(mVisitorPos.mReadPos), BfToken_None, &outNodeIdx); mVisitorPos.mReadPos -= 2; } } if (!isTypeRef) { mVisitorPos.mReadPos++; isTypeRef = IsTypeReference(nextNode, BfToken_None, &outNodeIdx); mVisitorPos.mReadPos--; } BfAstNode* outNode = mVisitorPos.Get(outNodeIdx); if (isTypeRef) { auto nextNode = mVisitorPos.Get(outNodeIdx + 1); if ((outNode != NULL) && (nextNode != NULL)) { auto tokenNode = BfNodeDynCast(nextNode); if (tokenNode != NULL) { int token = tokenNode->GetToken(); if ((token == BfToken_In) || (token == BfToken_LChevron)) { mVisitorPos.mReadPos = startReadIdx; return CreateForEachStatement(node, true); } } } } else { int checkNodeIdx = (outNodeIdx != -1) ? outNodeIdx : mVisitorPos.mReadPos + 1; auto checkNode = mVisitorPos.Get(checkNodeIdx); if (auto tokenNode = BfNodeDynCast(checkNode)) { BfToken token = tokenNode->GetToken(); // Is this an 'anonymous' foreach? if ((token != BfToken_Semicolon) && (token != BfToken_LChevron) && (token != BfToken_In) && (token != BfToken_AssignEquals)) { mVisitorPos.mReadPos = startReadIdx; auto forToken = BfNodeDynCast(node); auto parenToken = ExpectTokenAfter(forToken, BfToken_LParen); if (parenToken == NULL) return NULL; auto forEachStatement = mAlloc->Alloc(); ReplaceNode(forToken, forEachStatement); MEMBER_SET(forEachStatement, mForToken, forToken); MEMBER_SET(forEachStatement, mOpenParen, parenToken); auto expr = CreateExpressionAfter(forEachStatement); MEMBER_SET_CHECKED(forEachStatement, mCollectionExpression, expr); parenToken = ExpectTokenAfter(forEachStatement, BfToken_RParen); MEMBER_SET_CHECKED(forEachStatement, mCloseParen, parenToken); auto stmt = CreateStatementAfter(forEachStatement, CreateStmtFlags_FindTrailingSemicolon); if (stmt == NULL) return forEachStatement; MEMBER_SET(forEachStatement, mEmbeddedStatement, stmt); return forEachStatement; } } } auto nextNextNode = mVisitorPos.Get(mVisitorPos.mReadPos + 2); if (auto tokenNode = BfNodeDynCast(nextNextNode)) { if ((tokenNode != NULL) && ((tokenNode->GetToken() == BfToken_LChevron) || (tokenNode->GetToken() == BfToken_In))) { Fail("Ranged for statement must declare new value variable, consider adding a type name, 'var', or 'let'", tokenNode); mVisitorPos.mReadPos = startReadIdx; return CreateForEachStatement(node, false); } } BfAstNode* stmt; auto forStatement = mAlloc->Alloc(); BfDeferredAstSizedArray initializers(forStatement->mInitializers, mAlloc); BfDeferredAstSizedArray initializerCommas(forStatement->mInitializerCommas, mAlloc); BfDeferredAstSizedArray iterators(forStatement->mIterators, mAlloc); BfDeferredAstSizedArray iteratorCommas(forStatement->mIteratorCommas, mAlloc); ReplaceNode(forToken, forStatement); MEMBER_SET(forStatement, mForToken, forToken); MEMBER_SET(forStatement, mOpenParen, parenToken); // Initializers for (int listIdx = 0; true; listIdx++) { auto nextNode = mVisitorPos.GetNext(); if ((listIdx > 0) || (!IsSemicolon(nextNode))) { auto stmt = CreateStatementAfter(forStatement); if (stmt == NULL) return forStatement; initializers.push_back(stmt); MoveNode(stmt, forStatement); } nextNode = mVisitorPos.GetNext(); auto tokenNode = BfNodeDynCast(nextNode); if (tokenNode == NULL) return forStatement; if (tokenNode->GetToken() == BfToken_Semicolon) { MEMBER_SET(forStatement, mInitializerSemicolon, tokenNode); mVisitorPos.MoveNext(); break; } else if (tokenNode->GetToken() == BfToken_Comma) { MoveNode(tokenNode, forStatement); initializerCommas.push_back(tokenNode); mVisitorPos.MoveNext(); } else { Fail("Expected ',' or ';'", tokenNode); return forStatement; } } // Condition nextNode = mVisitorPos.GetNext(); if (!IsSemicolon(nextNode)) { bool doExpr = true; if (auto tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_RParen) { Fail("Expected expression or ';'", tokenNode); doExpr = false; } } if (doExpr) { auto expr = CreateExpressionAfter(forStatement); if (expr == NULL) return forStatement; MEMBER_SET(forStatement, mCondition, expr); } } auto tokenNode = ExpectTokenAfter(forStatement, BfToken_Semicolon); if (tokenNode == NULL) return forStatement; MEMBER_SET(forStatement, mConditionSemicolon, tokenNode); // Iterators for (int listIdx = 0; true; listIdx++) { if (listIdx == 0) { auto nextNode = mVisitorPos.GetNext(); if (auto tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_RParen) { MEMBER_SET(forStatement, mCloseParen, tokenNode); mVisitorPos.MoveNext(); break; } } } auto stmt = CreateStatementAfter(forStatement); if (stmt == NULL) return forStatement; iterators.push_back(stmt); MoveNode(stmt, forStatement); auto nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); if (tokenNode == NULL) return forStatement; if (tokenNode->GetToken() == BfToken_RParen) { MEMBER_SET(forStatement, mCloseParen, tokenNode); mVisitorPos.MoveNext(); break; } else if (tokenNode->GetToken() == BfToken_Comma) { MoveNode(tokenNode, forStatement); iteratorCommas.push_back(tokenNode); mVisitorPos.MoveNext(); } else { Fail("Expected ',' or ')'", tokenNode); return forStatement; } } stmt = CreateStatementAfter(forStatement, CreateStmtFlags_FindTrailingSemicolon); if (stmt == NULL) return forStatement; MEMBER_SET(forStatement, mEmbeddedStatement, stmt); return forStatement; } BfUsingStatement* BfReducer::CreateUsingStatement(BfAstNode* node) { auto tokenNode = BfNodeDynCast(node); auto usingStatement = mAlloc->Alloc(); ReplaceNode(tokenNode, usingStatement); MEMBER_SET(usingStatement, mUsingToken, tokenNode); tokenNode = ExpectTokenAfter(usingStatement, BfToken_LParen); if (tokenNode == NULL) return NULL; MEMBER_SET(usingStatement, mOpenParen, tokenNode); auto nextNode = mVisitorPos.GetNext(); if (nextNode != NULL) { BfVariableDeclaration* varDecl = mAlloc->Alloc(); int outNodeIdx = -1; auto nextNode = mVisitorPos.GetNext(); mVisitorPos.mReadPos++; bool isTypeReference = IsTypeReference(nextNode, BfToken_None, &outNodeIdx); mVisitorPos.mReadPos--; if (isTypeReference) { BfAstNode* outNode = mVisitorPos.Get(outNodeIdx); BfAstNode* outNodeNext = mVisitorPos.Get(outNodeIdx + 1); BfTokenNode* equalsNode = NULL; if ((outNode != NULL) && (BfNodeIsA(outNode)) && (BfNodeIsA(outNodeNext))) { auto typeRef = CreateTypeRefAfter(usingStatement); if (typeRef == NULL) return usingStatement; MEMBER_SET(varDecl, mTypeRef, typeRef); usingStatement->SetSrcEnd(typeRef->GetSrcEnd()); auto nameNode = ExpectIdentifierAfter(usingStatement, "variable name"); if (nameNode == NULL) return usingStatement; MEMBER_SET(varDecl, mNameNode, nameNode); usingStatement->SetSrcEnd(varDecl->GetSrcEnd()); auto equalsNode = ExpectTokenAfter(usingStatement, BfToken_AssignEquals); if (equalsNode == NULL) return usingStatement; MEMBER_SET(varDecl, mEqualsNode, equalsNode); usingStatement->SetSrcEnd(equalsNode->GetSrcEnd()); } } auto expr = CreateExpressionAfter(usingStatement); if (expr == NULL) return usingStatement; MEMBER_SET(varDecl, mInitializer, expr); MEMBER_SET(usingStatement, mVariableDeclaration, varDecl); } tokenNode = ExpectTokenAfter(usingStatement, BfToken_RParen); if (tokenNode == NULL) return usingStatement; MEMBER_SET(usingStatement, mCloseParen, tokenNode); auto stmt = CreateStatementAfter(usingStatement, CreateStmtFlags_FindTrailingSemicolon); if (stmt == NULL) return usingStatement; MEMBER_SET(usingStatement, mEmbeddedStatement, stmt); return usingStatement; } BfWhileStatement* BfReducer::CreateWhileStatement(BfAstNode* node) { auto tokenNode = BfNodeDynCast(node); auto whileStatement = mAlloc->Alloc(); ReplaceNode(tokenNode, whileStatement); MEMBER_SET(whileStatement, mWhileToken, tokenNode); tokenNode = ExpectTokenAfter(whileStatement, BfToken_LParen); if (tokenNode == NULL) return NULL; MEMBER_SET(whileStatement, mOpenParen, tokenNode); // Condition auto nextNode = mVisitorPos.GetNext(); if (!IsSemicolon(nextNode)) { auto expr = CreateExpressionAfter(whileStatement); if (expr == NULL) return whileStatement; MEMBER_SET(whileStatement, mCondition, expr); } tokenNode = ExpectTokenAfter(whileStatement, BfToken_RParen); if (tokenNode == NULL) return whileStatement; MEMBER_SET(whileStatement, mCloseParen, tokenNode); auto stmt = CreateStatementAfter(whileStatement, CreateStmtFlags_FindTrailingSemicolon); if (stmt == NULL) return whileStatement; MEMBER_SET(whileStatement, mEmbeddedStatement, stmt); return whileStatement; } BfDoStatement* BfReducer::CreateDoStatement(BfAstNode* node) { auto tokenNode = BfNodeDynCast(node); auto doStatement = mAlloc->Alloc(); ReplaceNode(tokenNode, doStatement); MEMBER_SET(doStatement, mDoToken, tokenNode); auto stmt = CreateStatementAfter(doStatement, CreateStmtFlags_FindTrailingSemicolon); if (stmt != NULL) { MEMBER_SET(doStatement, mEmbeddedStatement, stmt); } return doStatement; } BfRepeatStatement* BfReducer::CreateRepeatStatement(BfAstNode* node) { auto tokenNode = BfNodeDynCast(node); auto repeatStatement = mAlloc->Alloc(); ReplaceNode(tokenNode, repeatStatement); MEMBER_SET(repeatStatement, mRepeatToken, tokenNode); auto stmt = CreateStatementAfter(repeatStatement, CreateStmtFlags_FindTrailingSemicolon); if (stmt != NULL) { MEMBER_SET(repeatStatement, mEmbeddedStatement, stmt); } tokenNode = ExpectTokenAfter(repeatStatement, BfToken_While); if (tokenNode != NULL) { MEMBER_SET(repeatStatement, mWhileToken, tokenNode); } tokenNode = ExpectTokenAfter(repeatStatement, BfToken_LParen); if (tokenNode != NULL) { MEMBER_SET(repeatStatement, mOpenParen, tokenNode); } // Condition auto nextNode = mVisitorPos.GetNext(); if (!IsSemicolon(nextNode)) { auto expr = CreateExpressionAfter(repeatStatement); if (expr == NULL) return repeatStatement; MEMBER_SET(repeatStatement, mCondition, expr); } tokenNode = ExpectTokenAfter(repeatStatement, BfToken_RParen); if (tokenNode != NULL) { MEMBER_SET(repeatStatement, mCloseParen, tokenNode); } return repeatStatement; } BfSwitchStatement* BfReducer::CreateSwitchStatement(BfTokenNode* tokenNode) { auto switchStatement = mAlloc->Alloc(); BfDeferredAstSizedArray switchCases(switchStatement->mSwitchCases, mAlloc); ReplaceNode(tokenNode, switchStatement); switchStatement->mSwitchToken = tokenNode; tokenNode = ExpectTokenAfter(switchStatement, BfToken_LParen); if (tokenNode != NULL) { MEMBER_SET(switchStatement, mOpenParen, tokenNode); } auto switchValue = CreateExpressionAfter(switchStatement); if (switchValue != NULL) { MEMBER_SET(switchStatement, mSwitchValue, switchValue); } tokenNode = ExpectTokenAfter(switchStatement, BfToken_RParen); if (tokenNode != NULL) { MEMBER_SET(switchStatement, mCloseParen, tokenNode); } auto block = ExpectBlockAfter(switchStatement); if (block == NULL) return switchStatement; MoveNode(block, switchStatement); switchStatement->mOpenBrace = block->mOpenBrace; switchStatement->mCloseBrace = block->mCloseBrace; bool hadEmptyCaseStatement = false; BfSwitchCase* switchCase = NULL; SetAndRestoreValue prevVisitorPos(mVisitorPos, BfVisitorPos(block)); bool isDone = !mVisitorPos.MoveNext(); while (!isDone) { auto child = mVisitorPos.GetCurrent(); tokenNode = BfNodeDynCast(child); BfToken token = BfToken_None; if (tokenNode != NULL) token = tokenNode->GetToken(); if ((tokenNode == NULL) || (token != BfToken_Case) && (token != BfToken_When) && (token != BfToken_Default)) { Fail("Expected 'case'", child); return switchStatement; } //TODO: This error was getting annoying... Put back? // This check is here at the top, being processed for the previous switchCase because // we don't throw an error on the last case in the switch /*if (hadEmptyCaseStatement) FailAfter("Expected case statement, 'fallthrough', or 'break'", switchCase);*/ bool isDefault = token == BfToken_Default; switchCase = mAlloc->Alloc(); BfDeferredAstSizedArray caseExpressions(switchCase->mCaseExpressions, mAlloc); BfDeferredAstSizedArray caseCommas(switchCase->mCaseCommas, mAlloc); ReplaceNode(tokenNode, switchCase); BfTokenNode* whenToken = NULL; if (token == BfToken_When) whenToken = tokenNode; else switchCase->mCaseToken = tokenNode; for (int caseIdx = 0; true; caseIdx++) { if (!isDefault) { BfExpression* expr = NULL; bool wasWhenSet = whenToken != NULL; if (!wasWhenSet) { auto nextNode = mVisitorPos.GetNext(); whenToken = BfNodeDynCast(nextNode); if ((whenToken != NULL) && (whenToken->GetToken() != BfToken_When)) whenToken = NULL; } if (whenToken != NULL) { auto whenExpr = mAlloc->Alloc(); whenExpr->mWhenToken = whenToken; ReplaceNode(whenToken, whenExpr); //mVisitorPos.MoveNext(); //auto exprAfter = wasWhenSet ? (BfAstNode*)switchCase : (BfAstNode*)whenExpr; if (expr == NULL) { auto innerExpr = CreateExpressionAfter(whenToken); if (innerExpr != NULL) { MEMBER_SET(whenExpr, mExpression, innerExpr); } expr = whenExpr; } } if (expr == NULL) { if (auto bindToken = BfNodeDynCast(mVisitorPos.GetNext())) { if ((bindToken->GetToken() == BfToken_Var) || (bindToken->GetToken() == BfToken_Let)) { expr = CreateEnumCaseBindExpression(bindToken); } } } if (expr == NULL) expr = CreateExpressionAfter(switchCase); if (expr == NULL) { /// } else { caseExpressions.push_back(expr); MoveNode(expr, switchCase); } } if ((whenToken == NULL) && (!isDefault)) tokenNode = ExpectTokenAfter(switchCase, BfToken_When, BfToken_Colon, BfToken_Comma); else tokenNode = ExpectTokenAfter(switchCase, BfToken_Colon); if (tokenNode == NULL) break; if (tokenNode->GetToken() == BfToken_When) { whenToken = tokenNode; continue; } if (tokenNode->GetToken() == BfToken_Colon) { MEMBER_SET(switchCase, mColonToken, tokenNode); break; } if (isDefault) { Fail("Expected ':'", tokenNode); break; } MoveNode(tokenNode, switchCase); caseCommas.push_back(tokenNode); BF_ASSERT(whenToken == NULL); } if (isDefault) { if (switchStatement->mDefaultCase != NULL) { Fail("Only one default case is allowed", switchCase); // Add to normal switch cases just so we process it switchCases.push_back(switchCase); } else switchStatement->mDefaultCase = switchCase; } else { if (switchStatement->mDefaultCase != NULL) { Fail("Default case must be last case", switchStatement->mDefaultCase); } switchCases.push_back(switchCase); } hadEmptyCaseStatement = true; auto codeBlock = mAlloc->Alloc(); //codeBlock->mSource = switchCase->mSource; MEMBER_SET(switchCase, mCodeBlock, codeBlock); //switchCase->Add(codeBlock); BfDeferredAstSizedArray codeBlockChildArr(codeBlock->mChildArr, mAlloc); while (true) { auto nextNode = mVisitorPos.GetNext(); auto tokenNode = BfNodeDynCast(nextNode); if (tokenNode != NULL) { int token = tokenNode->GetToken(); if ((token == BfToken_Case) || (token == BfToken_Default) || (token == BfToken_When)) break; // Done! No fallthrough } nextNode = mVisitorPos.GetNext(); if (nextNode == NULL) break; hadEmptyCaseStatement = false; mVisitorPos.MoveNext(); // We need to use CreateStmtFlags_NoCaseExpr because otherwise during typing a new statement at the end of one case, it // could interpret the 'case' token for the next case as being part of a case expression in the first case auto stmt = CreateStatement(nextNode, (CreateStmtFlags)(CreateStmtFlags_FindTrailingSemicolon | CreateStmtFlags_NoCaseExpr | CreateStmtFlags_AllowLocalFunction)); if (stmt == NULL) { AddErrorNode(nextNode); } else { MoveNode(stmt, codeBlock); codeBlockChildArr.push_back(stmt); } } MoveNode(switchCase, switchStatement); if (!codeBlock->IsInitialized()) { int srcPos = switchCase->GetSrcEnd(); codeBlock->Init(srcPos, srcPos, srcPos); } isDone = !mVisitorPos.MoveNext(); } return switchStatement; } // Does everything but pull the trailing semicolon BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createStmtFlags) { auto subCreateStmtFlags = (CreateStmtFlags)(createStmtFlags & (CreateStmtFlags_NoCaseExpr | CreateStmtFlags_FindTrailingSemicolon | CreateStmtFlags_AllowUnterminatedExpression)); if (node->IsA()) { auto block = (BfBlock*)node; HandleBlock(block, (createStmtFlags & CreateStmtFlags_AllowUnterminatedExpression) != 0); return block; } BfVariableDeclaration* continuingVariable = NULL; BfTokenNode* refToken = NULL; if (auto tokenNode = BfNodeDynCast(node)) { int token = tokenNode->GetToken(); if ((token == BfToken_Ref) || (token == BfToken_Mut)) { refToken = tokenNode; } else if (token == BfToken_Semicolon) { Fail("Empty statement not allowed", tokenNode); auto emptyStatement = mAlloc->Alloc(); ReplaceNode(tokenNode, emptyStatement); emptyStatement->mTrailingSemicolon = tokenNode; return emptyStatement; } else if (token == BfToken_Break) { auto breakStmt = mAlloc->Alloc(); ReplaceNode(tokenNode, breakStmt); breakStmt->mBreakNode = tokenNode; if (auto label = BfNodeDynCast(mVisitorPos.GetNext())) { MEMBER_SET(breakStmt, mLabel, label); mVisitorPos.MoveNext(); } else if (auto tokenNode = BfNodeDynCast(mVisitorPos.GetNext())) { if (tokenNode->GetToken() == BfToken_Mixin) { MEMBER_SET(breakStmt, mLabel, tokenNode); mVisitorPos.MoveNext(); } } return breakStmt; } else if (token == BfToken_Continue) { auto continueStmt = mAlloc->Alloc(); ReplaceNode(tokenNode, continueStmt); continueStmt->mContinueNode = tokenNode; if (auto label = BfNodeDynCast(mVisitorPos.GetNext())) { MEMBER_SET(continueStmt, mLabel, label); mVisitorPos.MoveNext(); } else if (auto tokenNode = BfNodeDynCast(mVisitorPos.GetNext())) { if (tokenNode->GetToken() == BfToken_Mixin) { MEMBER_SET(continueStmt, mLabel, tokenNode); mVisitorPos.MoveNext(); } } return continueStmt; } else if (token == BfToken_Fallthrough) { auto fallthroughStmt = mAlloc->Alloc(); ReplaceNode(tokenNode, fallthroughStmt); fallthroughStmt->mFallthroughToken = tokenNode; return fallthroughStmt; } else if (token == BfToken_For) { return CreateForStatement(node); } else if (token == BfToken_Using) { return CreateUsingStatement(node); } else if (token == BfToken_While) { return CreateWhileStatement(node); } else if (token == BfToken_Do) { auto checkNode = mVisitorPos.Get(mVisitorPos.mReadPos + 2); auto checkToken = BfNodeDynCast(checkNode); if ((checkToken != NULL) && (checkToken->GetToken() == BfToken_While)) return CreateRepeatStatement(node); else return CreateDoStatement(node); } else if (token == BfToken_Repeat) { return CreateRepeatStatement(node); } else if (token == BfToken_Return) { auto returnStmt = mAlloc->Alloc(); ReplaceNode(node, returnStmt); MEMBER_SET(returnStmt, mReturnToken, tokenNode); auto nextNode = mVisitorPos.GetNext(); if (!IsSemicolon(nextNode)) { auto expr = CreateExpressionAfter(returnStmt); MEMBER_SET_CHECKED(returnStmt, mExpression, expr); } return returnStmt; } else if (token == BfToken_Delete) { auto deleteStmt = mAlloc->Alloc(); ReplaceNode(node, deleteStmt); MEMBER_SET(deleteStmt, mDeleteToken, tokenNode); auto nextNode = mVisitorPos.GetNext(); if (tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_Append) { MEMBER_SET(deleteStmt, mTargetTypeToken, tokenNode); } else if (tokenNode->GetToken() == BfToken_Colon) { MEMBER_SET(deleteStmt, mTargetTypeToken, tokenNode); mVisitorPos.MoveNext(); if (auto tokenNode = BfNodeDynCast(mVisitorPos.GetNext())) { if (tokenNode->mToken == BfToken_Append) { MEMBER_SET(deleteStmt, mAllocExpr, tokenNode); mVisitorPos.MoveNext(); } } if (deleteStmt->mAllocExpr == NULL) { auto allocExpr = CreateExpressionAfter(deleteStmt); if (allocExpr != NULL) { MEMBER_SET(deleteStmt, mAllocExpr, allocExpr); } } } } auto expr = CreateExpressionAfter(deleteStmt); MEMBER_SET_CHECKED(deleteStmt, mExpression, expr); return deleteStmt; } else if (token == BfToken_Throw) { auto throwStmt = mAlloc->Alloc(); ReplaceNode(node, throwStmt); MEMBER_SET(throwStmt, mThrowToken, tokenNode); auto expr = CreateExpressionAfter(throwStmt); MEMBER_SET_CHECKED(throwStmt, mExpression, expr); return throwStmt; } else if (token == BfToken_If) { subCreateStmtFlags = (CreateStmtFlags)(createStmtFlags & (CreateStmtFlags_FindTrailingSemicolon)); auto ifStmt = mAlloc->Alloc(); ReplaceNode(node, ifStmt); MEMBER_SET(ifStmt, mIfToken, tokenNode); tokenNode = ExpectTokenAfter(ifStmt, BfToken_LParen); MEMBER_SET_CHECKED(ifStmt, mOpenParen, tokenNode); auto condExpr = CreateExpressionAfter(ifStmt, CreateExprFlags_AllowVariableDecl); MEMBER_SET_CHECKED(ifStmt, mCondition, condExpr); tokenNode = ExpectTokenAfter(ifStmt, BfToken_RParen); MEMBER_SET_CHECKED(ifStmt, mCloseParen, tokenNode); auto trueStmt = CreateStatementAfter(ifStmt, subCreateStmtFlags); MEMBER_SET_CHECKED(ifStmt, mTrueStatement, trueStmt); auto nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_Else)) { MEMBER_SET(ifStmt, mElseToken, tokenNode); mVisitorPos.MoveNext(); auto falseStmt = CreateStatementAfter(ifStmt, subCreateStmtFlags); MEMBER_SET_CHECKED(ifStmt, mFalseStatement, falseStmt); } return ifStmt; } else if (token == BfToken_Switch) { return CreateSwitchStatement(tokenNode); } else if (token == BfToken_Defer) { auto deferStmt = mAlloc->Alloc(); ReplaceNode(tokenNode, deferStmt); deferStmt->mDeferToken = tokenNode; auto nextNode = mVisitorPos.GetNext(); if (auto nextTokenNode = BfNodeDynCast(nextNode)) { if (nextTokenNode->GetToken() == BfToken_Colon) { MEMBER_SET(deferStmt, mColonToken, nextTokenNode); mVisitorPos.MoveNext(); if (auto nextToken = BfNodeDynCast(mVisitorPos.GetNext())) { if ((nextToken->GetToken() == BfToken_Colon) || (nextToken->GetToken() == BfToken_Mixin)) { MEMBER_SET(deferStmt, mScopeName, nextToken); mVisitorPos.MoveNext(); } } else if (auto identifier = BfNodeDynCast(mVisitorPos.GetNext())) { MEMBER_SET(deferStmt, mScopeName, identifier); mVisitorPos.MoveNext(); } if (deferStmt->mScopeName == NULL) { FailAfter("Expected scope name", deferStmt); } } else if (nextTokenNode->GetToken() == BfToken_LParen) { MEMBER_SET(deferStmt, mOpenParen, nextTokenNode); mVisitorPos.MoveNext(); nextTokenNode = ExpectTokenAfter(deferStmt, BfToken_Scope, BfToken_Stack); MEMBER_SET_CHECKED(deferStmt, mScopeToken, nextTokenNode); nextTokenNode = ExpectTokenAfter(deferStmt, BfToken_RParen); MEMBER_SET_CHECKED(deferStmt, mCloseParen, nextTokenNode); } } if (auto nextTokenNode = BfNodeDynCast(mVisitorPos.GetNext())) { if (nextTokenNode->GetToken() == BfToken_LBracket) { auto bindNode = mAlloc->Alloc(); ReplaceNode(nextTokenNode, bindNode); MEMBER_SET(bindNode, mOpenBracket, nextTokenNode); mVisitorPos.MoveNext(); BfDeferredAstSizedArray params(bindNode->mParams, mAlloc); BfDeferredAstSizedArray commas(bindNode->mCommas, mAlloc); for (int paramIdx = 0; true; paramIdx++) { bool isRBracket = false; auto nextNode = mVisitorPos.GetNext(); if (auto tokenNode = BfNodeDynCast(nextNode)) isRBracket = tokenNode->GetToken() == BfToken_RBracket; if (!isRBracket) { auto nameIdentifier = ExpectIdentifierAfter(bindNode, "parameter name"); if (nameIdentifier == NULL) break; MoveNode(nameIdentifier, bindNode); params.push_back(nameIdentifier); } tokenNode = ExpectTokenAfter(bindNode, BfToken_Comma, BfToken_RBracket); if (tokenNode == NULL) return deferStmt; if (tokenNode->GetToken() == BfToken_RBracket) { MEMBER_SET(bindNode, mCloseBracket, tokenNode); break; } MoveNode(tokenNode, bindNode); commas.push_back(tokenNode); } MEMBER_SET(deferStmt, mBind, bindNode); } } BfAstNode* targetNode = CreateStatementAfter(deferStmt); if (targetNode != NULL) { BfAstNode* innerTarget = targetNode; if (auto exprStmt = BfNodeDynCast(innerTarget)) innerTarget = exprStmt->mExpression; if (deferStmt->mBind != NULL) { if (!innerTarget->IsA()) { Fail("Only blocks are allowed when defer binding is used", targetNode); } } else { if ((!innerTarget->IsA()) && (!innerTarget->IsA()) && (!innerTarget->IsA())) { Fail("Only invocation expressions, statement blocks, or deletes are allowed", targetNode); } } MEMBER_SET(deferStmt, mTargetNode, targetNode); } return deferStmt; } else if (token == BfToken_Comma) { auto prevVarDecl = mVisitorPos.Get(mVisitorPos.mWritePos - 1); if (auto exprStmt = BfNodeDynCast(prevVarDecl)) { continuingVariable = BfNodeDynCast(exprStmt->mExpression); } } else if ((token == BfToken_Const) || (token == BfToken_ReadOnly)) { auto stmt = CreateStatementAfter(tokenNode, (CreateStmtFlags)(CreateStmtFlags_FindTrailingSemicolon | CreateStmtFlags_ForceVariableDecl)); if (auto exprStmt = BfNodeDynCast(stmt)) { if (auto variableDecl = BfNodeDynCast(exprStmt->mExpression)) { if (variableDecl->mModSpecifier != NULL) { Fail(StrFormat("'%s' already specified", BfTokenToString(variableDecl->mModSpecifier->GetToken())), variableDecl->mModSpecifier); } MEMBER_SET(variableDecl, mModSpecifier, tokenNode); exprStmt->SetSrcStart(variableDecl->mSrcStart); return stmt; } } Fail(StrFormat("Unexpected '%s' specifier", BfTokenToString(tokenNode->GetToken())), tokenNode); return stmt; } else if (token == BfToken_Volatile) { Fail("Cannot create volatile local variables", tokenNode); return NULL; } else if (token == BfToken_Asm) { return CreateInlineAsmStatement(node); } else if (token == BfToken_Mixin) { auto methodDecl = mAlloc->Alloc(); BfDeferredAstSizedArray params(methodDecl->mParams, mAlloc); BfDeferredAstSizedArray commas(methodDecl->mCommas, mAlloc); ReplaceNode(tokenNode, methodDecl); methodDecl->mDocumentation = FindDocumentation(methodDecl); methodDecl->mMixinSpecifier = tokenNode; auto nameNode = ExpectIdentifierAfter(methodDecl); if (nameNode != NULL) { MEMBER_SET(methodDecl, mNameNode, nameNode); auto nextNode = mVisitorPos.GetNext(); if (tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_LChevron) { auto genericParams = CreateGenericParamsDeclaration(tokenNode); if (genericParams != NULL) { MEMBER_SET(methodDecl, mGenericParams, genericParams); } } } ParseMethod(methodDecl, ¶ms, &commas, true); } auto localMethodDecl = mAlloc->Alloc(); ReplaceNode(methodDecl, localMethodDecl); localMethodDecl->mMethodDeclaration = methodDecl; return localMethodDecl; } } if (auto identifier = BfNodeDynCast(node)) { node = CompactQualifiedName(identifier); } bool isLocalVariable = false; auto nextNode = mVisitorPos.GetNext(); if (auto nextToken = BfNodeDynCast(nextNode)) { if (nextToken->GetToken() == BfToken_Colon) { auto nameIdentifier = BfNodeDynCast(node); if (nameIdentifier != NULL) { BfLabelNode* labelNode = mAlloc->Alloc(); ReplaceNode(nameIdentifier, labelNode); labelNode->mLabel = nameIdentifier; mVisitorPos.MoveNext(); MEMBER_SET(labelNode, mColonToken, nextToken); BfAstNode* stmt = NULL; auto nextNode = mVisitorPos.GetNext(); if (nextNode != NULL) { mVisitorPos.MoveNext(); stmt = DoCreateStatement(nextNode); if (auto labelableStmt = BfNodeDynCast(stmt)) { MEMBER_SET(labelableStmt, mLabelNode, labelNode); return labelableStmt; } if (auto block = BfNodeDynCast(stmt)) { auto labeledBlock = mAlloc->Alloc(); ReplaceNode(block, labeledBlock); labeledBlock->mBlock = block; MEMBER_SET(labeledBlock, mLabelNode, labelNode); return labeledBlock; } } Fail("Label must appear before a labelable statement (if, for, do, while, switch, block)", labelNode); AddErrorNode(labelNode); return stmt; } } } int typeRefEndNode = -1; bool isTuple = false; if (IsTypeReference(node, BfToken_None, &typeRefEndNode, NULL, NULL, &isTuple)) isLocalVariable = true; if ((isLocalVariable) && (isTuple)) { if (typeRefEndNode != -1) { // When we're typing something like "(a, )" ... don't make that a type ref yet because it could be "(a, b) = " where // we're typing a tuple value rather than a tuple tpye ref auto checkNode = mVisitorPos.Get(typeRefEndNode); if (checkNode == NULL) isLocalVariable = false; } } if (nextNode == NULL) { // Treat ending identifier as just an identifier (could be block result) isLocalVariable = false; } if ((isLocalVariable) && (typeRefEndNode != -1) && (continuingVariable == NULL) && ((createStmtFlags & CreateStmtFlags_AllowLocalFunction) != 0)) { BfTokenNode* nextToken = BfNodeDynCast(node); if ((nextToken == NULL) || ((nextToken->GetToken() != BfToken_Delegate) && (nextToken->GetToken() != BfToken_Function))) { auto afterTypeRefNode = mVisitorPos.Get(typeRefEndNode); if (auto nameIdentifier = BfNodeDynCast(afterTypeRefNode)) { auto nextNextNode = mVisitorPos.Get(typeRefEndNode + 1); if (auto afterNameToken = BfNodeDynCast(nextNextNode)) { bool isLocalMethod = (afterNameToken->GetToken() == BfToken_LParen) || (afterNameToken->GetToken() == BfToken_LChevron); if (isLocalMethod) { int prevReadPos = mVisitorPos.mReadPos; mVisitorPos.mReadPos = typeRefEndNode; isLocalMethod = IsLocalMethod(nameIdentifier); mVisitorPos.mReadPos = prevReadPos; } if (isLocalMethod) { auto typeRef = CreateTypeRef(node); if (mVisitorPos.GetNext() != nameIdentifier) isLocalMethod = false; else { int prevReadPos = mVisitorPos.mReadPos; mVisitorPos.MoveNext(); isLocalMethod = IsLocalMethod(nameIdentifier); if (!isLocalMethod) mVisitorPos.mReadPos = prevReadPos; } if (!isLocalMethod) { // TypeRef didn't match what we expected, just set it up as a variable declaration auto variableDeclaration = mAlloc->Alloc(); ReplaceNode(typeRef, variableDeclaration); variableDeclaration->mTypeRef = typeRef; return variableDeclaration; } auto methodDecl = mAlloc->Alloc(); ReplaceNode(typeRef, methodDecl); methodDecl->mDocumentation = FindDocumentation(methodDecl); methodDecl->mReturnType = typeRef; BfDeferredAstSizedArray params(methodDecl->mParams, mAlloc); BfDeferredAstSizedArray commas(methodDecl->mCommas, mAlloc); MEMBER_SET(methodDecl, mNameNode, nameIdentifier); if (afterNameToken->GetToken() == BfToken_LChevron) { auto genericParams = CreateGenericParamsDeclaration(afterNameToken); if (genericParams != NULL) { MEMBER_SET(methodDecl, mGenericParams, genericParams); } } ParseMethod(methodDecl, ¶ms, &commas, true); auto localMethodDecl = mAlloc->Alloc(); ReplaceNode(methodDecl, localMethodDecl); localMethodDecl->mMethodDeclaration = methodDecl; return localMethodDecl; } } } } } if ((isLocalVariable) || (continuingVariable != NULL)) { auto variableDeclaration = mAlloc->Alloc(); BfTypeReference* typeRef = NULL; if (continuingVariable != NULL) { typeRef = continuingVariable->mTypeRef; variableDeclaration->mModSpecifier = continuingVariable->mModSpecifier; ReplaceNode(node, variableDeclaration); variableDeclaration->mPrecedingComma = (BfTokenNode*)node; } else { typeRef = CreateTypeRef(node); if (typeRef == NULL) return NULL; ReplaceNode(typeRef, variableDeclaration); } variableDeclaration->mTypeRef = typeRef; BfAstNode* variableNameNode = NULL; nextNode = mVisitorPos.GetNext(); if (auto tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_LParen) { mVisitorPos.mReadPos++; variableNameNode = CreateTupleExpression(tokenNode); } } if (variableNameNode == NULL) { auto checkToken = BfNodeDynCast(mVisitorPos.Get(mVisitorPos.mReadPos + 2)); if ((checkToken != NULL) && (checkToken->mToken == BfToken_Dot)) { FailAfter("Expected variable name", variableDeclaration); } else variableNameNode = ExpectIdentifierAfter(variableDeclaration, "variable name"); } if (variableNameNode == NULL) return variableDeclaration; bool isValidFinish = false; BfTokenNode* tokenNode; if (tokenNode = BfNodeDynCast(mVisitorPos.GetNext())) { int token = tokenNode->GetToken(); if ((token == BfToken_AssignEquals) || (token == BfToken_Semicolon) || (token == BfToken_Comma)) isValidFinish = true; } /*if (!isValidFinish) { if (auto nextIdentifier = BfNodeDynCast(mVisitorPos.GetNext())) { if (auto nextNextToken = BfNodeDynCast(mVisitorPos.Get(mVisitorPos.mReadPos + 2))) { if ((nextNextToken->GetToken() == BfToken_LParen) || (nextNextToken->GetToken() == BfToken_LChevron)) { // It's less destructive to not consume the identifier we see as the name, because it may not be. This handles the case // where we're typing some stuff before a local method declaration. Kindof a corner case... Fail("Unexpected type", typeRef); mVisitorPos.mReadPos--; return variableDeclaration; } } } }*/ // Is a local variable? tokenNode = ExpectTokenAfter(variableNameNode, BfToken_AssignEquals, BfToken_Semicolon, BfToken_Comma); variableDeclaration->mNameNode = variableNameNode; MoveNode(variableNameNode, variableDeclaration); if (tokenNode == NULL) return variableDeclaration; if (tokenNode->GetToken() == BfToken_AssignEquals) { MEMBER_SET(variableDeclaration, mEqualsNode, tokenNode); if (variableDeclaration->mInitializer == NULL) variableDeclaration->mInitializer = CreateExpressionAfter(variableDeclaration, (CreateExprFlags)(createStmtFlags & CreateStmtFlags_To_CreateExprFlags_Mask)); if (variableDeclaration->mInitializer == NULL) return variableDeclaration; MoveNode(variableDeclaration->mInitializer, variableDeclaration); } else mVisitorPos.mReadPos--; // Backtrack to the semicolon or comma return variableDeclaration; } if ((createStmtFlags & CreateStmtFlags_ForceVariableDecl) != 0) { Fail("Expected local variable declaration", node); return NULL; } // Must be an expression. Always set CreateExprFlags_NoCaseExpr, to keep ending statements in a switch case to look like case expressions CreateExprFlags exprFlags = (CreateExprFlags)(createStmtFlags & CreateStmtFlags_To_CreateExprFlags_Mask); if ((createStmtFlags & CreateStmtFlags_AllowUnterminatedExpression) == 0) exprFlags = (CreateExprFlags)(exprFlags | CreateExprFlags_NoCaseExpr); auto expr = CreateExpression(node, exprFlags); if (expr == NULL) return NULL; bool isOkUnary = false; if (auto unaryOperatorExpr = BfNodeDynCast(expr)) { isOkUnary = (unaryOperatorExpr->mOp == BfUnaryOp_Increment) || (unaryOperatorExpr->mOp == BfUnaryOp_PostIncrement) || (unaryOperatorExpr->mOp == BfUnaryOp_Decrement) || (unaryOperatorExpr->mOp == BfUnaryOp_PostDecrement); if ((unaryOperatorExpr->mOp == BfUnaryOp_Ref) || (unaryOperatorExpr->mOp == BfUnaryOp_Mut) || (unaryOperatorExpr->mOp == BfUnaryOp_Out)) { if (unaryOperatorExpr->mOp == BfUnaryOp_Ref) mPassInstance->Fail("Cannot use 'ref' in this context", unaryOperatorExpr); else if (unaryOperatorExpr->mOp == BfUnaryOp_Mut) mPassInstance->Fail("Cannot use 'mut' in this context", unaryOperatorExpr); else mPassInstance->Fail("Cannot use 'out' in this context", unaryOperatorExpr); return NULL; } } if ((!mPrevStmtHadError) && (!mStmtHasError)) { nextNode = mVisitorPos.GetNext(); if (nextNode != NULL) { if (!isOkUnary) expr->VerifyIsStatement(mPassInstance); } } return expr; } // This is conservative - it doesn't HAVE to return true, but in some cases may cause a parsing error if the nodes // can be consumed as a statement rather than an expression. We must be more careful about not returning 'true' // for something that can only be interpreted as a statement, however. bool BfReducer::IsTerminatingExpression(BfAstNode* node) { int parenDepth = 0; int chevronDepth = 0; int readIdx = mVisitorPos.mReadPos; bool prevWasValue = false; BfTokenNode* prevTokenNode = NULL; while (true) { auto node = mVisitorPos.Get(readIdx); if (node == NULL) break; auto tokenNode = BfNodeDynCast(node); if (tokenNode != NULL) { switch (tokenNode->GetToken()) { case BfToken_AssignEquals: if (parenDepth == 0) return false; break; case BfToken_LParen: chevronDepth = 0; parenDepth++; break; case BfToken_RParen: chevronDepth = 0; parenDepth--; break; case BfToken_LChevron: chevronDepth++; break; case BfToken_RChevron: // If we find a < and > that are not seperated by parens, that's a generic, which must be a // variable decl if it's not in parens if ((parenDepth == 0) && (chevronDepth > 0)) return false; chevronDepth--; break; case BfToken_RDblChevron: chevronDepth--; break; case BfToken_Comma: if (parenDepth == 0) return false; break; case BfToken_As: case BfToken_Append: case BfToken_Default: case BfToken_Is: case BfToken_Stack: case BfToken_Scope: case BfToken_New: case BfToken_RetType: case BfToken_SizeOf: case BfToken_This: case BfToken_TypeOf: case BfToken_LessEquals: case BfToken_GreaterEquals: case BfToken_LBracket: case BfToken_RBracket: case BfToken_Colon: case BfToken_Dot: case BfToken_DotDot: case BfToken_QuestionDot: case BfToken_QuestionLBracket: case BfToken_Plus: case BfToken_Minus: case BfToken_DblPlus: case BfToken_DblMinus: case BfToken_Star: case BfToken_ForwardSlash: case BfToken_Modulus: case BfToken_Ampersand: case BfToken_At: case BfToken_DblAmpersand: case BfToken_Bar: case BfToken_DblBar: case BfToken_Bang: case BfToken_Carat: case BfToken_Tilde: case BfToken_Question: case BfToken_DblQuestion: case BfToken_Arrow: case BfToken_FatArrow: // Allow these break; case BfToken_Semicolon: return false; default: // Disallow everything else return false; } } if ((node->IsExact()) || (node->IsExact()) || (node->IsExact()) || (node->IsExact())) { if (prevWasValue) { // Two values in a row cannot be a valid expression return false; } prevWasValue = true; } else { prevWasValue = false; } if (auto block = BfNodeDynCastExact(node)) { // Local method decl if ((parenDepth == 0) && (prevTokenNode != NULL) && (prevTokenNode->GetToken() == BfToken_RParen)) return false; } prevTokenNode = tokenNode; readIdx++; } int outEndNode = 0; bool couldBeExpr = false; if (IsTypeReference(node, BfToken_None, &outEndNode, &couldBeExpr)) { if (outEndNode == mVisitorPos.mTotalSize - 1) { if (auto name = BfNodeDynCast(mVisitorPos.Get(outEndNode))) { auto beforeNameToken = BfNodeDynCast(mVisitorPos.Get(outEndNode - 1)); // We treat "a*b" as a multiply rather than a variable declaration if ((beforeNameToken == NULL) || (beforeNameToken->GetToken() != BfToken_Star)) { return false; } } } } return true; } BfAstNode* BfReducer::CreateStatement(BfAstNode* node, CreateStmtFlags createStmtFlags) { AssertCurrentNode(node); node = ReplaceTokenStarter(node); if ((createStmtFlags & CreateStmtFlags_AllowUnterminatedExpression) != 0) { if (IsTerminatingExpression(node)) { mPrevStmtHadError = false; // Must be an expression. Always set CreateExprFlags_NoCaseExpr, to keep ending statements in a switch case to look like case expressions auto expr = CreateExpression(node, (CreateExprFlags)(createStmtFlags & CreateStmtFlags_To_CreateExprFlags_Mask | CreateExprFlags_NoCaseExpr)); auto nextNode = mVisitorPos.GetNext(); if (nextNode != NULL) { mPassInstance->FailAfter("Semicolon expected", expr); } return expr; } } mStmtHasError = false; auto stmtNode = DoCreateStatement(node, createStmtFlags); mPrevStmtHadError = mStmtHasError; if (stmtNode == NULL) return NULL; auto origStmtNode = stmtNode; if (stmtNode->IsA()) return stmtNode; auto nextNode = mVisitorPos.GetNext(); if (auto expr = BfNodeDynCast(stmtNode)) { if (((createStmtFlags & CreateStmtFlags_AllowUnterminatedExpression) != 0) && (nextNode == NULL)) return expr; auto stmt = mAlloc->Alloc(); ReplaceNode(expr, stmt); stmt->mExpression = expr; stmtNode = stmt; } if (auto stmt = BfNodeDynCast(stmtNode)) { if ((stmt->IsMissingSemicolon()) && ((createStmtFlags & CreateStmtFlags_FindTrailingSemicolon) != 0) && (!stmt->IsA())) { if (!IsSemicolon(nextNode)) { // Why did we have this BfIdentifierNode check? It failed to throw an error on just things like "{ a }" if (/*(origStmtNode->IsA()) || */(origStmtNode->IsA()) || (origStmtNode->IsA())) return stmt; if (origStmtNode->IsA()) { // For compound variables auto commaToken = BfNodeDynCast(nextNode); if ((commaToken != NULL) && (commaToken->GetToken() == BfToken_Comma)) return stmt; } if (((createStmtFlags & CreateStmtFlags_AllowUnterminatedExpression) != 0) && (origStmtNode->IsA()) && (nextNode == NULL)) return stmt; mPassInstance->FailAfterAt("Semicolon expected", node->GetSourceData(), stmt->GetSrcEnd() - 1); mPrevStmtHadError = true; return stmt; } if ((!stmt->IsA()) && (!stmt->IsA())) { mVisitorPos.MoveNext(); MEMBER_SET(stmt, mTrailingSemicolon, (BfTokenNode*)nextNode); } } } return stmtNode; } BfAstNode* BfReducer::CreateStatementAfter(BfAstNode* node, CreateStmtFlags createStmtFlags) { AssertCurrentNode(node); auto nextNode = mVisitorPos.GetNext(); if (nextNode == NULL) { FailAfter("Expected statement", node); return NULL; } mVisitorPos.MoveNext(); BfAstNode* stmt = CreateStatement(nextNode, createStmtFlags); if (stmt == NULL) { // Nope, didn't handle it mVisitorPos.mReadPos--; } return stmt; } bool BfReducer::IsExtendedTypeName(BfIdentifierNode* identifierNode) { auto nextNode = mVisitorPos.GetNext(); if (nextNode == NULL) return false; auto tokenNode = BfNodeDynCast(nextNode); if (tokenNode == NULL) return false; int token = tokenNode->GetToken(); return ((token == BfToken_Star) || (token == BfToken_Question) || (token == BfToken_Dot) || (token == BfToken_LChevron) || (token == BfToken_LBracket)); } static String TypeToString(BfTypeReference* typeRef) { if (typeRef == NULL) return "null"; if (auto qualifiedTypeRef = BfNodeDynCast(typeRef)) return "(" + TypeToString(qualifiedTypeRef->mLeft) + " . " + TypeToString(qualifiedTypeRef->mRight) + ")"; if (auto genericTypeInstanceRef = BfNodeDynCast(typeRef)) return TypeToString(genericTypeInstanceRef->mElementType) + "<...>"; return typeRef->ToString(); } BfTypeReference* BfReducer::DoCreateNamedTypeRef(BfIdentifierNode* identifierNode) { if (auto qualifiedNameNode = BfNodeDynCast(identifierNode)) { auto qualifiedTypeRef = mAlloc->Alloc(); ReplaceNode(identifierNode, qualifiedTypeRef); MoveNode(qualifiedNameNode->mLeft, qualifiedTypeRef); auto leftTypeRef = DoCreateNamedTypeRef(qualifiedNameNode->mLeft); MEMBER_SET(qualifiedTypeRef, mLeft, leftTypeRef); MEMBER_SET(qualifiedTypeRef, mDot, qualifiedNameNode->mDot); MoveNode(qualifiedNameNode->mRight, qualifiedNameNode); auto rightTypeRef = DoCreateNamedTypeRef(qualifiedNameNode->mRight); MEMBER_SET(qualifiedTypeRef, mRight, rightTypeRef); return qualifiedTypeRef; } else { auto namedTypeRef = mAlloc->Alloc(); namedTypeRef->mNameNode = identifierNode; ReplaceNode(identifierNode, namedTypeRef); namedTypeRef->SetTriviaStart(identifierNode->GetTriviaStart()); return namedTypeRef; } } BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, bool parseArrayBracket) { AssertCurrentNode(firstNode); auto identifierNode = BfNodeDynCast(firstNode); if (identifierNode == NULL) { if (auto memberReferenceExpression = BfNodeDynCast(firstNode)) { auto qualifiedTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, qualifiedTypeRef); BF_ASSERT(memberReferenceExpression->mTarget != NULL); if (memberReferenceExpression->mTarget != NULL) { MoveNode(memberReferenceExpression->mTarget, qualifiedTypeRef); auto leftTypeRef = DoCreateTypeRef(memberReferenceExpression->mTarget); MEMBER_SET(qualifiedTypeRef, mLeft, leftTypeRef); } MEMBER_SET(qualifiedTypeRef, mDot, memberReferenceExpression->mDotToken); if (memberReferenceExpression->mMemberName != NULL) { MoveNode(memberReferenceExpression->mMemberName, memberReferenceExpression); auto rightTypeRef = DoCreateTypeRef(memberReferenceExpression->mMemberName); MEMBER_SET(qualifiedTypeRef, mRight, rightTypeRef); } firstNode = qualifiedTypeRef; } else { bool isHandled = false; auto tokenNode = BfNodeDynCast(firstNode); if (tokenNode != NULL) { int token = tokenNode->GetToken(); if (token == BfToken_Dot) { auto dotTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, dotTypeRef); dotTypeRef->mDotToken = tokenNode; firstNode = dotTypeRef; isHandled = true; //return dotTypeRef; } else if ((token == BfToken_Star) && (mAllowTypeWildcard)) { auto wildcardTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, wildcardTypeRef); wildcardTypeRef->mWildcardToken = tokenNode; return wildcardTypeRef; } else if ((token == BfToken_Var) || (token == BfToken_Let)) { if (auto nextToken = BfNodeDynCast(mVisitorPos.GetNext())) { if ((nextToken->GetToken() == BfToken_Ref) || (nextToken->GetToken() == BfToken_Mut)) { auto varTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, varTypeRef); varTypeRef->mVarToken = tokenNode; MEMBER_SET(varTypeRef, mRefToken, nextToken); mVisitorPos.MoveNext(); return varTypeRef; } } if (token == BfToken_Var) { auto varTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, varTypeRef); varTypeRef->mVarToken = tokenNode; return varTypeRef; } else { auto letTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, letTypeRef); letTypeRef->mLetToken = tokenNode; return letTypeRef; } } else if ((mCompatMode) && (token == BfToken_Minus)) { auto constExpr = CreateExpression(tokenNode, CreateExprFlags_BreakOnRChevron); auto constTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, constTypeRef); MEMBER_SET_CHECKED(constTypeRef, mConstExpr, constExpr); return constTypeRef; } else if (token == BfToken_Const) { if (!mCompatMode) { //Fail("Invalid use of 'const', only fields and local variables can be declared as const", tokenNode); //AddErrorNode(tokenNode); auto constExpr = CreateExpressionAfter(tokenNode, CreateExprFlags_BreakOnRChevron); auto constTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, constTypeRef); MEMBER_SET(constTypeRef, mConstToken, tokenNode); MEMBER_SET_CHECKED(constTypeRef, mConstExpr, constExpr); return constTypeRef; } else { auto elementType = CreateTypeRefAfter(tokenNode, parseArrayBracket); auto constTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, constTypeRef); MEMBER_SET(constTypeRef, mConstToken, tokenNode); MEMBER_SET_CHECKED(constTypeRef, mElementType, elementType); return constTypeRef; } } else if (token == BfToken_Unsigned) { BF_ASSERT(mCompatMode); auto elementType = CreateTypeRefAfter(tokenNode, parseArrayBracket); BfTypeReference* rootElementParent = NULL; auto rootElement = elementType; while (auto elementedType = BfNodeDynCast(rootElement)) { rootElementParent = rootElement; rootElement = elementedType->mElementType; } auto unsignedTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, unsignedTypeRef); MEMBER_SET(unsignedTypeRef, mUnsignedToken, tokenNode); if (rootElement == elementType) { MEMBER_SET_CHECKED(unsignedTypeRef, mElementType, elementType); return unsignedTypeRef; } else { #ifdef BF_AST_HAS_PARENT_MEMBER BF_ASSERT(rootElementParent == rootElement->mParent); #endif auto elementedType = BfNodeDynCast(rootElementParent); MEMBER_SET_CHECKED(unsignedTypeRef, mElementType, rootElement); MEMBER_SET_CHECKED(elementedType, mElementType, unsignedTypeRef); elementType->SetSrcStart(unsignedTypeRef->GetSrcStart()); return elementType; } } else if (token == BfToken_RetType) { auto retTypeTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, retTypeTypeRef); MEMBER_SET(retTypeTypeRef, mRetTypeToken, tokenNode); tokenNode = ExpectTokenAfter(retTypeTypeRef, BfToken_LParen); MEMBER_SET_CHECKED(retTypeTypeRef, mOpenParen, tokenNode); auto elementType = CreateTypeRefAfter(retTypeTypeRef, parseArrayBracket); MEMBER_SET_CHECKED(retTypeTypeRef, mElementType, elementType); tokenNode = ExpectTokenAfter(retTypeTypeRef, BfToken_RParen); MEMBER_SET_CHECKED(retTypeTypeRef, mCloseParen, tokenNode); return retTypeTypeRef; } else if ((token == BfToken_Delegate) || (token == BfToken_Function)) { auto delegateTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, delegateTypeRef); MEMBER_SET(delegateTypeRef, mTypeToken, tokenNode); auto returnType = CreateTypeRefAfter(delegateTypeRef); MEMBER_SET_CHECKED(delegateTypeRef, mReturnType, returnType); tokenNode = ExpectTokenAfter(delegateTypeRef, BfToken_LParen); MEMBER_SET_CHECKED(delegateTypeRef, mOpenParen, tokenNode); BfDeferredAstSizedArray params(delegateTypeRef->mParams, mAlloc); BfDeferredAstSizedArray commas(delegateTypeRef->mCommas, mAlloc); auto closeNode = ParseMethodParams(delegateTypeRef, ¶ms, &commas, BfToken_RParen); if (closeNode == NULL) { if (!params.empty()) delegateTypeRef->AdjustSrcEnd(params.back()); if (!commas.empty()) delegateTypeRef->AdjustSrcEnd(commas.back()); } MEMBER_SET_CHECKED(delegateTypeRef, mCloseParen, closeNode); mVisitorPos.MoveNext(); return delegateTypeRef; } else if (token == BfToken_Decltype) { auto declTypeRef = mAlloc->Alloc(); ReplaceNode(tokenNode, declTypeRef); declTypeRef->mToken = tokenNode; tokenNode = ExpectTokenAfter(declTypeRef, BfToken_LParen); MEMBER_SET_CHECKED(declTypeRef, mOpenParen, tokenNode); auto targetExpr = CreateExpressionAfter(declTypeRef); MEMBER_SET_CHECKED(declTypeRef, mTarget, targetExpr); tokenNode = ExpectTokenAfter(declTypeRef, BfToken_RParen); MEMBER_SET_CHECKED(declTypeRef, mCloseParen, tokenNode); return declTypeRef; } else if (token == BfToken_LParen) { auto tupleTypeRef = mAlloc->Alloc(); BfDeferredAstSizedArray fieldTypes(tupleTypeRef->mFieldTypes, mAlloc); BfDeferredAstSizedArray fieldNames(tupleTypeRef->mFieldNames, mAlloc); BfDeferredAstSizedArray commas(tupleTypeRef->mCommas, mAlloc); ReplaceNode(firstNode, tupleTypeRef); tupleTypeRef->mOpenParen = tokenNode; while (true) { auto tupleFieldType = CreateTypeRefAfter(tupleTypeRef); if (tupleFieldType == NULL) return tupleTypeRef; fieldTypes.push_back(tupleFieldType); MoveNode(tupleFieldType, tupleTypeRef); auto nextNode = mVisitorPos.GetNext(); if (auto identifierNode = BfNodeDynCast(nextNode)) { while (fieldNames.size() < fieldTypes.size() - 1) fieldNames.push_back(NULL); MoveNode(identifierNode, tupleTypeRef); fieldNames.push_back(identifierNode); mVisitorPos.MoveNext(); } auto tokenNode = ExpectTokenAfter(tupleTypeRef, BfToken_Comma, BfToken_RParen); if (tokenNode == NULL) return tupleTypeRef; if (tokenNode->GetToken() == BfToken_RParen) { MEMBER_SET(tupleTypeRef, mCloseParen, tokenNode); //return tupleTypeRef; firstNode = tupleTypeRef; isHandled = true; break; } MoveNode(tokenNode, tupleTypeRef); commas.push_back(tokenNode); } } } else if (mCompatMode) { if (auto literalExpr = BfNodeDynCast(firstNode)) { auto constExpr = CreateExpression(literalExpr, CreateExprFlags_BreakOnRChevron); auto constTypeRef = mAlloc->Alloc(); ReplaceNode(firstNode, constTypeRef); MEMBER_SET_CHECKED(constTypeRef, mConstExpr, constExpr); return constTypeRef; } } if (!isHandled) { Fail("Expected type", firstNode); return NULL; } } } BfTypeReference* typeRef = BfNodeDynCast(firstNode); if (typeRef == NULL) { typeRef = DoCreateNamedTypeRef(identifierNode); } while (true) { auto nextNode = mVisitorPos.GetNext(); auto tokenNode = BfNodeDynCast(nextNode); if (tokenNode != NULL) { BfToken token = tokenNode->GetToken(); if (token == BfToken_Dot) { BfQualifiedTypeReference* qualifiedTypeRef = mAlloc->Alloc(); ReplaceNode(typeRef, qualifiedTypeRef); qualifiedTypeRef->mLeft = typeRef; MEMBER_SET(qualifiedTypeRef, mDot, tokenNode); mVisitorPos.MoveNext(); while (true) { bool handled = false; if (mAllowTypeWildcard) { auto nextNode = mVisitorPos.GetNext(); if (auto nextTokenNode = BfNodeDynCast(nextNode)) { if (nextTokenNode->mToken == BfToken_Star) { auto wildcardTypeRef = mAlloc->Alloc(); ReplaceNode(nextTokenNode, wildcardTypeRef); wildcardTypeRef->mWildcardToken = nextTokenNode; typeRef = wildcardTypeRef; handled = true; mVisitorPos.MoveNext(); } } } if (!handled) { auto rightIdentifer = ExpectIdentifierAfter(qualifiedTypeRef); if (rightIdentifer == NULL) return qualifiedTypeRef; auto namedTypeRef = mAlloc->Alloc(); namedTypeRef->mNameNode = rightIdentifer; ReplaceNode(rightIdentifer, namedTypeRef); namedTypeRef->SetTriviaStart(rightIdentifer->GetTriviaStart()); typeRef = namedTypeRef; } MEMBER_SET(qualifiedTypeRef, mRight, typeRef); nextNode = mVisitorPos.GetNext(); if (tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_Dot) { BfQualifiedTypeReference* outerQualifiedTypeRef = mAlloc->Alloc(); ReplaceNode(qualifiedTypeRef, outerQualifiedTypeRef); outerQualifiedTypeRef->mLeft = qualifiedTypeRef; MEMBER_SET(outerQualifiedTypeRef, mDot, tokenNode); qualifiedTypeRef = outerQualifiedTypeRef; mVisitorPos.MoveNext(); } else break; } else { break; } } typeRef = qualifiedTypeRef; } else if (token == BfToken_Star) { auto ptrType = mAlloc->Alloc(); ReplaceNode(typeRef, ptrType); ptrType->mElementType = typeRef; MEMBER_SET(ptrType, mStarNode, tokenNode); typeRef = ptrType; mVisitorPos.MoveNext(); } else if ((token == BfToken_Question) || (token == BfToken_QuestionLBracket)) { if (token == BfToken_QuestionLBracket) tokenNode = BreakQuestionLBracket(tokenNode); else mVisitorPos.MoveNext(); auto nullableType = mAlloc->Alloc(); ReplaceNode(typeRef, nullableType); nullableType->mElementType = typeRef; MEMBER_SET(nullableType, mQuestionToken, tokenNode); typeRef = nullableType; } else if (token == BfToken_LBracket) { if (!parseArrayBracket) return typeRef; auto arrayType = mAlloc->Alloc(); auto newArrayType = arrayType; ReplaceNode(typeRef, arrayType); arrayType->mOpenBracket = tokenNode; MoveNode(tokenNode, arrayType); arrayType->mDimensions = 1; arrayType->mElementType = typeRef; mVisitorPos.MoveNext(); while (true) { auto prevArrayType = BfNodeDynCast(arrayType->mElementType); if (prevArrayType == NULL) break; std::swap(prevArrayType->mOpenBracket, arrayType->mOpenBracket); std::swap(prevArrayType->mParams, arrayType->mParams); std::swap(prevArrayType->mCloseBracket, arrayType->mCloseBracket); std::swap(prevArrayType->mDimensions, arrayType->mDimensions); prevArrayType->SetSrcEnd(arrayType->GetSrcEnd()); arrayType = prevArrayType; } BF_ASSERT(arrayType->mParams.mVals == NULL); arrayType->mParams.mSize = 0; BfDeferredAstSizedArray params(arrayType->mParams, mAlloc); bool hasFailed = false; bool isSized = false; while (true) { nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); if (tokenNode != NULL) { if (tokenNode->GetToken() == BfToken_Comma) { MoveNode(tokenNode, arrayType); mVisitorPos.MoveNext(); arrayType->mDimensions++; params.push_back(tokenNode); } else if (tokenNode->GetToken() == BfToken_RBracket) { MoveNode(tokenNode, arrayType); mVisitorPos.MoveNext(); arrayType->mCloseBracket = tokenNode; break; } else tokenNode = NULL; } if (tokenNode == NULL) { BfExpression* sizeExpr = CreateExpressionAfter(arrayType); if (sizeExpr == NULL) { hasFailed = true; break; } MoveNode(sizeExpr, arrayType); params.push_back(sizeExpr); // if (params.size() == 0) // { // BfExpression* sizeExpr = CreateExpressionAfter(arrayType); // if (sizeExpr == NULL) // { // hasFailed = true; // break; // } // MoveNode(sizeExpr, arrayType); // params.push_back(sizeExpr); // tokenNode = ExpectTokenAfter(arrayType, BfToken_RBracket); // if (tokenNode == NULL) // { // hasFailed = true; // break; // } // MoveNode(tokenNode, arrayType); // arrayType->mCloseBracket = tokenNode; // break; // } // else // { // FailAfter("Either ',' or ']' expected", arrayType); // return arrayType; // } } } newArrayType->SetSrcEnd(arrayType->GetSrcEnd()); if (hasFailed) return newArrayType; typeRef = newArrayType; } else if (token == BfToken_LChevron) { auto genericInstance = mAlloc->Alloc(); BfDeferredSizedArray genericArguments(genericInstance->mGenericArguments, mAlloc); BfDeferredAstSizedArray commas(genericInstance->mCommas, mAlloc); ReplaceNode(typeRef, genericInstance); genericInstance->mOpenChevron = tokenNode; MoveNode(tokenNode, genericInstance); genericInstance->mElementType = typeRef; mVisitorPos.MoveNext(); bool isBoundName = false; bool isUnboundName = false; while (true) { auto nextNode = mVisitorPos.GetNext(); auto genericIdentifier = BfNodeDynCast(nextNode); bool doAddType = genericIdentifier != NULL; if (mCompatMode) { if (BfNodeDynCast(nextNode) != NULL) doAddType = true; } if (genericIdentifier == NULL) { auto nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); BfToken token = BfToken_None; if (tokenNode != NULL) token = tokenNode->GetToken(); if ((tokenNode != NULL) && ((token == BfToken_Const) || (token == BfToken_Ref) || (token == BfToken_Mut) || (token == BfToken_LParen) || (token == BfToken_Delegate) || (token == BfToken_Function) || (token == BfToken_Decltype) || ((token == BfToken_Star) && (mAllowTypeWildcard)))) doAddType = true; } if ((!doAddType) && (isBoundName)) { mPassInstance->FailAfter("Expected type", genericInstance); } if ((doAddType) && (!isUnboundName)) { auto genericArgumentTypeRef = CreateTypeRefAfter(genericInstance); if (genericArgumentTypeRef == NULL) return NULL; MoveNode(genericArgumentTypeRef, genericInstance); genericArguments.push_back(genericArgumentTypeRef); isBoundName = true; } else isUnboundName = true; nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); if (tokenNode == NULL) { FailAfter("Expected ',' or '>'", genericInstance); return genericInstance; } token = tokenNode->GetToken(); if (token == BfToken_RDblChevron) { tokenNode = BreakDoubleChevron(tokenNode); token = tokenNode->GetToken(); } else { mVisitorPos.MoveNext(); } if (token == BfToken_RChevron) { MoveNode(tokenNode, genericInstance); genericInstance->mCloseChevron = tokenNode; break; } if (token != BfToken_Comma) { Fail("Either ',' or '>' expected", tokenNode); mVisitorPos.mReadPos--; //AddErrorNode(tokenNode); return genericInstance; } MoveNode(tokenNode, genericInstance); commas.push_back(tokenNode); } typeRef = genericInstance; } else break; } else break; } return typeRef; } BfTypeReference* BfReducer::CreateTypeRef(BfAstNode* firstNode, bool parseArrayBracket) { if (auto tokenNode = BfNodeDynCast(firstNode)) { BfToken token = tokenNode->GetToken(); if ((token == BfToken_Ref) || (token == BfToken_Mut)) { auto nextNode = mVisitorPos.GetNext(); mVisitorPos.MoveNext(); auto typeRef = DoCreateTypeRef(nextNode, parseArrayBracket); if (typeRef == NULL) { mVisitorPos.mReadPos--; AddErrorNode(tokenNode); return NULL; } return CreateRefTypeRef(typeRef, tokenNode); } else if ((token == BfToken_In) || (token == BfToken_As)) { // This is mostly to allow a partially typed 'int' to be parsed as 'in' to make autocomplete nicer return CreateTypeRef(ReplaceTokenStarter(firstNode), parseArrayBracket); } } return DoCreateTypeRef(firstNode, parseArrayBracket); } BfTypeReference* BfReducer::CreateTypeRefAfter(BfAstNode* astNode, bool parseArrayBracket) { AssertCurrentNode(astNode); auto nextNode = mVisitorPos.GetNext(); if (nextNode == NULL) { FailAfter("Expected type", astNode); return NULL; } mVisitorPos.MoveNext(); int startPos = mVisitorPos.mReadPos; BfTypeReference* typeRef = CreateTypeRef(nextNode, parseArrayBracket); if (typeRef == NULL) { BF_ASSERT(mVisitorPos.mReadPos == startPos); mVisitorPos.mReadPos--; } return typeRef; } BfTypeReference* BfReducer::CreateRefTypeRef(BfTypeReference* elementType, BfTokenNode* refTokenNode) { BfToken refToken = refTokenNode->GetToken(); BF_ASSERT((refToken == BfToken_Ref) || (refToken == BfToken_Mut) || (refToken == BfToken_Out)); if (elementType->IsA()) { Fail("Multiple ref levels are not allowed", refTokenNode); AddErrorNode(refTokenNode); return elementType; } if (elementType->IsA()) { Fail("Refs to const values are not allowed", refTokenNode); AddErrorNode(refTokenNode); return elementType; } auto refTypeRef = mAlloc->Alloc(); MEMBER_SET(refTypeRef, mRefToken, refTokenNode); ReplaceNode(elementType, refTypeRef); refTypeRef->mElementType = elementType; return refTypeRef; } BfIdentifierNode* BfReducer::CompactQualifiedName(BfAstNode* leftNode) { AssertCurrentNode(leftNode); if ((leftNode == NULL) || (!leftNode->IsA())) return NULL; auto prevNode = mVisitorPos.Get(mVisitorPos.mWritePos - 1); auto leftIdentifier = (BfIdentifierNode*)leftNode; while (true) { auto nextToken = mVisitorPos.Get(mVisitorPos.mReadPos + 1); auto tokenNode = BfNodeDynCast(nextToken); if ((tokenNode == NULL) || ((tokenNode->GetToken() != BfToken_Dot) /*&& (tokenNode->GetToken() != BfToken_QuestionDot)*/)) return leftIdentifier; auto nextNextToken = mVisitorPos.Get(mVisitorPos.mReadPos + 2); auto rightIdentifier = BfNodeDynCast(nextNextToken); if (rightIdentifier == NULL) return leftIdentifier; // If the previous dotted span failed (IE: had chevrons) then don't insert qualified names in the middle of it auto prevNodeToken = BfNodeDynCast(prevNode); if ((prevNodeToken != NULL) && ((prevNodeToken->GetToken() == BfToken_Dot) || (prevNodeToken->GetToken() == BfToken_QuestionDot))) return leftIdentifier; mVisitorPos.MoveNext(); // past . mVisitorPos.MoveNext(); // past right auto qualifiedNameNode = mAlloc->Alloc(); ReplaceNode(leftIdentifier, qualifiedNameNode); qualifiedNameNode->mLeft = leftIdentifier; MEMBER_SET(qualifiedNameNode, mDot, tokenNode); MEMBER_SET(qualifiedNameNode, mRight, rightIdentifier); leftIdentifier = qualifiedNameNode; prevNode = NULL; } return leftIdentifier; } void BfReducer::CreateQualifiedNames(BfAstNode* node) { auto block = BfNodeDynCast(node); if (block == NULL) return; SetAndRestoreValue prevVisitorPos(mVisitorPos, BfVisitorPos(block)); bool isDone = !mVisitorPos.MoveNext(); while (!isDone) { auto child = mVisitorPos.GetCurrent(); BfAstNode* newNode = CompactQualifiedName(child); if (newNode == NULL) newNode = child; CreateQualifiedNames(child); isDone = !mVisitorPos.MoveNext(); if (newNode != NULL) mVisitorPos.Write(newNode); } mVisitorPos.Trim(); } BfAttributeDirective* BfReducer::CreateAttributeDirective(BfTokenNode* startToken) { BfAttributeDirective* attributeDirective = mAlloc->Alloc(); BfDeferredAstSizedArray arguments(attributeDirective->mArguments, mAlloc); BfDeferredAstSizedArray commas(attributeDirective->mCommas, mAlloc); ReplaceNode(startToken, attributeDirective); attributeDirective->mAttrOpenToken = startToken; auto nextNode = mVisitorPos.GetNext(); auto tokenNode = BfNodeDynCast(nextNode); if (tokenNode != NULL) { if (tokenNode->GetToken() == BfToken_Return) { auto attributeTargetSpecifier = mAlloc->Alloc(); ReplaceNode(tokenNode, attributeTargetSpecifier); MEMBER_SET(attributeDirective, mAttributeTargetSpecifier, attributeTargetSpecifier); attributeDirective->mAttributeTargetSpecifier->mTargetToken = tokenNode; mVisitorPos.MoveNext(); tokenNode = ExpectTokenAfter(attributeDirective, BfToken_Colon); if (tokenNode != NULL) MEMBER_SET(attributeDirective->mAttributeTargetSpecifier, mColonToken, tokenNode); attributeDirective->SetSrcEnd(attributeDirective->mAttributeTargetSpecifier->GetSrcEnd()); } } auto typeRef = CreateTypeRefAfter(attributeDirective); if (typeRef == NULL) { auto nextNode = mVisitorPos.GetNext(); if (BfTokenNode* endToken = BfNodeDynCast(nextNode)) { if (endToken->GetToken() == BfToken_RBracket) { mVisitorPos.MoveNext(); MEMBER_SET(attributeDirective, mCtorCloseParen, endToken); return attributeDirective; } } return attributeDirective; } MEMBER_SET(attributeDirective, mAttributeTypeRef, typeRef); tokenNode = ExpectTokenAfter(attributeDirective, BfToken_LParen, BfToken_RBracket, BfToken_Comma); if (tokenNode == NULL) return attributeDirective; if (tokenNode->GetToken() == BfToken_LParen) { MEMBER_SET(attributeDirective, mCtorOpenParen, tokenNode); tokenNode = ReadArguments(attributeDirective, attributeDirective, &arguments, &commas, BfToken_RParen, false); if (tokenNode == NULL) { auto nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_RBracket)) goto Do_RBracket; return attributeDirective; } MEMBER_SET(attributeDirective, mCtorCloseParen, tokenNode); tokenNode = ExpectTokenAfter(attributeDirective, BfToken_RBracket, BfToken_Comma); if (tokenNode == NULL) return attributeDirective; } Do_RBracket: if (tokenNode->GetToken() == BfToken_RBracket) { MEMBER_SET(attributeDirective, mAttrCloseToken, tokenNode); auto nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); if ((tokenNode == NULL) || (tokenNode->GetToken() != BfToken_LBracket)) return attributeDirective; mVisitorPos.MoveNext(); } // Has another one- chain it //mVisitorPos.MoveNext(); auto nextAttribute = CreateAttributeDirective(tokenNode); if (nextAttribute != NULL) { MEMBER_SET(attributeDirective, mNextAttribute, nextAttribute); } return attributeDirective; } BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool onlyAllowIdentifier) { auto attrib = CreateAttributeDirective(tokenNode); if (attrib == NULL) return NULL; if (!onlyAllowIdentifier) { auto expr = CreateExpressionAfter(attrib); if (expr != NULL) { if (auto identifier = BfNodeDynCast(expr)) { auto attrIdentifier = mAlloc->Alloc(); ReplaceNode(attrib, attrIdentifier); attrIdentifier->mAttributes = attrib; MEMBER_SET(attrIdentifier, mIdentifier, identifier); return attrIdentifier; } if ((expr->IsA()) || (expr->IsA()) || (expr->IsA())) { BfAttributedExpression* attribExpr = mAlloc->Alloc(); ReplaceNode(attrib, attribExpr); attribExpr->mAttributes = attrib; MEMBER_SET(attribExpr, mExpression, expr); return attribExpr; } } Fail("Prefixed attributes can only be used on constructor calls, invocations, or variable declarations", attrib); BfAttributedExpression* attribExpr = mAlloc->Alloc(); ReplaceNode(attrib, attribExpr); attribExpr->mAttributes = attrib; if (expr != NULL) MEMBER_SET(attribExpr, mExpression, expr); return attribExpr; } auto attrIdentifier = mAlloc->Alloc(); ReplaceNode(attrib, attrIdentifier); attrIdentifier->mAttributes = attrib; auto identifier = ExpectIdentifierAfter(attrib); if (identifier != NULL) { MEMBER_SET(attrIdentifier, mIdentifier, identifier); } return attrIdentifier; } BfTokenNode* BfReducer::ReadArguments(BfAstNode* parentNode, BfAstNode* afterNode, SizedArrayImpl* arguments, SizedArrayImpl* commas, BfToken endToken, bool allowSkippedArgs, CreateExprFlags createExprFlags) { for (int paramIdx = 0; true; paramIdx++) { auto nextNode = mVisitorPos.GetNext(); if ((nextNode == NULL) && (endToken == BfToken_None)) return NULL; BfTokenNode* tokenNode = BfNodeDynCastExact(nextNode); if (tokenNode != NULL) { if (tokenNode->GetToken() == endToken) { MoveNode(tokenNode, parentNode); mVisitorPos.MoveNext(); return tokenNode; } if (paramIdx > 0) { if (tokenNode->GetToken() != BfToken_Comma) { Fail("Expected comma", tokenNode); return NULL; } commas->push_back(tokenNode); MoveNode(tokenNode, parentNode); mVisitorPos.MoveNext(); } } else { if (paramIdx > 0) { FailAfter("Expected comma", afterNode); return NULL; } } if (allowSkippedArgs) { auto nextNode = mVisitorPos.GetNext(); if ((nextNode == NULL) && (endToken == BfToken_None)) return NULL; if (auto nextToken = BfNodeDynCastExact(nextNode)) { if (nextToken->GetToken() == endToken) continue; if (nextToken->GetToken() == BfToken_Comma) { arguments->push_back(NULL); continue; } } } auto argumentExpr = CreateExpressionAfter(afterNode, CreateExprFlags_AllowVariableDecl); if ((argumentExpr != NULL) || (endToken != BfToken_None)) arguments->push_back(argumentExpr); if (argumentExpr == NULL) { auto nextNode = mVisitorPos.GetNext(); if (auto tokenNode = BfNodeDynCastExact(nextNode)) { // Try to continue with param list even after an error if ((tokenNode->GetToken() == BfToken_Comma) || (tokenNode->GetToken() == endToken)) continue; } return NULL; } MoveNode(argumentExpr, parentNode); afterNode = parentNode; } } BfIdentifierNode* BfReducer::ExtractExplicitInterfaceRef(BfAstNode* memberDeclaration, BfIdentifierNode* nameIdentifier, BfTypeReference** outExplicitInterface, BfTokenNode** outExplicitInterfaceDotToken) { int dotTokenIdx = -1; if (auto qualifiedName = BfNodeDynCast(nameIdentifier)) { MoveNode(qualifiedName, memberDeclaration); MoveNode(qualifiedName->mDot, memberDeclaration); *outExplicitInterfaceDotToken = qualifiedName->mDot; auto explicitInterfaceRef = CreateTypeRef(qualifiedName->mLeft); BF_ASSERT(explicitInterfaceRef != NULL); MoveNode(explicitInterfaceRef, memberDeclaration); *outExplicitInterface = explicitInterfaceRef; return qualifiedName->mRight; } else if (IsTypeReference(nameIdentifier, BfToken_Dot, &dotTokenIdx)) { BfAstNode* dotToken = mVisitorPos.Get(dotTokenIdx); MoveNode(dotToken, memberDeclaration); *outExplicitInterfaceDotToken = (BfTokenNode*)dotToken; auto explicitInterfaceRef = CreateTypeRef(nameIdentifier); BF_ASSERT(explicitInterfaceRef != NULL); MoveNode(explicitInterfaceRef, memberDeclaration); *outExplicitInterface = explicitInterfaceRef; return ExpectIdentifierAfter(memberDeclaration); } return nameIdentifier; } BfFieldDtorDeclaration* BfReducer::CreateFieldDtorDeclaration(BfAstNode* srcNode) { BfFieldDtorDeclaration* firstFieldDtor = NULL; BfFieldDtorDeclaration* prevFieldDtor = NULL; auto nextNode = mVisitorPos.GetNext(); while (auto nextToken = BfNodeDynCast(nextNode)) { if (nextToken->GetToken() != BfToken_Tilde) break; auto fieldDtor = mAlloc->Alloc(); ReplaceNode(nextToken, fieldDtor); fieldDtor->mTildeToken = nextToken; //int prevReadPos = mVisitorPos.mReadPos; mVisitorPos.MoveNext(); if (prevFieldDtor != NULL) { MEMBER_SET(prevFieldDtor, mNextFieldDtor, fieldDtor); } else { firstFieldDtor = fieldDtor; MoveNode(fieldDtor, srcNode); } auto statement = CreateStatementAfter(srcNode); if (statement == NULL) { //mVisitorPos.mReadPos = prevReadPos; break; } MEMBER_SET(fieldDtor, mBody, statement); fieldDtor->SetSrcEnd(statement->GetSrcEnd()); prevFieldDtor = fieldDtor; srcNode->SetSrcEnd(fieldDtor->GetSrcEnd()); nextNode = mVisitorPos.GetNext(); // We used to NOT have this break here. Why were we allowing multiple ~'s when a block statement would have made more sense? break; // Wh } return firstFieldDtor; } BfFieldDeclaration* BfReducer::CreateFieldDeclaration(BfTokenNode* tokenNode, BfTypeReference* typeRef, BfIdentifierNode* nameIdentifier, BfFieldDeclaration* prevFieldDeclaration) { auto fieldDeclaration = mAlloc->Alloc(); if (prevFieldDeclaration != NULL) { ReplaceNode(tokenNode, fieldDeclaration); MEMBER_SET(fieldDeclaration, mPrecedingComma, tokenNode); MEMBER_SET(fieldDeclaration, mNameNode, nameIdentifier); fieldDeclaration->mDocumentation = prevFieldDeclaration->mDocumentation; fieldDeclaration->mAttributes = prevFieldDeclaration->mAttributes; fieldDeclaration->mInternalSpecifier = prevFieldDeclaration->mInternalSpecifier; fieldDeclaration->mProtectionSpecifier = prevFieldDeclaration->mProtectionSpecifier; fieldDeclaration->mStaticSpecifier = prevFieldDeclaration->mStaticSpecifier; fieldDeclaration->mTypeRef = prevFieldDeclaration->mTypeRef; fieldDeclaration->mConstSpecifier = prevFieldDeclaration->mConstSpecifier; fieldDeclaration->mReadOnlySpecifier = prevFieldDeclaration->mReadOnlySpecifier; fieldDeclaration->mVolatileSpecifier = prevFieldDeclaration->mVolatileSpecifier; fieldDeclaration->mNewSpecifier = prevFieldDeclaration->mNewSpecifier; fieldDeclaration->mExternSpecifier = prevFieldDeclaration->mExternSpecifier; tokenNode = ExpectTokenAfter(fieldDeclaration, BfToken_Semicolon, BfToken_AssignEquals, BfToken_Comma); if (tokenNode == NULL) return fieldDeclaration; mVisitorPos.mReadPos--; // Go back to token } else { ReplaceNode(typeRef, fieldDeclaration); fieldDeclaration->mTypeRef = typeRef; fieldDeclaration->mNameNode = nameIdentifier; fieldDeclaration->mInitializer = NULL; MoveNode(fieldDeclaration->mNameNode, fieldDeclaration); //mVisitorPos.MoveNext(); } BfToken token = tokenNode->GetToken(); if (token == BfToken_AssignEquals) { MEMBER_SET(fieldDeclaration, mEqualsNode, tokenNode); MoveNode(tokenNode, fieldDeclaration); mVisitorPos.MoveNext(); mIsFieldInitializer = true; fieldDeclaration->mInitializer = CreateExpressionAfter(fieldDeclaration); mIsFieldInitializer = false; if (fieldDeclaration->mInitializer != NULL) { MoveNode(fieldDeclaration->mInitializer, fieldDeclaration); auto nextToken = ExpectTokenAfter(fieldDeclaration, BfToken_Semicolon, BfToken_Tilde); if (nextToken != NULL) mVisitorPos.mReadPos--; // Backtrack, someone else eats these } } else if (token == BfToken_Comma) { // } else if (token == BfToken_Tilde) { // } else if (token != BfToken_Semicolon) { //MEMBER_SET(fieldDeclaration, mEqualsNode, tokenNode); FailAfter("';', '=', or '~' expected", nameIdentifier); return fieldDeclaration; } auto fieldDtor = CreateFieldDtorDeclaration(fieldDeclaration); if (fieldDtor != NULL) fieldDeclaration->mFieldDtor = fieldDtor; if (ExpectTokenAfter(fieldDeclaration, BfToken_Semicolon, BfToken_Comma) != NULL) { // This gets taken later mVisitorPos.mReadPos--; } fieldDeclaration->mDocumentation = FindDocumentation(mTypeMemberNodeStart, fieldDeclaration, true); return fieldDeclaration; } BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, int depth) { BfToken token = tokenNode->GetToken(); if (token == BfToken_Semicolon) return tokenNode; if (token == BfToken_LBracket) { auto attributes = CreateAttributeDirective(tokenNode); if (attributes == NULL) return NULL; auto nextNode = mVisitorPos.GetNext(); if (nextNode == NULL) { FailAfter("Expected member", attributes); return NULL; } mVisitorPos.MoveNext(); auto memberNode = ReadTypeMember(nextNode); if (memberNode == NULL) return NULL; auto member = BfNodeDynCast(memberNode); if (member == NULL) { if (auto innerType = BfNodeDynCast(memberNode)) { ReplaceNode(attributes, innerType); innerType->mAttributes = attributes; return innerType; } mPassInstance->Fail("Invalid target for attributes", memberNode); return memberNode; } ReplaceNode(attributes, member); member->mAttributes = attributes; return member; } if (token == BfToken_Operator) { auto operatorDecl = mAlloc->Alloc(); BfDeferredAstSizedArray params(operatorDecl->mParams, mAlloc); BfDeferredAstSizedArray commas(operatorDecl->mCommas, mAlloc); ReplaceNode(tokenNode, operatorDecl); operatorDecl->mOperatorToken = tokenNode; auto nextIdentifier = ExpectIdentifierAfter(operatorDecl, "type"); if (nextIdentifier == NULL) return operatorDecl; mVisitorPos.mReadPos--; // Backtrack, that's part of our type auto typeRef = CreateTypeRefAfter(operatorDecl); MEMBER_SET_CHECKED(operatorDecl, mReturnType, typeRef); operatorDecl->mIsConvOperator = true; ParseMethod(operatorDecl, ¶ms, &commas); return operatorDecl; } if (token == BfToken_This) { auto ctorDecl = mAlloc->Alloc(); BfDeferredAstSizedArray params(ctorDecl->mParams, mAlloc); BfDeferredAstSizedArray commas(ctorDecl->mCommas, mAlloc); ctorDecl->mReturnType = NULL; ReplaceNode(tokenNode, ctorDecl); MEMBER_SET(ctorDecl, mThisToken, tokenNode); ParseMethod(ctorDecl, ¶ms, &commas); return ctorDecl; } if (token == BfToken_Tilde) { auto thisToken = ExpectTokenAfter(tokenNode, BfToken_This); if (thisToken == NULL) { auto nextNode = mVisitorPos.GetNext(); auto nameIdentifier = BfNodeDynCast(nextNode); if (nameIdentifier != NULL) { // Eat DTOR name AddErrorNode(nameIdentifier); //nameIdentifier->RemoveSelf(); } else { //AddErrorNode(tokenNode); //return NULL; } AddErrorNode(tokenNode); return NULL; } auto dtorDecl = mAlloc->Alloc(); BfDeferredAstSizedArray params(dtorDecl->mParams, mAlloc); BfDeferredAstSizedArray commas(dtorDecl->mCommas, mAlloc); dtorDecl->mReturnType = NULL; ReplaceNode(tokenNode, dtorDecl); dtorDecl->mTildeToken = tokenNode; if (thisToken != NULL) { MEMBER_SET(dtorDecl, mThisToken, thisToken); } ParseMethod(dtorDecl, ¶ms, &commas); return dtorDecl; } if (token == BfToken_Mixin) { auto methodDecl = mAlloc->Alloc(); BfDeferredAstSizedArray params(methodDecl->mParams, mAlloc); BfDeferredAstSizedArray commas(methodDecl->mCommas, mAlloc); ReplaceNode(tokenNode, methodDecl); methodDecl->mDocumentation = FindDocumentation(methodDecl); methodDecl->mMixinSpecifier = tokenNode; //mVisitorPos.MoveNext(); auto nameNode = ExpectIdentifierAfter(methodDecl); if (nameNode != NULL) { MEMBER_SET(methodDecl, mNameNode, nameNode); auto nextNode = mVisitorPos.GetNext(); if (tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_LChevron) { auto genericParams = CreateGenericParamsDeclaration(tokenNode); if (genericParams != NULL) { MEMBER_SET(methodDecl, mGenericParams, genericParams); } } } ParseMethod(methodDecl, ¶ms, &commas); } return methodDecl; } if (token == BfToken_Case) { auto enumCaseDecl = mAlloc->Alloc(); BfDeferredAstSizedArray entries(enumCaseDecl->mEntries, mAlloc); BfDeferredAstSizedArray commas(enumCaseDecl->mCommas, mAlloc); ReplaceNode(tokenNode, enumCaseDecl); enumCaseDecl->mCaseToken = tokenNode; while (true) { auto caseName = ExpectIdentifierAfter(enumCaseDecl); if (caseName == NULL) break; auto enumEntry = mAlloc->Alloc(); ReplaceNode(caseName, enumEntry); enumEntry->mNameNode = caseName; entries.push_back(enumEntry); tokenNode = ExpectTokenAfter(enumEntry, BfToken_Comma, BfToken_AssignEquals, BfToken_LParen, BfToken_Semicolon); if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_LParen)) { auto typeRef = CreateTypeRef(tokenNode); tokenNode = NULL; auto tupleType = BfNodeDynCast(typeRef); if (tupleType != NULL) { MEMBER_SET(enumEntry, mTypeRef, tupleType); tokenNode = ExpectTokenAfter(enumEntry, BfToken_Comma, BfToken_AssignEquals, BfToken_Semicolon); } } if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_AssignEquals)) { MEMBER_SET(enumEntry, mEqualsNode, tokenNode); tokenNode = NULL; auto initializer = CreateExpressionAfter(enumEntry); if (initializer != NULL) { MEMBER_SET(enumEntry, mInitializer, initializer); tokenNode = ExpectTokenAfter(enumEntry, BfToken_Comma, BfToken_Semicolon); } } MoveNode(enumEntry, enumCaseDecl); if (tokenNode == NULL) return enumCaseDecl; if (tokenNode->GetToken() == BfToken_Semicolon) { mVisitorPos.mReadPos--; return enumCaseDecl; } MoveNode(tokenNode, enumCaseDecl); commas.push_back(tokenNode); } return enumCaseDecl; } auto nextNode = mVisitorPos.GetNext(); if (nextNode == NULL) FailAfter("Type expected", tokenNode); if ((token == BfToken_Struct) || (token == BfToken_Enum) || (token == BfToken_Class) || (token == BfToken_Delegate) || (token == BfToken_Function) || (token == BfToken_Interface) || (token == BfToken_Extension) || (token == BfToken_TypeAlias)) { mVisitorPos.mReadPos -= depth; BfAstNode* startNode = mVisitorPos.GetCurrent(); auto startToken = BfNodeDynCast(startNode); auto topLevelObject = CreateTopLevelObject(startToken, NULL); auto typeDecl = BfNodeDynCast(topLevelObject); if (typeDecl == NULL) { AddErrorNode(tokenNode); return NULL; } return typeDecl; } if (token == BfToken_Comma) { auto prevNode = mVisitorPos.Get(mVisitorPos.mWritePos - 1); auto prevFieldDecl = BfNodeDynCast(prevNode); if (prevFieldDecl != NULL) { auto nameIdentifier = ExpectIdentifierAfter(tokenNode); if (nameIdentifier == NULL) { AddErrorNode(tokenNode); return NULL; } return CreateFieldDeclaration(tokenNode, prevFieldDecl->mTypeRef, nameIdentifier, prevFieldDecl); } } switch (token) { case BfToken_Sealed: case BfToken_Static: case BfToken_Const: case BfToken_Mut: case BfToken_Public: case BfToken_Protected: case BfToken_Private: case BfToken_Virtual: case BfToken_Override: case BfToken_Abstract: case BfToken_Concrete: case BfToken_Internal: case BfToken_Extern: case BfToken_New: case BfToken_Implicit: case BfToken_Explicit: case BfToken_ReadOnly: case BfToken_Inline: case BfToken_Volatile: break; default: AddErrorNode(tokenNode); Fail("Unexpected token", tokenNode); return NULL; break; } int startNodeIdx = gAssertCurrentNodeIdx; BfAstNode* typeMember = NULL; nextNode = mVisitorPos.GetNext(); if (nextNode != NULL) { mVisitorPos.MoveNext(); typeMember = ReadTypeMember(nextNode, depth + 1); } auto memberDecl = BfNodeDynCast(typeMember); if (memberDecl == NULL) // May be an embedded type { if (auto typeDecl = BfNodeDynCast(typeMember)) return typeMember; } if (typeMember == NULL) { auto propertyDeclaration = mAlloc->Alloc(); ReplaceNode(tokenNode, propertyDeclaration); propertyDeclaration->mDocumentation = FindDocumentation(propertyDeclaration); typeMember = memberDecl = propertyDeclaration; } if (memberDecl == NULL) return NULL; if (token == BfToken_Static) { if (memberDecl->mStaticSpecifier != NULL) { AddErrorNode(memberDecl->mStaticSpecifier); Fail("Static already specified", memberDecl->mStaticSpecifier); } MEMBER_SET(memberDecl, mStaticSpecifier, tokenNode); auto fieldDecl = BfNodeDynCast(memberDecl); if (fieldDecl != NULL) { if ((fieldDecl->mStaticSpecifier != NULL) && (fieldDecl->mConstSpecifier != NULL)) Fail("Cannot use 'static' and 'const' together", fieldDecl); } return memberDecl; } if ((token == BfToken_Public) || (token == BfToken_Protected) || (token == BfToken_Private)) { if (memberDecl->mProtectionSpecifier != NULL) { AddErrorNode(memberDecl->mProtectionSpecifier); Fail("Protection already specified", memberDecl->mProtectionSpecifier); } MEMBER_SET(memberDecl, mProtectionSpecifier, tokenNode); return memberDecl; } if (token == BfToken_Internal) { if (memberDecl->mInternalSpecifier != NULL) { AddErrorNode(memberDecl->mInternalSpecifier); Fail("Internal already specified", memberDecl->mInternalSpecifier); } MEMBER_SET(memberDecl, mInternalSpecifier, tokenNode); return memberDecl; } if (auto methodDecl = BfNodeDynCast(memberDecl)) { if ((token == BfToken_Virtual) || (token == BfToken_Override) || (token == BfToken_Abstract) || (token == BfToken_Concrete)) { if (methodDecl->mVirtualSpecifier != NULL) { AddErrorNode(methodDecl->mVirtualSpecifier); if (methodDecl->mVirtualSpecifier->GetToken() == tokenNode->GetToken()) Fail(StrFormat("Already specified '%s'", BfTokenToString(tokenNode->GetToken())), methodDecl->mVirtualSpecifier); else Fail(StrFormat("Cannot specify both '%s' and '%s'", BfTokenToString(methodDecl->mVirtualSpecifier->GetToken()), BfTokenToString(tokenNode->GetToken())), methodDecl->mVirtualSpecifier); } MEMBER_SET(methodDecl, mVirtualSpecifier, tokenNode); return memberDecl; } if (token == BfToken_Extern) { if (methodDecl->mExternSpecifier != NULL) { AddErrorNode(methodDecl->mExternSpecifier); Fail("Extern already specified", methodDecl->mExternSpecifier); } MEMBER_SET(methodDecl, mExternSpecifier, tokenNode); return memberDecl; } if (token == BfToken_New) { if (methodDecl->mNewSpecifier != NULL) { AddErrorNode(methodDecl->mNewSpecifier); Fail("New already specified", methodDecl->mNewSpecifier); } MEMBER_SET(methodDecl, mNewSpecifier, tokenNode); return memberDecl; } if (token == BfToken_Mut) { if (methodDecl->mMutSpecifier != NULL) { AddErrorNode(methodDecl->mMutSpecifier); Fail("Mut already specified", methodDecl->mMutSpecifier); } MEMBER_SET(methodDecl, mMutSpecifier, tokenNode); return memberDecl; } if (token == BfToken_ReadOnly) { if (methodDecl->mReadOnlySpecifier == NULL) { MEMBER_SET(methodDecl, mReadOnlySpecifier, tokenNode); } return memberDecl; } } if (auto operatorDecl = BfNodeDynCast(memberDecl)) { if ((token == BfToken_Implicit) || (token == BfToken_Explicit)) { if (operatorDecl->mExplicitToken != NULL) { AddErrorNode(operatorDecl->mExplicitToken); Fail(StrFormat("'%s' already specified", BfTokenToString(operatorDecl->mExplicitToken->GetToken())), operatorDecl->mExplicitToken); } MEMBER_SET(operatorDecl, mExplicitToken, tokenNode); return memberDecl; } } if (auto propDecl = BfNodeDynCast(memberDecl)) { if ((token == BfToken_Virtual) || (token == BfToken_Override) || (token == BfToken_Abstract) || (token == BfToken_Concrete)) { if (propDecl->mVirtualSpecifier != NULL) { AddErrorNode(propDecl->mVirtualSpecifier); if (propDecl->mVirtualSpecifier->GetToken() == token) Fail(StrFormat("Already specified '%s'", BfTokenToString(token)), propDecl->mVirtualSpecifier); else Fail(StrFormat("Cannot specify both '%s' and '%s'", BfTokenToString(propDecl->mVirtualSpecifier->GetToken()), BfTokenToString(token)), propDecl->mVirtualSpecifier); } MEMBER_SET(propDecl, mVirtualSpecifier, tokenNode); return memberDecl; } } if (auto fieldDecl = BfNodeDynCast(memberDecl)) { if (token == BfToken_Override) { // Must be typing an 'override' over a field declaration auto propDecl = mAlloc->Alloc(); propDecl->mVirtualSpecifier = tokenNode; typeMember = memberDecl = propDecl; } bool handled = false; if (token == BfToken_Const) { MEMBER_SET(fieldDecl, mConstSpecifier, tokenNode); handled = true; } if (token == BfToken_ReadOnly) { if (fieldDecl->mReadOnlySpecifier == NULL) { MEMBER_SET(fieldDecl, mReadOnlySpecifier, tokenNode); } handled = true; } if (token == BfToken_Inline) { MEMBER_SET(fieldDecl, mReadOnlySpecifier, tokenNode); handled = true; } if (token == BfToken_Volatile) { MEMBER_SET(fieldDecl, mVolatileSpecifier, tokenNode); handled = true; } if (token == BfToken_Extern) { MEMBER_SET(fieldDecl, mExternSpecifier, tokenNode); handled = true; } if (token == BfToken_Internal) { MEMBER_SET(fieldDecl, mInternalSpecifier, tokenNode); handled = true; } if (token == BfToken_New) { if (fieldDecl->mNewSpecifier != NULL) { Fail("New already specified", tokenNode); } MEMBER_SET(fieldDecl, mNewSpecifier, tokenNode); handled = true; } if ((fieldDecl->mStaticSpecifier != NULL) && (fieldDecl->mConstSpecifier != NULL)) Fail("Cannot use 'static' and 'const' together", fieldDecl); if ((fieldDecl->mReadOnlySpecifier != NULL) && (fieldDecl->mConstSpecifier != NULL)) Fail("Cannot use 'readonly' and 'const' together", fieldDecl); if ((fieldDecl->mVolatileSpecifier != NULL) && (fieldDecl->mConstSpecifier != NULL)) Fail("Cannot use 'volatile' and 'const' together", fieldDecl); if (handled) return fieldDecl; } // Eat node if (memberDecl != NULL) ReplaceNode(tokenNode, memberDecl); Fail("Invalid token", tokenNode); return memberDecl; } void BfReducer::ReadPropertyBlock(BfPropertyDeclaration* propertyDeclaration, BfBlock* block) { SetAndRestoreValue prevVisitorPos(mVisitorPos, BfVisitorPos(block)); BfDeferredAstSizedArray methods(propertyDeclaration->mMethods, mAlloc); bool hadGet = false; bool hadSet = false; while (true) { BfTokenNode* protectionSpecifier = NULL; BfAttributeDirective* attributes = NULL; auto child = mVisitorPos.GetNext(); if (child == NULL) break; String accessorName; BfTokenNode* mutSpecifier = NULL; while (true) { auto tokenNode = BfNodeDynCast(child); if (tokenNode == NULL) break; BfToken token = tokenNode->GetToken(); if (token == BfToken_LBracket) { mVisitorPos.MoveNext(); attributes = CreateAttributeDirective(tokenNode); child = mVisitorPos.GetNext(); } tokenNode = BfNodeDynCast(child); if (tokenNode == NULL) break; token = tokenNode->GetToken(); if ((token == BfToken_Private) || (token == BfToken_Protected) || (token == BfToken_Public) || (token == BfToken_Internal)) { if (protectionSpecifier != NULL) { Fail("Protection already specified", protectionSpecifier); } protectionSpecifier = tokenNode; mVisitorPos.MoveNext(); child = mVisitorPos.GetCurrent(); } else if (token == BfToken_Mut) { Fail("'mut' must be specified after get/set", tokenNode); mutSpecifier = tokenNode; mVisitorPos.MoveNext(); } else break; child = mVisitorPos.GetNext(); } auto identifierNode = child; auto accessorIdentifier = BfNodeDynCast(child); if (accessorIdentifier != NULL) { accessorName = accessorIdentifier->ToString(); mVisitorPos.MoveNext(); child = mVisitorPos.GetNext(); } if (accessorName == "get") { // if (hadGet) // Fail("Only one 'get' method can be specified", accessorIdentifier); hadGet = true; } else if (accessorName == "set") { // if (hadSet) // Fail("Only one 'set' method can be specified", accessorIdentifier); hadSet = true; } else { Fail("Expected 'set' or 'get'", identifierNode); } BfAstNode* bodyAfterNode = accessorIdentifier; BfAstNode* body = NULL; auto tokenNode = BfNodeDynCast(child); if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_Mut)) { if (mutSpecifier != NULL) { Fail("'mut' already specified", mutSpecifier); } mutSpecifier = tokenNode; bodyAfterNode = tokenNode; mVisitorPos.MoveNext(); child = mVisitorPos.GetCurrent(); } auto endSemicolon = BfNodeDynCast(child); if ((endSemicolon != NULL) && (endSemicolon->GetToken() == BfToken_Semicolon)) { body = endSemicolon; mVisitorPos.MoveNext(); } if (body == NULL) { if (bodyAfterNode != NULL) { body = ExpectBlockAfter(bodyAfterNode); } else { auto accessorBlock = BfNodeDynCast(child); if (accessorBlock == NULL) { if (child != NULL) { Fail("Block expected", child); AddErrorNode(child); mVisitorPos.MoveNext(); } continue; } body = accessorBlock; mVisitorPos.MoveNext(); } } if (auto block = BfNodeDynCast(body)) { if (((attributes == NULL) && (IsNodeRelevant(block))) || ((attributes != NULL) && (IsNodeRelevant(attributes, block)))) { HandleBlock(block); } } if (body == NULL) { if (protectionSpecifier != NULL) AddErrorNode(protectionSpecifier); if (accessorIdentifier != NULL) AddErrorNode(accessorIdentifier); if (mutSpecifier != NULL) AddErrorNode(mutSpecifier); continue; } auto method = mAlloc->Alloc(); method->mPropertyDeclaration = propertyDeclaration; if (protectionSpecifier != NULL) MEMBER_SET(method, mProtectionSpecifier, protectionSpecifier); if (accessorIdentifier != NULL) MEMBER_SET(method, mNameNode, accessorIdentifier); if (body != NULL) { MEMBER_SET(method, mBody, body); } if (mutSpecifier != NULL) MEMBER_SET(method, mMutSpecifier, mutSpecifier); // if ((accessorBlock != NULL) && (IsNodeRelevant(propertyDeclaration))) // HandleBlock(accessorBlock); if (attributes != NULL) MEMBER_SET(method, mAttributes, attributes); methods.push_back(method); } } BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, int depth) { SetAndRestoreValue prevTypeMemberNodeStart(mTypeMemberNodeStart, node, false); if (depth == 0) prevTypeMemberNodeStart.Set(); AssertCurrentNode(node); node = ReplaceTokenStarter(node); BfTokenNode* refToken = NULL; if (auto tokenNode = BfNodeDynCast(node)) { BfToken token = tokenNode->GetToken(); bool isTypeRef = false; if ((token == BfToken_Delegate) || (token == BfToken_Function)) { // We need to differentiate between a delegate type reference and a delegate type declaration int endNodeIdx = -1; if (IsTypeReference(node, BfToken_LParen, &endNodeIdx)) { isTypeRef = true; } } if (isTypeRef) { // Handled below } else if ((token == BfToken_Ref) || (token == BfToken_Mut)) { refToken = tokenNode; mVisitorPos.MoveNext(); // Read type member } else if ((token == BfToken_Var) || (token == BfToken_Let) || (token == BfToken_RetType) || (token == BfToken_Decltype) || (token == BfToken_LParen)) { // Read type member } else return ReadTypeMember(tokenNode, depth); } else if (auto block = BfNodeDynCast(node)) { Fail("Expected method declaration", node); HandleBlock(block); auto methodDecl = mAlloc->Alloc(); ReplaceNode(block, methodDecl); methodDecl->mDocumentation = FindDocumentation(methodDecl); methodDecl->mBody = block; return methodDecl; } BfTokenNode* indexerThisToken = NULL; bool isIndexProp = false; auto origNode = node; if (refToken != NULL) { auto nextNode = mVisitorPos.Get(mVisitorPos.mReadPos); if (nextNode != NULL) node = nextNode; } auto typeRef = CreateTypeRef(node); if (typeRef == NULL) { if (refToken != NULL) { AddErrorNode(refToken); if (mVisitorPos.Get(mVisitorPos.mReadPos) == node) { mVisitorPos.mReadPos--; return NULL; } } #ifdef BF_AST_HAS_PARENT_MEMBER BF_ASSERT(node->mParent != NULL); #endif AddErrorNode(node); return NULL; } if (refToken != NULL) typeRef = CreateRefTypeRef(typeRef, refToken); node = typeRef; auto nextNode = mVisitorPos.GetNext(); if (auto tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_This) indexerThisToken = tokenNode; } BfTokenNode* explicitInterfaceDot = NULL; BfTypeReference* explicitInterface = NULL; bool forceIsMethod = false; nextNode = mVisitorPos.GetNext(); auto nameIdentifier = BfNodeDynCast(nextNode); if (nameIdentifier != NULL) { mVisitorPos.MoveNext(); bool doExplicitInterface = false; int endNodeIdx = -1; //mVisitorPos.mReadPos++; int nameIdentifierIdx = mVisitorPos.mReadPos; doExplicitInterface = IsTypeReference(nameIdentifier, BfToken_LParen, &endNodeIdx); //mVisitorPos.mReadPos--; BfAstNode* endNode = mVisitorPos.Get(endNodeIdx); if (!doExplicitInterface) { if (auto endToken = BfNodeDynCastExact(endNode)) { if (endToken->GetToken() == BfToken_This) { indexerThisToken = endToken; doExplicitInterface = true; } } else if (auto block = BfNodeDynCastExact(endNode)) { doExplicitInterface = true; // Qualified property } } if (doExplicitInterface) { auto prevEndNode = mVisitorPos.Get(endNodeIdx - 1); int explicitInterfaceDotIdx = QualifiedBacktrack(prevEndNode, endNodeIdx - 1); if (explicitInterfaceDotIdx != -1) { explicitInterfaceDot = (BfTokenNode*)mVisitorPos.Get(explicitInterfaceDotIdx); mVisitorPos.mReadPos = nameIdentifierIdx; explicitInterfaceDot->SetToken(BfToken_Bar); // Hack to stop TypeRef parsing explicitInterface = CreateTypeRef(nameIdentifier); explicitInterfaceDot->SetToken(BfToken_Dot); if (explicitInterface == NULL) return NULL; mVisitorPos.mReadPos = explicitInterfaceDotIdx; if (indexerThisToken == NULL) { nameIdentifier = ExpectIdentifierAfter(explicitInterfaceDot); if (nameIdentifier == NULL) { // Looks like a method declaration auto methodDeclaration = mAlloc->Alloc(); BfDeferredAstSizedArray params(methodDeclaration->mParams, mAlloc); BfDeferredAstSizedArray commas(methodDeclaration->mCommas, mAlloc); if (typeRef != NULL) ReplaceNode(typeRef, methodDeclaration); else ReplaceNode(nameIdentifier, methodDeclaration); methodDeclaration->mDocumentation = FindDocumentation(mTypeMemberNodeStart); MEMBER_SET(methodDeclaration, mReturnType, typeRef); MEMBER_SET(methodDeclaration, mExplicitInterface, explicitInterface); MEMBER_SET(methodDeclaration, mExplicitInterfaceDotToken, explicitInterfaceDot); return methodDeclaration; } } } } } else if (auto nextToken = BfNodeDynCast(nextNode)) { if (nextToken->GetToken() == BfToken_Operator) { auto operatorDecl = mAlloc->Alloc(); BfDeferredAstSizedArray params(operatorDecl->mParams, mAlloc); BfDeferredAstSizedArray commas(operatorDecl->mCommas, mAlloc); ReplaceNode(typeRef, operatorDecl); operatorDecl->mReturnType = typeRef; mVisitorPos.MoveNext(); MEMBER_SET(operatorDecl, mOperatorToken, nextToken); bool hadFailedOperator = false; auto nextNode = mVisitorPos.GetNext(); if (auto nextToken = BfNodeDynCast(nextNode)) { operatorDecl->mBinOp = TokenToBinaryOp(nextToken->GetToken()); if (operatorDecl->mBinOp != BfBinaryOp_None) { MEMBER_SET(operatorDecl, mOpTypeToken, nextToken); mVisitorPos.MoveNext(); } else { operatorDecl->mUnaryOp = TokenToUnaryOp(nextToken->GetToken()); if (operatorDecl->mUnaryOp != BfUnaryOp_None) { MEMBER_SET(operatorDecl, mOpTypeToken, nextToken); mVisitorPos.MoveNext(); } else { operatorDecl->mAssignOp = TokenToAssignmentOp(nextToken->GetToken()); if (operatorDecl->mAssignOp == BfAssignmentOp_Assign) { Fail("The assignment operator '=' cannot be overridden", nextToken); } if (operatorDecl->mAssignOp != BfAssignmentOp_None) { MEMBER_SET(operatorDecl, mOpTypeToken, nextToken); mVisitorPos.MoveNext(); } else if (nextToken->GetToken() != BfToken_LParen) { Fail("Invalid operator type", nextToken); MEMBER_SET(operatorDecl, mOpTypeToken, nextToken); mVisitorPos.MoveNext(); } } } } if ((operatorDecl->mOpTypeToken == NULL) && (operatorDecl->mReturnType == NULL) && (!hadFailedOperator)) { FailAfter("Expected operator type", operatorDecl); return NULL; } ParseMethod(operatorDecl, ¶ms, &commas); // This was the one ambiguous case if ((operatorDecl->mBinOp == BfBinaryOp_Subtract) && (params.size() == 1)) { operatorDecl->mBinOp = BfBinaryOp_None; operatorDecl->mUnaryOp = BfUnaryOp_Negate; } return operatorDecl; } else if (nextToken->GetToken() == BfToken_LParen) { Fail("Method name, 'this', or '~this' expected", node); nameIdentifier = BfNodeDynCast(origNode); if (nameIdentifier != NULL) { // Remove TypeRef ReplaceNode(typeRef, nameIdentifier); typeRef = NULL; } } } if ((nameIdentifier != NULL) || (forceIsMethod) || (indexerThisToken != NULL)) { //ExtractExplicitInterfaceRef int blockAfterIdx = mVisitorPos.mReadPos + 1; BfAstNode* blockAfterPos = nameIdentifier; BfPropertyDeclaration* propertyDeclaration = NULL; if (indexerThisToken != NULL) { auto indexerDeclaration = mAlloc->Alloc(); BfDeferredAstSizedArray params(indexerDeclaration->mParams, mAlloc); BfDeferredAstSizedArray commas(indexerDeclaration->mCommas, mAlloc); ReplaceNode(typeRef, indexerDeclaration); indexerDeclaration->mTypeRef = typeRef; MEMBER_SET(indexerDeclaration, mThisToken, indexerThisToken); mVisitorPos.MoveNext(); if (explicitInterface != NULL) { MEMBER_SET(indexerDeclaration, mExplicitInterface, explicitInterface); MEMBER_SET(indexerDeclaration, mExplicitInterfaceDotToken, explicitInterfaceDot); //mVisitorPos.mReadPos = endNodeIdx; } auto openToken = ExpectTokenAfter(indexerDeclaration, BfToken_LBracket); if (openToken == NULL) return indexerDeclaration; MEMBER_SET(indexerDeclaration, mOpenBracket, openToken); auto endToken = ParseMethodParams(indexerDeclaration, ¶ms, &commas, BfToken_RBracket); if (endToken == NULL) return indexerDeclaration; MEMBER_SET(indexerDeclaration, mCloseBracket, endToken); propertyDeclaration = indexerDeclaration; blockAfterPos = propertyDeclaration; mVisitorPos.MoveNext(); blockAfterIdx = mVisitorPos.mReadPos + 1; auto block = ExpectBlockAfter(blockAfterPos); if (block == NULL) return indexerDeclaration; } else { blockAfterPos = nameIdentifier; } nextNode = mVisitorPos.Get(blockAfterIdx); auto block = BfNodeDynCast(nextNode); auto tokenNode = BfNodeDynCast(nextNode); // Property. // If we don't have a token afterwards then still treat it as a property for autocomplete purposes if (((block != NULL) || (tokenNode == NULL)) && (typeRef != NULL)) { //mVisitorPos.mReadPos = blockAfterIdx; if (propertyDeclaration == NULL) { if (block == NULL) { //// Actually treat it as a method //auto methodDecl = mAlloc->Alloc(); //ReplaceNode(typeRef, methodDecl); //methodDecl->mDocumentation = FindDocumentation(mTypeMemberNodeStart); //methodDecl->mReturnType = typeRef; //if (explicitInterface != NULL) //{ // MEMBER_SET(methodDecl, mExplicitInterface, explicitInterface); // MEMBER_SET(methodDecl, mExplicitInterfaceDotToken, explicitInterfaceDot); //} //// Don't set the name identifier, this could be bogus ////mVisitorPos.mReadPos--; // //// WHY did we want to not set this? //// If we don't, then typing a new method name will end up treating the name node as a typeRef //// which can autocomplete incorrectly //MEMBER_SET(methodDecl, mNameNode, nameIdentifier); //return methodDecl; auto propDecl = mAlloc->Alloc(); ReplaceNode(typeRef, propDecl); propDecl->mDocumentation = FindDocumentation(mTypeMemberNodeStart); propDecl->mTypeRef = typeRef; if (explicitInterface != NULL) { MEMBER_SET(propDecl, mExplicitInterface, explicitInterface); MEMBER_SET(propDecl, mExplicitInterfaceDotToken, explicitInterfaceDot); } // Don't set the name identifier, this could be bogus //mVisitorPos.mReadPos--; // WHY did we want to not set this? // If we don't, then typing a new method name will end up treating the name node as a typeRef // which can autocomplete incorrectly MEMBER_SET(propDecl, mNameNode, nameIdentifier); return propDecl; } mVisitorPos.mReadPos = blockAfterIdx; propertyDeclaration = mAlloc->Alloc(); ReplaceNode(typeRef, propertyDeclaration); propertyDeclaration->mDocumentation = FindDocumentation(mTypeMemberNodeStart); propertyDeclaration->mTypeRef = typeRef; if (explicitInterface != NULL) { MEMBER_SET(propertyDeclaration, mExplicitInterface, explicitInterface); MEMBER_SET(propertyDeclaration, mExplicitInterfaceDotToken, explicitInterfaceDot); } MEMBER_SET(propertyDeclaration, mNameNode, nameIdentifier); //mVisitorPos.MoveNext(); } else mVisitorPos.mReadPos = blockAfterIdx; if (block != NULL) { MEMBER_SET(propertyDeclaration, mDefinitionBlock, block); ReadPropertyBlock(propertyDeclaration, block); } return propertyDeclaration; } //nextNode = mVisitorPos.Get(mVisitorPos.mReadPos + 2); /*if (tokenNode == NULL) { mVisitorPos.MoveNext(); ExpectTokenAfter(nameIdentifier, BfToken_Semicolon); // Just 'eat' the typeRef by stuffing it into a property declaration auto fieldDecl = mAlloc->Alloc(); ReplaceNode(typeRef, fieldDecl); fieldDecl->mTypeRef = typeRef; return fieldDecl; }*/ if (tokenNode == NULL) { auto fieldDecl = mAlloc->Alloc(); ReplaceNode(nameIdentifier, fieldDecl); fieldDecl->mDocumentation = FindDocumentation(mTypeMemberNodeStart); fieldDecl->mNameNode = nameIdentifier; return fieldDecl; } BfToken token = tokenNode->GetToken(); if ((token == BfToken_LParen) || (token == BfToken_LChevron)) { if (token == BfToken_LChevron) { //mVisitorPos.mReadPos++; bool isTypeRef = IsTypeReference(nameIdentifier, BfToken_LParen); //mVisitorPos.mReadPos--; if (!isTypeRef) { bool onNewLine = false; auto src = nameIdentifier->GetSourceData(); int srcStart = nameIdentifier->GetSrcStart(); for (int srcIdx = typeRef->GetSrcEnd(); srcIdx < srcStart; srcIdx++) if (src->mSrc[srcIdx] == '\n') onNewLine = false; if (onNewLine) { // Actually it looks like a partially formed type declaration followed by a method // which returns a generic type FailAfter("Name expected", typeRef); auto fieldDecl = mAlloc->Alloc(); ReplaceNode(typeRef, fieldDecl); fieldDecl->mDocumentation = FindDocumentation(mTypeMemberNodeStart); fieldDecl->mTypeRef = typeRef; return fieldDecl; } } } // Looks like a method declaration auto methodDeclaration = mAlloc->Alloc(); BfDeferredAstSizedArray params(methodDeclaration->mParams, mAlloc); BfDeferredAstSizedArray commas(methodDeclaration->mCommas, mAlloc); if (typeRef != NULL) ReplaceNode(typeRef, methodDeclaration); else ReplaceNode(nameIdentifier, methodDeclaration); methodDeclaration->mDocumentation = FindDocumentation(mTypeMemberNodeStart); if (explicitInterface != NULL) { MEMBER_SET(methodDeclaration, mExplicitInterface, explicitInterface); MEMBER_SET(methodDeclaration, mExplicitInterfaceDotToken, explicitInterfaceDot); } if (token == BfToken_LChevron) { auto genericParams = CreateGenericParamsDeclaration(tokenNode); if (genericParams != NULL) { MEMBER_SET(methodDeclaration, mGenericParams, genericParams); } } methodDeclaration->mReturnType = typeRef; MEMBER_SET_CHECKED(methodDeclaration, mNameNode, nameIdentifier); mCurMethodDecl = methodDeclaration; ParseMethod(methodDeclaration, ¶ms, &commas); mCurMethodDecl = NULL; return methodDeclaration; } return CreateFieldDeclaration(tokenNode, typeRef, nameIdentifier, NULL); } FailAfter("Member name expected", node); // Same fail case as "expected member declaration" auto fieldDecl = mAlloc->Alloc(); ReplaceNode(typeRef, fieldDecl); fieldDecl->mDocumentation = FindDocumentation(mTypeMemberNodeStart); fieldDecl->mTypeRef = typeRef; return fieldDecl; } BfInvocationExpression* BfReducer::CreateInvocationExpression(BfAstNode* target, CreateExprFlags createExprFlags) { auto tokenNode = ExpectTokenAfter(target, BfToken_LParen, BfToken_LChevron, BfToken_Bang); auto invocationExpr = mAlloc->Alloc(); BfDeferredAstSizedArray arguments(invocationExpr->mArguments, mAlloc); BfDeferredAstSizedArray commas(invocationExpr->mCommas, mAlloc); invocationExpr->mTarget = target; ReplaceNode(target, invocationExpr); if (tokenNode == NULL) return invocationExpr; if (tokenNode->GetToken() == BfToken_Bang) { MoveNode(tokenNode, invocationExpr); if (tokenNode->GetSrcEnd() == invocationExpr->mTarget->GetSrcEnd() + 1) { BfAstNode* target = invocationExpr->mTarget; while (true) { if (auto qualifiedNameNode = BfNodeDynCast(target)) target = qualifiedNameNode->mRight; else if (auto memberRefExpr = BfNodeDynCast(target)) target = memberRefExpr->mMemberName; else if (auto attribIdentifierNode = BfNodeDynCast(target)) target = attribIdentifierNode->mIdentifier; else break; } if (target != NULL) { BF_ASSERT(tokenNode->GetSrcEnd() == target->GetSrcEnd() + 1); target->SetSrcEnd(tokenNode->GetSrcEnd()); invocationExpr->mTarget->SetSrcEnd(tokenNode->GetSrcEnd()); if (auto nextToken = BfNodeDynCast(mVisitorPos.GetNext())) { if (nextToken->GetToken() == BfToken_Colon) { /*auto scopedInvocationTarget = mAlloc->Alloc(); ReplaceNode(invocationExpr->mTarget, scopedInvocationTarget); scopedInvocationTarget->mTarget = invocationExpr->mTarget; invocationExpr->mTarget = scopedInvocationTarget; MEMBER_SET(scopedInvocationTarget, mColonToken, nextToken); mVisitorPos.MoveNext(); if (auto nextToken = BfNodeDynCast(mVisitorPos.GetNext())) { if ((nextToken->GetToken() == BfToken_Colon) || (nextToken->GetToken() == BfToken_Mixin)) { MEMBER_SET(scopedInvocationTarget, mScopeName, nextToken); mVisitorPos.MoveNext(); } } else if (auto identifier = BfNodeDynCast(mVisitorPos.GetNext())) { MEMBER_SET(scopedInvocationTarget, mScopeName, identifier); mVisitorPos.MoveNext(); } if (scopedInvocationTarget->mScopeName == NULL) { FailAfter("Expected scope name", scopedInvocationTarget); }*/ auto scopedInvocationTarget = CreateScopedInvocationTarget(invocationExpr->mTarget, nextToken); invocationExpr->SetSrcEnd(scopedInvocationTarget->GetSrcEnd()); } } } } else Fail("No space allowed before token", tokenNode); tokenNode = ExpectTokenAfter(invocationExpr, BfToken_LParen, BfToken_LChevron); if (tokenNode == NULL) return invocationExpr; } if (tokenNode->GetToken() == BfToken_LChevron) { auto genericParamsDecl = CreateGenericArguments(tokenNode); MEMBER_SET_CHECKED(invocationExpr, mGenericArgs, genericParamsDecl); tokenNode = ExpectTokenAfter(invocationExpr, BfToken_LParen); } MEMBER_SET_CHECKED(invocationExpr, mOpenParen, tokenNode); tokenNode = ReadArguments(invocationExpr, invocationExpr, &arguments, &commas, BfToken_RParen, true); if (tokenNode != NULL) { MEMBER_SET(invocationExpr, mCloseParen, tokenNode); } return invocationExpr; } BfDelegateBindExpression* BfReducer::CreateDelegateBindExpression(BfAstNode* allocNode) { auto delegateBindExpr = mAlloc->Alloc(); ReplaceNode(allocNode, delegateBindExpr); MEMBER_SET(delegateBindExpr, mNewToken, allocNode); auto tokenNode = ExpectTokenAfter(delegateBindExpr, BfToken_FatArrow); MEMBER_SET_CHECKED(delegateBindExpr, mFatArrowToken, tokenNode); auto expr = CreateExpressionAfter(delegateBindExpr); MEMBER_SET_CHECKED(delegateBindExpr, mTarget, expr); auto nextNode = mVisitorPos.GetNext(); if (tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_LChevron) { auto genericParamsDecl = CreateGenericArguments(tokenNode); MEMBER_SET_CHECKED(delegateBindExpr, mGenericArgs, genericParamsDecl); } } return delegateBindExpr; } BfLambdaBindExpression* BfReducer::CreateLambdaBindExpression(BfAstNode* allocNode, BfTokenNode* parenToken) { auto lambdaBindExpr = mAlloc->Alloc(); BfDeferredAstSizedArray params(lambdaBindExpr->mParams, mAlloc); BfDeferredAstSizedArray commas(lambdaBindExpr->mCommas, mAlloc); BfTokenNode* tokenNode; if (allocNode != NULL) { ReplaceNode(allocNode, lambdaBindExpr); MEMBER_SET(lambdaBindExpr, mNewToken, allocNode); tokenNode = ExpectTokenAfter(lambdaBindExpr, BfToken_LParen, BfToken_LBracket); } else { ReplaceNode(parenToken, lambdaBindExpr); tokenNode = parenToken; } //auto tokenNode = ExpectTokenAfter(lambdaBindExpr, BfToken_LParen, BfToken_LBracket); if (tokenNode == NULL) return lambdaBindExpr; if (tokenNode->GetToken() == BfToken_LBracket) { auto lambdaCapture = mAlloc->Alloc(); ReplaceNode(tokenNode, lambdaCapture); MEMBER_SET(lambdaBindExpr, mLambdaCapture, lambdaCapture); MEMBER_SET(lambdaCapture, mOpenBracket, tokenNode); while (true) { tokenNode = ExpectTokenAfter(lambdaBindExpr, BfToken_Ampersand, BfToken_AssignEquals, BfToken_RBracket); if (tokenNode == NULL) return lambdaBindExpr; if ((tokenNode->GetToken() == BfToken_Ampersand) || (tokenNode->GetToken() == BfToken_AssignEquals)) { MEMBER_SET(lambdaCapture, mCaptureToken, tokenNode); lambdaBindExpr->SetSrcEnd(lambdaCapture->GetSrcEnd()); } if (tokenNode->GetToken() == BfToken_RBracket) { MEMBER_SET(lambdaCapture, mCloseBracket, tokenNode); lambdaBindExpr->SetSrcEnd(lambdaCapture->GetSrcEnd()); break; } } tokenNode = ExpectTokenAfter(lambdaBindExpr, BfToken_LParen); } MEMBER_SET_CHECKED(lambdaBindExpr, mOpenParen, tokenNode); for (int paramIdx = 0; true; paramIdx++) { bool isRParen = false; auto nextNode = mVisitorPos.GetNext(); if (auto tokenNode = BfNodeDynCast(nextNode)) isRParen = tokenNode->GetToken() == BfToken_RParen; if (!isRParen) { auto nameIdentifier = ExpectIdentifierAfter(lambdaBindExpr, "parameter name"); if (nameIdentifier == NULL) return lambdaBindExpr; MoveNode(nameIdentifier, lambdaBindExpr); params.push_back(nameIdentifier); } tokenNode = ExpectTokenAfter(lambdaBindExpr, BfToken_Comma, BfToken_RParen); if (tokenNode == NULL) return lambdaBindExpr; if (tokenNode->GetToken() == BfToken_RParen) { MEMBER_SET(lambdaBindExpr, mCloseParen, tokenNode); break; } MoveNode(tokenNode, lambdaBindExpr); commas.push_back(tokenNode); } tokenNode = ExpectTokenAfter(lambdaBindExpr, BfToken_FatArrow); MEMBER_SET_CHECKED(lambdaBindExpr, mFatArrowToken, tokenNode); auto nextNode = mVisitorPos.GetNext(); auto block = BfNodeDynCast(nextNode); if (block != NULL) { HandleBlock(block, true); mVisitorPos.MoveNext(); MEMBER_SET_CHECKED(lambdaBindExpr, mBody, block); } else { auto expr = CreateExpressionAfter(lambdaBindExpr); MEMBER_SET_CHECKED(lambdaBindExpr, mBody, expr); } auto lambdaDtor = CreateFieldDtorDeclaration(lambdaBindExpr); if (lambdaDtor != NULL) { if ((mIsFieldInitializer) && (!mInParenExpr)) { Fail("Ambiguous destructor: could be field destructor or lambda destructor. Disambiguate with parentheses, either '(lambda) ~ fieldDtor' or '(lambda ~ lambdaDtor)'", lambdaBindExpr); } lambdaBindExpr->mDtor = lambdaDtor; } return lambdaBindExpr; } BfCollectionInitializerExpression* BfReducer::CreateCollectionInitializerExpression(BfBlock* block) { auto arrayInitializerExpression = mAlloc->Alloc(); BfDeferredAstSizedArray values(arrayInitializerExpression->mValues, mAlloc); BfDeferredAstSizedArray commas(arrayInitializerExpression->mCommas, mAlloc); ReplaceNode(block, arrayInitializerExpression); MEMBER_SET(arrayInitializerExpression, mOpenBrace, block->mOpenBrace); if (block->mCloseBrace != NULL) MEMBER_SET(arrayInitializerExpression, mCloseBrace, block->mCloseBrace); block->mOpenBrace = NULL; block->mCloseBrace = NULL; SetAndRestoreValue prevVisitorPos(mVisitorPos, BfVisitorPos(block)); bool isDone = !mVisitorPos.MoveNext(); while (true) { auto head = mVisitorPos.GetCurrent(); if (head == NULL) break; BfExpression* expression; if (auto innerBlock = BfNodeDynCast(head)) expression = CreateCollectionInitializerExpression(innerBlock); else expression = CreateExpression(head); if (expression == NULL) break; auto nextNode = mVisitorPos.GetNext(); bool atEnd = nextNode == NULL; auto tokenNode = atEnd ? NULL : ExpectTokenAfter(expression, BfToken_Comma, BfToken_RBrace); MoveNode(expression, arrayInitializerExpression); values.push_back(expression); if ((!atEnd) && (tokenNode == NULL)) break; if (atEnd) break; MoveNode(tokenNode, arrayInitializerExpression); commas.push_back(tokenNode); isDone = !mVisitorPos.MoveNext(); } return arrayInitializerExpression; } BfCollectionInitializerExpression * BfReducer::CreateCollectionInitializerExpression(BfTokenNode* openToken) { auto arrayInitializerExpression = mAlloc->Alloc(); BfDeferredAstSizedArray values(arrayInitializerExpression->mValues, mAlloc); BfDeferredAstSizedArray commas(arrayInitializerExpression->mCommas, mAlloc); ReplaceNode(openToken, arrayInitializerExpression); MEMBER_SET(arrayInitializerExpression, mOpenBrace, openToken); bool isDone = !mVisitorPos.MoveNext(); while (true) { auto head = mVisitorPos.GetCurrent(); if (head == NULL) break; BfExpression* expression; if (auto innerBlock = BfNodeDynCast(head)) expression = CreateCollectionInitializerExpression(innerBlock); else { if (auto tokenNode = BfNodeDynCast(head)) { if (tokenNode->mToken == BfToken_RParen) { MEMBER_SET(arrayInitializerExpression, mCloseBrace, tokenNode); return arrayInitializerExpression; } } expression = CreateExpression(head); } if (expression == NULL) break; auto nextNode = mVisitorPos.GetNext(); bool atEnd = nextNode == NULL; auto tokenNode = atEnd ? NULL : ExpectTokenAfter(expression, BfToken_Comma, BfToken_RParen); MoveNode(expression, arrayInitializerExpression); values.push_back(expression); if ((!atEnd) && (tokenNode == NULL)) break; if (atEnd) break; MoveNode(tokenNode, arrayInitializerExpression); if (tokenNode->GetToken() == BfToken_RParen) { MEMBER_SET(arrayInitializerExpression, mCloseBrace, tokenNode); break; } commas.push_back(tokenNode); isDone = !mVisitorPos.MoveNext(); } return arrayInitializerExpression; } BfScopedInvocationTarget* BfReducer::CreateScopedInvocationTarget(BfAstNode*& targetRef, BfTokenNode* colonToken) { auto scopedInvocationTarget = mAlloc->Alloc(); ReplaceNode(targetRef, scopedInvocationTarget); scopedInvocationTarget->mTarget = targetRef; targetRef = scopedInvocationTarget; if (colonToken == NULL) return scopedInvocationTarget; MEMBER_SET(scopedInvocationTarget, mColonToken, colonToken); mVisitorPos.MoveNext(); if (auto nextToken = BfNodeDynCast(mVisitorPos.GetNext())) { if ((nextToken->GetToken() == BfToken_Colon) || (nextToken->GetToken() == BfToken_Mixin)) { MEMBER_SET(scopedInvocationTarget, mScopeName, nextToken); mVisitorPos.MoveNext(); } } else if (auto identifier = BfNodeDynCast(mVisitorPos.GetNext())) { MEMBER_SET(scopedInvocationTarget, mScopeName, identifier); mVisitorPos.MoveNext(); } if (scopedInvocationTarget->mScopeName == NULL) { FailAfter("Expected scope name", scopedInvocationTarget); } return scopedInvocationTarget; } BfAstNode* BfReducer::CreateAllocNode(BfTokenNode* allocToken) { if (allocToken->GetToken() == BfToken_Scope) { auto nextToken = BfNodeDynCast(mVisitorPos.GetNext()); if ((nextToken != NULL) && (nextToken->GetToken() == BfToken_Colon)) { auto scopeNode = mAlloc->Alloc(); ReplaceNode(allocToken, scopeNode); scopeNode->mScopeToken = allocToken; MEMBER_SET(scopeNode, mColonToken, nextToken); mVisitorPos.MoveNext(); if (auto nextToken = BfNodeDynCast(mVisitorPos.GetNext())) { if ((nextToken->GetToken() == BfToken_Colon) || (nextToken->GetToken() == BfToken_Mixin)) { MEMBER_SET(scopeNode, mTargetNode, nextToken); mVisitorPos.MoveNext(); } } else if (auto identifier = BfNodeDynCast(mVisitorPos.GetNext())) { MEMBER_SET(scopeNode, mTargetNode, identifier); mVisitorPos.MoveNext(); } if (scopeNode->mTargetNode == NULL) { FailAfter("Expected scope name", scopeNode); } return scopeNode; } } if (allocToken->GetToken() == BfToken_New) {// auto nextToken = BfNodeDynCast(mVisitorPos.GetNext()); if ((nextToken != NULL) && (nextToken->GetToken() == BfToken_Colon)) { // auto newNode = mAlloc->Alloc(); ReplaceNode(allocToken, newNode); newNode->mNewToken = allocToken; MEMBER_SET(newNode, mColonToken, nextToken); mVisitorPos.MoveNext(); if (auto nextTokenNode = BfNodeDynCast(mVisitorPos.GetNext())) { BfToken nextToken = nextTokenNode->GetToken(); if ((nextToken == BfToken_LParen) || (nextToken == BfToken_This) || (nextToken == BfToken_Null)) { auto allocExpr = CreateExpressionAfter(newNode, (CreateExprFlags)(CreateExprFlags_NoCast | CreateExprFlags_ExitOnParenExpr)); if (allocExpr != NULL) { MEMBER_SET(newNode, mAllocNode, allocExpr); } } } else { int endNodeIdx = -1; int nodeIdx = mVisitorPos.mReadPos; mVisitorPos.MoveNext(); if (IsTypeReference(mVisitorPos.GetCurrent(), BfToken_Bang, &endNodeIdx)) { if (auto bangToken = BfNodeDynCast(mVisitorPos.Get(endNodeIdx))) { if (auto prevIdentifier = BfNodeDynCast(mVisitorPos.Get(endNodeIdx - 1))) { if (bangToken->GetSrcStart() == prevIdentifier->GetSrcEnd()) { if (endNodeIdx == nodeIdx + 2) { MEMBER_SET(newNode, mAllocNode, prevIdentifier); prevIdentifier->SetSrcEnd(bangToken->GetSrcEnd()); } else { mVisitorPos.mReadPos = nodeIdx + 1; BfExpression* expr = CreateExpression(mVisitorPos.Get(nodeIdx + 1), CreateExprFlags_ExitOnBang); expr->SetSrcEnd(bangToken->GetSrcEnd()); MEMBER_SET(newNode, mAllocNode, expr); BfAstNode* memberNode = expr; if (auto memberRefExpr = BfNodeDynCast(expr)) { memberNode = memberRefExpr->mMemberName; } else if (auto qualifiedIdentifier = BfNodeDynCast(expr)) { memberNode = qualifiedIdentifier->mRight; } if (memberNode != NULL) memberNode->SetSrcEnd(bangToken->GetSrcEnd()); } newNode->SetSrcEnd(bangToken->GetSrcEnd()); mVisitorPos.mReadPos = endNodeIdx; BfTokenNode* colonToken = NULL; if (auto nextToken = BfNodeDynCast(mVisitorPos.Get(endNodeIdx + 1))) { if (nextToken->GetToken() == BfToken_Colon) colonToken = nextToken; } auto scopedInvocationTarget = CreateScopedInvocationTarget(newNode->mAllocNode, colonToken); newNode->SetSrcEnd(scopedInvocationTarget->GetSrcEnd()); } } } } if (newNode->mAllocNode == NULL) { mVisitorPos.mReadPos = nodeIdx; if (auto identifier = BfNodeDynCast(mVisitorPos.GetNext())) { MEMBER_SET(newNode, mAllocNode, identifier); mVisitorPos.MoveNext(); } // This causes parse ambiguities /*mVisitorPos.mReadPos = nodeIdx; auto allocExpr = CreateExpressionAfter(newNode, BfReducer::CreateExprFlags_NoCast); if (allocExpr != NULL) { MEMBER_SET(newNode, mAllocNode, allocExpr); }*/ } } if (newNode->mAllocNode == NULL) { FailAfter("Expected allocator expression", newNode); } return newNode; } } return allocToken; } BfObjectCreateExpression* BfReducer::CreateObjectCreateExpression(BfAstNode* allocNode) { auto objectCreateExpr = mAlloc->Alloc(); BfDeferredAstSizedArray arguments(objectCreateExpr->mArguments, mAlloc); BfDeferredAstSizedArray commas(objectCreateExpr->mCommas, mAlloc); ReplaceNode(allocNode, objectCreateExpr); MEMBER_SET(objectCreateExpr, mNewNode, allocNode); auto nextNode = mVisitorPos.GetNext(); BfTokenNode* tokenNode; // Why did we want this syntax? // if (tokenNode = BfNodeDynCast(mVisitorPos.GetNext())) // { // if (tokenNode->GetToken() == BfToken_Star) // { // MEMBER_SET(objectCreateExpr, mStarToken, tokenNode); // mVisitorPos.MoveNext(); // } // } auto typeRef = CreateTypeRefAfter(objectCreateExpr); if (typeRef == NULL) return objectCreateExpr; if (auto ptrType = BfNodeDynCast(typeRef)) { if (auto arrayType = BfNodeDynCast(ptrType->mElementType)) { MEMBER_SET(objectCreateExpr, mStarToken, ptrType->mStarNode); typeRef = ptrType->mElementType; } } MEMBER_SET(objectCreateExpr, mTypeRef, typeRef); if (auto block = BfNodeDynCast(mVisitorPos.GetNext())) { mVisitorPos.MoveNext(); MEMBER_SET(objectCreateExpr, mOpenToken, block->mOpenBrace); // { SetAndRestoreValue prevVisitorPos(mVisitorPos, BfVisitorPos(block)); ReadArguments(objectCreateExpr, objectCreateExpr, &arguments, &commas, BfToken_None, true); } MEMBER_SET(objectCreateExpr, mCloseToken, block->mCloseBrace); return objectCreateExpr; } tokenNode = BfNodeDynCast(mVisitorPos.GetNext()); if (tokenNode == NULL) return objectCreateExpr; if (tokenNode->GetToken() != BfToken_LParen) return objectCreateExpr; mVisitorPos.MoveNext(); MEMBER_SET(objectCreateExpr, mOpenToken, tokenNode); BfToken endToken = (BfToken)(tokenNode->GetToken() + 1); tokenNode = ReadArguments(objectCreateExpr, objectCreateExpr, &arguments, &commas, BfToken_RParen, true); if (tokenNode == NULL) return objectCreateExpr; MEMBER_SET(objectCreateExpr, mCloseToken, tokenNode); return objectCreateExpr; } BfExpression* BfReducer::CreateIndexerExpression(BfExpression* target) { auto tokenNode = ExpectTokenAfter(target, BfToken_LBracket, BfToken_QuestionLBracket); auto indexerExpr = mAlloc->Alloc(); BfDeferredAstSizedArray arguments(indexerExpr->mArguments, mAlloc); BfDeferredAstSizedArray commas(indexerExpr->mCommas, mAlloc); indexerExpr->mTarget = target; ReplaceNode(target, indexerExpr); indexerExpr->mOpenBracket = tokenNode; MoveNode(indexerExpr->mOpenBracket, indexerExpr); BfAstNode* argAfterNode = indexerExpr; BfAttributeDirective* attributeDirective = NULL; if (auto tokenNode = BfNodeDynCast(mVisitorPos.GetNext())) { if (tokenNode->mToken == BfToken_LBracket) { mVisitorPos.MoveNext(); attributeDirective = CreateAttributeDirective(tokenNode); argAfterNode = attributeDirective; } } indexerExpr->mCloseBracket = ReadArguments(indexerExpr, argAfterNode, &arguments, &commas, BfToken_RBracket, false); if (attributeDirective != NULL) { BfAttributedExpression* attribExpr = mAlloc->Alloc(); attribExpr->mAttributes = attributeDirective; MEMBER_SET(attribExpr, mExpression, indexerExpr); return attribExpr; } return indexerExpr; } BfMemberReferenceExpression* BfReducer::CreateMemberReferenceExpression(BfAstNode* target) { auto tokenNode = ExpectTokenAfter(target, BfToken_Dot, BfToken_DotDot, BfToken_QuestionDot); auto memberReferenceExpr = mAlloc->Alloc(); if (target != NULL) { memberReferenceExpr->mTarget = target; ReplaceNode(target, memberReferenceExpr); } MEMBER_SET_CHECKED(memberReferenceExpr, mDotToken, tokenNode); auto nextNode = mVisitorPos.GetNext(); if (auto literalExpr = BfNodeDynCast(nextNode)) { // Special case for "tuple.0" type references if (literalExpr->mValue.mTypeCode == BfTypeCode_IntUnknown) { MEMBER_SET(memberReferenceExpr, mMemberName, literalExpr); mVisitorPos.MoveNext(); return memberReferenceExpr; } } if (tokenNode = BfNodeDynCast(mVisitorPos.GetNext())) { if (tokenNode->GetToken() == BfToken_LBracket) { mVisitorPos.MoveNext(); auto attrIdentifier = CreateAttributedExpression(tokenNode, true); if (attrIdentifier != NULL) { MEMBER_SET(memberReferenceExpr, mMemberName, attrIdentifier); } } } if (memberReferenceExpr->mMemberName == NULL) { auto memberName = ExpectIdentifierAfter(memberReferenceExpr); if (memberName != NULL) { MEMBER_SET(memberReferenceExpr, mMemberName, memberName); } } return memberReferenceExpr; } BfTupleExpression* BfReducer::CreateTupleExpression(BfTokenNode* node, BfExpression* innerExpr) { auto tupleExpr = mAlloc->Alloc(); ReplaceNode(node, tupleExpr); tupleExpr->mOpenParen = node; BfDeferredAstSizedArray names(tupleExpr->mNames, mAlloc); BfDeferredAstSizedArray values(tupleExpr->mValues, mAlloc); BfDeferredAstSizedArray commas(tupleExpr->mCommas, mAlloc); while (true) { BfTokenNode* closeParenToken; if (innerExpr == NULL) { bool skipExpr = false; if (values.size() != 0) { if (auto nextToken = BfNodeDynCastExact(mVisitorPos.GetNext())) { if (nextToken->GetToken() == BfToken_RParen) { // Unterminated - default initialize skipExpr = true; } } } if (!skipExpr) innerExpr = CreateExpressionAfter(tupleExpr, CreateExprFlags_PermissiveVariableDecl); } if (innerExpr == NULL) { // Failed, but can we pull in the closing rparen? auto nextNode = mVisitorPos.GetNext(); if (closeParenToken = BfNodeDynCast(nextNode)) { if (closeParenToken->GetToken() == BfToken_RParen) { MEMBER_SET(tupleExpr, mCloseParen, closeParenToken); mVisitorPos.MoveNext(); } } break; } if (innerExpr->IsA()) closeParenToken = ExpectTokenAfter(innerExpr, BfToken_RParen, BfToken_Comma, BfToken_Colon); else closeParenToken = ExpectTokenAfter(innerExpr, BfToken_RParen, BfToken_Comma); if (closeParenToken == NULL) { values.push_back(innerExpr); MoveNode(innerExpr, tupleExpr); break; } //TODO: Why did we have this compat mode thing? It kept us from properly creating tuples with names if ((closeParenToken->GetToken() == BfToken_Colon) /*&& (!mCompatMode)*/) { BfTupleNameNode* tupleNameNode = mAlloc->Alloc(); ReplaceNode(innerExpr, tupleNameNode); tupleNameNode->mNameNode = (BfIdentifierNode*)innerExpr; MEMBER_SET(tupleNameNode, mColonToken, closeParenToken); while ((int)values.size() > names.size()) names.push_back(NULL); names.push_back(tupleNameNode); MoveNode(tupleNameNode, tupleExpr); innerExpr = CreateExpressionAfter(tupleExpr); if (innerExpr == NULL) break; closeParenToken = ExpectTokenAfter(innerExpr, BfToken_RParen, BfToken_Comma); } values.push_back(innerExpr); MoveNode(innerExpr, tupleExpr); innerExpr = NULL; if (closeParenToken == NULL) break; if (closeParenToken->GetToken() == BfToken_RParen) { MEMBER_SET(tupleExpr, mCloseParen, closeParenToken); break; } commas.push_back(closeParenToken); MoveNode(closeParenToken, tupleExpr); } return tupleExpr; } BfAstNode* BfReducer::HandleTopLevel(BfBlock* node) { SetAndRestoreValue prevVisitorPos(mVisitorPos, BfVisitorPos(node)); BfAstNode* prevNode = NULL; bool hadPrevFail = false; bool isDone = !mVisitorPos.MoveNext(); while (!isDone) { auto child = mVisitorPos.GetCurrent(); if (child == prevNode) { // If we're stuck on an error and can't process any more nodes break; } prevNode = child; auto tokenNode = BfNodeDynCast(child); if (tokenNode == NULL) { if (!hadPrevFail) Fail("Namespace or type declaration expected", child); hadPrevFail = true; isDone = !mVisitorPos.MoveNext(); mVisitorPos.Write(child); // Just keep it... continue; } auto newNode = CreateTopLevelObject(tokenNode, NULL); hadPrevFail = newNode == NULL; isDone = !mVisitorPos.MoveNext(); if (newNode != NULL) mVisitorPos.Write(newNode); } mVisitorPos.Trim(); return node; } BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDirective* attributes) { AssertCurrentNode(tokenNode); bool isSimpleEnum = false; if (tokenNode->GetToken() == BfToken_Enum) { int checkReadPos = mVisitorPos.mReadPos + 1; // Do we just have a value list with no members? auto nextNode = mVisitorPos.Get(checkReadPos); auto checkNode = nextNode; while (checkNode != NULL) { if (auto block = BfNodeDynCast(checkNode)) { SetAndRestoreValue prevVisitorPos(mVisitorPos, BfVisitorPos(block)); mVisitorPos.MoveNext(); BfAstNode* headNode = block->mChildArr.GetAs(0); if (auto nameNode = BfNodeDynCast(headNode)) { auto nextNode = mVisitorPos.Get(1); if (auto nextToken = BfNodeDynCast(nextNode)) { if ((nextToken->GetToken() == BfToken_Comma) || (nextToken->GetToken() == BfToken_AssignEquals)) isSimpleEnum = true; } if (nextNode == NULL) isSimpleEnum = true; } break; } checkReadPos++; auto nextCheckNode = mVisitorPos.Get(checkReadPos); checkNode = nextCheckNode; } } switch (tokenNode->GetToken()) { case BfToken_Using: { if (auto nextTokenNode = BfNodeDynCast(mVisitorPos.GetNext())) { if (nextTokenNode->mToken == BfToken_Static) { auto usingDirective = mAlloc->Alloc(); ReplaceNode(tokenNode, usingDirective); usingDirective->mUsingToken = tokenNode; MEMBER_SET(usingDirective, mStaticToken, nextTokenNode); mVisitorPos.MoveNext(); auto typeRef = CreateTypeRefAfter(usingDirective); if (typeRef != NULL) MEMBER_SET(usingDirective, mTypeRef, typeRef); tokenNode = ExpectTokenAfter(usingDirective, BfToken_Semicolon); if (tokenNode != NULL) MEMBER_SET(usingDirective, mTrailingSemicolon, tokenNode); mExteriorNodes.Add(usingDirective); return usingDirective; } } auto usingDirective = mAlloc->Alloc(); ReplaceNode(tokenNode, usingDirective); usingDirective->mUsingToken = tokenNode; auto identifierNode = ExpectIdentifierAfter(usingDirective); if (identifierNode != NULL) { identifierNode = CompactQualifiedName(identifierNode); MEMBER_SET(usingDirective, mNamespace, identifierNode); tokenNode = ExpectTokenAfter(usingDirective, BfToken_Semicolon); if (tokenNode == NULL) { // Failure, but eat any following dot for autocompletion purposes auto nextNode = mVisitorPos.GetNext(); if (tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_Dot) { auto qualifiedNameNode = mAlloc->Alloc(); ReplaceNode(usingDirective->mNamespace, qualifiedNameNode); qualifiedNameNode->mLeft = usingDirective->mNamespace; MEMBER_SET(qualifiedNameNode, mDot, tokenNode); usingDirective->mNamespace = qualifiedNameNode; usingDirective->SetSrcEnd(qualifiedNameNode->GetSrcEnd()); return usingDirective; } } } else if (tokenNode != NULL) { MEMBER_SET(usingDirective, mTrailingSemicolon, tokenNode); } } mExteriorNodes.Add(usingDirective); return usingDirective; } break; case BfToken_Namespace: { auto namespaceDeclaration = mAlloc->Alloc(); namespaceDeclaration->mNamespaceNode = tokenNode; auto identifierNode = ExpectIdentifierAfter(tokenNode); if (identifierNode == NULL) return namespaceDeclaration; identifierNode = CompactQualifiedName(identifierNode); namespaceDeclaration->mNameNode = identifierNode; ReplaceNode(tokenNode, namespaceDeclaration); MoveNode(identifierNode, namespaceDeclaration); auto blockNode = ExpectBlockAfter(namespaceDeclaration); if (blockNode == NULL) return namespaceDeclaration; MoveNode(blockNode, namespaceDeclaration); namespaceDeclaration->mBlock = blockNode; HandleTopLevel(namespaceDeclaration->mBlock); return namespaceDeclaration; } break; case BfToken_LBracket: { auto attributes = CreateAttributeDirective(tokenNode); if (attributes == NULL) return NULL; auto nextNode = mVisitorPos.GetNext(); auto nextToken = BfNodeDynCast(nextNode); if (nextToken == NULL) { FailAfter("Expected type declaration", tokenNode); return NULL; } mVisitorPos.MoveNext(); auto topLevelObject = CreateTopLevelObject(nextToken, attributes); if (topLevelObject == NULL) return NULL; auto typeDeclaration = BfNodeDynCast(topLevelObject); if (typeDeclaration == NULL) { Fail("Invalid type specifier", tokenNode); return NULL; } typeDeclaration->mAttributes = attributes; ReplaceNode(attributes, typeDeclaration); return typeDeclaration; } break; case BfToken_Sealed: case BfToken_Abstract: case BfToken_Concrete: case BfToken_Internal: case BfToken_Public: case BfToken_Private: case BfToken_Protected: case BfToken_Static: { auto nextNode = mVisitorPos.GetNext(); if ((tokenNode->GetToken() == BfToken_Static) && BfNodeIsA(nextNode)) { // It's a global block! auto typeDeclaration = mAlloc->Alloc(); ReplaceNode(tokenNode, typeDeclaration); typeDeclaration->mDocumentation = FindDocumentation(typeDeclaration); typeDeclaration->mStaticSpecifier = tokenNode; auto block = BfNodeDynCast(nextNode); MEMBER_SET(typeDeclaration, mDefineNode, block); mVisitorPos.MoveNext(); HandleTypeDeclaration(typeDeclaration, attributes); return typeDeclaration; } nextNode = mVisitorPos.GetNext(); auto nextToken = BfNodeDynCast(nextNode); if (nextToken == NULL) { AddErrorNode(tokenNode); FailAfter("Expected type declaration", tokenNode); return NULL; } mVisitorPos.MoveNext(); auto topLevelObject = CreateTopLevelObject(nextToken, attributes); if (topLevelObject == NULL) { AddErrorNode(tokenNode); return NULL; } auto typeDeclaration = BfNodeDynCast(topLevelObject); if (typeDeclaration == NULL) { AddErrorNode(tokenNode); Fail("Invalid type specifier", tokenNode); return NULL; } ReplaceNode(tokenNode, typeDeclaration); BfToken token = tokenNode->GetToken(); if ((token == BfToken_Public) || (token == BfToken_Protected) || (token == BfToken_Private)) { if (typeDeclaration->mProtectionSpecifier != NULL) { Fail("Protection already specified", tokenNode); } MEMBER_SET(typeDeclaration, mProtectionSpecifier, tokenNode); } if (token == BfToken_Internal) { if (typeDeclaration->mInternalSpecifier != NULL) { Fail("Internal already specified", typeDeclaration->mInternalSpecifier); } MEMBER_SET(typeDeclaration, mInternalSpecifier, tokenNode); } if (token == BfToken_Static) { if (typeDeclaration->mStaticSpecifier != NULL) { Fail("Static already specified", tokenNode); } MEMBER_SET(typeDeclaration, mStaticSpecifier, tokenNode); } if (token == BfToken_Sealed) { if (typeDeclaration->mSealedSpecifier != NULL) { Fail("Sealed already specified", tokenNode); } MEMBER_SET(typeDeclaration, mSealedSpecifier, tokenNode); } if ((token == BfToken_Abstract) || (token == BfToken_Concrete)) { if (typeDeclaration->mAbstractSpecifier != NULL) { Fail(StrFormat("'%s' already specified", typeDeclaration->mAbstractSpecifier->ToString().c_str()), tokenNode); } MEMBER_SET(typeDeclaration, mAbstractSpecifier, tokenNode); } //TODO: Store type specifiers return typeDeclaration; } break; case BfToken_Delegate: case BfToken_Function: { auto typeDeclaration = mAlloc->Alloc(); SetAndRestoreValue prevTypeDecl(mCurTypeDecl, typeDeclaration); ReplaceNode(tokenNode, typeDeclaration); typeDeclaration->mDocumentation = FindDocumentation(typeDeclaration); typeDeclaration->mTypeNode = tokenNode; auto retType = CreateTypeRefAfter(typeDeclaration); if (retType == NULL) return typeDeclaration; auto methodDecl = mAlloc->Alloc(); MEMBER_SET(methodDecl, mReturnType, retType); BfDeferredAstSizedArray params(methodDecl->mParams, mAlloc); BfDeferredAstSizedArray commas(methodDecl->mCommas, mAlloc); methodDecl->mDocumentation = FindDocumentation(methodDecl); BfBlock* defineBlock = mAlloc->Alloc(); MoveNode(defineBlock, typeDeclaration); BfDeferredAstSizedArray members(defineBlock->mChildArr, mAlloc); members.push_back(methodDecl); MoveNode(methodDecl, typeDeclaration); typeDeclaration->mDefineNode = defineBlock; auto name = ExpectIdentifierAfter(retType); if (name == NULL) { ReplaceNode(retType, methodDecl); return typeDeclaration; } ReplaceNode(name, methodDecl); MEMBER_SET_CHECKED(typeDeclaration, mNameNode, name); auto nextNode = mVisitorPos.GetNext(); if (tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_LChevron) { auto genericParams = CreateGenericParamsDeclaration(tokenNode); MEMBER_SET_CHECKED(typeDeclaration, mGenericParams, genericParams); methodDecl->SetSrcEnd(genericParams->GetSrcEnd()); } } if (!ParseMethod(methodDecl, ¶ms, &commas)) return typeDeclaration; if (methodDecl->mEndSemicolon == NULL) FailAfter("Expected ';'", methodDecl->mCloseParen); //MEMBER_SET(methodDecl, mReturnType, retType); return typeDeclaration; } break; case BfToken_TypeAlias: { auto identifierNode = ExpectIdentifierAfter(tokenNode); if (identifierNode == NULL) return NULL; auto typeDeclaration = mAlloc->Alloc(); BfDeferredAstSizedArray baseClasses(typeDeclaration->mBaseClasses, mAlloc); BfDeferredAstSizedArray baseClassCommas(typeDeclaration->mBaseClassCommas, mAlloc); mLastTypeDecl = typeDeclaration; typeDeclaration->mTypeNode = tokenNode; typeDeclaration->mNameNode = identifierNode; ReplaceNode(tokenNode, typeDeclaration); MoveNode(identifierNode, typeDeclaration); typeDeclaration->mDocumentation = FindDocumentation(typeDeclaration); auto nextNode = mVisitorPos.GetNext(); auto chevronToken = BfNodeDynCast(nextNode); if ((chevronToken != NULL) && (chevronToken->GetToken() == BfToken_LChevron)) { auto genericMethodParams = CreateGenericParamsDeclaration(chevronToken); if (genericMethodParams != NULL) { MEMBER_SET(typeDeclaration, mGenericParams, genericMethodParams); } } auto tokenNode = ExpectTokenAfter(typeDeclaration, BfToken_AssignEquals); if (tokenNode != NULL) { MEMBER_SET(typeDeclaration, mEqualsToken, tokenNode); auto aliasToType = CreateTypeRefAfter(typeDeclaration); if (aliasToType != NULL) { MEMBER_SET(typeDeclaration, mAliasToType, aliasToType); auto tokenNode = ExpectTokenAfter(typeDeclaration, BfToken_Semicolon); if (tokenNode != NULL) MEMBER_SET(typeDeclaration, mEndSemicolon, tokenNode); } } if (!IsNodeRelevant(typeDeclaration)) typeDeclaration->mIgnoreDeclaration = true; return typeDeclaration; } break; case BfToken_Class: case BfToken_Struct: case BfToken_Interface: case BfToken_Enum: case BfToken_Extension: { if ((tokenNode->GetToken() == BfToken_Enum) && (isSimpleEnum)) break; auto identifierNode = ExpectIdentifierAfter(tokenNode); if (identifierNode == NULL) { AddErrorNode(tokenNode); return NULL; } // We put extra effort in here to continue after failure, since 'return NULL' failure // means we don't parse members inside type (messes up colorization and such) auto typeDeclaration = mAlloc->Alloc(); BfDeferredAstSizedArray baseClasses(typeDeclaration->mBaseClasses, mAlloc); BfDeferredAstSizedArray baseClassCommas(typeDeclaration->mBaseClassCommas, mAlloc); mLastTypeDecl = typeDeclaration; typeDeclaration->mTypeNode = tokenNode; typeDeclaration->mNameNode = identifierNode; ReplaceNode(tokenNode, typeDeclaration); MoveNode(identifierNode, typeDeclaration); typeDeclaration->mDocumentation = FindDocumentation(typeDeclaration); auto nextNode = mVisitorPos.GetNext(); auto chevronToken = BfNodeDynCast(nextNode); if ((chevronToken != NULL) && (chevronToken->GetToken() == BfToken_LChevron)) { auto genericMethodParams = CreateGenericParamsDeclaration(chevronToken); if (genericMethodParams != NULL) { MEMBER_SET(typeDeclaration, mGenericParams, genericMethodParams); } } nextNode = mVisitorPos.GetNext(); auto tokenNode = BfNodeDynCast(nextNode); if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_Colon)) { MEMBER_SET(typeDeclaration, mColonToken, tokenNode); mVisitorPos.MoveNext(); tokenNode = NULL; for (int baseTypeIdx = 0; true; baseTypeIdx++) { nextNode = mVisitorPos.GetNext(); if ((baseTypeIdx > 0) && (BfNodeDynCast(nextNode))) break; if (baseTypeIdx > 0) { BfTokenNode* commaToken = NULL; if (typeDeclaration->mGenericParams != NULL) { commaToken = ExpectTokenAfter(typeDeclaration, BfToken_Comma, BfToken_Where); if ((commaToken != NULL) && (commaToken->GetToken() == BfToken_Where)) { mVisitorPos.mReadPos--; break; } } else commaToken = ExpectTokenAfter(typeDeclaration, BfToken_Comma); if (commaToken == NULL) break; MoveNode(commaToken, typeDeclaration); baseClassCommas.push_back(commaToken); } auto baseType = CreateTypeRefAfter(typeDeclaration); if (baseType == NULL) break; MoveNode(baseType, typeDeclaration); baseClasses.push_back(baseType); } nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); } if (tokenNode != NULL) { if (tokenNode->GetToken() == BfToken_Where) { mVisitorPos.MoveNext(); auto constraints = CreateGenericConstraintsDeclaration(tokenNode); if (constraints != NULL) { MEMBER_SET(typeDeclaration, mGenericConstraintsDeclaration, constraints); } } if (tokenNode->GetToken() == BfToken_Semicolon) { typeDeclaration->mDefineNode = tokenNode; MoveNode(tokenNode, typeDeclaration); mVisitorPos.MoveNext(); return typeDeclaration; } } auto blockNode = ExpectBlockAfter(typeDeclaration); if (blockNode != NULL) { typeDeclaration->mDefineNode = blockNode; MoveNode(blockNode, typeDeclaration); HandleTypeDeclaration(typeDeclaration, attributes); } return typeDeclaration; } break; } if (isSimpleEnum) { auto identifierNode = ExpectIdentifierAfter(tokenNode, "enum name"); if (identifierNode == NULL) return NULL; // We put extra effort in here to continue after failure, since 'return NULL' failure // means we don't parse members inside type (messes up colorization and such) auto typeDeclaration = mAlloc->Alloc(); BfDeferredAstSizedArray baseClasses(typeDeclaration->mBaseClasses, mAlloc); auto prevTypeDecl = mCurTypeDecl; mCurTypeDecl = typeDeclaration; typeDeclaration->mTypeNode = tokenNode; typeDeclaration->mNameNode = identifierNode; ReplaceNode(tokenNode, typeDeclaration); MoveNode(identifierNode, typeDeclaration); typeDeclaration->mDocumentation = FindDocumentation(typeDeclaration); auto nextNode = mVisitorPos.GetNext(); auto tokenNode = BfNodeDynCast(nextNode); if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_Colon)) { MEMBER_SET(typeDeclaration, mColonToken, tokenNode); mVisitorPos.MoveNext(); tokenNode = NULL; auto baseType = CreateTypeRefAfter(typeDeclaration); if (baseType == NULL) return NULL; MoveNode(baseType, typeDeclaration); baseClasses.push_back(baseType); } auto blockNode = ExpectBlockAfter(typeDeclaration); if (blockNode != NULL) { SetAndRestoreValue prevVisitorPos(mVisitorPos, BfVisitorPos(blockNode)); mVisitorPos.MoveNext(); for (int fieldNum = 0; true; fieldNum++) { BfAstNode* child = mVisitorPos.GetCurrent(); if (child == NULL) break; if (fieldNum > 0) { auto commaToken = BfNodeDynCast(child); if ((commaToken == NULL) || (commaToken->GetToken() != BfToken_Comma)) { Fail("Comma expected", child); break; } MoveNode(commaToken, mCurTypeDecl); mVisitorPos.MoveNext(); mVisitorPos.Write(commaToken); child = mVisitorPos.GetCurrent(); } if (child == NULL) break; auto fieldDecl = mAlloc->Alloc(); mVisitorPos.MoveNext(); mVisitorPos.Write(fieldDecl); ReplaceNode(child, fieldDecl); auto valueName = BfNodeDynCast(child); if (valueName == NULL) { Fail("Enum value name expected", child); break; } MEMBER_SET(fieldDecl, mNameNode, valueName); auto nextNode = mVisitorPos.GetCurrent(); if (auto equalsToken = BfNodeDynCast(nextNode)) { if (equalsToken->GetToken() == BfToken_AssignEquals) { MEMBER_SET(fieldDecl, mEqualsNode, equalsToken); fieldDecl->mInitializer = CreateExpressionAfter(fieldDecl); if (fieldDecl->mInitializer != NULL) { mVisitorPos.MoveNext(); MoveNode(fieldDecl->mInitializer, fieldDecl); } } } fieldDecl->mDocumentation = FindDocumentation(fieldDecl, NULL, true); MoveNode(fieldDecl, mCurTypeDecl); } mVisitorPos.Trim(); } typeDeclaration->mDefineNode = blockNode; if (blockNode != NULL) { MoveNode(blockNode, typeDeclaration); } mCurTypeDecl = prevTypeDecl; return typeDeclaration; } Fail("Unexpected token", tokenNode); return NULL; } BfTokenNode* BfReducer::ExpectTokenAfter(BfAstNode* node, BfToken token) { AssertCurrentNode(node); auto nextNode = mVisitorPos.GetNext(); auto tokenNode = BfNodeDynCast(nextNode); if ((tokenNode == NULL) || (tokenNode->GetToken() != token)) { FailAfter(StrFormat("Expected '%s'", BfTokenToString(token)), node); return NULL; } mVisitorPos.MoveNext(); return tokenNode; } BfTokenNode* BfReducer::ExpectTokenAfter(BfAstNode* node, BfToken tokenA, BfToken tokenB) { AssertCurrentNode(node); auto nextNode = mVisitorPos.GetNext(); auto tokenNode = BfNodeDynCast(nextNode); if ((tokenNode == NULL) || ((tokenNode->GetToken() != tokenA) && (tokenNode->GetToken() != tokenB))) { FailAfter(StrFormat("Expected '%s' or '%s'", BfTokenToString(tokenA), BfTokenToString(tokenB)), node); return NULL; } mVisitorPos.MoveNext(); return tokenNode; } BfTokenNode* BfReducer::ExpectTokenAfter(BfAstNode* node, BfToken tokenA, BfToken tokenB, BfToken tokenC) { AssertCurrentNode(node); auto nextNode = mVisitorPos.GetNext(); auto tokenNode = BfNodeDynCast(nextNode); BfToken token = BfToken_Null; if (tokenNode != NULL) token = tokenNode->GetToken(); if ((tokenNode == NULL) || ((token != tokenA) && (token != tokenB) && (token != tokenC))) { FailAfter(StrFormat("Expected '%s', '%s', or '%s'", BfTokenToString(tokenA), BfTokenToString(tokenB), BfTokenToString(tokenC)), node); return NULL; } mVisitorPos.MoveNext(); return tokenNode; } BfTokenNode* BfReducer::ExpectTokenAfter(BfAstNode* node, BfToken tokenA, BfToken tokenB, BfToken tokenC, BfToken tokenD) { AssertCurrentNode(node); auto nextNode = mVisitorPos.GetNext(); auto tokenNode = BfNodeDynCast(nextNode); BfToken token = BfToken_Null; if (tokenNode != NULL) token = tokenNode->GetToken(); if ((tokenNode == NULL) || ((token != tokenA) && (token != tokenB) && (token != tokenC) && (token != tokenD))) { FailAfter(StrFormat("Expected '%s', '%s', '%s', or '%s'", BfTokenToString(tokenA), BfTokenToString(tokenB), BfTokenToString(tokenC), BfTokenToString(tokenD)), node); return NULL; } mVisitorPos.MoveNext(); return tokenNode; } BfIdentifierNode* BfReducer::ExpectIdentifierAfter(BfAstNode* node, const char* typeName) { AssertCurrentNode(node); auto nextNode = mVisitorPos.GetNext(); auto identifierNode = BfNodeDynCast(nextNode); if (identifierNode == NULL) { if (typeName != NULL) FailAfter(StrFormat("Expected %s", typeName), node); else FailAfter("Expected identifier", node); return NULL; } mVisitorPos.MoveNext(); return identifierNode; } BfBlock* BfReducer::ExpectBlockAfter(BfAstNode* node) { AssertCurrentNode(node); auto nextNode = mVisitorPos.GetNext(); auto block = BfNodeDynCast(nextNode); if (block == NULL) { FailAfter("Block expected", node); return NULL; } mVisitorPos.MoveNext(); return block; } BfTokenNode* BfReducer::BreakDoubleChevron(BfTokenNode* tokenNode) { // Break up those chevrons auto firstChevron = mAlloc->Alloc(); firstChevron->SetToken(BfToken_RChevron); int triviaStart; int srcStart; int srcEnd; tokenNode->GetSrcPositions(triviaStart, srcStart, srcEnd); firstChevron->Init(triviaStart, srcStart, srcEnd - 1); tokenNode->SetToken(BfToken_RChevron); tokenNode->SetSrcStart(srcStart + 1); tokenNode->SetTriviaStart(srcStart); return firstChevron; } BfTokenNode* BfReducer::BreakQuestionLBracket(BfTokenNode* tokenNode) { // Break up those chevrons auto firstToken = mAlloc->Alloc(); firstToken->SetToken(BfToken_Question); int triviaStart; int srcStart; int srcEnd; tokenNode->GetSrcPositions(triviaStart, srcStart, srcEnd); firstToken->Init(triviaStart, srcStart, srcEnd - 1); tokenNode->SetToken(BfToken_LBracket); tokenNode->SetSrcStart(srcStart + 1); tokenNode->SetTriviaStart(srcStart); return firstToken; } BfCommentNode * BfReducer::FindDocumentation(BfAstNode* defNodeHead, BfAstNode* defNodeEnd, bool checkDocAfter) { if (defNodeEnd == NULL) defNodeEnd = defNodeHead; else if (defNodeHead == NULL) defNodeHead = defNodeEnd; while (mDocumentCheckIdx < mSource->mSidechannelRootNode->mChildArr.mSize) { auto checkComment = BfNodeDynCast(mSource->mSidechannelRootNode->mChildArr[mDocumentCheckIdx]); if ((checkComment == NULL) || (checkComment->mCommentKind == BfCommentKind_Normal)) { mDocumentCheckIdx++; continue; } if (checkComment->GetSrcEnd() > defNodeEnd->GetSrcStart()) { if (checkComment->mCommentKind == BfCommentKind_Documentation_Post) { int defEnd = defNodeEnd->GetSrcEnd(); if (checkDocAfter) { int endDiff = defEnd - checkComment->GetSrcStart(); if (endDiff > 256) return NULL; for (int idx = defEnd; idx < checkComment->GetSrcStart(); idx++) { char c = mSource->mSrc[idx]; if (idx == defEnd) { if ((c == ';') || (c == ',')) continue; } if (c == '\n') return NULL; // No newline allowed if (!isspace((uint8)c)) return NULL; } mDocumentCheckIdx++; return checkComment; } } return NULL; } if (checkComment->mCommentKind != BfCommentKind_Documentation_Pre) { // Skip this, not used mDocumentCheckIdx++; continue; } if (mDocumentCheckIdx < mSource->mSidechannelRootNode->mChildArr.mSize - 1) { auto nextComment = mSource->mSidechannelRootNode->mChildArr[mDocumentCheckIdx + 1]; if (nextComment->GetSrcEnd() <= defNodeHead->GetSrcStart()) { // This comment is still before the node in question mDocumentCheckIdx++; continue; } } mDocumentCheckIdx++; int defSrcIdx = defNodeHead->GetSrcStart(); for (int idx = checkComment->GetSrcEnd(); idx < defSrcIdx; idx++) { char c = mSource->mSrc[idx]; if (!isspace((uint8)c)) return NULL; } return checkComment; } return NULL; } BfTokenNode* BfReducer::ParseMethodParams(BfAstNode* node, SizedArrayImpl* params, SizedArrayImpl* commas, BfToken endToken) { BfAstNode* nameAfterNode = node; BfAttributeDirective* attributes = NULL; for (int paramIdx = 0; true; paramIdx++) { auto nextNode = ReplaceTokenStarter(mVisitorPos.GetNext(), mVisitorPos.mReadPos + 1); auto tokenNode = BfNodeDynCast(nextNode); if (tokenNode != NULL) { BfToken token = tokenNode->GetToken(); if ((paramIdx > 0) && (token == BfToken_AssignEquals)) { auto paramDecl = params->back(); MEMBER_SET(paramDecl, mEqualsNode, tokenNode); paramDecl->mEqualsNode = tokenNode; mVisitorPos.MoveNext(); mSkipCurrentNodeAssert = true; auto initExpr = CreateExpressionAfter(node); mSkipCurrentNodeAssert = false; if (initExpr == NULL) return NULL; MEMBER_SET(paramDecl, mInitializer, initExpr); auto nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); if (tokenNode == NULL) return NULL; token = tokenNode->GetToken(); } if (token == endToken) return tokenNode; if ((paramIdx == 0) && ( (token == BfToken_Out) || (token == BfToken_Ref) || (token == BfToken_Mut) || (token == BfToken_Delegate) || (token == BfToken_Function) || (token == BfToken_Params) || (token == BfToken_LParen) || (token == BfToken_Var) || (token == BfToken_LBracket))) { // These get picked up below } else { if ((paramIdx == 0) || (token != BfToken_Comma)) { Fail("Expected ')' or parameter list", tokenNode); return NULL; } if (paramIdx > 0) commas->push_back(tokenNode); MoveNode(tokenNode, node); mVisitorPos.MoveNext(); } nameAfterNode = tokenNode; } else { if (paramIdx > 0) { FailAfter("Expected ')' or additional parameters", nameAfterNode); return NULL; } } attributes = NULL; BfTokenNode* modTokenNode = NULL; nextNode = ReplaceTokenStarter(mVisitorPos.GetNext(), mVisitorPos.mReadPos + 1); tokenNode = BfNodeDynCast(nextNode); BfTypeReference* typeRef = NULL; if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_LBracket)) { mVisitorPos.MoveNext(); attributes = CreateAttributeDirective(tokenNode); if (attributes != NULL) { nameAfterNode = attributes; auto nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); } } int paramStartReadPos = mVisitorPos.mReadPos; bool isParams = false; if (tokenNode != NULL) { BfToken token = tokenNode->GetToken(); if ((token == BfToken_Var) || (token == BfToken_LParen) || (token == BfToken_Delegate) || (token == BfToken_Function)) { mVisitorPos.MoveNext(); typeRef = CreateTypeRef(tokenNode); } else { if ((token != BfToken_Out) && (token != BfToken_Ref) && (token != BfToken_Mut) && (token != BfToken_Params)) { Fail("Invalid token", tokenNode); return NULL; } if (token == BfToken_Params) isParams = true; modTokenNode = tokenNode; nameAfterNode = modTokenNode; mVisitorPos.MoveNext(); } } if (typeRef == NULL) { auto typeIdentifierNode = ExpectIdentifierAfter(nameAfterNode, "parameter type"); if (typeIdentifierNode == NULL) { mVisitorPos.mReadPos = paramStartReadPos; break; } typeRef = CreateTypeRef(typeIdentifierNode); if (typeRef == NULL) { mVisitorPos.mReadPos = paramStartReadPos; break; } } BfToken modToken = BfToken_None; if (modTokenNode != NULL) modToken = modTokenNode->GetToken(); if ((modTokenNode != NULL) && ((modToken == BfToken_Ref) || (modToken == BfToken_Mut) || (modToken == BfToken_Out))) { typeRef = CreateRefTypeRef(typeRef, modTokenNode); modTokenNode = NULL; } auto paramDecl = mAlloc->Alloc(); ReplaceNode(typeRef, paramDecl); MoveNode(paramDecl, node); params->push_back(paramDecl); MEMBER_SET(paramDecl, mTypeRef, typeRef); if (attributes != NULL) { MEMBER_SET(paramDecl, mAttributes, attributes); attributes = NULL; } if (modTokenNode != NULL) { MEMBER_SET(paramDecl, mModToken, modTokenNode); } bool allowNameFail = false; bool nextIsName = false; auto afterNameTokenNode = BfNodeDynCast(mVisitorPos.Get(mVisitorPos.mReadPos + 2)); if (afterNameTokenNode != NULL) { BfToken afterNameToken = afterNameTokenNode->GetToken(); if ((afterNameToken == BfToken_Comma) || (afterNameToken == BfToken_AssignEquals) || (afterNameToken == BfToken_RParen)) { nextIsName = true; } } // We definitely have a failure, but we want to attempt to scan to the actual param name if we can... if (!nextIsName) { int nameIdx = -1; int checkIdx = mVisitorPos.mReadPos + 1; bool useNameIdx = true; int parenDepth = 1; int bracketDepth = 0; while (true) { auto checkNode = mVisitorPos.Get(checkIdx); auto checkTokenNode = BfNodeDynCast(checkNode); if (checkTokenNode != NULL) { BfToken checkToken = checkTokenNode->GetToken(); if (nameIdx == -1) { if ((parenDepth == 1) && (bracketDepth == 0)) { if ((checkToken == BfToken_Comma) || (checkToken == BfToken_AssignEquals) || (checkToken == BfToken_RParen)) { if (auto nameIdentifier = BfNodeDynCast(mVisitorPos.Get(checkIdx - 1))) { nameIdx = checkIdx - 1; } else { useNameIdx = false; break; } } } } if (checkToken == BfToken_RParen) parenDepth--; else if (checkToken == BfToken_LParen) parenDepth++; else if (checkToken == BfToken_LBracket) bracketDepth++; else if (checkToken == BfToken_RBracket) bracketDepth--; if (parenDepth == 0) { if (bracketDepth != 0) useNameIdx = false; break; } if (checkToken == BfToken_Semicolon) { useNameIdx = false; break; } } else if (auto identifier = BfNodeDynCast(checkNode)) { // Okay } else { // Nothing else is okay useNameIdx = false; break; } checkIdx++; } if ((useNameIdx) && (nameIdx != -1)) { if (nameIdx <= mVisitorPos.mReadPos) { // We have a valid-enough param list but a missing name, so keep going allowNameFail = true; } else { for (int errIdx = mVisitorPos.mReadPos + 1; errIdx < nameIdx; errIdx++) { auto node = mVisitorPos.Get(errIdx); if (auto token = BfNodeDynCast(node)) mPassInstance->Fail("Unexpected token", node); else mPassInstance->Fail("Unexpected identifier", node); AddErrorNode(node); } auto nameIdentifierNode = BfNodeDynCast(mVisitorPos.Get(nameIdx)); paramDecl->mNameNode = nameIdentifierNode; MoveNode(nameIdentifierNode, paramDecl); nameAfterNode = nameIdentifierNode; mVisitorPos.mReadPos = nameIdx; continue; //mVisitorPos.mReadPos = nameIdx - 1; } } } if (auto nameToken = BfNodeDynCast(mVisitorPos.GetNext())) { if ((nameToken->GetToken() == BfToken_This)) { bool isDelegate = false; bool isFunction = false; if (auto delegateTypeRef = BfNodeDynCast(node)) { if (delegateTypeRef->mTypeToken->GetToken() == BfToken_Function) isFunction = true; else isDelegate = true; } else if (mCurTypeDecl->mTypeNode->GetToken() == BfToken_Function) isFunction = true; else if (mCurTypeDecl->mTypeNode->GetToken() == BfToken_Delegate) isDelegate = true; if (isFunction || isDelegate) { if (paramIdx != 0) Fail("'this' can only be used as the first parameter", nameToken); if (!isFunction) Fail("'this' can only be specified on function types", nameToken); mVisitorPos.MoveNext(); paramDecl->mNameNode = nameToken; MoveNode(nameToken, paramDecl); nameAfterNode = nameToken; } } } if (paramDecl->mNameNode == NULL) { auto nameIdentifierNode = ExpectIdentifierAfter(node, "parameter name"); if (nameIdentifierNode == NULL) { if (!allowNameFail) return NULL; } else { paramDecl->mNameNode = nameIdentifierNode; MoveNode(nameIdentifierNode, paramDecl); nameAfterNode = nameIdentifierNode; } } } if (attributes != NULL) { Fail("Unexpected attributes", attributes); AddErrorNode(attributes); } return NULL; } bool BfReducer::ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayImpl* params, SizedArrayImpl* commas, bool alwaysIncludeBlock) { auto tokenNode = ExpectTokenAfter(methodDeclaration, BfToken_LParen, BfToken_Bang); if (tokenNode == NULL) return false; if (tokenNode->GetToken() == BfToken_Bang) { Fail("Cannot include '!' in the method declaration", tokenNode); MoveNode(tokenNode, methodDeclaration); tokenNode = ExpectTokenAfter(methodDeclaration, BfToken_LParen); if (tokenNode == NULL) return false; } methodDeclaration->mOpenParen = tokenNode; MoveNode(methodDeclaration->mOpenParen, methodDeclaration); methodDeclaration->mCloseParen = ParseMethodParams(methodDeclaration, params, commas, BfToken_RParen); // RParen if (methodDeclaration->mCloseParen == NULL) { auto nextNode = mVisitorPos.GetNext(); while (auto checkToken = BfNodeDynCast(nextNode)) { if (checkToken->GetToken() == BfToken_RParen) { methodDeclaration->mCloseParen = checkToken; break; } else { // Just eat it - for autocompletion. This helps make cases nicer where we're typing in the "in" for "int", for example MoveNode(checkToken, methodDeclaration); AddErrorNode(checkToken); mVisitorPos.MoveNext(); nextNode = mVisitorPos.GetNext(); } } if (methodDeclaration->mCloseParen == NULL) return false; } MoveNode(methodDeclaration->mCloseParen, methodDeclaration); mVisitorPos.MoveNext(); auto typeDecl = mCurTypeDecl; auto nextNode = mVisitorPos.GetNext(); if (tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_Mut) { if (methodDeclaration->mMutSpecifier != NULL) { AddErrorNode(methodDeclaration->mMutSpecifier); Fail("Mut already specified", methodDeclaration->mMutSpecifier); } MEMBER_SET(methodDeclaration, mMutSpecifier, tokenNode); mVisitorPos.MoveNext(); nextNode = mVisitorPos.GetNext(); } } if (tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_Where) { mVisitorPos.MoveNext(); auto genericConstraints = CreateGenericConstraintsDeclaration(tokenNode); MEMBER_SET_CHECKED_BOOL(methodDeclaration, mGenericConstraintsDeclaration, genericConstraints); } } auto ctorDecl = BfNodeDynCast(methodDeclaration); nextNode = mVisitorPos.GetNext(); auto endToken = BfNodeDynCast(nextNode); if ((endToken != NULL) && (endToken->GetToken() == BfToken_Colon)) { if (auto ctorDecl = BfNodeDynCast(methodDeclaration)) { MEMBER_SET(ctorDecl, mInitializerColonToken, endToken); mVisitorPos.MoveNext(); auto nextNode = mVisitorPos.GetNext(); endToken = ExpectTokenAfter(ctorDecl, BfToken_This, BfToken_Base); if (endToken != NULL) { auto invocationExpr = CreateInvocationExpression(endToken); if (invocationExpr != NULL) { MEMBER_SET(ctorDecl, mInitializer, invocationExpr); } } else if (auto identifierAfter = BfNodeDynCast(nextNode)) { // In process of typing - just eat identifier so we don't error out on whole method MoveNode(identifierAfter, ctorDecl); } } endToken = NULL; } if ((endToken != NULL) && (endToken->GetToken() == BfToken_Semicolon)) { MEMBER_SET_CHECKED_BOOL(methodDeclaration, mEndSemicolon, endToken); mVisitorPos.MoveNext(); } else { nextNode = mVisitorPos.GetNext(); auto blockNode = BfNodeDynCast(nextNode); if (blockNode != NULL) { methodDeclaration->mBody = blockNode; MoveNode(blockNode, methodDeclaration); mVisitorPos.MoveNext(); if ((IsNodeRelevant(methodDeclaration)) || (alwaysIncludeBlock)) { SetAndRestoreValue prevMethodDeclaration(mCurMethodDecl, methodDeclaration); HandleBlock(blockNode, methodDeclaration->mMixinSpecifier != NULL); } return true; } else { nextNode = mVisitorPos.GetNext(); auto tokenNode = BfNodeDynCast(nextNode); if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_FatArrow)) { MEMBER_SET(methodDeclaration, mFatArrowToken, tokenNode); mVisitorPos.MoveNext(); auto methodExpression = CreateExpressionAfter(methodDeclaration); MEMBER_SET_CHECKED_BOOL(methodDeclaration, mBody, methodExpression); auto semicolonToken = ExpectTokenAfter(methodDeclaration, BfToken_Semicolon); MEMBER_SET_CHECKED_BOOL(methodDeclaration, mEndSemicolon, semicolonToken); return true; } } FailAfter("Expected method body", methodDeclaration); } return true; } BfGenericArgumentsNode* BfReducer::CreateGenericArguments(BfTokenNode* tokenNode) { auto genericArgs = mAlloc->Alloc(); BfDeferredAstSizedArray genericArgsArray(genericArgs->mGenericArgs, mAlloc); BfDeferredAstSizedArray commas(genericArgs->mCommas, mAlloc); ReplaceNode(tokenNode, genericArgs); genericArgs->mOpenChevron = tokenNode; while (true) { auto genericArg = CreateTypeRefAfter(genericArgs); if (genericArg == NULL) { genericArgsArray.push_back(NULL); // Leave empty for purposes of generic argument count auto nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); if (tokenNode != NULL) { // Try to get right chevron. Reduces error count when we're typing out a generic argument list if (tokenNode->GetToken() == BfToken_RDblChevron) tokenNode = BreakDoubleChevron(tokenNode); if (tokenNode->GetToken() == BfToken_RChevron) { MoveNode(tokenNode, genericArgs); genericArgs->mCloseChevron = tokenNode; mVisitorPos.MoveNext(); } } return genericArgs; } MoveNode(genericArg, genericArgs); genericArgsArray.push_back(genericArg); auto nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); if (tokenNode == NULL) { FailAfter("Expected ',' or '>'", genericArgs); return genericArgs; } BfToken token = tokenNode->GetToken(); if (token == BfToken_RDblChevron) tokenNode = BreakDoubleChevron(tokenNode); if (token == BfToken_RChevron) { MoveNode(tokenNode, genericArgs); genericArgs->mCloseChevron = tokenNode; mVisitorPos.MoveNext(); break; } if (token != BfToken_Comma) { Fail("Either , or > expected", tokenNode); return genericArgs; } MoveNode(tokenNode, genericArgs); commas.push_back(tokenNode); mVisitorPos.MoveNext(); } return genericArgs; } BfGenericParamsDeclaration* BfReducer::CreateGenericParamsDeclaration(BfTokenNode* tokenNode) { auto genericParams = mAlloc->Alloc(); BfDeferredAstSizedArray genericParamsArr(genericParams->mGenericParams, mAlloc); BfDeferredAstSizedArray commas(genericParams->mCommas, mAlloc); ReplaceNode(tokenNode, genericParams); genericParams->mOpenChevron = tokenNode; mVisitorPos.MoveNext(); while (true) { auto genericIdentifier = ExpectIdentifierAfter(genericParams, "generic parameters"); if (genericIdentifier == NULL) return genericParams; MoveNode(genericIdentifier, genericParams); genericParamsArr.push_back(genericIdentifier); auto nextNode = mVisitorPos.GetNext(); tokenNode = BfNodeDynCast(nextNode); if (tokenNode == NULL) { FailAfter("Expected ',' or '>'", genericParams); return genericParams; } BfToken token = tokenNode->GetToken(); if (token == BfToken_RDblChevron) tokenNode = BreakDoubleChevron(tokenNode); MoveNode(tokenNode, genericParams); mVisitorPos.MoveNext(); if (token == BfToken_RChevron) { genericParams->mCloseChevron = tokenNode; break; } if (token != BfToken_Comma) { Fail("Either , or > expected", tokenNode); return genericParams; } commas.push_back(tokenNode); } return genericParams; } BfGenericConstraintsDeclaration* BfReducer::CreateGenericConstraintsDeclaration(BfTokenNode* tokenNode) { auto constraintsDeclaration = mAlloc->Alloc(); BfDeferredAstSizedArray genericConstraintsArr(constraintsDeclaration->mGenericConstraints, mAlloc); bool isDone = false; for (int constraintIdx = 0; !isDone; constraintIdx++) { BfGenericConstraint* genericConstraint = mAlloc->Alloc(); BfDeferredAstSizedArray constraintTypes(genericConstraint->mConstraintTypes, mAlloc); BfDeferredAstSizedArray commas(genericConstraint->mCommas, mAlloc); ReplaceNode(tokenNode, genericConstraint); genericConstraint->mWhereToken = tokenNode; genericConstraintsArr.push_back(genericConstraint); auto genericParamName = ExpectIdentifierAfter(genericConstraint, "generic parameter name"); if (genericParamName != NULL) { MEMBER_SET(genericConstraint, mGenericParamName, genericParamName); tokenNode = ExpectTokenAfter(genericConstraint, BfToken_Colon); } else isDone = true; if (tokenNode != NULL) { MEMBER_SET(genericConstraint, mColonToken, tokenNode); } else isDone = true; for (int typeIdx = 0; !isDone; typeIdx++) { if (typeIdx > 0) { auto nextNode = mVisitorPos.GetNext(); if (BfNodeDynCast(nextNode)) { isDone = true; break; } tokenNode = ExpectTokenAfter(genericConstraint, BfToken_Comma, BfToken_LBrace, BfToken_Where, BfToken_Semicolon); if (tokenNode == NULL) { isDone = true; break; } BfToken token = tokenNode->GetToken(); if (token == BfToken_Where) break; if ((token == BfToken_LBrace) || (token == BfToken_Semicolon)) { //return constraintsDeclaration; isDone = true; break; } MoveNode(tokenNode, genericConstraint); commas.push_back(tokenNode); } auto nextNode = mVisitorPos.GetNext(); if (auto constraintToken = BfNodeDynCast(nextNode)) { bool addToConstraint = false; switch (constraintToken->GetToken()) { case BfToken_Class: case BfToken_Struct: case BfToken_Const: case BfToken_Var: addToConstraint = true; break; } if (addToConstraint) { BfAstNode* constraintNode = constraintToken; MoveNode(constraintToken, genericConstraint); bool addToConstraint = false; mVisitorPos.MoveNext(); if (constraintToken->GetToken() == BfToken_Struct) { addToConstraint = true; nextNode = mVisitorPos.GetNext(); if (tokenNode = BfNodeDynCast(nextNode)) { if (tokenNode->GetToken() == BfToken_Star) { auto tokenPair = mAlloc->Alloc(); ReplaceNode(constraintToken, tokenPair); MEMBER_SET(tokenPair, mLeft, constraintToken); MEMBER_SET(tokenPair, mRight, tokenNode); constraintNode = tokenPair; MoveNode(constraintToken, genericConstraint); genericConstraint->SetSrcEnd(tokenNode->GetSrcEnd()); mVisitorPos.MoveNext(); } } } else if (constraintToken->GetToken() == BfToken_Const) { constraintTypes.push_back(constraintNode); auto typeRef = CreateTypeRefAfter(nextNode); if (typeRef == NULL) { isDone = true; break; } MoveNode(typeRef, genericConstraint); constraintTypes.push_back(typeRef); continue; } constraintTypes.push_back(constraintNode); continue; } } auto typeRef = CreateTypeRefAfter(genericConstraint); if (typeRef == NULL) { isDone = true; break; } MoveNode(typeRef, genericConstraint); constraintTypes.push_back(typeRef); } if (constraintIdx == 0) ReplaceNode(genericConstraint, constraintsDeclaration); else MoveNode(genericConstraint, constraintsDeclaration); } return constraintsDeclaration; } void BfReducer::HandleBlock(BfBlock* block, bool allowEndingExpression) { //for (auto node : block->mChildren) SetAndRestoreValue prevVisitorPos(mVisitorPos, BfVisitorPos(block)); bool isDone = !mVisitorPos.MoveNext(); BfAstNode* nextNode = NULL; while (!isDone) { BfAstNode* node = mVisitorPos.GetCurrent(); CreateStmtFlags flags = (CreateStmtFlags)(CreateStmtFlags_FindTrailingSemicolon | CreateStmtFlags_AllowLocalFunction); if (allowEndingExpression) flags = (CreateStmtFlags)(flags | CreateStmtFlags_AllowUnterminatedExpression); auto statement = CreateStatement(node, flags); if (statement == NULL) { auto nextNode = mVisitorPos.GetNext(); isDone = !mVisitorPos.MoveNext(); #ifdef BF_AST_HAS_PARENT_MEMBER BF_ASSERT(node->mParent != NULL); #endif node->RemoveSelf(); BF_ASSERT(node->GetSourceData() == mSource->mSourceData); mSource->AddErrorNode(node); if (nextNode == NULL) break; continue; } isDone = !mVisitorPos.MoveNext(); mVisitorPos.Write(statement); } mVisitorPos.Trim(); } void BfReducer::HandleTypeDeclaration(BfTypeDeclaration* typeDecl, BfAttributeDirective* attributes) { SetAndRestoreValue prevTypeDecl(mCurTypeDecl, typeDecl); SetAndRestoreValue prevVisitorPos(mVisitorPos, BfVisitorPos(BfNodeDynCast(typeDecl->mDefineNode))); if (attributes != NULL) { MEMBER_SET(typeDecl, mAttributes, attributes); } if (!IsNodeRelevant(typeDecl)) { typeDecl->mIgnoreDeclaration = true; return; } BfAstNode* prevNode = NULL; bool isDone = !mVisitorPos.MoveNext(); while (!isDone) { auto node = mVisitorPos.GetCurrent(); if (node == prevNode) { BF_FATAL("Should have handled node already"); // If we're stuck on an error and can't process any more nodes break; } prevNode = node; BfAstNode* typeMember = BfNodeDynCast(node); if (typeMember == NULL) typeMember = ReadTypeMember(node); //methodDeclaration->mDocumentation = FindDocumentation(methodDeclaration); isDone = !mVisitorPos.MoveNext(); if (typeMember != NULL) { mVisitorPos.Write(typeMember); } } mVisitorPos.Trim(); } void BfReducer::HandleRoot(BfRootNode* rootNode) { String fileName; auto parser = rootNode->GetSourceData()->ToParserData(); if (parser != NULL) fileName = parser->mFileName; BP_ZONE_F("BfReducer::HandleRoot %s", fileName.c_str()); mAlloc = &rootNode->GetSourceData()->mAlloc; mSystem = mSource->mSystem; HandleTopLevel(rootNode); BfSizedArrayInitIndirect(mSource->mSourceData->mExteriorNodes, mExteriorNodes, mAlloc); mAlloc = NULL; if (mPassInstance->HasFailed()) mSource->mParsingFailed = true; } static String NodeToString(BfAstNode* node) { return String(&node->GetSourceData()->mSrc[node->GetSrcStart()], node->GetSrcLength()); } BfInlineAsmStatement* BfReducer::CreateInlineAsmStatement(BfAstNode* asmNode) { auto asmToken = BfNodeDynCast(asmNode); auto nextNode = mVisitorPos.GetNext(); auto blockNode = BfNodeDynCast(nextNode); if (blockNode == NULL) return (BfInlineAsmStatement*)Fail("Expected inline assembly block", asmNode); ReplaceNode(asmToken, blockNode); BfInlineAsmStatement* asmStatement = (BfInlineAsmStatement*)blockNode; { auto processInstrNodes = [&](const Array& nodes) -> BfInlineAsmInstruction* { int nodeCount = (int)nodes.size(); int curNodeIdx = 0; auto instNode = mAlloc->Alloc(); //instNode->mSource = asmStatement->mSource; int srcStart = nodes.front()->GetSrcStart(); int srcEnd = nodes.back()->GetSrcEnd(); instNode->Init(srcStart, srcStart, srcEnd); auto replaceWithLower = [](String& s) { std::transform(s.begin(), s.end(), s.begin(), ::tolower); }; auto readIdent = [&](String& outStr, bool forceLowerCase, const StringImpl& errorExpectation, bool peekOnly) -> bool { if (curNodeIdx >= nodeCount) { if (!peekOnly) Fail(StrFormat("Expected %s", errorExpectation.c_str()), instNode); return false; } BfAstNode* curNode = nodes[curNodeIdx]; if (!peekOnly) ++curNodeIdx; if (!BfNodeDynCast(curNode)) { if (!peekOnly) Fail(StrFormat("Found \"%s\", expected %s", NodeToString(curNode).c_str(), errorExpectation.c_str()), instNode); return false; } outStr = NodeToString(curNode); if (forceLowerCase) replaceWithLower(outStr); return true; }; auto readToken = [&](BfToken tokenType, const StringImpl& errorExpectation, bool peekOnly) -> bool { if (curNodeIdx >= nodeCount) { if (!peekOnly) Fail(StrFormat("Expected %s", errorExpectation.c_str()), instNode); return false; } BfAstNode* curNode = nodes[curNodeIdx]; if (!peekOnly) ++curNodeIdx; auto tokenNode = BfNodeDynCast(curNode); if (!tokenNode || tokenNode->GetToken() != tokenType) { if (!peekOnly) Fail(StrFormat("Found \"%s\", expected %s", NodeToString(curNode).c_str(), errorExpectation.c_str()), instNode); return false; } return true; }; auto readInteger = [&](int& outInt, const StringImpl& errorExpectation, bool peekOnly, int& outAdvanceTokenCount) -> bool { int origCurNodeIdx = curNodeIdx; outAdvanceTokenCount = 0; bool negate = false; if (readToken(BfToken_Minus, "", true)) { ++curNodeIdx; ++outAdvanceTokenCount; negate = true; } if (curNodeIdx >= nodeCount) { if (!peekOnly) Fail(StrFormat("Expected %s", errorExpectation.c_str()), instNode); else curNodeIdx = origCurNodeIdx; return false; } BfAstNode* curNode = nodes[curNodeIdx]; ++curNodeIdx; ++outAdvanceTokenCount; auto litNode = BfNodeDynCast(curNode); if (!litNode || litNode->mValue.mTypeCode != BfTypeCode_Int32) { if (!peekOnly) Fail(StrFormat("Found \"%s\", expected %s", NodeToString(curNode).c_str(), errorExpectation.c_str()), instNode); else curNodeIdx = origCurNodeIdx; return false; } outInt = litNode->mValue.mInt32; if (negate) outInt = -outInt; if (peekOnly) curNodeIdx = origCurNodeIdx; return true; }; auto readArgMemPrimaryExpr = [&](BfInlineAsmInstruction::AsmArg& outArg) -> bool { String primaryIdent; int primaryInt; int advanceTokenCount = 0; if (readIdent(primaryIdent, false, "", true)) { outArg.mMemFlags = BfInlineAsmInstruction::AsmArg::ARGMEMF_BaseReg; outArg.mReg = primaryIdent; ++curNodeIdx; return true; } else if (readInteger(primaryInt, "", true, advanceTokenCount)) { outArg.mMemFlags = BfInlineAsmInstruction::AsmArg::ARGMEMF_ImmediateDisp; outArg.mInt = primaryInt; curNodeIdx += advanceTokenCount; return true; } else { Fail(StrFormat("Found \"%s\", expected integer or identifier", NodeToString(nodes[curNodeIdx]).c_str()), instNode); return false; } }; std::function readArgMemMulExpr = [&](BfInlineAsmInstruction::AsmArg& outArg) -> bool { BfInlineAsmInstruction::AsmArg exprArgLeft, exprArgRight; if (!readArgMemPrimaryExpr(exprArgLeft)) return false; if (!readToken(BfToken_Star, "", true)) { outArg = exprArgLeft; return true; } ++curNodeIdx; if (!readArgMemMulExpr(exprArgRight)) return false; bool leftIdent = (exprArgLeft.mMemFlags & BfInlineAsmInstruction::AsmArg::ARGMEMF_BaseReg) != 0; bool rightIdent = (exprArgRight.mMemFlags & BfInlineAsmInstruction::AsmArg::ARGMEMF_BaseReg) != 0; if (leftIdent && rightIdent) { Fail(StrFormat("Memory expressions can only scale by an integer", NodeToString(nodes[curNodeIdx]).c_str()), instNode); return false; } else if (leftIdent || rightIdent) { if (leftIdent) { outArg = exprArgLeft; outArg.mAdjRegScalar = exprArgRight.mInt; } else { outArg = exprArgRight; outArg.mAdjRegScalar = exprArgLeft.mInt; } outArg.mMemFlags &= ~BfInlineAsmInstruction::AsmArg::ARGMEMF_BaseReg; outArg.mMemFlags |= BfInlineAsmInstruction::AsmArg::ARGMEMF_AdjReg; outArg.mAdjReg = outArg.mReg; outArg.mReg.clear(); } else { outArg = exprArgLeft; outArg.mInt = exprArgLeft.mInt * exprArgRight.mInt; } return true; }; std::function readArgMemAddExpr = [&](BfInlineAsmInstruction::AsmArg& outArg, bool subtractLeft) -> bool // can't use 'auto' here since it's recursive { BfInlineAsmInstruction::AsmArg exprArgLeft, exprArgRight; if (!readArgMemMulExpr(exprArgLeft)) return false; if (subtractLeft) { if (exprArgLeft.mMemFlags != BfInlineAsmInstruction::AsmArg::ARGMEMF_ImmediateDisp) { Fail("Memory expressions can only subtract by an integer", instNode); return false; } exprArgLeft.mInt = -exprArgLeft.mInt; } bool subtract = false; if (!readToken(BfToken_Plus, "", true)) { if (!readToken(BfToken_Minus, "", true)) { outArg = exprArgLeft; return true; } else subtract = true; } ++curNodeIdx; if (!readArgMemAddExpr(exprArgRight, subtract)) return false; bool leftScaling = (exprArgLeft.mMemFlags & BfInlineAsmInstruction::AsmArg::ARGMEMF_AdjReg) != 0; bool rightScaling = (exprArgRight.mMemFlags & BfInlineAsmInstruction::AsmArg::ARGMEMF_AdjReg) != 0; if (leftScaling && rightScaling) { Fail("Memory expressions can only have one scaling register and one non-scaling register", instNode); return false; } BfInlineAsmInstruction::AsmArg* scaledArg = leftScaling ? &exprArgLeft : (rightScaling ? &exprArgRight : nullptr); if (scaledArg) { BfInlineAsmInstruction::AsmArg* otherArg = leftScaling ? &exprArgRight : &exprArgLeft; outArg = *scaledArg; outArg.mMemFlags |= otherArg->mMemFlags; if (otherArg->mMemFlags & BfInlineAsmInstruction::AsmArg::ARGMEMF_BaseReg) { if (scaledArg->mMemFlags & BfInlineAsmInstruction::AsmArg::ARGMEMF_BaseReg) { Fail("Memory expressions can involve at most two registers", instNode); return false; } outArg.mReg = otherArg->mReg; } if (otherArg->mMemFlags & BfInlineAsmInstruction::AsmArg::ARGMEMF_ImmediateDisp) { outArg.mInt += otherArg->mInt; } } else { outArg.mInt = 0; if (exprArgLeft.mMemFlags & BfInlineAsmInstruction::AsmArg::ARGMEMF_ImmediateDisp) { outArg.mMemFlags |= BfInlineAsmInstruction::AsmArg::ARGMEMF_ImmediateDisp; outArg.mInt += exprArgLeft.mInt; } if (exprArgRight.mMemFlags & BfInlineAsmInstruction::AsmArg::ARGMEMF_ImmediateDisp) { outArg.mMemFlags |= BfInlineAsmInstruction::AsmArg::ARGMEMF_ImmediateDisp; outArg.mInt += exprArgRight.mInt; } bool leftIdent = (exprArgLeft.mMemFlags & BfInlineAsmInstruction::AsmArg::ARGMEMF_BaseReg) != 0; bool rightIdent = (exprArgRight.mMemFlags & BfInlineAsmInstruction::AsmArg::ARGMEMF_BaseReg) != 0; if (leftIdent && rightIdent) { outArg.mMemFlags |= (BfInlineAsmInstruction::AsmArg::ARGMEMF_BaseReg | BfInlineAsmInstruction::AsmArg::ARGMEMF_AdjReg); outArg.mReg = exprArgLeft.mReg; outArg.mAdjReg = exprArgRight.mReg; outArg.mAdjRegScalar = 1; } else if (leftIdent) { outArg.mMemFlags |= BfInlineAsmInstruction::AsmArg::ARGMEMF_BaseReg; outArg.mReg = exprArgLeft.mReg; } else if (rightIdent) { outArg.mMemFlags |= BfInlineAsmInstruction::AsmArg::ARGMEMF_BaseReg; outArg.mReg = exprArgRight.mReg; } } return true; }; auto parseArg = [&](BfInlineAsmInstruction::AsmArg& outArg) -> bool { bool keepGoing = true; while (keepGoing) { keepGoing = false; int peekInt; String peekStr; int advanceTokenCount; if (readInteger(peekInt, "", true, advanceTokenCount)) { outArg.mType = BfInlineAsmInstruction::AsmArg::ARGTYPE_Immediate; outArg.mInt = peekInt; curNodeIdx += advanceTokenCount; } else if (readIdent(peekStr, false, "", true)) { ++curNodeIdx; String s(peekStr); replaceWithLower(s); String tempIdent; if ((s == "cs" || s == "ds" || s == "es" || s == "fs" || s == "gs" || s == "ss") && readToken(BfToken_Colon, "", true)) { ++curNodeIdx; outArg.mSegPrefix = s; keepGoing = true; } else if (s == "st" && readToken(BfToken_LParen, "", true)) { ++curNodeIdx; outArg.mType = BfInlineAsmInstruction::AsmArg::ARGTYPE_FloatReg; if (!readInteger(peekInt, "integer floating-point register number", false, advanceTokenCount)) return false; outArg.mInt = peekInt; if (!readToken(BfToken_RParen, "')'", false)) return false; } else if ((s == "byte" || s == "word" || s == "dword" || s == "qword" || s == "xword" || s == "xmmword" || s == "opaque") && readIdent(tempIdent, true, "", true)) { if (tempIdent != "ptr") { Fail(StrFormat("Found \"%s\", expected \"ptr\"", NodeToString(nodes[curNodeIdx]).c_str()), instNode); return false; } ++curNodeIdx; outArg.mSizePrefix = s; keepGoing = true; } else { outArg.mType = BfInlineAsmInstruction::AsmArg::ARGTYPE_IntReg; outArg.mReg = peekStr; } } else if (readToken(BfToken_LBracket, "", true)) { ++curNodeIdx; BfInlineAsmInstruction::AsmArg exprArgLeft; if (!readArgMemAddExpr(exprArgLeft, false)) return false; if (!readToken(BfToken_RBracket, "']'", false)) return false; if (readToken(BfToken_Dot, "", true)) { ++curNodeIdx; if (!readIdent(outArg.mMemberSuffix, false, "struct member suffix identifier", false)) return false; } outArg.mType = BfInlineAsmInstruction::AsmArg::ARGTYPE_Memory; outArg.mMemFlags = exprArgLeft.mMemFlags; //outArg.mSegPrefix = already_set_leave_me_alone; //outArg.mSizePrefix = already_set_leave_me_alone; outArg.mInt = exprArgLeft.mInt; outArg.mReg = exprArgLeft.mReg; outArg.mAdjReg = exprArgLeft.mAdjReg; outArg.mAdjRegScalar = exprArgLeft.mAdjRegScalar; //outArg.mMemberSuffix = already_set_leave_me_alone; return true; } else return false; } return true; }; BfInlineAsmInstruction::AsmInst& outInst = instNode->mAsmInst; // instruction / instruction prefix / label String opStr; if (!readIdent(opStr, false, "instruction, instruction prefix, or label", false)) return nullptr; if (readToken(BfToken_Colon, "", true)) { ++curNodeIdx; outInst.mLabel = opStr; if (curNodeIdx >= nodeCount) return instNode; if (!readIdent(opStr, false, "instruction or instruction prefix", false)) return nullptr; } replaceWithLower(opStr); // check for instruction prefix(s) while (opStr == "lock" || opStr == "rep" || opStr == "repe" || opStr == "repne" || opStr == "repz" || opStr == "repnz") { if (curNodeIdx >= nodeCount) // in case prefix is listed like a separate instruction break; outInst.mOpPrefixes.push_back(opStr); if (!readIdent(opStr, true, "instruction or instruction prefix", false)) return nullptr; } outInst.mOpCode = opStr; BfInlineAsmInstruction::AsmArg asmArg; while (parseArg(asmArg)) { outInst.mArgs.push_back(asmArg); asmArg = BfInlineAsmInstruction::AsmArg(); if (!readToken(BfToken_Comma, "", true)) break; ++curNodeIdx; } if (curNodeIdx < nodeCount) return (BfInlineAsmInstruction*)Fail(StrFormat("Found unexpected \"%s\"", NodeToString(nodes[curNodeIdx]).c_str()), instNode); //String testStr = outInst.ToString(); int unusedLineChar = 0; auto bfParser = instNode->GetSourceData()->ToParserData(); if (bfParser != NULL) bfParser->GetLineCharAtIdx(instNode->GetSrcStart(), outInst.mDebugLine, unusedLineChar); //return (BfInlineAsmInstruction*)Fail(StrFormat("Line %d\n", outInst.mDebugLine), instNode); return instNode; }; // split nodes by newlines into individual instructions, skipping empty lines Array instrNodes; Array dstInstructions; //BCF: Add this back /*for (auto child = asmStatement->mChildren.mHead; child; child = child->mNext) { auto childToken = BfNodeDynCast(child); if (childToken && childToken->GetToken() == BfToken_AsmNewline) { if (!instrNodes.empty()) { BfInlineAsmInstruction* instNode = processInstrNodes(instrNodes); if (instNode) dstInstructions.push_back(instNode); instrNodes.clear(); } } else if (childToken && childToken->GetToken() == BfToken_Asm) { // ignore the actual 'asm' keyword as we no longer need it continue; //CDH FIXME this is because ReplaceNode adds the original 'asm' keyword as a child, which I don't need; maybe I'm missing how the CST->AST replacment pattern is intended to work? } else { instrNodes.push_back(child); } }*/ if (!instrNodes.empty()) { BfInlineAsmInstruction* instNode = processInstrNodes(instrNodes); if (instNode) dstInstructions.push_back(instNode); instrNodes.Clear(); } for (auto & instNode : dstInstructions) MoveNode(instNode, asmStatement); asmStatement->mInstructions = std::move(dstInstructions); } return asmStatement; }