From 9289ebf4c9464a1c7e68a7474701d26a2ae1c8a1 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Wed, 25 Aug 2021 17:07:01 +0200 Subject: [PATCH] patterns: Initial namespace support --- .../libimhex/include/hex/lang/ast_node.hpp | 1 + plugins/libimhex/include/hex/lang/parser.hpp | 47 ++- plugins/libimhex/include/hex/lang/token.hpp | 8 +- plugins/libimhex/source/lang/lexer.cpp | 5 + plugins/libimhex/source/lang/parser.cpp | 301 +++++++++++------- source/views/view_pattern.cpp | 2 +- 6 files changed, 240 insertions(+), 124 deletions(-) diff --git a/plugins/libimhex/include/hex/lang/ast_node.hpp b/plugins/libimhex/include/hex/lang/ast_node.hpp index d236b6333..49f3da09f 100644 --- a/plugins/libimhex/include/hex/lang/ast_node.hpp +++ b/plugins/libimhex/include/hex/lang/ast_node.hpp @@ -161,6 +161,7 @@ namespace hex::lang { return new ASTNodeTypeDecl(*this); } + void setName(const std::string &name) { this->m_name = name; } [[nodiscard]] std::string_view getName() const { return this->m_name; } [[nodiscard]] ASTNode* getType() { return this->m_type; } [[nodiscard]] std::optional getEndian() const { return this->m_endian; } diff --git a/plugins/libimhex/include/hex/lang/parser.hpp b/plugins/libimhex/include/hex/lang/parser.hpp index 8b4b3a102..c7ae65365 100644 --- a/plugins/libimhex/include/hex/lang/parser.hpp +++ b/plugins/libimhex/include/hex/lang/parser.hpp @@ -32,6 +32,7 @@ namespace hex::lang { std::unordered_map m_types; std::vector m_matchedOptionals; + std::vector> m_currNamespace; u32 getLineNumber(s32 index) const { return this->m_curr[index].lineNumber; @@ -51,9 +52,20 @@ namespace hex::lang { return this->m_curr[index].type; } + std::string getNamespacePrefixedName(const std::string &name) { + std::string result; + for (const auto &part : this->m_currNamespace.back()) { + result += part + "::"; + } + + result += name; + + return result; + } + ASTNode* parseFunctionCall(); ASTNode* parseStringLiteral(); - ASTNode* parseScopeResolution(std::vector &path); + std::string parseScopeResolution(); ASTNode* parseRValue(ASTNodeRValue::Path &path); ASTNode* parseFactor(); ASTNode* parseUnaryExpression(); @@ -81,21 +93,23 @@ namespace hex::lang { void parseAttribute(Attributable *currNode); ASTNode* parseConditional(); ASTNode* parseWhileStatement(); - ASTNode* parseType(s32 startIndex); + ASTNodeTypeDecl* parseType(); ASTNode* parseUsingDeclaration(); ASTNode* parsePadding(); - ASTNode* parseMemberVariable(); - ASTNode* parseMemberArrayVariable(); - ASTNode* parseMemberPointerVariable(); + ASTNode* parseMemberVariable(ASTNodeTypeDecl *type); + ASTNode* parseMemberArrayVariable(ASTNodeTypeDecl *type); + ASTNode* parseMemberPointerVariable(ASTNodeTypeDecl *type); ASTNode* parseMember(); ASTNode* parseStruct(); ASTNode* parseUnion(); ASTNode* parseEnum(); ASTNode* parseBitfield(); - ASTNode* parseVariablePlacement(); - ASTNode* parseArrayVariablePlacement(); - ASTNode* parsePointerVariablePlacement(); - ASTNode* parseStatement(); + ASTNode* parseVariablePlacement(ASTNodeTypeDecl *type); + ASTNode* parseArrayVariablePlacement(ASTNodeTypeDecl *type); + ASTNode* parsePointerVariablePlacement(ASTNodeTypeDecl *type); + ASTNode* parsePlacement(); + std::vector parseNamespace(); + std::vector parseStatements(); std::vector parseTillToken(Token::Type endTokenType, const auto value) { std::vector program; @@ -105,7 +119,8 @@ namespace hex::lang { }; while (this->m_curr->type != endTokenType || (*this->m_curr) != value) { - program.push_back(parseStatement()); + for (auto statement : parseStatements()) + program.push_back(statement); } this->m_curr++; @@ -132,6 +147,10 @@ namespace hex::lang { return true; } + void reset() { + this->m_curr = this->m_originalPosition; + } + template bool sequence() { if constexpr (S == Normal) @@ -146,14 +165,14 @@ namespace hex::lang { bool sequence(Token::Type type, auto value, auto ... args) { if constexpr (S == Normal) { if (!peek(type, value)) { - this->m_curr = this->m_originalPosition; + reset(); return false; } this->m_curr++; if (!sequence(args...)) { - this->m_curr = this->m_originalPosition; + reset(); return false; } @@ -167,7 +186,7 @@ namespace hex::lang { if (!sequence(args...)) return true; - this->m_curr = this->m_originalPosition; + reset(); return false; } else __builtin_unreachable(); @@ -196,7 +215,7 @@ namespace hex::lang { bool variant(Token::Type type1, auto value1, Token::Type type2, auto value2) { if (!peek(type1, value1)) { if (!peek(type2, value2)) { - this->m_curr = this->m_originalPosition; + reset(); return false; } } diff --git a/plugins/libimhex/include/hex/lang/token.hpp b/plugins/libimhex/include/hex/lang/token.hpp index 3a3935f2f..b8cb76bb6 100644 --- a/plugins/libimhex/include/hex/lang/token.hpp +++ b/plugins/libimhex/include/hex/lang/token.hpp @@ -35,7 +35,8 @@ namespace hex::lang { Parent, While, Function, - Return + Return, + Namespace }; enum class Operator { @@ -66,7 +67,8 @@ namespace hex::lang { TernaryConditional, Dollar, AddressOf, - SizeOf + SizeOf, + ScopeResolution }; enum class ValueType { @@ -208,6 +210,7 @@ namespace hex::lang { #define KEYWORD_WHILE COMPONENT(Keyword, While) #define KEYWORD_FUNCTION COMPONENT(Keyword, Function) #define KEYWORD_RETURN COMPONENT(Keyword, Return) +#define KEYWORD_NAMESPACE COMPONENT(Keyword, Namespace) #define INTEGER hex::lang::Token::Type::Integer, hex::lang::Token::IntegerLiteral(u64(0)) #define IDENTIFIER hex::lang::Token::Type::Identifier, "" @@ -241,6 +244,7 @@ namespace hex::lang { #define OPERATOR_DOLLAR COMPONENT(Operator, Dollar) #define OPERATOR_ADDRESSOF COMPONENT(Operator, AddressOf) #define OPERATOR_SIZEOF COMPONENT(Operator, SizeOf) +#define OPERATOR_SCOPERESOLUTION COMPONENT(Operator, ScopeResolution) #define VALUETYPE_CUSTOMTYPE COMPONENT(ValueType, CustomType) #define VALUETYPE_PADDING COMPONENT(ValueType, Padding) diff --git a/plugins/libimhex/source/lang/lexer.cpp b/plugins/libimhex/source/lang/lexer.cpp index daa559971..89aa5f11c 100644 --- a/plugins/libimhex/source/lang/lexer.cpp +++ b/plugins/libimhex/source/lang/lexer.cpp @@ -284,6 +284,9 @@ namespace hex::lang { } else if (c == '.') { tokens.emplace_back(TOKEN(Separator, Dot)); offset += 1; + } else if (code.substr(offset, 2) == "::") { + tokens.emplace_back(TOKEN(Operator, ScopeResolution)); + offset += 2; } else if (c == '@') { tokens.emplace_back(TOKEN(Operator, AtDeclaration)); offset += 1; @@ -428,6 +431,8 @@ namespace hex::lang { tokens.emplace_back(TOKEN(Keyword, Function)); else if (identifier == "return") tokens.emplace_back(TOKEN(Keyword, Return)); + else if (identifier == "namespace") + tokens.emplace_back(TOKEN(Keyword, Namespace)); // Check for built-in types else if (identifier == "u8") diff --git a/plugins/libimhex/source/lang/parser.cpp b/plugins/libimhex/source/lang/parser.cpp index f26dc857e..112fdafbf 100644 --- a/plugins/libimhex/source/lang/parser.cpp +++ b/plugins/libimhex/source/lang/parser.cpp @@ -1,7 +1,6 @@ #include #include -#include #define MATCHES(x) (begin() && x) @@ -20,7 +19,11 @@ namespace hex::lang { // Identifier([(parseMathematicalExpression)|<(parseMathematicalExpression),...>(parseMathematicalExpression)] ASTNode* Parser::parseFunctionCall() { - auto functionName = getValue(-2); + std::string functionName = parseScopeResolution(); + + if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN))) + throwParseError("expected '(' after function name"); + std::vector params; auto paramCleanup = SCOPE_GUARD { for (auto ¶m : params) @@ -51,18 +54,21 @@ namespace hex::lang { return new ASTNodeStringLiteral(getValue(-1)); } - // Identifier:: - ASTNode* Parser::parseScopeResolution(std::vector &path) { - if (peek(IDENTIFIER, -1)) - path.push_back(getValue(-1)); + std::string Parser::parseScopeResolution() { + std::string name; - if (MATCHES(sequence(SEPARATOR_SCOPE_RESOLUTION))) { - if (MATCHES(sequence(IDENTIFIER))) - return this->parseScopeResolution(path); + while (true) { + name += getValue(-1); + + if (MATCHES(sequence(OPERATOR_SCOPERESOLUTION, IDENTIFIER))) { + name += "::"; + continue; + } else - throwParseError("expected member name", -1); - } else - return TO_NUMERIC_EXPRESSION(new ASTNodeScopeResolution(path)); + break; + } + + return name; } // @@ -98,13 +104,22 @@ namespace hex::lang { throwParseError("expected closing parenthesis"); } return node; - } else if (MATCHES(sequence(IDENTIFIER, SEPARATOR_SCOPE_RESOLUTION))) { - std::vector path; - this->m_curr--; - return this->parseScopeResolution(path); - } else if (MATCHES(sequence(IDENTIFIER, SEPARATOR_ROUNDBRACKETOPEN))) { - return TO_NUMERIC_EXPRESSION(this->parseFunctionCall()); - } else if (MATCHES(oneOf(IDENTIFIER, KEYWORD_PARENT))) { + } else if (MATCHES(sequence(IDENTIFIER))) { + auto originalPos = this->m_curr; + this->m_curr++; + parseScopeResolution(); + bool isFunction = peek(SEPARATOR_ROUNDBRACKETOPEN); + this->m_curr = originalPos; + + if (isFunction) { + this->m_curr++; + return TO_NUMERIC_EXPRESSION(parseFunctionCall()); + } + else { + ASTNodeRValue::Path path; + return TO_NUMERIC_EXPRESSION(this->parseRValue(path)); + } + } else if (MATCHES(oneOf(KEYWORD_PARENT))) { ASTNodeRValue::Path path; return TO_NUMERIC_EXPRESSION(this->parseRValue(path)); } else if (MATCHES(sequence(OPERATOR_DOLLAR))) { @@ -397,17 +412,29 @@ namespace hex::lang { } bodyCleanup.release(); - return new ASTNodeFunctionDefinition(functionName, params, body); + return new ASTNodeFunctionDefinition(getNamespacePrefixedName(functionName), params, body); } ASTNode* Parser::parseFunctionStatement() { bool needsSemicolon = true; ASTNode *statement; - if (MATCHES(sequence(IDENTIFIER, SEPARATOR_ROUNDBRACKETOPEN))) - statement = parseFunctionCall(); - else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER))) - statement = parseMemberVariable(); + if (peek(IDENTIFIER)) { + auto originalPos = this->m_curr; + this->m_curr++; + parseScopeResolution(); + bool isFunction = peek(SEPARATOR_ROUNDBRACKETOPEN); + this->m_curr = originalPos; + + if (isFunction) { + this->m_curr++; + statement = parseFunctionCall(); + } + else + statement = parseMemberVariable(parseType()); + } + else if (peek(KEYWORD_BE) || peek(KEYWORD_LE) || peek(VALUETYPE_ANY)) + statement = parseMemberVariable(parseType()); else if (MATCHES(sequence(IDENTIFIER, OPERATOR_ASSIGNMENT))) statement = parseFunctionVariableAssignment(); else if (MATCHES(sequence(KEYWORD_RETURN))) @@ -418,7 +445,8 @@ namespace hex::lang { } else if (MATCHES(sequence(KEYWORD_WHILE, SEPARATOR_ROUNDBRACKETOPEN))) { statement = parseFunctionWhileLoop(); needsSemicolon = false; - } else + } + else throwParseError("invalid sequence", 0); if (needsSemicolon && !MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) { @@ -558,34 +586,36 @@ namespace hex::lang { /* Type declarations */ // [be|le] - ASTNode* Parser::parseType(s32 startIndex) { + ASTNodeTypeDecl* Parser::parseType() { std::optional endian; - if (peekOptional(KEYWORD_LE, 0)) + if (MATCHES(sequence(KEYWORD_LE))) endian = std::endian::little; - else if (peekOptional(KEYWORD_BE, 0)) + else if (MATCHES(sequence(KEYWORD_BE))) endian = std::endian::big; - if (getType(startIndex) == Token::Type::Identifier) { // Custom type - if (!this->m_types.contains(getValue(startIndex))) - throwParseError("failed to parse type"); + if (MATCHES(sequence(IDENTIFIER))) { // Custom type + std::string typeName = parseScopeResolution(); - return new ASTNodeTypeDecl({ }, this->m_types[getValue(startIndex)]->clone(), endian); - } - else { // Builtin type - return new ASTNodeTypeDecl({ }, new ASTNodeBuiltinType(getValue(startIndex)), endian); + if (this->m_types.contains(typeName)) + return new ASTNodeTypeDecl({ }, this->m_types[typeName]->clone(), endian); + else if (this->m_types.contains(getNamespacePrefixedName(typeName))) + return new ASTNodeTypeDecl({ }, this->m_types[getNamespacePrefixedName(typeName)]->clone(), endian); + else + throwParseError(hex::format("unknown type '{}'", typeName)); } + else if (MATCHES(sequence(VALUETYPE_ANY))) { // Builtin type + return new ASTNodeTypeDecl({ }, new ASTNodeBuiltinType(getValue(-1)), endian); + } else throwParseError("failed to parse type. Expected identifier or builtin type"); } // using Identifier = (parseType) ASTNode* Parser::parseUsingDeclaration() { - auto *type = dynamic_cast(parseType(-1)); + auto name = getValue(-2); + auto *type = dynamic_cast(parseType()); if (type == nullptr) throwParseError("invalid type used in variable declaration", -1); - if (peekOptional(KEYWORD_BE) || peekOptional(KEYWORD_LE)) - return new ASTNodeTypeDecl(getValue(-4), type, type->getEndian()); - else - return new ASTNodeTypeDecl(getValue(-3), type, type->getEndian()); + return new ASTNodeTypeDecl(name, type, type->getEndian()); } // padding[(parseMathematicalExpression)] @@ -601,16 +631,14 @@ namespace hex::lang { } // (parseType) Identifier - ASTNode* Parser::parseMemberVariable() { - auto type = dynamic_cast(parseType(-2)); + ASTNode* Parser::parseMemberVariable(ASTNodeTypeDecl *type) { if (type == nullptr) throwParseError("invalid type used in variable declaration", -1); return new ASTNodeVariableDecl(getValue(-1), type); } // (parseType) Identifier[(parseMathematicalExpression)] - ASTNode* Parser::parseMemberArrayVariable() { - auto type = dynamic_cast(parseType(-3)); + ASTNode* Parser::parseMemberArrayVariable(ASTNodeTypeDecl *type) { if (type == nullptr) throwParseError("invalid type used in variable declaration", -1); auto name = getValue(-2); @@ -634,33 +662,40 @@ namespace hex::lang { } // (parseType) *Identifier : (parseType) - ASTNode* Parser::parseMemberPointerVariable() { + ASTNode* Parser::parseMemberPointerVariable(ASTNodeTypeDecl *type) { auto name = getValue(-2); - auto pointerType = dynamic_cast(parseType(-4)); - if (pointerType == nullptr) throwParseError("invalid type used in variable declaration", -1); + auto sizeType = parseType(); - if (!MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && sequence(VALUETYPE_UNSIGNED))) - throwParseError("expected unsigned builtin type as size", -1); + { + auto builtinType = dynamic_cast(sizeType->getType()); - auto sizeType = dynamic_cast(parseType(-1)); - if (sizeType == nullptr) throwParseError("invalid type used for pointer size", -1); + if (builtinType == nullptr || !Token::isUnsigned(builtinType->getType())) + throwParseError("invalid type used for pointer size", -1); + } - return new ASTNodePointerVariableDecl(name, pointerType, sizeType); + return new ASTNodePointerVariableDecl(name, type, sizeType); } // [(parsePadding)|(parseMemberVariable)|(parseMemberArrayVariable)|(parseMemberPointerVariable)] ASTNode* Parser::parseMember() { ASTNode *member; - if (MATCHES(sequence(VALUETYPE_PADDING, SEPARATOR_SQUAREBRACKETOPEN))) + + if (peek(KEYWORD_BE) || peek(KEYWORD_LE) || peek(VALUETYPE_ANY) || peek(IDENTIFIER)) { + // Some kind of variable definition + + auto type = parseType(); + + if (MATCHES(sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN)) && sequence(SEPARATOR_SQUAREBRACKETOPEN)) + member = parseMemberArrayVariable(type); + else if (MATCHES(sequence(IDENTIFIER))) + member = parseMemberVariable(type); + else if (MATCHES(sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) + member = parseMemberPointerVariable(type); + } + else if (MATCHES(sequence(VALUETYPE_PADDING, SEPARATOR_SQUAREBRACKETOPEN))) member = parsePadding(); - else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN) && sequence(SEPARATOR_SQUAREBRACKETOPEN))) - member = parseMemberArrayVariable(); - else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER))) - member = parseMemberVariable(); - else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) - member = parseMemberPointerVariable(); else if (MATCHES(sequence(KEYWORD_IF, SEPARATOR_ROUNDBRACKETOPEN))) return parseConditional(); else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) @@ -686,8 +721,6 @@ namespace hex::lang { if (this->m_types.contains(typeName)) throwParseError(hex::format("redefinition of type '{}'", typeName)); - this->m_types.insert({ typeName, new ASTNodeTypeDecl(typeName, nullptr) }); - while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { structNode->addMember(parseMember()); } @@ -706,8 +739,6 @@ namespace hex::lang { if (this->m_types.contains(typeName)) throwParseError(hex::format("redefinition of type '{}'", typeName)); - this->m_types.insert({ typeName, new ASTNodeTypeDecl(typeName, nullptr) }); - while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { unionNode->addMember(parseMember()); } @@ -719,14 +750,9 @@ namespace hex::lang { // enum Identifier : (parseType) { <...> } ASTNode* Parser::parseEnum() { - std::string typeName; - if (peekOptional(KEYWORD_BE) || peekOptional(KEYWORD_LE)) - typeName = getValue(-5); - else - typeName = getValue(-4); + auto typeName = getNamespacePrefixedName(getValue(-2)); - auto underlyingType = dynamic_cast(parseType(-2)); - if (underlyingType == nullptr) throwParseError("failed to parse type", -2); + auto underlyingType = parseType(); if (underlyingType->getEndian().has_value()) throwParseError("underlying type may not have an endian specification", -2); const auto enumNode = new ASTNodeEnum(underlyingType); @@ -735,8 +761,6 @@ namespace hex::lang { if (this->m_types.contains(typeName)) throwParseError(hex::format("redefinition of type '{}'", typeName)); - this->m_types.insert({ typeName, new ASTNodeTypeDecl(typeName, nullptr) }); - ASTNode *lastEntry = nullptr; while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { if (MATCHES(sequence(IDENTIFIER, OPERATOR_ASSIGNMENT))) { @@ -784,8 +808,6 @@ namespace hex::lang { if (this->m_types.contains(typeName)) throwParseError(hex::format("redefinition of type '{}'", typeName)); - this->m_types.insert({ typeName, new ASTNodeTypeDecl(typeName, nullptr) }); - while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { if (MATCHES(sequence(IDENTIFIER, OPERATOR_INHERIT))) { auto name = getValue(-2); @@ -807,18 +829,19 @@ namespace hex::lang { } // (parseType) Identifier @ Integer - ASTNode* Parser::parseVariablePlacement() { - auto type = dynamic_cast(parseType(-3)); - if (type == nullptr) throwParseError("invalid type used in variable declaration", -1); + ASTNode* Parser::parseVariablePlacement(ASTNodeTypeDecl *type) { + auto name = getValue(-1); - return new ASTNodeVariableDecl(getValue(-2), type, parseMathematicalExpression()); + if (!MATCHES(sequence(OPERATOR_AT))) + throwParseError("expected placement instruction", -1); + + auto placementOffset = parseMathematicalExpression(); + + return new ASTNodeVariableDecl(name, type, placementOffset); } // (parseType) Identifier[[(parseMathematicalExpression)]] @ Integer - ASTNode* Parser::parseArrayVariablePlacement() { - auto type = dynamic_cast(parseType(-3)); - if (type == nullptr) throwParseError("invalid type used in variable declaration", -1); - + ASTNode* Parser::parseArrayVariablePlacement(ASTNodeTypeDecl *type) { auto name = getValue(-2); ASTNode *size = nullptr; @@ -837,58 +860,115 @@ namespace hex::lang { if (!MATCHES(sequence(OPERATOR_AT))) throwParseError("expected placement instruction", -1); + auto placementOffset = parseMathematicalExpression(); + sizeCleanup.release(); - return new ASTNodeArrayVariableDecl(name, type, size, parseMathematicalExpression()); + return new ASTNodeArrayVariableDecl(name, type, size, placementOffset); } // (parseType) *Identifier : (parseType) @ Integer - ASTNode* Parser::parsePointerVariablePlacement() { + ASTNode* Parser::parsePointerVariablePlacement(ASTNodeTypeDecl *type) { auto name = getValue(-2); - auto temporaryPointerType = dynamic_cast(parseType(-4)); - if (temporaryPointerType == nullptr) throwParseError("invalid type used in variable declaration", -1); + auto sizeType = parseType(); + auto sizeCleanup = SCOPE_GUARD { delete sizeType; }; - if (!MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && sequence(VALUETYPE_UNSIGNED))) - throwParseError("expected unsigned builtin type as size", -1); + { + auto builtinType = dynamic_cast(sizeType->getType()); - auto temporaryPointerSizeType = dynamic_cast(parseType(-1)); - if (temporaryPointerSizeType == nullptr) throwParseError("invalid size type used in pointer declaration", -1); + if (builtinType == nullptr || !Token::isUnsigned(builtinType->getType())) + throwParseError("invalid type used for pointer size", -1); + } if (!MATCHES(sequence(OPERATOR_AT))) throwParseError("expected placement instruction", -1); - return new ASTNodePointerVariableDecl(name, temporaryPointerType, temporaryPointerSizeType, parseMathematicalExpression()); + auto placementOffset = parseMathematicalExpression(); + + sizeCleanup.release(); + + return new ASTNodePointerVariableDecl(name, type, sizeType, placementOffset); } + std::vector Parser::parseNamespace() { + std::vector statements; + if (!MATCHES(sequence(IDENTIFIER))) + throwParseError("expected namespace identifier"); + + this->m_currNamespace.push_back(this->m_currNamespace.back()); + + while (true) { + this->m_currNamespace.back().push_back(getValue(-1)); + + if (MATCHES(sequence(OPERATOR_SCOPERESOLUTION, IDENTIFIER))) + continue; + else + break; + } + + if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN))) + throwParseError("expected '{' at start of namespace"); + + while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { + auto newStatements = parseStatements(); + std::copy(newStatements.begin(), newStatements.end(), std::back_inserter(statements)); + } + + this->m_currNamespace.pop_back(); + + return statements; + } + + ASTNode* Parser::parsePlacement() { + auto type = parseType(); + + if (MATCHES(sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN))) + return parseArrayVariablePlacement(type); + else if (MATCHES(sequence(IDENTIFIER))) + return parseVariablePlacement(type); + else if (MATCHES(sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) + return parsePointerVariablePlacement(type); + else throwParseError("invalid sequence", 0); + } /* Program */ // <(parseUsingDeclaration)|(parseVariablePlacement)|(parseStruct)> - ASTNode* Parser::parseStatement() { + std::vector Parser::parseStatements() { ASTNode *statement; - if (MATCHES(sequence(KEYWORD_USING, IDENTIFIER, OPERATOR_ASSIGNMENT) && (optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY))) - statement = dynamic_cast(parseUsingDeclaration()); - else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN))) - statement = parseArrayVariablePlacement(); - else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER, OPERATOR_AT))) - statement = parseVariablePlacement(); - else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) - statement = parsePointerVariablePlacement(); + if (MATCHES(sequence(KEYWORD_USING, IDENTIFIER, OPERATOR_ASSIGNMENT))) + statement = parseUsingDeclaration(); + else if (peek(IDENTIFIER)) { + auto originalPos = this->m_curr; + this->m_curr++; + parseScopeResolution(); + bool isFunction = peek(SEPARATOR_ROUNDBRACKETOPEN); + this->m_curr = originalPos; + + if (isFunction) { + this->m_curr++; + statement = parseFunctionCall(); + } + else + statement = parsePlacement(); + } + else if (peek(KEYWORD_BE) || peek(KEYWORD_LE) || peek(VALUETYPE_ANY)) + statement = parsePlacement(); else if (MATCHES(sequence(KEYWORD_STRUCT, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN))) statement = parseStruct(); else if (MATCHES(sequence(KEYWORD_UNION, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN))) statement = parseUnion(); - else if (MATCHES(sequence(KEYWORD_ENUM, IDENTIFIER, OPERATOR_INHERIT) && (optional(KEYWORD_BE), optional(KEYWORD_LE)) && sequence(VALUETYPE_UNSIGNED, SEPARATOR_CURLYBRACKETOPEN))) + else if (MATCHES(sequence(KEYWORD_ENUM, IDENTIFIER, OPERATOR_INHERIT))) statement = parseEnum(); else if (MATCHES(sequence(KEYWORD_BITFIELD, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN))) statement = parseBitfield(); - else if (MATCHES(sequence(IDENTIFIER, SEPARATOR_ROUNDBRACKETOPEN))) - statement = parseFunctionCall(); else if (MATCHES(sequence(KEYWORD_FUNCTION, IDENTIFIER, SEPARATOR_ROUNDBRACKETOPEN))) statement = parseFunctionDefintion(); + else if (MATCHES(sequence(KEYWORD_NAMESPACE))) + return parseNamespace(); else throwParseError("invalid sequence", 0); if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN, SEPARATOR_SQUAREBRACKETOPEN))) @@ -897,18 +977,25 @@ namespace hex::lang { if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) throwParseError("missing ';' at end of expression", -1); - if (auto typeDecl = dynamic_cast(statement); typeDecl != nullptr) - this->m_types.insert({ typeDecl->getName().data(), typeDecl }); + if (auto typeDecl = dynamic_cast(statement); typeDecl != nullptr) { + auto typeName = getNamespacePrefixedName(typeDecl->getName().data()); - return statement; + typeDecl->setName(typeName); + this->m_types.insert({ typeName, typeDecl }); + } + + return { statement }; } - // <(parseStatement)...> EndOfProgram + // <(parseNamespace)...> EndOfProgram std::optional> Parser::parse(const std::vector &tokens) { this->m_curr = tokens.begin(); this->m_types.clear(); + this->m_currNamespace.clear(); + this->m_currNamespace.emplace_back(); + try { auto program = parseTillToken(SEPARATOR_ENDOFPROGRAM); diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index 102daf177..0007513f8 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -15,7 +15,7 @@ namespace hex { static TextEditor::LanguageDefinition langDef; if (!initialized) { static const char* const keywords[] = { - "using", "struct", "union", "enum", "bitfield", "be", "le", "if", "else", "false", "true", "parent", "addressof", "sizeof", "$", "while", "fn", "return" + "using", "struct", "union", "enum", "bitfield", "be", "le", "if", "else", "false", "true", "parent", "addressof", "sizeof", "$", "while", "fn", "return", "namespace" }; for (auto& k : keywords) langDef.mKeywords.insert(k);