diff options
Diffstat (limited to 'tools/slang-cpp-extractor/parser.cpp')
| -rw-r--r-- | tools/slang-cpp-extractor/parser.cpp | 2261 |
1 files changed, 0 insertions, 2261 deletions
diff --git a/tools/slang-cpp-extractor/parser.cpp b/tools/slang-cpp-extractor/parser.cpp deleted file mode 100644 index 3a4891829..000000000 --- a/tools/slang-cpp-extractor/parser.cpp +++ /dev/null @@ -1,2261 +0,0 @@ -#include "parser.h" - -#include "../../source/compiler-core/slang-name-convention-util.h" -#include "../../source/core/slang-io.h" -#include "../../source/core/slang-string-util.h" -#include "identifier-lookup.h" -#include "options.h" - -namespace CppExtract -{ -using namespace Slang; - -// If fails then we need more bits to identify types -SLANG_COMPILE_TIME_ASSERT(int(Node::Kind::CountOf) <= 8 * sizeof(uint32_t)); - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Parser !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -Parser::Parser(NodeTree* nodeTree, DiagnosticSink* sink) - : m_sink(sink), m_nodeTree(nodeTree), m_nodeTypeEnabled(0) -{ - // Enable types by default - const Node::Kind defaultEnabled[] = { - Node::Kind::ClassType, - Node::Kind::StructType, - Node::Kind::Namespace, - Node::Kind::AnonymousNamespace, - Node::Kind::Field, - - // These are disabled by default because AST uses macro magic to build up the types - // Node::Type::TypeDef, - // Node::Type::Enum, - // Node::Type::EnumClass, - - Node::Kind::Callable, - }; - setKindsEnabled(defaultEnabled, SLANG_COUNT_OF(defaultEnabled)); -} - -void Parser::setKindEnabled(Node::Kind kind, bool isEnabled) -{ - if (isEnabled) - { - m_nodeTypeEnabled |= (NodeTypeBitType(1) << int(kind)); - } - else - { - m_nodeTypeEnabled &= ~(NodeTypeBitType(1) << int(kind)); - } -} - -void Parser::setKindsEnabled(const Node::Kind* kinds, Index kindsCount, bool isEnabled) -{ - for (Index i = 0; i < kindsCount; ++i) - { - setKindEnabled(kinds[i], isEnabled); - } -} - -bool Parser::_isMarker(const UnownedStringSlice& name) -{ - return name.startsWith(m_options->m_markPrefix.getUnownedSlice()) && - name.endsWith(m_options->m_markSuffix.getUnownedSlice()); -} - -SlangResult Parser::expect(TokenType type, Token* outToken) -{ - if (m_reader.peekTokenType() != type) - { - m_sink->diagnose(m_reader.peekToken(), CPPDiagnostics::expectingToken, type); - return SLANG_FAIL; - } - - if (outToken) - { - *outToken = m_reader.advanceToken(); - } - else - { - m_reader.advanceToken(); - } - return SLANG_OK; -} - -bool Parser::advanceIfToken(TokenType type, Token* outToken) -{ - if (m_reader.peekTokenType() == type) - { - Token token = m_reader.advanceToken(); - if (outToken) - { - *outToken = token; - } - return true; - } - return false; -} - -bool Parser::advanceIfMarker(Token* outToken) -{ - const Token peekToken = m_reader.peekToken(); - if (peekToken.type == TokenType::Identifier && _isMarker(peekToken.getContent())) - { - m_reader.advanceToken(); - if (outToken) - { - *outToken = peekToken; - } - return true; - } - return false; -} - -bool Parser::advanceIfStyle(IdentifierStyle style, Token* outToken) -{ - if (m_reader.peekTokenType() == TokenType::Identifier) - { - IdentifierStyle readStyle = - m_nodeTree->m_identifierLookup->get(m_reader.peekToken().getContent()); - if (readStyle == style) - { - Token token = m_reader.advanceToken(); - if (outToken) - { - *outToken = token; - } - return true; - } - } - return false; -} - - -SlangResult Parser::pushAnonymousNamespace() -{ - m_currentScope = m_currentScope->getAnonymousNamespace(); - - if (m_sourceOrigin) - { - m_sourceOrigin->addNode(m_currentScope); - } - - // Add the to the scope stack so can pop. - m_scopeStack.add(m_currentScope); - - return SLANG_OK; -} - -SlangResult Parser::pushScope(ScopeNode* scopeNode) -{ - // We can only have one 'special' scope. - SLANG_ASSERT(scopeNode || m_scopeStack.getLast()); - - // We keep to track. - m_scopeStack.add(scopeNode); - - // If we pass nullptr, we don't update the current scope. - if (scopeNode == nullptr) - { - return SLANG_OK; - } - - if (m_sourceOrigin) - { - m_sourceOrigin->addNode(scopeNode); - } - - if (scopeNode->m_name.hasContent()) - { - // For anonymous namespace, we should look if we already have one and just reopen that. - // Doing so will mean will find anonymous namespace clashes - - if (Node* foundNode = m_currentScope->findChild(scopeNode->m_name.getContent())) - { - if (scopeNode->isClassLike()) - { - m_sink->diagnose( - m_reader.peekToken(), - CPPDiagnostics::typeAlreadyDeclared, - scopeNode->m_name.getContent()); - m_sink->diagnose( - foundNode->m_name, - CPPDiagnostics::seeDeclarationOf, - scopeNode->m_name.getContent()); - return SLANG_FAIL; - } - - if (foundNode->m_kind == Node::Kind::Namespace) - { - if (foundNode->m_kind != scopeNode->m_kind) - { - // Different types can't work - m_sink->diagnose( - m_reader.peekToken(), - CPPDiagnostics::typeAlreadyDeclared, - scopeNode->m_name.getContent()); - return SLANG_FAIL; - } - - ScopeNode* foundScopeNode = as<ScopeNode>(foundNode); - SLANG_ASSERT(foundScopeNode); - - // Make sure the node is empty, as we are *not* going to add it, we are just going - // to use the pre-existing namespace - SLANG_ASSERT(scopeNode->m_children.getCount() == 0); - - // We can just use the pre-existing namespace - m_currentScope = foundScopeNode; - return SLANG_OK; - } - } - } - - m_currentScope->addChild(scopeNode); - m_currentScope = scopeNode; - return SLANG_OK; -} - -SlangResult Parser::popScope() -{ - if (m_scopeStack.getCount() <= 0) - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::scopeNotClosed); - return SLANG_FAIL; - } - - ScopeNode* topScope = m_scopeStack.getLast(); - m_scopeStack.removeLast(); - - // If the top is nullptr, we don't change the current scope - if (topScope == nullptr) - { - return SLANG_OK; - } - - m_currentScope = m_currentScope->m_parentScope; - return SLANG_OK; -} - -SlangResult Parser::_maybeConsumeScope() -{ - // Look for either ; or { to open scope - while (true) - { - const TokenType type = m_reader.peekTokenType(); - if (type == TokenType::Semicolon) - { - m_reader.advanceToken(); - return SLANG_OK; - } - else if (type == TokenType::LBrace) - { - // m_reader.advanceToken(); - return consumeToClosingBrace(); - } - else if (type == TokenType::EndOfFile) - { - return SLANG_OK; - } - - m_reader.advanceToken(); - } -} - -SlangResult Parser::consumeToClosingBrace(const Token* inOpenBraceToken) -{ - Token openToken; - if (inOpenBraceToken) - { - openToken = *inOpenBraceToken; - } - else - { - openToken = m_reader.advanceToken(); - } - SLANG_ASSERT(openToken.type == TokenType::LBrace); - - while (true) - { - switch (m_reader.peekTokenType()) - { - case TokenType::EndOfFile: - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::didntFindMatchingBrace); - m_sink->diagnose(openToken, CPPDiagnostics::seeOpen); - return SLANG_FAIL; - } - case TokenType::LBrace: - { - SLANG_RETURN_ON_FAIL(consumeToClosingBrace()); - break; - } - case TokenType::RBrace: - { - m_reader.advanceToken(); - return SLANG_OK; - } - default: - { - m_reader.advanceToken(); - break; - } - } - } -} - - -SlangResult Parser::_parseEnum() -{ - // We are looking for - // enum ([class name] | [name]) [: base] ( { | ; ) - - Token enumToken; - - // consume enum - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &enumToken)); - - if (!m_currentScope->canContainTypes()) - { - m_sink->diagnose(enumToken.loc, CPPDiagnostics::cannotDeclareTypeInScope); - return SLANG_FAIL; - } - - Node::Kind kind = Node::Kind::Enum; - - Token nameToken; - if (advanceIfToken(TokenType::Identifier, &nameToken)) - { - const IdentifierStyle style = m_nodeTree->m_identifierLookup->get(nameToken.getContent()); - - if (style == IdentifierStyle::Class) - { - kind = Node::Kind::EnumClass; - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &nameToken)); - } - else if (style == IdentifierStyle::None) - { - // It holds the name then - } - else - { - m_sink->diagnose( - nameToken.loc, - CPPDiagnostics::expectingIdentifier, - nameToken.getContent()); - return SLANG_FAIL; - } - } - - RefPtr<EnumNode> node = new EnumNode(kind); - node->m_name = nameToken; - node->m_reflectionType = m_currentScope->getContainedReflectionType(); - - if (advanceIfToken(TokenType::Colon)) - { - // We may have tokens up to { or ; - List<Token> backingTokens; - - while (true) - { - TokenType tokenType = m_reader.peekTokenType(); - if (tokenType == TokenType::Semicolon || tokenType == TokenType::LBrace || - tokenType == TokenType::EndOfFile) - { - break; - } - - backingTokens.add(m_reader.advanceToken()); - } - - // TODO - Look up the backing type. It can only be an integral. We can assume it must be - // defined before lookup for our uses here. If we can't find the type, we could assume it's - // size is undefined - - if (backingTokens.getCount() > 0) - { - node->m_backingTokens.swapWith(backingTokens); - } - } - - pushScope(node); - - if (advanceIfToken(TokenType::Semicolon)) - { - if (nameToken.type != TokenType::Invalid) - { - Node* node = m_currentScope->findChild(nameToken.getContent()); - if (node) - { - // Strictly speaking we should check the backing type etc, match, but for now ignore - // and assume it's ok - - if (node->m_kind == kind) - { - return SLANG_OK; - } - m_sink->diagnose( - nameToken.loc, - CPPDiagnostics::typeAlreadyDeclared, - nameToken.getContent()); - return SLANG_FAIL; - } - return popScope(); - } - } - - SLANG_RETURN_ON_FAIL(expect(TokenType::LBrace)); - - while (true) - { - TokenType tokenType = m_reader.peekTokenType(); - if (tokenType == TokenType::RBrace) - { - break; - } - - RefPtr<EnumCaseNode> caseNode(new EnumCaseNode); - - // We could also check if the name is a valid identifier for name, for now just assume. - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &caseNode->m_name)); - - if (node->findChild(caseNode->m_name.getContent())) - { - m_sink->diagnose( - caseNode->m_name.loc, - CPPDiagnostics::identifierAlreadyDefined, - caseNode->m_name.getContent()); - return SLANG_FAIL; - } - - caseNode->m_reflectionType = m_currentScope->getContainedReflectionType(); - - // Add the value - node->addChild(caseNode); - - if (advanceIfToken(TokenType::OpAssign)) - { - List<Token> valueTokens; - SLANG_RETURN_ON_FAIL(_parseExpression(valueTokens)); - - if (valueTokens.getCount() > 0) - { - caseNode->m_valueTokens.swapWith(valueTokens); - } - } - - tokenType = m_reader.peekTokenType(); - if (tokenType == TokenType::Comma) - { - m_reader.advanceToken(); - continue; - } - - break; - } - - SLANG_RETURN_ON_FAIL(expect(TokenType::RBrace)); - SLANG_RETURN_ON_FAIL(expect(TokenType::Semicolon)); - - return popScope(); -} - -SlangResult Parser::_consumeTemplate() -{ - // Skip the current 'template' token. - m_reader.advanceToken(); - - // Consume everything in <> - SLANG_RETURN_ON_FAIL(expect(TokenType::OpLess)); - - { - Index arrowCount = 1; - while (true) - { - auto tokenType = m_reader.peekTokenType(); - - if (tokenType == TokenType::OpLess) - { - m_reader.advanceToken(); - arrowCount++; - } - else if (tokenType == TokenType::OpGreater) - { - m_reader.advanceToken(); - if (arrowCount == 1) - { - break; - } - --arrowCount; - } - else if (tokenType == TokenType::OpRsh) - { - if (arrowCount < 2) - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::unexpectedTemplateClose); - return SLANG_FAIL; - } - m_reader.advanceToken(); - if (arrowCount == 2) - { - break; - } - arrowCount -= 2; - } - else if (tokenType == TokenType::EndOfFile) - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::unexpectedEndOfFile); - return SLANG_FAIL; - } - else - { - m_reader.advanceToken(); - } - } - } - - // Search for { or ; to consume remaining - while (true) - { - auto tokenType = m_reader.peekTokenType(); - - switch (tokenType) - { - case TokenType::EndOfFile: - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::unexpectedEndOfFile); - return SLANG_FAIL; - } - case TokenType::Semicolon: - { - // Ends with semicolon if it's a template pre-declaration - m_reader.advanceToken(); - return SLANG_OK; - } - case TokenType::LBrace: - { - // If ends with {, means could be body of a struct/class or a body of a - // function/method. Consume it - SLANG_RETURN_ON_FAIL(consumeToClosingBrace()); - // If we hit a ; just consume and ignore - advanceIfToken(TokenType::Semicolon); - return SLANG_OK; - } - default: - { - // Consume - m_reader.advanceToken(); - break; - } - } - } -} - -SlangResult Parser::_maybeParseNode(Node::Kind kind) -{ - // We are looking for - // struct/class identifier [: [public|private|protected] Identifier ] { - // [public|private|proctected:]* marker ( identifier ); - - if (kind == Node::Kind::Namespace) - { - // consume namespace - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier)); - - Token name; - if (advanceIfToken(TokenType::LBrace)) - { - return pushAnonymousNamespace(); - } - else if (advanceIfToken(TokenType::Identifier, &name)) - { - if (advanceIfToken(TokenType::LBrace)) - { - // Okay looks like we are opening a namespace - RefPtr<ScopeNode> node(new ScopeNode(Node::Kind::Namespace)); - node->m_name = name; - - node->m_reflectionType = m_currentScope->getContainedReflectionType(); - // Push the node - return pushScope(node); - } - } - - // Just ignore it then - return SLANG_OK; - } - else if (Node::isKindEnumLike(kind)) - { - return _parseEnum(); - } - - // Must be class | struct - - SLANG_ASSERT(kind == Node::Kind::ClassType || kind == Node::Kind::StructType); - - Token name; - - // consume class | struct - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier)); - // Next is the class name - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &name)); - - - if (m_reader.peekTokenType() == TokenType::Semicolon) - { - // pre declaration; - return SLANG_OK; - } - - RefPtr<ClassLikeNode> node(new ClassLikeNode(kind)); - node->m_name = name; - - // We default to the containing scope for reflection type. - if (!m_options->m_requireMark) - { - node->m_reflectionType = m_currentScope->getContainedReflectionType(); - } - else - { - // Defaults to not reflected - SLANG_ASSERT(!node->isReflected()); - } - - if (advanceIfToken(TokenType::Colon)) - { - // Could have public - advanceIfStyle(IdentifierStyle::Access); - - if (!advanceIfToken(TokenType::Identifier, &node->m_super)) - { - return SLANG_OK; - } - } - - // We only accept a single super class. Consume everything afterwards until we hit the { brace - - if (m_reader.peekTokenType() != TokenType::LBrace) - { - // Consume up until we see a brace else it's an error - while (true) - { - const TokenType peekTokenType = m_reader.peekTokenType(); - if (peekTokenType == TokenType::EndOfFile) - { - // Expecting brace - m_sink->diagnose( - m_reader.peekToken(), - CPPDiagnostics::expectingToken, - TokenType::LBrace); - return SLANG_FAIL; - } - else if (peekTokenType == TokenType::LBrace) - { - break; - } - m_reader.advanceToken(); - } - - return pushScope(node); - } - - const Token braceToken = m_reader.advanceToken(); - - // Push the class scope - return pushScope(node); -} - -SlangResult Parser::_consumeToSync() -{ - while (true) - { - TokenType type = m_reader.peekTokenType(); - - switch (type) - { - case TokenType::Semicolon: - { - m_reader.advanceToken(); - return SLANG_OK; - } - case TokenType::Pound: - case TokenType::EndOfFile: - case TokenType::LBrace: - case TokenType::RBrace: - { - return SLANG_OK; - } - } - - m_reader.advanceToken(); - } -} - -SlangResult Parser::_maybeParseTemplateArg(Index& ioTemplateDepth) -{ - switch (m_reader.peekTokenType()) - { - case TokenType::Identifier: - { - TokenReader::ParsingCursor nameCursor; - SLANG_RETURN_ON_FAIL(_maybeParseType(ioTemplateDepth, nameCursor)); - return SLANG_OK; - } - case TokenType::IntegerLiteral: - { - m_reader.advanceToken(); - return SLANG_OK; - } - default: - break; - } - return SLANG_FAIL; -} - -SlangResult Parser::_maybeParseTemplateArgs(Index& ioTemplateDepth) -{ - if (!advanceIfToken(TokenType::OpLess)) - { - return SLANG_FAIL; - } - - ioTemplateDepth++; - - while (true) - { - if (ioTemplateDepth == 0) - { - return SLANG_OK; - } - - switch (m_reader.peekTokenType()) - { - case TokenType::OpGreater: - { - if (ioTemplateDepth <= 0) - { - m_sink->diagnose(m_reader.peekToken(), CPPDiagnostics::unexpectedTemplateClose); - return SLANG_FAIL; - } - ioTemplateDepth--; - m_reader.advanceToken(); - return SLANG_OK; - } - case TokenType::OpRsh: - { - if (ioTemplateDepth <= 1) - { - m_sink->diagnose(m_reader.peekToken(), CPPDiagnostics::unexpectedTemplateClose); - return SLANG_FAIL; - } - ioTemplateDepth -= 2; - m_reader.advanceToken(); - return SLANG_OK; - } - default: - { - while (true) - { - SLANG_RETURN_ON_FAIL(_maybeParseTemplateArg(ioTemplateDepth)); - - if (m_reader.peekTokenType() == TokenType::Comma) - { - m_reader.advanceToken(); - // If there is a comma parse another arg - continue; - } - break; - } - break; - } - } - } -} - -SlangResult Parser::_maybeConsume(IdentifierStyle style) -{ - while (advanceIfStyle(style)) - ; - return SLANG_OK; -} - -// True if two of these token types of the same type placed immediately after one another -// produce a different token. Can be conservative, as if not strictly required -// it will just mean more spacing in the output -static bool _canRepeatTokenType(TokenType type) -{ - switch (type) - { - case TokenType::OpAdd: - case TokenType::OpSub: - case TokenType::OpAnd: - case TokenType::OpOr: - case TokenType::OpGreater: - case TokenType::OpLess: - case TokenType::Identifier: - case TokenType::OpAssign: - case TokenType::Colon: - { - return false; - } - default: - break; - } - return true; -} - -// Returns true if there needs to be a space between the previous token type, and the current token -// type for correct output. It is assumed that the token stream is appropriate. -// The implementation might need more sophistication, but this at least avoids Blah const * -> -// Blahconst* -static bool _tokenConcatNeedsSpace(TokenType prev, TokenType cur) -{ - if ((cur == TokenType::OpAssign) || (prev == cur && !_canRepeatTokenType(cur))) - { - return true; - } - return false; -} - -void Parser::_getTypeTokens( - TokenReader::ParsingCursor start, - TokenReader::ParsingCursor nameCursor, - List<Token>& outToks) -{ - auto endCursor = m_reader.getCursor(); - m_reader.setCursor(start); - - while (!m_reader.isAtCursor(endCursor)) - { - if (m_reader.getCursor() == nameCursor) - { - m_reader.advanceToken(); - } - else - { - outToks.add(m_reader.advanceToken()); - } - } -} - -UnownedStringSlice Parser::_concatType( - TokenReader::ParsingCursor start, - TokenReader::ParsingCursor nameCursor) -{ - List<Token> toks; - _getTypeTokens(start, nameCursor, toks); - return _concatTokens(toks.getBuffer(), toks.getCount()); -} - -UnownedStringSlice Parser::_concatTokens(const Token* toks, Index toksCount) -{ - StringBuilder buf; - - TokenType prevTokenType = TokenType::Unknown; - for (Index i = 0; i < toksCount; ++i) - { - const auto token = toks[i]; - - // Check if we need a space between tokens - if (_tokenConcatNeedsSpace(prevTokenType, token.type)) - { - buf << " "; - } - - buf << token.getContent(); - - prevTokenType = token.type; - } - - StringSlicePool* typePool = m_nodeTree->m_typePool; - return typePool->getSlice(typePool->add(buf)); -} - -UnownedStringSlice Parser::_concatTokens(TokenReader::ParsingCursor start) -{ - auto endCursor = m_reader.getCursor(); - - m_reader.setCursor(start); - - TokenType prevTokenType = TokenType::Unknown; - - StringBuilder buf; - while (!m_reader.isAtCursor(endCursor)) - { - const Token token = m_reader.advanceToken(); - // Check if we need a space between tokens - if (_tokenConcatNeedsSpace(prevTokenType, token.type)) - { - buf << " "; - } - buf << token.getContent(); - - prevTokenType = token.type; - } - - StringSlicePool* typePool = m_nodeTree->m_typePool; - return typePool->getSlice(typePool->add(buf)); -} - -SlangResult Parser::_maybeParseType( - Index& ioTemplateDepth, - TokenReader::ParsingCursor& outNameCursor) -{ - outNameCursor = TokenReader::ParsingCursor(); - - while (true) - { - if (m_reader.peekTokenType() == TokenType::Identifier) - { - const IdentifierStyle style = - m_nodeTree->m_identifierLookup->get(m_reader.peekToken().getContent()); - - if (style == IdentifierStyle::TypeModifier || - style == IdentifierStyle::IntegerModifier || style == IdentifierStyle::Class || - style == IdentifierStyle::Struct) - { - // These are ok keywords in this context - } - else if (hasFlag(style, IdentifierFlag::Keyword)) - { - return SLANG_FAIL; - } - } - - _maybeConsume(IdentifierStyle::TypeModifier); - - if (advanceIfStyle(IdentifierStyle::IntegerModifier)) - { - // Consume the integer typename (if there is one) - const Token peekToken = m_reader.peekToken(); - if (peekToken.type == TokenType::Identifier) - { - const IdentifierStyle style = - m_nodeTree->m_identifierLookup->get(peekToken.getContent()); - if (style == IdentifierStyle::IntegerType) - { - m_reader.advanceToken(); - } - } - break; - } - - advanceIfToken(TokenType::Scope); - while (true) - { - // if we have a struct/class prefix in front of a name just consume it. - if (m_reader.peekTokenType() == TokenType::Identifier) - { - const IdentifierStyle style = - m_nodeTree->m_identifierLookup->get(m_reader.peekToken().getContent()); - if (style == IdentifierStyle::Class || style == IdentifierStyle::Struct) - { - m_reader.advanceToken(); - } - } - - Token identifierToken; - if (!advanceIfToken(TokenType::Identifier, &identifierToken)) - { - return SLANG_FAIL; - } - - const IdentifierStyle style = - m_nodeTree->m_identifierLookup->get(identifierToken.getContent()); - if (hasFlag(style, IdentifierFlag::Keyword)) - { - return SLANG_FAIL; - } - - if (advanceIfToken(TokenType::Scope)) - { - continue; - } - break; - } - - if (m_reader.peekTokenType() == TokenType::OpLess) - { - SLANG_RETURN_ON_FAIL(_maybeParseTemplateArgs(ioTemplateDepth)); - } - - if (m_reader.peekTokenType() == TokenType::Scope) - { - // Skip the scope and repeat - m_reader.advanceToken(); - continue; - } - - break; - } - - // Strip all the consts etc modifiers - _maybeConsume(IdentifierStyle::TypeModifier); - - // It's a reference and we are done - if (advanceIfToken(TokenType::OpBitAnd)) - { - return SLANG_OK; - } - - while (true) - { - if (advanceIfToken(TokenType::OpMul)) - { - // Strip all the consts - _maybeConsume(IdentifierStyle::TypeModifier); - continue; - } - break; - } - - if (advanceIfToken(TokenType::LParent)) - { - // TODO(JS): - // Doesn't handle all the modifiers just (*SomeName) - - SLANG_RETURN_ON_FAIL(expect(TokenType::OpMul)); - outNameCursor = m_reader.getCursor(); - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier)); - - SLANG_RETURN_ON_FAIL(expect(TokenType::RParent)); - - // We need to parse and add the params - if (m_reader.peekTokenType() != TokenType::LParent) - { - m_sink->diagnose( - m_reader.peekToken(), - CPPDiagnostics::expectingToken, - TokenType::LParent); - return SLANG_FAIL; - } - - // Consume the params - SLANG_RETURN_ON_FAIL(_consumeBalancedParens()); - } - else if (m_reader.peekTokenType() == TokenType::Identifier) - { - auto potentialNameCursor = m_reader.getCursor(); - m_reader.advanceToken(); - if (m_reader.peekTokenType() == TokenType::LBracket) - { - outNameCursor = potentialNameCursor; - while (advanceIfToken(TokenType::LBracket)) - { - List<Token> exprToks; - SLANG_RETURN_ON_FAIL(_parseExpression(exprToks)); - SLANG_RETURN_ON_FAIL(expect(TokenType::RBracket)); - } - } - else - { - // Wasn't an array type..., so rewind - m_reader.setCursor(potentialNameCursor); - } - } - - return SLANG_OK; -} - -SlangResult Parser::_maybeParseType(List<Token>& outToks, Token& outName) -{ - // Set to unknown - outName = Token(); - - auto startCursor = m_reader.getCursor(); - - TokenReader::ParsingCursor nameCursor; - - Index templateDepth = 0; - SlangResult res = _maybeParseType(templateDepth, nameCursor); - if (SLANG_FAILED(res) && m_sink->getErrorCount()) - { - return res; - } - - if (templateDepth != 0) - { - m_sink->diagnose(m_reader.peekToken(), CPPDiagnostics::unexpectedTemplateClose); - return SLANG_FAIL; - } - - auto endCursor = m_reader.getCursor(); - m_reader.setCursor(startCursor); - - if (nameCursor.isValid()) - { - while (!m_reader.isAtCursor(endCursor)) - { - if (m_reader.getCursor() == nameCursor) - { - outName = m_reader.advanceToken(); - } - else - { - outToks.add(m_reader.advanceToken()); - } - } - } - else - { - while (!m_reader.isAtCursor(endCursor)) - { - outToks.add(m_reader.advanceToken()); - } - } - - return SLANG_OK; -} - -SlangResult Parser::_parseSpecialMacro() -{ - Token name; - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &name)); - - List<Token> params; - - if (m_reader.peekTokenType() == TokenType::LParent) - { - // Mark the start - auto startCursor = m_reader.getCursor(); - - // Consume the params - SLANG_RETURN_ON_FAIL(_consumeBalancedParens()); - - auto endCursor = m_reader.getCursor(); - m_reader.setCursor(startCursor); - - while (!m_reader.isAtCursor(endCursor)) - { - params.add(m_reader.advanceToken()); - } - } - - // Can do special handling here - const UnownedStringSlice suffix = name.getContent().tail(m_options->m_markPrefix.getLength()); - - if (suffix == "COM_INTERFACE") - { - // TODO(JS): It's a com interface. Extact the GUID - } - - return SLANG_OK; -} - -SlangResult Parser::_parseMarker() -{ - SLANG_ASSERT( - m_reader.peekTokenType() == TokenType::Identifier && - _isMarker(m_reader.peekToken().getContent()) && m_currentScope->isClassLike()); - - ClassLikeNode* node = as<ClassLikeNode>(m_currentScope); - - if (node->m_marker.type != TokenType::Unknown) - { - m_sink->diagnose( - m_reader.peekToken(), - CPPDiagnostics::classMarkerAlreadyFound, - node->m_name.getContent()); - m_sink->diagnose(node->m_marker, CPPDiagnostics::previousLocation); - return SLANG_FAIL; - } - - // Set the marker token. - node->m_marker = m_reader.advanceToken(); - - // Looks like it's a marker - UnownedStringSlice slice(node->m_marker.getContent()); - - // Strip the prefix and suffix - slice = UnownedStringSlice( - slice.begin() + m_options->m_markPrefix.getLength(), - slice.end() - m_options->m_markSuffix.getLength()); - - // Strip ABSTRACT_ if it's there - UnownedStringSlice abstractSlice("ABSTRACT_"); - if (slice.startsWith(abstractSlice)) - { - slice = UnownedStringSlice(slice.begin() + abstractSlice.getLength(), slice.end()); - } - - // TODO: We could strip other stuff or have other heuristics there, but this is - // probably okay for now - - // Set the typeSet - node->m_typeSet = m_nodeTree->getOrAddTypeSet(slice); - - // Okay now looking for ( identifier) - Token typeNameToken; - - SLANG_RETURN_ON_FAIL(expect(TokenType::LParent)); - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &typeNameToken)); - SLANG_RETURN_ON_FAIL(expect(TokenType::RParent)); - - if (typeNameToken.getContent() != node->m_name.getContent()) - { - m_sink->diagnose( - typeNameToken, - CPPDiagnostics::typeNameDoesntMatch, - node->m_name.getContent()); - return SLANG_FAIL; - } - - // If has the marker it is assumed reflected - node->m_reflectionType = ReflectionType::Reflected; - return SLANG_OK; -} - -SlangResult Parser::_maybeParseType(UnownedStringSlice& outType, Token& outName) -{ - auto startCursor = m_reader.getCursor(); - - Index templateDepth = 0; - - TokenReader::ParsingCursor nameCursor; - - SlangResult res = _maybeParseType(templateDepth, nameCursor); - if (SLANG_FAILED(res) && m_sink->getErrorCount()) - { - return res; - } - - if (templateDepth != 0) - { - m_sink->diagnose(m_reader.peekToken(), CPPDiagnostics::unexpectedTemplateClose); - return SLANG_FAIL; - } - - if (nameCursor.isValid()) - { - const auto cursor = m_reader.getCursor(); - m_reader.setCursor(nameCursor); - outName = m_reader.peekToken(); - m_reader.setCursor(cursor); - - // Extract the contents - List<Token> toks; - _getTypeTokens(startCursor, nameCursor, toks); - outType = _concatTokens(toks.getBuffer(), toks.getCount()); - } - else - { - // We can build up the out type, from the tokens we found - outType = _concatTokens(startCursor); - } - return SLANG_OK; -} - -static bool _isBalancedOpen(TokenType tokenType) -{ - return tokenType == TokenType::LBrace || tokenType == TokenType::LParent || - tokenType == TokenType::LBracket; -} - -static bool _isBalancedClose(TokenType tokenType) -{ - return tokenType == TokenType::RBrace || tokenType == TokenType::RParent || - tokenType == TokenType::RBracket; -} - -static TokenType _getBalancedClose(TokenType tokenType) -{ - SLANG_ASSERT(_isBalancedOpen(tokenType)); - switch (tokenType) - { - case TokenType::LBrace: - return TokenType::RBrace; - case TokenType::LParent: - return TokenType::RParent; - case TokenType::LBracket: - return TokenType::RBracket; - default: - return TokenType::Unknown; - } -} - -SlangResult Parser::_parseBalanced(DiagnosticSink* sink) -{ - const TokenType openTokenType = m_reader.peekTokenType(); - if (!_isBalancedOpen(openTokenType)) - { - return SLANG_FAIL; - } - - // Save the start token - const Token startToken = m_reader.advanceToken(); - // Get the token type that would close the open - const TokenType closeTokenType = _getBalancedClose(openTokenType); - - while (true) - { - const TokenType tokenType = m_reader.peekTokenType(); - - // If we hit the closing token, we are done - if (tokenType == closeTokenType) - { - m_reader.advanceToken(); - return SLANG_OK; - } - - // If we hit a balanced open, recurse - if (_isBalancedOpen(tokenType)) - { - SLANG_RETURN_ON_FAIL(_parseBalanced(sink)); - continue; - } - - // If we hit a close token that doesn't match, then the balancing has gone wrong - if (_isBalancedClose(tokenType)) - { - // Only diagnose if required - if (sink) - { - sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::unexpectedUnbalancedToken); - sink->diagnose(startToken, CPPDiagnostics::seeOpen); - } - return SLANG_FAIL; - } - - // If we hit the end of the file and have not hit the closing token, then - // somethings gone wrong - if (tokenType == TokenType::EndOfFile) - { - if (sink) - { - sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::unexpectedEndOfFile); - sink->diagnose(startToken, CPPDiagnostics::seeOpen); - } - - return SLANG_FAIL; - } - - // Skip the token - m_reader.advanceToken(); - } -} - -SlangResult Parser::_consumeBalancedParens() -{ - SLANG_ASSERT(m_reader.peekTokenType() == TokenType::LParent); - - Index parenCount = 0; - - while (true) - { - const TokenType tokenType = m_reader.peekTokenType(); - - switch (tokenType) - { - case TokenType::LParent: - { - parenCount++; - break; - } - case TokenType::RParent: - { - --parenCount; - // If no more parens then we are done - if (parenCount == 0) - { - m_reader.advanceToken(); - return SLANG_OK; - } - break; - } - case TokenType::EndOfFile: - { - // If we hit the end of the file, then not balanced - return SLANG_FAIL; - } - default: - break; - } - - m_reader.advanceToken(); - } -} - -SlangResult Parser::_parseExpression(List<Token>& outExprTokens) -{ - Index parenCount = 0; - Index bracketCount = 0; - - // TODO(JS): NOTE! This doesn't handle an expression that contains a template params in - // Something<Arg1, 3>, because without knowing what Something is, it's not known if < is a - // comparison or or a 'template' bracket - // - // This can be worked around in the originating source by placing in parens - - while (true) - { - TokenType tokenType = m_reader.peekTokenType(); - - switch (tokenType) - { - case TokenType::LParent: - { - parenCount++; - break; - } - case TokenType::RParent: - { - // If no parens, and nothing else is open then we are done - if (parenCount == 0) - { - if (bracketCount) - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::cannotParseExpression); - return SLANG_FAIL; - } - - return SLANG_OK; - } - --parenCount; - break; - } - case TokenType::LBracket: - { - bracketCount++; - break; - } - case TokenType::RBracket: - { - // If no brackets are open we are done - if (bracketCount == 0) - { - if (parenCount) - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::cannotParseExpression); - return SLANG_FAIL; - } - return SLANG_OK; - } - --bracketCount; - break; - } - case TokenType::EndOfFile: - { - if ((bracketCount | parenCount) == 0) - { - return SLANG_OK; - } - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::cannotParseExpression); - return SLANG_FAIL; - } - case TokenType::RBrace: - case TokenType::Semicolon: - case TokenType::Comma: - { - if ((bracketCount | parenCount) == 0) - { - return SLANG_OK; - } - break; - } - - default: - break; - } - - outExprTokens.add(m_reader.advanceToken()); - } -} - -SlangResult Parser::_parseTypeDef() -{ - if (!m_currentScope->canContainTypes()) - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::cannotDeclareTypeInScope); - return SLANG_FAIL; - } - - // Consume the typedef - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier)); - - Token nameToken; - // Parse the type - List<Token> toks; - SLANG_RETURN_ON_FAIL(_maybeParseType(toks, nameToken)); - - // Followed by the name - if (nameToken.type != TokenType::Identifier) - { - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &nameToken)); - } - - if (Node::lookupNameInScope(m_currentScope, nameToken.getContent())) - { - m_sink->diagnose( - nameToken.loc, - CPPDiagnostics::identifierAlreadyDefined, - nameToken.getContent()); - return SLANG_FAIL; - } - - SLANG_RETURN_ON_FAIL(expect(TokenType::Semicolon)); - - RefPtr<TypeDefNode> node = new TypeDefNode; - node->m_name = nameToken; - node->m_reflectionType = m_currentScope->getContainedReflectionType(); - - // Set what aliases too - node->m_targetTypeTokens.swapWith(toks); - - m_currentScope->addChild(node); - - return SLANG_OK; -} - - -bool Parser::_isCtor() -{ - bool isCtor = false; - // It's a constructor - if (m_currentScope->isClassLike() && m_reader.peekTokenType() == TokenType::Identifier && - m_reader.peekToken().getContent() == m_currentScope->m_name.getContent()) - { - // We need to check it's followed immediately by ( to be sure it's a ctor - - auto cursor = m_reader.getCursor(); - m_reader.advanceToken(); - isCtor = (m_reader.peekTokenType() == TokenType::LParent); - m_reader.setCursor(cursor); - } - - return isCtor; -} - -bool isAlphaNumeric(char c) -{ - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); -} - -SlangResult Parser::_maybeParseContained(Node** outNode) -{ - *outNode = nullptr; - - _maybeConsume(IdentifierStyle::CallableMisc); - - bool isStatic = false; - bool isVirtual = false; - - while (m_reader.peekTokenType() == TokenType::Identifier) - { - const IdentifierStyle style = - m_nodeTree->m_identifierLookup->get(m_reader.peekToken().getContent()); - - // Check for virtualness - if (style == IdentifierStyle::Virtual) - { - isVirtual = true; - m_reader.advanceToken(); - continue; - } - - // Check if static - if (style == IdentifierStyle::Static) - { - isStatic = true; - m_reader.advanceToken(); - continue; - } - - break; - } - - _maybeConsume(IdentifierStyle::CallableMisc); - - UnownedStringSlice typeName; - Token nameToken; - - bool isConstructor = false; - - if (m_currentScope->isClassLike()) - { - // If it's a dtor - if (advanceIfToken(TokenType::OpBitNot, &nameToken)) - { - // Dtor - // For Dtor we don't hold the full name just the ~ - Token tok; - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &tok)); - - if (tok.getContent() != m_currentScope->m_name.getContent()) - { - m_sink->diagnose( - m_reader.peekLoc(), - CPPDiagnostics::destructorNameDoesntMatch, - m_currentScope->m_name.getContent()); - return SLANG_FAIL; - } - } - else if (_isCtor()) - { - nameToken = m_reader.advanceToken(); - isConstructor = true; - } - } - - // If don't have a name it's not a dtor or ctor, so see if it's a type - if (nameToken.type == TokenType::Unknown) - { - if (SLANG_FAILED(_maybeParseType(typeName, nameToken))) - { - if (m_sink->getErrorCount()) - { - return SLANG_FAIL; - } - - _consumeToSync(); - return SLANG_OK; - } - } - - if (nameToken.type == TokenType::Unknown) - { - // Has a calling convention (must be a function/method) - Token callingConventionToken; - advanceIfStyle(IdentifierStyle::CallingConvention, &callingConventionToken); - - // Expecting a name - if (!advanceIfToken(TokenType::Identifier, &nameToken)) - { - _consumeToSync(); - return SLANG_OK; - } - } - - // Handles other scenarios, but here for catching operator overloading - if (nameToken.type == TokenType::Identifier) - { - const auto style = m_nodeTree->m_identifierLookup->get(nameToken.getContent()); - if (style != IdentifierStyle::None) - { - _consumeToSync(); - return SLANG_OK; - } - } - - if (m_reader.peekTokenType() == TokenType::LParent) - { - if (!m_currentScope->canContainCallable()) - { - SLANG_RETURN_ON_FAIL(_consumeBalancedParens()); - // Consume everything up to ; or { - SLANG_RETURN_ON_FAIL(_consumeToSync()); - - return SLANG_OK; - } - - // Looks like it's a callable - m_reader.advanceToken(); - - List<CallableNode::Param> params; - - if (m_reader.peekTokenType() != TokenType::RParent) - { - while (true) - { - Token paramName; - UnownedStringSlice type; - SlangResult res = _maybeParseType(type, paramName); - - if (SLANG_FAILED(res)) - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::expectingType); - return res; - } - - if (paramName.type != TokenType::Identifier) - { - if (m_reader.peekTokenType() == TokenType::Identifier) - { - paramName = m_reader.advanceToken(); - } - } - - // If we have a name check for default value - if (paramName.type == TokenType::Identifier && advanceIfToken(TokenType::OpAssign)) - { - // Check if we have a default value - List<Token> exprTokens; - SLANG_RETURN_ON_FAIL(_parseExpression(exprTokens)); - } - - CallableNode::Param param; - param.m_name = paramName; - param.m_type = type; - - params.add(param); - - { - const auto peekType = m_reader.peekTokenType(); - if (peekType == TokenType::RParent) - { - break; - } - if (peekType == TokenType::Comma) - { - m_reader.advanceToken(); - continue; - } - } - - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::expectingToken, ", or ) or ="); - return SLANG_FAIL; - } - } - - // Skip ) - m_reader.advanceToken(); - - // Parse suffix - bool isPure = false; - - // const? - _maybeConsume(IdentifierStyle::TypeModifier); - - if (isConstructor) - { - // Initializer list - if (advanceIfToken(TokenType::Colon)) - { - while (true) - { - auto peekType = m_reader.peekTokenType(); - if (peekType == TokenType::Semicolon || peekType == TokenType::LBrace || - peekType == TokenType::EndOfFile) - { - break; - } - // Consume - m_reader.advanceToken(); - } - } - } - - // = 0 ? or = default - if (advanceIfToken(TokenType::OpAssign)) - { - if (m_reader.peekTokenType() == TokenType::IntegerLiteral) - { - Int value = -1; - if (SLANG_SUCCEEDED( - StringUtil::parseInt(m_reader.peekToken().getContent(), value)) && - value == 0) - { - isPure = true; - m_reader.advanceToken(); - } - else - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::expectingToken, "0"); - return SLANG_FAIL; - } - } - else if (advanceIfStyle(IdentifierStyle::Default)) - { - } - else - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::cannotParseCallable); - return SLANG_FAIL; - } - } - - if (m_reader.peekTokenType() == TokenType::Semicolon) - { - m_reader.advanceToken(); - } - else if (m_reader.peekTokenType() == TokenType::LBrace) - { - SLANG_RETURN_ON_FAIL(consumeToClosingBrace()); - } - else - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::expectingToken, "; or {"); - return SLANG_FAIL; - } - - RefPtr<CallableNode> callableNode = new CallableNode; - - callableNode->m_returnType = typeName; - callableNode->m_name = nameToken; - callableNode->m_reflectionType = m_currentScope->getContainedReflectionType(); - - callableNode->m_isVirtual = isVirtual; - callableNode->m_isPure = isPure; - callableNode->m_isStatic = isStatic; - - callableNode->m_params.swapWith(params); - - Node* nodeWithName = m_currentScope->findChild(nameToken.getContent()); - - if (nodeWithName) - { - CallableNode* initialOverload = as<CallableNode>(nodeWithName); - if (!initialOverload) - { - m_sink->diagnose(m_reader.peekLoc(), CPPDiagnostics::cannotOverload); - m_sink->diagnose(nodeWithName->getSourceLoc(), CPPDiagnostics::seeDeclarationOf); - return SLANG_FAIL; - } - - callableNode->m_nextOverload = initialOverload->m_nextOverload; - initialOverload->m_nextOverload = initialOverload; - - m_currentScope->addChildIgnoringName(callableNode); - } - else - { - m_currentScope->addChild(callableNode); - } - - *outNode = callableNode; - return SLANG_OK; - } - else - { - // Looks like variable - if (!m_currentScope->canContainFields() || nameToken.type != TokenType::Identifier) - { - _consumeToSync(); - return SLANG_OK; - } - - // Check if has a default value - if (advanceIfToken(TokenType::OpAssign)) - { - List<Token> exprTokens; - SLANG_RETURN_ON_FAIL(_parseExpression(exprTokens)); - } - - // Hit end of field/variable - if (m_reader.peekTokenType() == TokenType::Semicolon) - { - RefPtr<FieldNode> fieldNode = new FieldNode; - - fieldNode->m_fieldType = typeName; - fieldNode->m_name = nameToken; - fieldNode->m_reflectionType = m_currentScope->getContainedReflectionType(); - fieldNode->m_isStatic = isStatic; - if (fieldNode->m_reflectionType == ReflectionType::Reflected) - { - static const char* illegalTypes[] = { - "size_t", - "Int", - "UInt", - "Index", - "Count", - "UIndex", - "UCount", - "PtrInt", - "intptr_t", - "uintptr_t"}; - for (const auto& illegalType : illegalTypes) - { - int index = typeName.indexOf(UnownedStringSlice(illegalType)); - if (index != -1) - { - index += UnownedStringSlice(illegalType).getLength(); - if (index >= typeName.getLength() || !isAlphaNumeric(typeName[index])) - { - // Cannot use this type in a field (as it's arch dependent - m_sink->diagnose( - nameToken, - CPPDiagnostics::cannoseUseArchDependentType, - illegalType); - return SLANG_FAIL; - } - } - } - } - m_currentScope->addChild(fieldNode); - - *outNode = fieldNode; - return SLANG_OK; - } - } - - _consumeToSync(); - return SLANG_OK; -} - -/* static */ Node::Kind Parser::_toNodeKind(IdentifierStyle style) -{ - switch (style) - { - case IdentifierStyle::Class: - return Node::Kind::ClassType; - case IdentifierStyle::Struct: - return Node::Kind::StructType; - case IdentifierStyle::Namespace: - return Node::Kind::Namespace; - case IdentifierStyle::Enum: - return Node::Kind::Enum; - case IdentifierStyle::TypeDef: - return Node::Kind::TypeDef; - default: - return Node::Kind::Invalid; - } -} - -static UnownedStringSlice _trimUnderscorePrefix(const UnownedStringSlice& slice) -{ - if (slice.getLength() && slice[0] == '_') - { - return UnownedStringSlice(slice.begin() + 1, slice.end()); - } - else - { - return slice; - } -} - -SlangResult Parser::_parsePreDeclare() -{ - // Skip the declare type token - m_reader.advanceToken(); - - SLANG_RETURN_ON_FAIL(expect(TokenType::LParent)); - - // Get the typeSet - Token typeSetToken; - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &typeSetToken)); - TypeSet* typeSet = m_nodeTree->getOrAddTypeSet(typeSetToken.getContent()); - - SLANG_RETURN_ON_FAIL(expect(TokenType::Comma)); - - // Get the type of type - Node::Kind nodeKind; - { - Token typeToken; - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &typeToken)); - - const IdentifierStyle style = m_nodeTree->m_identifierLookup->get(typeToken.getContent()); - - if (style != IdentifierStyle::Struct && style != IdentifierStyle::Class) - { - m_sink->diagnose( - typeToken, - CPPDiagnostics::expectingTypeKeyword, - typeToken.getContent()); - return SLANG_FAIL; - } - nodeKind = _toNodeKind(style); - } - - Token name; - Token super; - - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &name)); - - if (advanceIfToken(TokenType::Colon)) - { - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &super)); - } - - SLANG_RETURN_ON_FAIL(expect(TokenType::RParent)); - - switch (nodeKind) - { - case Node::Kind::ClassType: - case Node::Kind::StructType: - { - RefPtr<ClassLikeNode> node(new ClassLikeNode(nodeKind)); - - node->m_name = name; - node->m_super = super; - node->m_typeSet = typeSet; - - // Assume it is reflected - node->m_reflectionType = ReflectionType::Reflected; - - SLANG_RETURN_ON_FAIL(pushScope(node)); - // Pop out of the node - popScope(); - break; - } - default: - { - return SLANG_FAIL; - } - } - - - return SLANG_OK; -} - -SlangResult Parser::_parseTypeSet() -{ - // Skip the declare type token - m_reader.advanceToken(); - - SLANG_RETURN_ON_FAIL(expect(TokenType::LParent)); - - Token typeSetToken; - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &typeSetToken)); - - TypeSet* typeSet = m_nodeTree->getOrAddTypeSet(typeSetToken.getContent()); - - SLANG_RETURN_ON_FAIL(expect(TokenType::Comma)); - - // Get the type of type - Token typeToken; - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &typeToken)); - - SLANG_RETURN_ON_FAIL(expect(TokenType::RParent)); - - // Set the typename - typeSet->m_typeName = typeToken.getContent(); - - return SLANG_OK; -} - -SlangResult Parser::parse(SourceOrigin* sourceOrigin, const Options* options) -{ - SLANG_ASSERT(options); - m_options = options; - - // Set the current origin - m_sourceOrigin = sourceOrigin; - - SourceFile* sourceFile = sourceOrigin->m_sourceFile; - - SourceManager* manager = sourceFile->getSourceManager(); - - SourceView* sourceView = manager->createSourceView(sourceFile, nullptr, SourceLoc::fromRaw(0)); - - Lexer lexer; - - // Set up the scope stack - m_scopeStack.clear(); - - m_currentScope = m_nodeTree->m_rootNode; - m_scopeStack.add(m_currentScope); - - if (!options->m_requireMark) - { - m_currentScope->m_reflectionOverride = ReflectionType::Reflected; - } - - lexer.initialize(sourceView, m_sink, m_nodeTree->m_namePool, manager->getMemoryArena()); - m_tokenList = lexer.lexAllSemanticTokens(); - // See if there were any errors - if (m_sink->getErrorCount()) - { - return SLANG_FAIL; - } - - m_reader = TokenReader(m_tokenList); - - while (true) - { - switch (m_reader.peekTokenType()) - { - case TokenType::OpBitNot: - { - // Handle dtor - if (m_currentScope->isClassLike()) - { - Node* containedNode = nullptr; - SLANG_RETURN_ON_FAIL(_maybeParseContained(&containedNode)); - } - else - { - // consume - m_reader.advanceToken(); - } - break; - } - case TokenType::Identifier: - { - const IdentifierStyle style = - m_nodeTree->m_identifierLookup->get(m_reader.peekToken().getContent()); - - switch (style) - { - case IdentifierStyle::Extern: - { - m_reader.advanceToken(); - - Token externType; - SLANG_RETURN_ON_FAIL(expect(TokenType::StringLiteral, &externType)); - - if (advanceIfToken(TokenType::LBrace)) - { - // Push a 'special' scope (which is basically transparent) - pushScope(nullptr); - } - break; - } - case IdentifierStyle::Template: - { - SLANG_RETURN_ON_FAIL(_consumeTemplate()); - break; - } - case IdentifierStyle::PreDeclare: - { - SLANG_RETURN_ON_FAIL(_parsePreDeclare()); - break; - } - case IdentifierStyle::TypeSet: - { - SLANG_RETURN_ON_FAIL(_parseTypeSet()); - break; - } - case IdentifierStyle::Reflected: - { - m_reader.advanceToken(); - if (m_currentScope) - { - m_currentScope->m_reflectionOverride = ReflectionType::Reflected; - } - break; - } - case IdentifierStyle::Unreflected: - { - m_reader.advanceToken(); - if (m_currentScope) - { - m_currentScope->m_reflectionOverride = ReflectionType::NotReflected; - } - break; - } - case IdentifierStyle::Access: - { - m_reader.advanceToken(); - SLANG_RETURN_ON_FAIL(expect(TokenType::Colon)); - break; - } - case IdentifierStyle::TypeDef: - { - if (isTypeEnabled(Node::Kind::TypeDef)) - { - SLANG_RETURN_ON_FAIL(_parseTypeDef()); - } - else - { - m_reader.advanceToken(); - SLANG_RETURN_ON_FAIL(_consumeToSync()); - } - break; - } - default: - { - IdentifierFlags flags = getFlags(style); - - if (flags & IdentifierFlag::StartScope) - { - Node::Kind kind = _toNodeKind(style); - SLANG_ASSERT(kind != Node::Kind::Invalid); - - if (isTypeEnabled(kind)) - { - SLANG_RETURN_ON_FAIL(_maybeParseNode(kind)); - } - else - { - SLANG_RETURN_ON_FAIL(_maybeConsumeScope()); - } - } - else - { - UnownedStringSlice content = m_reader.peekToken().getContent(); - - // If it's a marker handle it - if (_isMarker(content)) - { - if (!m_currentScope->isClassLike()) - { - m_sink->diagnose( - m_reader.peekLoc(), - CPPDiagnostics::classMarkerOutsideOfClass); - return SLANG_FAIL; - } - - SLANG_RETURN_ON_FAIL(_parseMarker()); - break; - } - - if (m_options->m_markPrefix.getLength() > 0 && - content.startsWith(m_options->m_markPrefix.getUnownedSlice())) - { - SLANG_RETURN_ON_FAIL(_parseSpecialMacro()); - break; - } - - - // Special case the node that's the root of the hierarchy (as far as - // reflection is concerned) This could be a field - if (m_currentScope->canContainFields() || - m_currentScope->canContainCallable()) - { - Node* containedNode = nullptr; - SLANG_RETURN_ON_FAIL(_maybeParseContained(&containedNode)); - } - else - { - m_reader.advanceToken(); - } - } - break; - } - } - break; - } - case TokenType::LBrace: - { - SLANG_RETURN_ON_FAIL(consumeToClosingBrace()); - break; - } - case TokenType::RBrace: - { - SLANG_RETURN_ON_FAIL(popScope()); - m_reader.advanceToken(); - break; - } - case TokenType::EndOfFile: - { - // Okay we need to confirm that we are in the root node, and with no open braces - if (m_currentScope != m_nodeTree->getRootNode()) - { - m_sink->diagnose(m_reader.peekToken(), CPPDiagnostics::braceOpenAtEndOfFile); - return SLANG_FAIL; - } - if (m_sink->getErrorCount()) - return SLANG_FAIL; - return SLANG_OK; - } - case TokenType::Pound: - { - Token token = m_reader.peekToken(); - if (token.flags & TokenFlag::AtStartOfLine) - { - // We are just going to ignore all of these for now.... - m_reader.advanceToken(); - for (;;) - { - auto t = m_reader.peekToken(); - if (t.type == TokenType::EndOfFile || (t.flags & TokenFlag::AtStartOfLine)) - { - break; - } - m_reader.advanceToken(); - } - break; - } - // Skip it then - m_reader.advanceToken(); - break; - } - default: - { - // Skip it then - m_reader.advanceToken(); - break; - } - } - } -} - -} // namespace CppExtract |
