diff --git a/cli/source/subcommands/docs.cpp b/cli/source/subcommands/docs.cpp index 37334879..abffcc1c 100644 --- a/cli/source/subcommands/docs.cpp +++ b/cli/source/subcommands/docs.cpp @@ -21,8 +21,8 @@ namespace pl::cli::sub { namespace { - std::string getTypeEndian(const core::ast::ASTNodeTypeDecl *typeDecl) { - auto endian = typeDecl->getEndian(); + std::string getTypeEndian(const core::ast::ASTNodeTypeApplication *typeApp) { + auto endian = typeApp->getEndian(); if (!endian.has_value()) return ""; @@ -35,15 +35,12 @@ namespace pl::cli::sub { } std::string getTypeName(const core::ast::ASTNode *type) { - if (auto builtinType = dynamic_cast(type)) - return core::Token::getTypeName(builtinType->getType()); - else if (auto typeDecl = dynamic_cast(type)) { - if (typeDecl->getName().empty()) - return getTypeEndian(typeDecl) + getTypeName(typeDecl->getType().get()); - else - return getTypeEndian(typeDecl) + typeDecl->getName(); + if (auto typeApp = dynamic_cast(type); typeApp != nullptr) { + return fmt::format("{}{}", getTypeEndian(typeApp), getTypeName(typeApp->getType().get())); + } else if (auto typeDecl = dynamic_cast(type); typeDecl != nullptr) { + return typeDecl->getName(); } else { - return "???"; + return ""; } } @@ -72,12 +69,10 @@ namespace pl::cli::sub { std::string result = "<"; for (const auto &templateParam : templateParams) { - if (auto typeDecl = dynamic_cast(templateParam.get()); typeDecl != nullptr) - result += typeDecl->getName(); - else if (auto lvalue = dynamic_cast(templateParam.get()); lvalue != nullptr) - result += fmt::format("auto {}", lvalue->getLValueName()); - else - continue; + if (templateParam->isType()) + result += templateParam->getName().get(); + else + result += fmt::format("auto {}", templateParam->getName().get()); result += ", "; } @@ -89,8 +84,8 @@ namespace pl::cli::sub { } std::string generateTypeDocumentation(const std::string &name, const core::ast::ASTNodeTypeDecl *type) { - if (auto typeDecl = dynamic_cast(type->getType().get())) { - return fmt::format("```rust\nusing {}{} = {}{};\n```", name, generateTemplateParams(type), getTypeName(typeDecl), generateAttributes(typeDecl)); + if (auto typeApp = dynamic_cast(type->getType().get())) { + return fmt::format("```rust\nusing {}{} = {}{};\n```", name, generateTemplateParams(type), getTypeName(typeApp), generateAttributes(type)); } else if (dynamic_cast(type->getType().get())) { return fmt::format("```rust\nstruct {}{} {{ ... }}{};\n```", name, generateTemplateParams(type), generateAttributes(type)); } else if (dynamic_cast(type->getType().get())) { diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 29cbf1e6..b1935689 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -44,6 +44,7 @@ add_library(libpl ${LIBRARY_TYPE} source/pl/core/ast/ast_node_struct.cpp source/pl/core/ast/ast_node_ternary_expression.cpp source/pl/core/ast/ast_node_try_catch_statement.cpp + source/pl/core/ast/ast_node_type_application.cpp source/pl/core/ast/ast_node_type_decl.cpp source/pl/core/ast/ast_node_type_operator.cpp source/pl/core/ast/ast_node_union.cpp diff --git a/lib/include/pl/core/ast/ast_node_array_variable_decl.hpp b/lib/include/pl/core/ast/ast_node_array_variable_decl.hpp index b77c9e93..2103155f 100644 --- a/lib/include/pl/core/ast/ast_node_array_variable_decl.hpp +++ b/lib/include/pl/core/ast/ast_node_array_variable_decl.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace pl::core::ast { @@ -10,7 +11,7 @@ namespace pl::core::ast { class ASTNodeArrayVariableDecl : public ASTNode, public Attributable { public: - ASTNodeArrayVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&size, std::unique_ptr &&placementOffset = {}, std::unique_ptr &&placementSection = {}, bool constant = false); + ASTNodeArrayVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&size, std::unique_ptr &&placementOffset = {}, std::unique_ptr &&placementSection = {}, bool constant = false); ASTNodeArrayVariableDecl(const ASTNodeArrayVariableDecl &other); [[nodiscard]] std::unique_ptr clone() const override { @@ -24,7 +25,7 @@ namespace pl::core::ast { return this->m_name; } - [[nodiscard]] const std::shared_ptr &getType() const { + [[nodiscard]] const std::shared_ptr &getType() const { return this->m_type; } @@ -42,7 +43,7 @@ namespace pl::core::ast { private: std::string m_name; - std::shared_ptr m_type; + std::shared_ptr m_type; std::unique_ptr m_size; std::unique_ptr m_placementOffset, m_placementSection; bool m_constant; diff --git a/lib/include/pl/core/ast/ast_node_bitfield_array_variable_decl.hpp b/lib/include/pl/core/ast/ast_node_bitfield_array_variable_decl.hpp index 1ec9abf1..1a339fa6 100644 --- a/lib/include/pl/core/ast/ast_node_bitfield_array_variable_decl.hpp +++ b/lib/include/pl/core/ast/ast_node_bitfield_array_variable_decl.hpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include @@ -15,7 +15,7 @@ namespace pl::core::ast { class ASTNodeBitfieldArrayVariableDecl : public ASTNode, public Attributable { public: - ASTNodeBitfieldArrayVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&size); + ASTNodeBitfieldArrayVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&size); ASTNodeBitfieldArrayVariableDecl(const ASTNodeBitfieldArrayVariableDecl &other); [[nodiscard]] std::unique_ptr clone() const override { @@ -28,7 +28,7 @@ namespace pl::core::ast { return this->m_name; } - [[nodiscard]] const std::shared_ptr &getType() const { + [[nodiscard]] const std::shared_ptr &getType() const { return this->m_type; } @@ -38,7 +38,7 @@ namespace pl::core::ast { private: std::string m_name; - std::shared_ptr m_type; + std::shared_ptr m_type; std::unique_ptr m_size; void createArray(Evaluator *evaluator, std::shared_ptr &resultPattern) const; diff --git a/lib/include/pl/core/ast/ast_node_bitfield_field.hpp b/lib/include/pl/core/ast/ast_node_bitfield_field.hpp index 99e77fe6..2983edfb 100644 --- a/lib/include/pl/core/ast/ast_node_bitfield_field.hpp +++ b/lib/include/pl/core/ast/ast_node_bitfield_field.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include @@ -42,7 +42,7 @@ namespace pl::core::ast { class ASTNodeBitfieldFieldSizedType : public ASTNodeBitfieldField { public: - ASTNodeBitfieldFieldSizedType(std::string name, std::unique_ptr &&type, std::unique_ptr &&size); + ASTNodeBitfieldFieldSizedType(std::string name, std::unique_ptr &&type, std::unique_ptr &&size); ASTNodeBitfieldFieldSizedType(const ASTNodeBitfieldFieldSizedType &other); [[nodiscard]] std::unique_ptr clone() const override { @@ -52,7 +52,7 @@ namespace pl::core::ast { [[nodiscard]] std::shared_ptr createBitfield(Evaluator *evaluator, u64 byteOffset, u8 bitOffset, u8 bitSize) const override; private: - std::unique_ptr m_type; + std::unique_ptr m_type; }; } \ No newline at end of file diff --git a/lib/include/pl/core/ast/ast_node_cast.hpp b/lib/include/pl/core/ast/ast_node_cast.hpp index 125b6910..6f42759d 100644 --- a/lib/include/pl/core/ast/ast_node_cast.hpp +++ b/lib/include/pl/core/ast/ast_node_cast.hpp @@ -1,12 +1,13 @@ #pragma once #include +#include namespace pl::core::ast { class ASTNodeCast : public ASTNode { public: - ASTNodeCast(std::unique_ptr &&value, std::unique_ptr &&type, bool reinterpret); + ASTNodeCast(std::unique_ptr &&value, std::unique_ptr &&type, bool reinterpret); ASTNodeCast(const ASTNodeCast &other); [[nodiscard]] std::unique_ptr clone() const override { @@ -20,7 +21,7 @@ namespace pl::core::ast { private: std::unique_ptr m_value; - std::unique_ptr m_type; + std::unique_ptr m_type; bool m_reinterpret; }; diff --git a/lib/include/pl/core/ast/ast_node_pointer_variable_decl.hpp b/lib/include/pl/core/ast/ast_node_pointer_variable_decl.hpp index ee2176db..48668b3b 100644 --- a/lib/include/pl/core/ast/ast_node_pointer_variable_decl.hpp +++ b/lib/include/pl/core/ast/ast_node_pointer_variable_decl.hpp @@ -2,7 +2,7 @@ #include #include - +#include namespace pl::core::ast { @@ -11,7 +11,7 @@ namespace pl::core::ast { class ASTNodePointerVariableDecl : public ASTNode, public Attributable { public: - ASTNodePointerVariableDecl(std::string name, std::shared_ptr type, std::shared_ptr sizeType, std::unique_ptr &&placementOffset = nullptr, std::unique_ptr &&placementSection = nullptr); + ASTNodePointerVariableDecl(std::string name, std::shared_ptr type, std::shared_ptr sizeType, std::unique_ptr &&placementOffset = nullptr, std::unique_ptr &&placementSection = nullptr); ASTNodePointerVariableDecl(const ASTNodePointerVariableDecl &other); [[nodiscard]] std::unique_ptr clone() const override { @@ -20,7 +20,7 @@ namespace pl::core::ast { [[nodiscard]] const std::string &getName() const { return this->m_name; } [[nodiscard]] constexpr const std::shared_ptr &getType() const { return this->m_type; } - [[nodiscard]] constexpr const std::shared_ptr &getSizeType() const { return this->m_sizeType; } + [[nodiscard]] constexpr const std::shared_ptr &getSizeType() const { return this->m_sizeType; } [[nodiscard]] constexpr const std::unique_ptr &getPlacementOffset() const { return this->m_placementOffset; } void createPatterns(Evaluator *evaluator, std::vector> &resultPatterns) const override; @@ -28,7 +28,7 @@ namespace pl::core::ast { private: std::string m_name; std::shared_ptr m_type; - std::shared_ptr m_sizeType; + std::shared_ptr m_sizeType; std::unique_ptr m_placementOffset, m_placementSection; }; diff --git a/lib/include/pl/core/ast/ast_node_scope_resolution.hpp b/lib/include/pl/core/ast/ast_node_scope_resolution.hpp index 77937640..4a151a56 100644 --- a/lib/include/pl/core/ast/ast_node_scope_resolution.hpp +++ b/lib/include/pl/core/ast/ast_node_scope_resolution.hpp @@ -1,12 +1,13 @@ #pragma once #include +#include namespace pl::core::ast { class ASTNodeScopeResolution : public ASTNode { public: - explicit ASTNodeScopeResolution(std::shared_ptr &&type, std::string name); + explicit ASTNodeScopeResolution(std::shared_ptr &&type, std::string name); ASTNodeScopeResolution(const ASTNodeScopeResolution &other); [[nodiscard]] std::unique_ptr clone() const override { @@ -16,7 +17,7 @@ namespace pl::core::ast { [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override; private: - std::shared_ptr m_type; + std::shared_ptr m_type; std::string m_name; }; diff --git a/lib/include/pl/core/ast/ast_node_template_parameter.hpp b/lib/include/pl/core/ast/ast_node_template_parameter.hpp new file mode 100644 index 00000000..33e5c997 --- /dev/null +++ b/lib/include/pl/core/ast/ast_node_template_parameter.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +namespace pl::core::ast { + + class ASTNodeTemplateParameter : public ASTNode { + public: + explicit ASTNodeTemplateParameter(Token::Identifier name, bool isType) + : m_name(std::move(name)), m_isType(isType) {} + + ASTNodeTemplateParameter(const ASTNodeTemplateParameter &) = default; + + [[nodiscard]] std::unique_ptr clone() const override { + return std::unique_ptr(new ASTNodeTemplateParameter(*this)); + } + + [[nodiscard]] const auto &getName() const { + return this->m_name; + } + + [[nodiscard]] bool isType() const { + return this->m_isType; + } + + private: + Token::Identifier m_name; + bool m_isType; + }; + +} \ No newline at end of file diff --git a/lib/include/pl/core/ast/ast_node_type_appilication.hpp b/lib/include/pl/core/ast/ast_node_type_appilication.hpp new file mode 100644 index 00000000..be68c677 --- /dev/null +++ b/lib/include/pl/core/ast/ast_node_type_appilication.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +namespace pl::core::ast { + + class ASTNodeTypeApplication : public ASTNode { + public: + explicit ASTNodeTypeApplication(std::shared_ptr type); + + ASTNodeTypeApplication(const ASTNodeTypeApplication &); + + [[nodiscard]] std::unique_ptr clone() const override { + return std::unique_ptr(new ASTNodeTypeApplication(*this)); + } + + void setTemplateArguments(std::vector> &&arguments) { + this->m_templateArguments = std::move(arguments); + } + + std::vector> evaluateTemplateArguments(Evaluator *evaluator) const; + + [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override; + void createPatterns(Evaluator *evaluator, std::vector> &resultPatterns) const override; + + [[nodiscard]] const std::shared_ptr &getType() const { + return this->m_type; + } + + void setReference(bool reference) { + this->m_reference = reference; + } + + [[nodiscard]] bool isReference() const { + return this->m_reference; + } + + const ast::ASTNode* getTypeDefinition(Evaluator *evaluator) const; + + [[nodiscard]] const std::string getTypeName() const; + + void setEndian(std::endian endian) { + this->m_endian = endian; + } + + [[nodiscard]] std::optional getEndian() const { return this->m_endian; } + + void setTemplateParameterIndex(int index) { + this->m_templateParameterIndex = index; + } + + [[nodiscard]] int getTemplateParameterIndex() const { + return this->m_templateParameterIndex; + } + + private: + std::shared_ptr m_type; + std::vector> m_templateArguments; + bool m_reference = false; + std::optional m_endian; + size_t m_templateParameterIndex = 0; + }; + +} \ No newline at end of file diff --git a/lib/include/pl/core/ast/ast_node_type_decl.hpp b/lib/include/pl/core/ast/ast_node_type_decl.hpp index 13dbb391..162e7b5d 100644 --- a/lib/include/pl/core/ast/ast_node_type_decl.hpp +++ b/lib/include/pl/core/ast/ast_node_type_decl.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -10,11 +11,13 @@ namespace pl::core::ast { + class ASTNodeTypeApplication; + class ASTNodeTypeDecl : public ASTNode, public Attributable { public: explicit ASTNodeTypeDecl(std::string name); - ASTNodeTypeDecl(std::string name, std::shared_ptr type, std::optional endian = std::nullopt); + ASTNodeTypeDecl(std::string name, std::shared_ptr type); ASTNodeTypeDecl(const ASTNodeTypeDecl &other); [[nodiscard]] std::unique_ptr clone() const override { @@ -26,71 +29,54 @@ namespace pl::core::ast { } [[nodiscard]] const std::string &getName() const { return this->m_name; } [[nodiscard]] const std::shared_ptr &getType() const; - [[nodiscard]] std::optional getEndian() const { return this->m_endian; } - [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override; void createPatterns(Evaluator *evaluator, std::vector> &resultPatterns) const override; void addAttribute(std::unique_ptr &&attribute) override; [[nodiscard]] bool isValid() const { - return this->m_valid; + return this->m_type != nullptr; } [[nodiscard]] bool isTemplateType() const { - return this->m_templateType; + return !this->m_templateParameters.empty(); } [[nodiscard]] bool isForwardDeclared() const { return this->m_forwardDeclared; } - void setReference(bool reference) { - this->m_reference = reference; - } - - [[nodiscard]] bool isReference() const { - return this->m_reference; - } - void setCompleted(bool completed = true) { this->m_completed = completed; } - void setType(std::shared_ptr type, bool templateType = false) { - this->m_valid = true; - this->m_templateType = templateType; + void setType(std::shared_ptr type) { this->m_type = std::move(type); } - void setEndian(std::endian endian) { - this->m_endian = endian; - } - [[nodiscard]] const std::vector> &getTemplateParameters() const { + [[nodiscard]] const std::vector> &getTemplateParameters() const { return this->m_templateParameters; } - void setTemplateParameters(std::vector> &&types) { - if (!types.empty()) - this->m_templateType = true; - + void setTemplateParameters(std::vector> &&types) { this->m_templateParameters = std::move(types); } + [[nodiscard]] const std::string getTypeName() const; + + const ASTNode* getTypeDefinition(Evaluator *evaluator) const; + private: bool m_forwardDeclared = false; - bool m_valid = true; - bool m_templateType = false; bool m_completed = false; mutable bool m_alreadyCopied = false; std::string m_name; std::shared_ptr m_type; - std::optional m_endian; - std::vector> m_templateParameters; - bool m_reference = false; + std::vector> m_templateParameters; + std::vector> m_templateArguments; - mutable std::unique_ptr m_currTemplateParameterType; + mutable std::unique_ptr m_currTemplateParameterType; }; } \ No newline at end of file diff --git a/lib/include/pl/core/ast/ast_node_variable_decl.hpp b/lib/include/pl/core/ast/ast_node_variable_decl.hpp index c409bb5c..85d8cf90 100644 --- a/lib/include/pl/core/ast/ast_node_variable_decl.hpp +++ b/lib/include/pl/core/ast/ast_node_variable_decl.hpp @@ -4,13 +4,14 @@ #include #include #include +#include namespace pl::core::ast { class ASTNodeVariableDecl : public ASTNode, public Attributable { public: - ASTNodeVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&placementOffset = nullptr, std::unique_ptr &&placementSection = nullptr, bool inVariable = false, bool outVariable = false, bool constant = false); + ASTNodeVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&placementOffset = nullptr, std::unique_ptr &&placementSection = nullptr, bool inVariable = false, bool outVariable = false, bool constant = false); ASTNodeVariableDecl(const ASTNodeVariableDecl &other); @@ -19,7 +20,7 @@ namespace pl::core::ast { } [[nodiscard]] const std::string &getName() const { return this->m_name; } - [[nodiscard]] constexpr const std::shared_ptr &getType() const { return this->m_type; } + [[nodiscard]] constexpr const std::shared_ptr &getType() const { return this->m_type; } [[nodiscard]] constexpr const std::unique_ptr &getPlacementOffset() const { return this->m_placementOffset; } [[nodiscard]] constexpr bool isInVariable() const { return this->m_inVariable; } @@ -39,7 +40,7 @@ namespace pl::core::ast { private: std::string m_name; - std::shared_ptr m_type; + std::shared_ptr m_type; std::unique_ptr m_placementOffset, m_placementSection; bool m_inVariable = false, m_outVariable = false; diff --git a/lib/include/pl/core/evaluator.hpp b/lib/include/pl/core/evaluator.hpp index 5e60292e..4d644c17 100644 --- a/lib/include/pl/core/evaluator.hpp +++ b/lib/include/pl/core/evaluator.hpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -138,10 +139,7 @@ namespace pl::core { } void pushTemplateParameters() { - if (this->m_templateParameters.empty()) this->m_templateParameters.emplace_back(); - else - this->m_templateParameters.push_back(this->m_templateParameters.back()); } void popTemplateParameters() { @@ -156,6 +154,34 @@ namespace pl::core { return this->m_templateParameters.back(); } + void pushTypeTemplateParameters() { + this->m_typeTemplateParameters.emplace_back(); + } + + void popTypeTemplateParameters() { + this->m_typeTemplateParameters.pop_back(); + } + + [[nodiscard]] const std::vector>& getTypeTemplateParameters() const { + return this->m_typeTemplateParameters.back(); + } + + [[nodiscard]] std::vector>& getTypeTemplateParameters() { + return this->m_typeTemplateParameters.back(); + } + + void setCurrentTemplateArguments(std::vector> &&args) { + this->m_currentTemplateArguments = std::move(args); + } + + [[nodiscard]] const std::vector>& getCurrentTemplateArguments() const { + return this->m_currentTemplateArguments; + } + + [[nodiscard]] std::vector>& getCurrentTemplateArguments() { + return this->m_currentTemplateArguments; + } + void pushSectionId(u64 id); void popSectionId(); [[nodiscard]] u64 getSectionId() const; @@ -304,7 +330,7 @@ namespace pl::core { void createParameterPack(const std::string &name, const std::vector &values); void createArrayVariable(const std::string &name, const ast::ASTNode *type, size_t entryCount, u64 section, bool constant = false); - std::shared_ptr createVariable(const std::string &name, const ast::ASTNodeTypeDecl *type, const std::optional &value = std::nullopt, bool outVariable = false, bool reference = false, bool templateVariable = false, bool constant = false); + std::shared_ptr createVariable(const std::string &name, const ast::ASTNodeTypeApplication *type, const std::optional &value = std::nullopt, bool outVariable = false, bool reference = false, bool templateVariable = false, bool constant = false); std::shared_ptr& getVariableByName(const std::string &name); void setVariable(const std::string &name, const Token::Literal &value); void setVariable(std::shared_ptr &pattern, const Token::Literal &value); @@ -465,7 +491,6 @@ namespace pl::core { this->m_patternLanguage = runtime; } - std::optional findTypeName(const ast::ASTNodeTypeDecl *type); void addAttributedPattern(const std::string &attribute, ptrn::Pattern *pattern) { m_attributedPatterns[attribute].insert(pattern); @@ -521,6 +546,8 @@ namespace pl::core { std::map> m_outVariables; std::map m_outVariableValues; std::vector>> m_templateParameters; + std::vector>> m_typeTemplateParameters; + std::vector> m_currentTemplateArguments; std::function m_dangerousFunctionCalledCallback = []{ return false; }; std::function m_breakpointHitCallback = []{ }; diff --git a/lib/include/pl/core/parser.hpp b/lib/include/pl/core/parser.hpp index 427faa72..76b40540 100644 --- a/lib/include/pl/core/parser.hpp +++ b/lib/include/pl/core/parser.hpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include @@ -182,29 +184,28 @@ namespace pl::core { hlp::safe_unique_ptr parseMatchStatement(const std::function()> &memberParser); hlp::safe_unique_ptr parseTryCatchStatement(const std::function()> &memberParser); hlp::safe_unique_ptr parseWhileStatement(); - hlp::safe_unique_ptr getCustomType(const std::string &baseTypeName); - hlp::safe_unique_ptr parseCustomType(); - void parseCustomTypeParameters(hlp::safe_unique_ptr &type); - hlp::safe_unique_ptr parseType(); - std::vector> parseTemplateList(); + hlp::safe_unique_ptr getCustomType(const std::string &baseTypeName); + hlp::safe_unique_ptr parseCustomType(); + void parseCustomTypeParameters(hlp::safe_unique_ptr &type); + hlp::safe_unique_ptr parseType(); + std::vector> parseTemplateList(); hlp::safe_shared_ptr parseImportStatement(); hlp::safe_shared_ptr parseUsingDeclaration(); hlp::safe_unique_ptr parsePadding(); - hlp::safe_unique_ptr parseMemberVariable(const hlp::safe_shared_ptr &type, bool constant, const std::string &identifier); - hlp::safe_unique_ptr parseMemberArrayVariable(const hlp::safe_shared_ptr &type, bool constant); - hlp::safe_unique_ptr parseMemberPointerVariable(const hlp::safe_shared_ptr &type); - hlp::safe_unique_ptr parseMemberPointerArrayVariable(const hlp::safe_shared_ptr &type); + hlp::safe_unique_ptr parseMemberVariable(const hlp::safe_shared_ptr &type, bool constant, const std::string &identifier); + hlp::safe_unique_ptr parseMemberArrayVariable(const hlp::safe_shared_ptr &type, bool constant); + hlp::safe_unique_ptr parseMemberPointerVariable(const hlp::safe_shared_ptr &type); + hlp::safe_unique_ptr parseMemberPointerArrayVariable(const hlp::safe_shared_ptr &type); hlp::safe_unique_ptr parseMember(); hlp::safe_shared_ptr parseStruct(); hlp::safe_shared_ptr parseUnion(); hlp::safe_shared_ptr parseEnum(); hlp::safe_shared_ptr parseBitfield(); hlp::safe_unique_ptr parseBitfieldEntry(); - void parseForwardDeclaration(); - hlp::safe_unique_ptr parseVariablePlacement(const hlp::safe_shared_ptr &type); - hlp::safe_unique_ptr parseArrayVariablePlacement(const hlp::safe_shared_ptr &type); - hlp::safe_unique_ptr parsePointerVariablePlacement(const hlp::safe_shared_ptr &type); - hlp::safe_unique_ptr parsePointerArrayVariablePlacement(const hlp::safe_shared_ptr &type); + hlp::safe_unique_ptr parseVariablePlacement(const hlp::safe_shared_ptr &type); + hlp::safe_unique_ptr parseArrayVariablePlacement(const hlp::safe_shared_ptr &type); + hlp::safe_unique_ptr parsePointerVariablePlacement(const hlp::safe_shared_ptr &type); + hlp::safe_unique_ptr parsePointerArrayVariablePlacement(const hlp::safe_shared_ptr &type); hlp::safe_unique_ptr parsePlacement(); std::vector> parseNamespace(); std::vector> parseStatements(); @@ -213,7 +214,7 @@ namespace pl::core { std::optional parseDocComment(bool global); - hlp::safe_shared_ptr addType(const std::string &name, hlp::safe_unique_ptr &&node, std::optional endian = std::nullopt); + hlp::safe_shared_ptr addType(const std::string &name, hlp::safe_unique_ptr &&node); void includeGuard(); diff --git a/lib/include/pl/core/parser_manager.hpp b/lib/include/pl/core/parser_manager.hpp index e588f1a2..24da9bbc 100644 --- a/lib/include/pl/core/parser_manager.hpp +++ b/lib/include/pl/core/parser_manager.hpp @@ -36,6 +36,20 @@ namespace pl::core { void reset() { this->m_onceIncluded.clear(); + for (const auto &[_, types] : this->m_parsedTypes) { + for (const auto &[_, type] : types) { + if (type != nullptr && type->isValid()) { + if (auto builtinType = dynamic_cast(type->getType().get()); builtinType != nullptr) { + if (builtinType->getType() != Token::ValueType::CustomType) { + type->setType(nullptr); + } + } + } else { + type->setType(nullptr); + } + } + } + this->m_parsedTypes.clear(); } diff --git a/lib/source/pl/core/ast/ast_node_array_variable_decl.cpp b/lib/source/pl/core/ast/ast_node_array_variable_decl.cpp index 7f68c239..93bf5378 100644 --- a/lib/source/pl/core/ast/ast_node_array_variable_decl.cpp +++ b/lib/source/pl/core/ast/ast_node_array_variable_decl.cpp @@ -18,15 +18,12 @@ namespace pl::core::ast { - ASTNodeArrayVariableDecl::ASTNodeArrayVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&size, std::unique_ptr &&placementOffset, std::unique_ptr &&placementSection, bool constant) + ASTNodeArrayVariableDecl::ASTNodeArrayVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&size, std::unique_ptr &&placementOffset, std::unique_ptr &&placementSection, bool constant) :m_name(std::move(name)), m_type(std::move(type)), m_size(std::move(size)), m_placementOffset(std::move(placementOffset)), m_placementSection(std::move(placementSection)), m_constant(constant) { } ASTNodeArrayVariableDecl::ASTNodeArrayVariableDecl(const ASTNodeArrayVariableDecl &other) : ASTNode(other), Attributable(other) { this->m_name = other.m_name; - if (other.m_type->isForwardDeclared()) - this->m_type = other.m_type; - else - this->m_type = std::shared_ptr(static_cast(other.m_type->clone().release())); + this->m_type = std::shared_ptr(static_cast(other.m_type->clone().release())); if (other.m_size != nullptr) this->m_size = other.m_size->clone(); @@ -79,14 +76,14 @@ namespace pl::core::ast { evaluator->setBitwiseReadOffset(startOffset); this->execute(evaluator); } else { - auto type = this->m_type->evaluate(evaluator); + auto type = this->m_type->getTypeDefinition(evaluator); auto &pattern = resultPatterns.emplace_back(); - if (auto builtinType = dynamic_cast(type.get()); builtinType != nullptr && builtinType->getType() != Token::ValueType::CustomType) + if (auto builtinType = dynamic_cast(type); builtinType != nullptr && builtinType->getType() != Token::ValueType::CustomType) createStaticArray(evaluator, pattern); else { bool isStaticType = false; - if (auto attributable = dynamic_cast(type.get())) + if (auto attributable = dynamic_cast(type)) isStaticType = attributable->hasAttribute("static", false); if (isStaticType) diff --git a/lib/source/pl/core/ast/ast_node_bitfield_array_variable_decl.cpp b/lib/source/pl/core/ast/ast_node_bitfield_array_variable_decl.cpp index 7d82fa32..7bc284bb 100644 --- a/lib/source/pl/core/ast/ast_node_bitfield_array_variable_decl.cpp +++ b/lib/source/pl/core/ast/ast_node_bitfield_array_variable_decl.cpp @@ -5,15 +5,12 @@ namespace pl::core::ast { - ASTNodeBitfieldArrayVariableDecl::ASTNodeBitfieldArrayVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&size) + ASTNodeBitfieldArrayVariableDecl::ASTNodeBitfieldArrayVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&size) : ASTNode(), m_name(std::move(name)), m_type(std::move(type)), m_size(std::move(size)) { } ASTNodeBitfieldArrayVariableDecl::ASTNodeBitfieldArrayVariableDecl(const ASTNodeBitfieldArrayVariableDecl &other) : ASTNode(other), Attributable(other) { this->m_name = other.m_name; - if (other.m_type->isForwardDeclared()) - this->m_type = other.m_type; - else - this->m_type = std::shared_ptr(static_cast(other.m_type->clone().release())); + this->m_type = std::shared_ptr(static_cast(other.m_type->clone().release())); if (other.m_size != nullptr) this->m_size = other.m_size->clone(); @@ -24,11 +21,11 @@ namespace pl::core::ast { auto startOffset = evaluator->getBitwiseReadOffset(); - auto type = this->m_type->evaluate(evaluator); + auto type = this->m_type->getTypeDefinition(evaluator); auto &pattern = resultPatterns.emplace_back(); - if (dynamic_cast(type.get()) != nullptr - || dynamic_cast(type.get()) != nullptr) { + if (dynamic_cast(type) != nullptr + || dynamic_cast(type) != nullptr) { createArray(evaluator, pattern); } else { err::E0001.throwError("Bitfield arrays may only contain bitwise fields.", { }, this->getLocation()); diff --git a/lib/source/pl/core/ast/ast_node_bitfield_field.cpp b/lib/source/pl/core/ast/ast_node_bitfield_field.cpp index e887bfec..a901d8c7 100644 --- a/lib/source/pl/core/ast/ast_node_bitfield_field.cpp +++ b/lib/source/pl/core/ast/ast_node_bitfield_field.cpp @@ -61,11 +61,11 @@ namespace pl::core::ast { } - ASTNodeBitfieldFieldSizedType::ASTNodeBitfieldFieldSizedType(std::string name, std::unique_ptr &&type, std::unique_ptr &&size) + ASTNodeBitfieldFieldSizedType::ASTNodeBitfieldFieldSizedType(std::string name, std::unique_ptr &&type, std::unique_ptr &&size) : ASTNodeBitfieldField(std::move(name), std::move(size)), m_type(std::move(type)) { } ASTNodeBitfieldFieldSizedType::ASTNodeBitfieldFieldSizedType(const ASTNodeBitfieldFieldSizedType &other) : ASTNodeBitfieldField(other) { - this->m_type = std::unique_ptr(static_cast(other.m_type->clone().release())); + this->m_type = std::unique_ptr(static_cast(other.m_type->clone().release())); } [[nodiscard]] std::shared_ptr ASTNodeBitfieldFieldSizedType::createBitfield(Evaluator *evaluator, u64 byteOffset, u8 bitOffset, u8 bitSize) const { diff --git a/lib/source/pl/core/ast/ast_node_cast.cpp b/lib/source/pl/core/ast/ast_node_cast.cpp index e92c7295..1f5681e0 100644 --- a/lib/source/pl/core/ast/ast_node_cast.cpp +++ b/lib/source/pl/core/ast/ast_node_cast.cpp @@ -105,11 +105,11 @@ namespace pl::core::ast { literal)); } - ASTNodeCast::ASTNodeCast(std::unique_ptr &&value, std::unique_ptr &&type, bool reinterpret) : m_value(std::move(value)), m_type(std::move(type)), m_reinterpret(reinterpret) { } + ASTNodeCast::ASTNodeCast(std::unique_ptr &&value, std::unique_ptr &&type, bool reinterpret) : m_value(std::move(value)), m_type(std::move(type)), m_reinterpret(reinterpret) { } ASTNodeCast::ASTNodeCast(const ASTNodeCast &other) : ASTNode(other) { this->m_value = other.m_value->clone(); - this->m_type = other.m_type->clone(); + this->m_type = std::unique_ptr(dynamic_cast(other.m_type->clone().release())); this->m_reinterpret = other.m_reinterpret; } @@ -123,7 +123,7 @@ namespace pl::core::ast { ON_SCOPE_EXIT { evaluator->popSectionId(); }; auto evaluatedValue = this->m_value->evaluate(evaluator); - auto evaluatedType = this->m_type->evaluate(evaluator); + auto evaluatedType = this->m_type->getTypeDefinition(evaluator); auto literal = dynamic_cast(evaluatedValue.get()); if (literal == nullptr) @@ -139,7 +139,7 @@ namespace pl::core::ast { auto value = literal->getValue(); if (!m_reinterpret) { - auto type = dynamic_cast(evaluatedType.get())->getType(); + auto type = dynamic_cast(evaluatedType)->getType(); value = std::visit(wolv::util::overloaded { [&evaluator, &type](const std::shared_ptr &value) -> Token::Literal { diff --git a/lib/source/pl/core/ast/ast_node_function_definition.cpp b/lib/source/pl/core/ast/ast_node_function_definition.cpp index 5f02cfd6..25ae569f 100644 --- a/lib/source/pl/core/ast/ast_node_function_definition.cpp +++ b/lib/source/pl/core/ast/ast_node_function_definition.cpp @@ -83,7 +83,7 @@ namespace pl::core::ast { for (u32 paramIndex = 0; paramIndex < this->m_params.size() && paramIndex < params.size(); paramIndex++) { const auto &[name, type] = this->m_params[paramIndex]; - if (auto typeNode = dynamic_cast(type.get()); typeNode != nullptr) { + if (auto typeNode = dynamic_cast(type.get()); typeNode != nullptr) { bool reference = typeNode->isReference(); if (params[paramIndex].isString()) diff --git a/lib/source/pl/core/ast/ast_node_pointer_variable_decl.cpp b/lib/source/pl/core/ast/ast_node_pointer_variable_decl.cpp index 657f179f..f05b160f 100644 --- a/lib/source/pl/core/ast/ast_node_pointer_variable_decl.cpp +++ b/lib/source/pl/core/ast/ast_node_pointer_variable_decl.cpp @@ -10,13 +10,13 @@ namespace pl::core::ast { - ASTNodePointerVariableDecl::ASTNodePointerVariableDecl(std::string name, std::shared_ptr type, std::shared_ptr sizeType, std::unique_ptr &&placementOffset, std::unique_ptr &&placementSection) + ASTNodePointerVariableDecl::ASTNodePointerVariableDecl(std::string name, std::shared_ptr type, std::shared_ptr sizeType, std::unique_ptr &&placementOffset, std::unique_ptr &&placementSection) : ASTNode(), m_name(std::move(name)), m_type(std::move(type)), m_sizeType(std::move(sizeType)), m_placementOffset(std::move(placementOffset)), m_placementSection(std::move(placementSection)) { } ASTNodePointerVariableDecl::ASTNodePointerVariableDecl(const ASTNodePointerVariableDecl &other) : ASTNode(other), Attributable(other) { this->m_name = other.m_name; this->m_type = other.m_type->clone(); - this->m_sizeType = std::shared_ptr(static_cast(other.m_sizeType->clone().release())); + this->m_sizeType = std::shared_ptr(static_cast(other.m_sizeType->clone().release())); if (other.m_placementOffset != nullptr) this->m_placementOffset = other.m_placementOffset->clone(); diff --git a/lib/source/pl/core/ast/ast_node_scope_resolution.cpp b/lib/source/pl/core/ast/ast_node_scope_resolution.cpp index 8c8c708f..e5ee988a 100644 --- a/lib/source/pl/core/ast/ast_node_scope_resolution.cpp +++ b/lib/source/pl/core/ast/ast_node_scope_resolution.cpp @@ -8,7 +8,7 @@ namespace pl::core::ast { - ASTNodeScopeResolution::ASTNodeScopeResolution(std::shared_ptr &&type, std::string name) + ASTNodeScopeResolution::ASTNodeScopeResolution(std::shared_ptr &&type, std::string name) : m_type(std::move(type)), m_name(std::move(name)) { } ASTNodeScopeResolution::ASTNodeScopeResolution(const ASTNodeScopeResolution &other) : ASTNode(other) { @@ -20,9 +20,9 @@ namespace pl::core::ast { [[nodiscard]] std::unique_ptr ASTNodeScopeResolution::evaluate(Evaluator *evaluator) const { [[maybe_unused]] auto context = evaluator->updateRuntime(this); - auto type = this->m_type->evaluate(evaluator); + auto type = this->m_type->getTypeDefinition(evaluator); - if (auto enumType = dynamic_cast(type.get())) { + if (auto enumType = dynamic_cast(type)) { const auto &[min, max] = enumType->getEnumValue(evaluator, m_name); return std::make_unique(min); } else { diff --git a/lib/source/pl/core/ast/ast_node_type_application.cpp b/lib/source/pl/core/ast/ast_node_type_application.cpp new file mode 100644 index 00000000..a2215d30 --- /dev/null +++ b/lib/source/pl/core/ast/ast_node_type_application.cpp @@ -0,0 +1,154 @@ +#include +#include +#include +#include + +namespace pl::core::ast { + + static std::string computeTemplateTypeString(const std::vector> &arguments) { + std::string templateTypeString; + for (size_t i = 0; i < arguments.size(); i++) { + auto &templateArgument = arguments[i]; + if (auto literal = dynamic_cast(templateArgument.get()); literal != nullptr) { + const auto &value = literal->getValue(); + if (value.isString()) { + auto string = value.toString(); + if (string.size() > 32) + string = "..."; + templateTypeString += fmt::format("\"{}\", ", hlp::encodeByteString({ string.begin(), string.end() })); + } + else if (value.isPattern()) { + templateTypeString += fmt::format("{}{{ }}, ", value.toPattern()->getTypeName()); + } + else { + templateTypeString += fmt::format("{}, ", value.toString(true)); + } + } else if (auto typeNode = dynamic_cast(templateArgument.get()); typeNode != nullptr) { + templateTypeString += fmt::format("{}, ", typeNode->getTypeName()); + } + } + + return templateTypeString.size() > 2 ? templateTypeString.substr(0, templateTypeString.size() - 2) : templateTypeString; + } + + ASTNodeTypeApplication::ASTNodeTypeApplication(std::shared_ptr type) + : m_type(std::move(type)) { }; + + ASTNodeTypeApplication::ASTNodeTypeApplication(const ASTNodeTypeApplication &other) + : ASTNode(other), m_type(other.m_type) { + for (const auto &arg : other.m_templateArguments) + this->m_templateArguments.emplace_back(arg->clone()); + }; + + std::vector> ASTNodeTypeApplication::evaluateTemplateArguments(Evaluator *evaluator) const + { + std::vector> templateArgs(this->m_templateArguments.size()); + std::string templateTypeString; + for (size_t i = 0; i < this->m_templateArguments.size(); i++) { + auto &templateArgument = this->m_templateArguments[i]; + templateArgs[i] = templateArgument->evaluate(evaluator); + } + + return templateArgs; + } + + + [[nodiscard]] std::unique_ptr ASTNodeTypeApplication::evaluate(Evaluator *evaluator) const { + [[maybe_unused]] auto context = evaluator->updateRuntime(this); + auto evaluatedTemplateArguments = this->evaluateTemplateArguments(evaluator); + auto evaluatedType = std::make_unique(this->m_type); + if (this->m_type == nullptr) { + auto& templateTypeParameters = evaluator->getTypeTemplateParameters(); + if (this->m_templateParameterIndex >= templateTypeParameters.size()) { + err::E0004.throwError("Template parameter index out of bounds.", {}, this->getLocation()); + } else { + evaluatedType->m_type = templateTypeParameters[this->m_templateParameterIndex]; + } + } else { + evaluatedType->m_type = this->m_type; + } + + evaluatedType->m_templateArguments = std::move(evaluatedTemplateArguments); + evaluatedType->setLocation(this->getLocation()); + evaluatedType->setShouldDocument(this->shouldDocument()); + evaluatedType->setDocComment(this->getDocComment()); + return evaluatedType; + } + + void ASTNodeTypeApplication::createPatterns(Evaluator *evaluator, std::vector> &resultPatterns) const { + [[maybe_unused]] auto context = evaluator->updateRuntime(this); + auto actualType = this->m_type; + if (actualType == nullptr) { + auto& templateTypeParameters = evaluator->getTypeTemplateParameters(); + if (this->m_templateParameterIndex >= templateTypeParameters.size()) { + err::E0004.throwError("Template parameter index out of bounds.", {}, this->getLocation()); + } + actualType = templateTypeParameters[this->m_templateParameterIndex]; + + if (actualType.get() == this) { + err::E0004.throwError("Recursive type definition detected.", {}, this->getLocation()); + } + } + + auto templateArgs = this->evaluateTemplateArguments(evaluator); + auto templateTypeString = computeTemplateTypeString(templateArgs); + evaluator->setCurrentTemplateArguments(std::move(templateArgs)); + auto currEndian = evaluator->getDefaultEndian(); + ON_SCOPE_EXIT { evaluator->setDefaultEndian(currEndian); }; + + evaluator->setDefaultEndian(this->m_endian.value_or(currEndian)); + actualType->createPatterns(evaluator, resultPatterns); + for(auto& pattern : resultPatterns) { + if (!pattern->hasOverriddenEndian()) + pattern->setEndian(evaluator->getDefaultEndian()); + if (auto typeDecl = dynamic_cast(actualType.get()); typeDecl != nullptr) { + if (!typeDecl->getName().empty()) { + if (this->m_templateArguments.empty()) { + pattern->setTypeName(typeDecl->getName()); + } else { + pattern->setTypeName(fmt::format("{}<{}>", typeDecl->getName(), templateTypeString)); + } + } + } + } + } + + const ast::ASTNode* ASTNodeTypeApplication::getTypeDefinition(Evaluator *evaluator) const{ + if (this->m_type == nullptr) { + auto& templateTypeParameters = evaluator->getTypeTemplateParameters(); + if (this->m_templateParameterIndex >= templateTypeParameters.size()) { + err::E0004.throwError("Template parameter index out of bounds.", {}, this->getLocation()); + } + auto type = templateTypeParameters[this->m_templateParameterIndex].get(); + if (auto typeApp = dynamic_cast(type); typeApp != nullptr) { + return typeApp->getTypeDefinition(evaluator); + } + } + + ast::ASTNode* type = this->getType().get(); + if (auto typDecl = dynamic_cast(type); typDecl != nullptr) { + return typDecl->getTypeDefinition(evaluator); + } else if(auto builtinType = dynamic_cast(type); builtinType != nullptr) { + return builtinType; + } + + return nullptr; + } + + [[nodiscard]] const std::string ASTNodeTypeApplication::getTypeName() const { + if(auto typeDecl = dynamic_cast(this->m_type.get()); typeDecl != nullptr) { + std::string typeName = typeDecl->getName(); + if (this->m_templateArguments.empty()) { + return typeName; + } else { + return fmt::format("{}<{}>", typeName, computeTemplateTypeString(this->m_templateArguments)); + } + } else if(auto builtinType = dynamic_cast(this->m_type.get()); builtinType != nullptr) { + return Token::getTypeName(builtinType->getType()); + } else if(auto typeApp = dynamic_cast(this->m_type.get()); typeApp != nullptr) { + return typeApp->getTypeName(); + } else { + return "????"; + } + } +} \ No newline at end of file diff --git a/lib/source/pl/core/ast/ast_node_type_decl.cpp b/lib/source/pl/core/ast/ast_node_type_decl.cpp index 7db99ca1..e037eedd 100644 --- a/lib/source/pl/core/ast/ast_node_type_decl.cpp +++ b/lib/source/pl/core/ast/ast_node_type_decl.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include @@ -8,10 +10,10 @@ namespace pl::core::ast { - ASTNodeTypeDecl::ASTNodeTypeDecl(std::string name) : m_forwardDeclared(true), m_valid(false), m_name(std::move(name)) { } + ASTNodeTypeDecl::ASTNodeTypeDecl(std::string name) : m_forwardDeclared(true), m_name(std::move(name)) { } - ASTNodeTypeDecl::ASTNodeTypeDecl(std::string name, std::shared_ptr type, std::optional endian) - : m_name(std::move(name)), m_type(std::move(type)), m_endian(endian) { } + ASTNodeTypeDecl::ASTNodeTypeDecl(std::string name, std::shared_ptr type) + : m_name(std::move(name)), m_type(std::move(type)){ } ASTNodeTypeDecl::ASTNodeTypeDecl(const ASTNodeTypeDecl &other) : ASTNode(other), Attributable(other) { this->m_name = other.m_name; @@ -26,15 +28,14 @@ namespace pl::core::ast { } } - this->m_endian = other.m_endian; this->m_forwardDeclared = other.m_forwardDeclared; - this->m_reference = other.m_reference; this->m_completed = other.m_completed; - this->m_valid = other.m_valid; - this->m_templateType = other.m_templateType; for (const auto &templateParameter : other.m_templateParameters) { - this->m_templateParameters.push_back(templateParameter->clone()); + this->m_templateParameters.push_back(std::shared_ptr(dynamic_cast(templateParameter->clone().release()))); + } + for (const auto &templateArguments : other.m_templateArguments) { + this->m_templateArguments.push_back(templateArguments->clone()); } } @@ -45,81 +46,30 @@ namespace pl::core::ast { return this->m_type; } - [[nodiscard]] std::unique_ptr ASTNodeTypeDecl::evaluate(Evaluator *evaluator) const { - [[maybe_unused]] auto context = evaluator->updateRuntime(this); - - auto type = this->getType()->evaluate(evaluator); - - if (auto attributable = dynamic_cast(type.get())) { - for (auto &attribute : this->getAttributes()) { - auto copy = attribute->clone(); - if (auto node = dynamic_cast(copy.get())) { - attributable->addAttribute(std::unique_ptr(node)); - (void)copy.release(); - } - } - } - - return type; - } - void ASTNodeTypeDecl::createPatterns(Evaluator *evaluator, std::vector> &resultPatterns) const { [[maybe_unused]] auto context = evaluator->updateRuntime(this); - std::vector> templateParamLiterals(this->m_templateParameters.size()); - - // Get template parameter values before pushing a new template parameter scope so that variables from the parent scope are used before being overwritten. - std::string templateTypeString; - for (size_t i = 0; i < this->m_templateParameters.size(); i++) { - auto &templateParameter = this->m_templateParameters[i]; - if (auto lvalue = dynamic_cast(templateParameter.get())) { - if (!lvalue->getRValue()) - err::E0003.throwError(fmt::format("No value set for non-type template parameter {}. This is a bug.", lvalue->getLValueName()), {}, this->getLocation()); - auto valueNode = lvalue->getRValue()->evaluate(evaluator); - if (auto literal = dynamic_cast(valueNode.get()); literal != nullptr) { - const auto &value = literal->getValue(); - - if (value.isString()) { - auto string = value.toString(); - if (string.size() > 32) - string = "..."; - templateTypeString += fmt::format("\"{}\", ", hlp::encodeByteString({ string.begin(), string.end() })); - } - else if (value.isPattern()) { - templateTypeString += fmt::format("{}{{ }}, ", value.toPattern()->getTypeName()); - } - else { - templateTypeString += fmt::format("{}, ", value.toString(true)); - } + std::vector> dummyPatterns; - templateParamLiterals[i] = std::make_unique(value); - } else { - err::E0003.throwError(fmt::format("Template parameter {} is not a literal. This is a bug.", lvalue->getLValueName()), {}, this->getLocation()); - } - } else if (const auto *typeNode = dynamic_cast(templateParameter.get())) { - const ASTNode *node = typeNode->getType().get(); - while (node != nullptr) { - if (const auto *innerNode = dynamic_cast(node)) { - if (const auto name = innerNode->getName(); !name.empty()) { - templateTypeString += fmt::format("{}, ", name); - break; - } - node = innerNode->getType().get(); - } - if (const auto *innerNode = dynamic_cast(node)) { - templateTypeString += fmt::format("{}, ", Token::getTypeName(innerNode->getType())); + bool requiresNewScope = dynamic_cast(this->getType().get()) != nullptr; - break; - } - } - } + evaluator->pushTemplateParameters(); + evaluator->pushTypeTemplateParameters(); + + if(requiresNewScope) { + evaluator->pushScope(nullptr, dummyPatterns); } - evaluator->pushTemplateParameters(); ON_SCOPE_EXIT { - evaluator->popTemplateParameters(); + evaluator->popTemplateParameters(); + evaluator->popTypeTemplateParameters(); + if (requiresNewScope) { + evaluator->popScope(); + } }; + auto& templateArguments = evaluator->getCurrentTemplateArguments(); + std::vector> templatePatterns; { @@ -130,18 +80,22 @@ namespace pl::core::ast { for (size_t i = 0; i < this->m_templateParameters.size(); i++) { auto &templateParameter = this->m_templateParameters[i]; - if (auto lvalue = dynamic_cast(templateParameter.get())) { - auto value = templateParamLiterals[i]->getValue(); + if (i >= templateArguments.size()) { + break; + } + if (!templateParameter->isType()) { + auto& argument = templateArguments[i]; + auto literal = dynamic_cast(argument.get()); + auto value = literal->getValue(); // Allow the evaluator to throw an error at the correct source location. if (this->m_currTemplateParameterType == nullptr) { - this->m_currTemplateParameterType = std::make_unique(""); - this->m_currTemplateParameterType->setType(std::make_unique(Token::ValueType::Auto)); + this->m_currTemplateParameterType = std::make_unique(std::make_shared(Token::ValueType::Auto)); } - this->m_currTemplateParameterType->setLocation(lvalue->getLocation()); + this->m_currTemplateParameterType->setLocation(templateParameter->getLocation()); - auto variable = evaluator->createVariable(lvalue->getLValueName(), this->m_currTemplateParameterType.get(), value, false, value.isPattern(), true, true); + auto variable = evaluator->createVariable(templateParameter->getName().get(), this->m_currTemplateParameterType.get(), value, false, value.isPattern(), true, true); if (variable != nullptr) { variable->setInitialized(false); evaluator->setVariable(variable, value); @@ -150,31 +104,21 @@ namespace pl::core::ast { templateVariable->setVisibility(ptrn::Visibility::Hidden); templatePatterns.emplace_back(std::move(templateVariable)); } + } else { + auto& argument = templateArguments[i]; + evaluator->getTypeTemplateParameters().emplace_back(std::move(argument)); } } } - auto currEndian = evaluator->getDefaultEndian(); - ON_SCOPE_EXIT { evaluator->setDefaultEndian(currEndian); }; + auto type = this->getType(); - evaluator->setDefaultEndian(this->m_endian.value_or(currEndian)); - this->getType()->createPatterns(evaluator, resultPatterns); + type->createPatterns(evaluator, resultPatterns); for (auto &pattern : resultPatterns) { if (pattern == nullptr) continue; - if (!pattern->hasOverriddenEndian()) - pattern->setEndian(evaluator->getDefaultEndian()); - - if (!this->m_name.empty()) { - if (this->m_templateParameters.empty()) { - pattern->setTypeName(this->m_name); - } else if (templateTypeString.size() >= 2) { - pattern->setTypeName(fmt::format("{}<{}>", this->m_name, templateTypeString.substr(0, templateTypeString.size() - 2))); - } - } - if (auto iterable = dynamic_cast(pattern.get()); iterable != nullptr) { auto scope = iterable->getEntries(); std::move(templatePatterns.begin(), templatePatterns.end(), std::back_inserter(scope)); @@ -193,13 +137,34 @@ namespace pl::core::ast { } void ASTNodeTypeDecl::addAttribute(std::unique_ptr &&attribute) { - if (this->isValid()) { - if (auto attributable = dynamic_cast(this->getType().get()); attributable != nullptr) { - attributable->addAttribute(std::unique_ptr(static_cast(attribute->clone().release()))); - } + if(auto attributable = dynamic_cast(this->m_type.get()); attributable != nullptr) { + attributable->addAttribute(std::unique_ptr(dynamic_cast(attribute->clone().release()))); } - Attributable::addAttribute(std::move(attribute)); } + const ASTNode* ASTNodeTypeDecl::getTypeDefinition(Evaluator *evaluator) const { + if (m_type == nullptr) + err::E0004.throwError(fmt::format("Cannot use incomplete type '{}' before it has been defined.", this->m_name), "Try defining this type further up in your code before trying to instantiate it.", this->getLocation()); + else if (auto typeApp = dynamic_cast(m_type.get()); typeApp != nullptr) + return typeApp->getTypeDefinition(evaluator); + else + return m_type.get(); + } + + [[nodiscard]] const std::string ASTNodeTypeDecl::getTypeName() const { + if (this->isTemplateType()) { + std::string typeName = this->m_name + "<"; + for (const auto& param : this->m_templateParameters) { + typeName += param->getName().get() + ", "; + } + if (!this->m_templateParameters.empty()) { + typeName = typeName.substr(0, typeName.size() - 2); + } + typeName += ">"; + return typeName; + } else { + return this->m_name; + } + } } \ No newline at end of file diff --git a/lib/source/pl/core/ast/ast_node_type_operator.cpp b/lib/source/pl/core/ast/ast_node_type_operator.cpp index dd1964df..036247d0 100644 --- a/lib/source/pl/core/ast/ast_node_type_operator.cpp +++ b/lib/source/pl/core/ast/ast_node_type_operator.cpp @@ -57,17 +57,9 @@ namespace pl::core::ast { result = u128(pattern->getSize()); break; case Token::Operator::TypeNameOf: { - if (auto typeDecl = dynamic_cast(this->m_expression.get()); typeDecl != nullptr) { - ASTNodeTypeDecl *node; - while (true) { - node = dynamic_cast(typeDecl->getType().get()); - if (node != nullptr) - typeDecl = node; - else - break; - } - - result = typeDecl->getName(); + if (auto typeApp = dynamic_cast(this->m_expression.get()); typeApp != nullptr) { + auto evaluatedType = typeApp->evaluate(evaluator); + result = dynamic_cast(evaluatedType.get())->getTypeName(); } else { result = pattern->getTypeName(); } diff --git a/lib/source/pl/core/ast/ast_node_variable_decl.cpp b/lib/source/pl/core/ast/ast_node_variable_decl.cpp index 8f52d4b4..8e73416b 100644 --- a/lib/source/pl/core/ast/ast_node_variable_decl.cpp +++ b/lib/source/pl/core/ast/ast_node_variable_decl.cpp @@ -7,12 +7,12 @@ namespace pl::core::ast { - ASTNodeVariableDecl::ASTNodeVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&placementOffset, std::unique_ptr &&placementSection, bool inVariable, bool outVariable, bool constant) + ASTNodeVariableDecl::ASTNodeVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&placementOffset, std::unique_ptr &&placementSection, bool inVariable, bool outVariable, bool constant) : ASTNode(), m_name(std::move(name)), m_type(std::move(type)), m_placementOffset(std::move(placementOffset)), m_placementSection(std::move(placementSection)), m_inVariable(inVariable), m_outVariable(outVariable), m_constant(constant) { } ASTNodeVariableDecl::ASTNodeVariableDecl(const ASTNodeVariableDecl &other) : ASTNode(other), Attributable(other) { this->m_name = other.m_name; - this->m_type = std::shared_ptr(static_cast(other.m_type->clone().release())); + this->m_type = std::shared_ptr(static_cast(other.m_type->clone().release())); if (other.m_placementOffset != nullptr) this->m_placementOffset = other.m_placementOffset->clone(); diff --git a/lib/source/pl/core/evaluator.cpp b/lib/source/pl/core/evaluator.cpp index 4cdc1f41..28e3b49c 100644 --- a/lib/source/pl/core/evaluator.cpp +++ b/lib/source/pl/core/evaluator.cpp @@ -280,79 +280,7 @@ namespace pl::core { variables.push_back(std::unique_ptr(pattern)); } - std::optional Evaluator::findTypeName(const ast::ASTNodeTypeDecl *type) { - const ast::ASTNodeTypeDecl *typeDecl = type; - while (true) { - if (auto name = typeDecl->getName(); !name.empty()) { - if (const auto &templateParams = typeDecl->getTemplateParameters(); templateParams.empty()) { - return name; - } else { - std::string templateTypeString; - for (const auto &templateParameter : templateParams) { - if (auto lvalue = dynamic_cast(templateParameter.get())) { - if (!lvalue->getRValue()) - err::E0003.throwError(fmt::format("No value set for non-type template parameter {}. This is a bug.", lvalue->getLValueName()), {}, type->getLocation()); - auto valueNode = lvalue->getRValue()->evaluate(this); - if (auto literal = dynamic_cast(valueNode.get()); literal != nullptr) { - const auto &value = literal->getValue(); - - if (value.isString()) { - auto string = value.toString(); - if (string.size() > 32) - string = "..."; - templateTypeString += fmt::format("\"{}\", ", hlp::encodeByteString({ string.begin(), string.end() })); - } else if (value.isPattern()) { - templateTypeString += fmt::format("{}{{ }}, ", value.toPattern()->getTypeName()); - } else { - templateTypeString += fmt::format("{}, ", value.toString(true)); - } - } else { - err::E0003.throwError(fmt::format("Template parameter {} is not a literal. This is a bug.", lvalue->getLValueName()), {}, type->getLocation()); - } - } else if (const auto *typeNode = dynamic_cast(templateParameter.get())) { - const auto *node = typeNode->getType().get(); - while (node != nullptr) { - if (const auto *innerNode = dynamic_cast(node)) { - if (const auto &innerNodeName = innerNode->getName(); !innerNodeName.empty()) { - templateTypeString += fmt::format("{}, ", innerNodeName); - break; - } - node = innerNode->getType().get(); - } - if (const auto *innerNode = dynamic_cast(node)) { - templateTypeString += fmt::format("{}, ", Token::getTypeName(innerNode->getType())); - - break; - } - } - } - } - - templateTypeString = templateTypeString.substr(0, templateTypeString.size() - 2); - - return fmt::format("{}<{}>", name, templateTypeString); - } - } - else if (auto innerType = dynamic_cast(typeDecl->getType().get()); innerType != nullptr) - typeDecl = innerType; - else - return std::nullopt; - } - } - - static ast::ASTNodeBuiltinType* getBuiltinType(const ast::ASTNodeTypeDecl *type) { - const ast::ASTNodeTypeDecl *typeDecl = type; - while (true) { - if (auto innerType = dynamic_cast(typeDecl->getType().get()); innerType != nullptr) - typeDecl = innerType; - else if (auto builtinType = dynamic_cast(typeDecl->getType().get()); builtinType != nullptr) - return builtinType; - else - return nullptr; - } - } - - std::shared_ptr Evaluator::createVariable(const std::string &name, const ast::ASTNodeTypeDecl *type, const std::optional &value, bool outVariable, bool reference, bool templateVariable, bool constant) { + std::shared_ptr Evaluator::createVariable(const std::string &name, const ast::ASTNodeTypeApplication *type, const std::optional &value, bool outVariable, bool reference, bool templateVariable, bool constant) { auto startPos = this->getBitwiseReadOffset(); ON_SCOPE_EXIT { this->setBitwiseReadOffset(startPos); }; @@ -393,7 +321,8 @@ namespace pl::core { this->setBitwiseReadOffset(startOffset); - if (auto builtinType = getBuiltinType(type); builtinType != nullptr && builtinType->getType() == Token::ValueType::Auto) { + auto typeDefinition = type->getTypeDefinition(this); + if (auto builtinType = dynamic_cast(typeDefinition); builtinType != nullptr && builtinType->getType() == Token::ValueType::Auto) { // Handle auto variables if (!value.has_value()) pattern = std::make_shared(this, 0, 0, 0); @@ -425,11 +354,7 @@ namespace pl::core { } else { pattern = std::make_shared(this, 0, 0, 0); - - if (auto typeName = findTypeName(type); typeName.has_value()) - pattern->setTypeName(typeName.value()); - else - err::E0003.throwError("Cannot determine type.", "", type->getLocation()); + pattern->setTypeName(type->getTypeName()); } } diff --git a/lib/source/pl/core/parser.cpp b/lib/source/pl/core/parser.cpp index c1f552d0..41482d08 100644 --- a/lib/source/pl/core/parser.cpp +++ b/lib/source/pl/core/parser.cpp @@ -32,7 +32,6 @@ #include #include #include - #include #include @@ -152,10 +151,10 @@ namespace pl::core { continue; } if (this->m_types.contains(typeName)) - return create(this->m_types[typeName].unwrap(), getValue(-1).get()); + return create(std::shared_ptr(this->m_types[typeName].unwrap()), getValue(-1).get()); for (auto &potentialName : getNamespacePrefixedNames(typeName)) { if (this->m_types.contains(potentialName)) { - return create(this->m_types[potentialName].unwrap(), getValue(-1).get()); + return create(std::shared_ptr(this->m_types[potentialName].unwrap()), getValue(-1).get()); } } @@ -1306,12 +1305,20 @@ namespace pl::core { /* Type declarations */ - hlp::safe_unique_ptr Parser::getCustomType(const std::string &baseTypeName) { + hlp::safe_unique_ptr Parser::getCustomType(const std::string &baseTypeName) { if (!this->m_currTemplateType.empty()) { + size_t index = 0; for (const auto &templateParameter : this->m_currTemplateType.front()->getTemplateParameters()) { - if (const auto templateType = dynamic_cast(templateParameter.get()); templateType != nullptr) - if (templateType->getName() == baseTypeName) - return create("", templateParameter); + if (const auto templateType = dynamic_cast(templateParameter.get()); templateType != nullptr){ + if (templateType->getName().get() == baseTypeName) { + auto type = create(nullptr); + type->setTemplateParameterIndex(index); + return type; + } + if (templateType->isType()){ + index++; + } + } } } @@ -1326,7 +1333,7 @@ namespace pl::core { return nullptr; } - return create("", type.unwrapUnchecked()); + return create(type.unwrapUnchecked()); } } @@ -1334,7 +1341,7 @@ namespace pl::core { } // - void Parser::parseCustomTypeParameters(hlp::safe_unique_ptr &type) { + void Parser::parseCustomTypeParameters(hlp::safe_unique_ptr &type) { if (const auto actualType = dynamic_cast(type->getType().get()); actualType != nullptr) if (const auto &templateTypes = actualType->getTemplateParameters(); !templateTypes.empty()) { if (!sequence(tkn::Operator::BoolLessThan)) { @@ -1342,6 +1349,8 @@ namespace pl::core { return; } + std::vector> templateArguments; + u32 index = 0; do { if (index >= templateTypes.size()) { @@ -1350,25 +1359,18 @@ namespace pl::core { } auto parameter = templateTypes[index]; - if (const auto typeDecl = dynamic_cast(parameter.get()); typeDecl != nullptr) { + if (parameter->isType()) { auto newType = parseType(); if (newType == nullptr) return; - if (newType->isForwardDeclared()) { - error("Cannot use forward declared type as template parameter."); - } - typeDecl->setType(std::move(newType), true); - typeDecl->setName(""); - } else if (const auto value = dynamic_cast(parameter.get()); value != nullptr) { - auto rvalue = parseMathematicalExpression(true); - if (rvalue == nullptr) + templateArguments.emplace_back(newType.unwrapUnchecked().release()); + } else { + auto value = parseMathematicalExpression(true); + if (value == nullptr) return; - value->setRValue(std::move(rvalue)); - } else { - error("Invalid template parameter type."); - return; + templateArguments.push_back(std::move(value.unwrapUnchecked())); } index++; @@ -1383,13 +1385,12 @@ namespace pl::core { error("Expected '>' to close template list, got {}.", getFormattedToken(0)); return; } - - type = hlp::safe_unique_ptr(dynamic_cast(type->clone().release())); + type->setTemplateArguments(std::move(templateArguments)); } } // Identifier - hlp::safe_unique_ptr Parser::parseCustomType() { + hlp::safe_unique_ptr Parser::parseCustomType() { auto baseTypeName = parseNamespaceResolution(); auto type = getCustomType(baseTypeName); @@ -1404,7 +1405,7 @@ namespace pl::core { } // [be|le] - hlp::safe_unique_ptr Parser::parseType() { + hlp::safe_unique_ptr Parser::parseType() { const bool reference = sequence(tkn::Keyword::Reference); std::optional endian; @@ -1413,13 +1414,13 @@ namespace pl::core { else if (sequence(tkn::Keyword::BigEndian)) endian = std::endian::big; - hlp::safe_unique_ptr result = nullptr; + hlp::safe_unique_ptr result = nullptr; if (sequence(tkn::Literal::Identifier)) { // Custom type result = parseCustomType(); } else if (sequence(tkn::ValueType::Any)) { // Builtin type auto type = getValue(-1); - result = create(Token::getTypeName(type), create(type)); + result = create(createShared(type)); } if (result == nullptr) { @@ -1435,18 +1436,17 @@ namespace pl::core { } // <(parseType), ...> - std::vector> Parser::parseTemplateList() { - std::vector> result; - + std::vector> Parser::parseTemplateList() { + std::vector> result; if (sequence(tkn::Operator::BoolLessThan)) { do { if (sequence(tkn::Literal::Identifier)) { - result.emplace_back(createShared(getValue(-1).get())); + result.push_back(createShared(getValue(-1), true)); auto templateIdentifier = std::get_if(&((m_curr[-1]).value)); if (templateIdentifier != nullptr) templateIdentifier->setType(Token::Identifier::IdentifierType::TemplateArgument); } else if (sequence(tkn::ValueType::Auto, tkn::Literal::Identifier)) { - result.emplace_back(createShared(getValue(-1).get(), nullptr)); + result.push_back(createShared(getValue(-1), false)); auto templateIdentifier = std::get_if(&((m_curr[-1]).value)); if (templateIdentifier != nullptr) templateIdentifier->setType(Token::Identifier::IdentifierType::TemplateArgument); @@ -1553,16 +1553,28 @@ namespace pl::core { hlp::safe_shared_ptr Parser::parseUsingDeclaration() { const auto name = getValue(-1).get(); auto typedefIdentifier = std::get_if(&((m_curr[-1]).value)); - if (typedefIdentifier != nullptr) - typedefIdentifier->setType(Token::Identifier::IdentifierType::Typedef); auto templateList = this->parseTemplateList(); if (!sequence(tkn::Operator::Assign)) { - error("Expected '=' after using declaration type name, got {}.", getFormattedToken(0)); + // Forward declaration + auto typeName = getNamespacePrefixedNames(name).back(); + if (typedefIdentifier != nullptr) + typedefIdentifier->setType(Token::Identifier::IdentifierType::UDT); + + if (this->m_types.contains(name)) { + return nullptr; + } + + auto typeDecl = createShared(name); + typeDecl->setTemplateParameters(unwrapSafePointerVector(std::move(templateList))); + this->m_types.insert({ typeName, typeDecl }); return nullptr; } + if (typedefIdentifier != nullptr) + typedefIdentifier->setType(Token::Identifier::IdentifierType::Typedef); + auto type = addType(name, nullptr); if (type == nullptr) return nullptr; @@ -1576,17 +1588,7 @@ namespace pl::core { return nullptr; this->m_currTemplateType.pop_back(); - - - if (const auto containedType = replaceType.get(); containedType != nullptr && !containedType->isTemplateType()) - replaceType->setType(containedType->clone()); - - const auto endian = replaceType->getEndian(); type->setType(std::move(replaceType)); - - if (endian.has_value()) - type->setEndian(*endian); - return type; } @@ -1606,11 +1608,11 @@ namespace pl::core { return nullptr; } - return create("$padding$", createShared("", createShared(Token::ValueType::Padding)), std::move(size)); + return create("$padding$", createShared(createShared(Token::ValueType::Padding)), std::move(size)); } // (parseType) Identifier - hlp::safe_unique_ptr Parser::parseMemberVariable(const hlp::safe_shared_ptr &type, bool constant, const std::string &identifier) { + hlp::safe_unique_ptr Parser::parseMemberVariable(const hlp::safe_shared_ptr &type, bool constant, const std::string &identifier) { auto memberIdentifier = std::get_if(&((m_curr[-1]).value)); if (peek(tkn::Separator::Comma)) { @@ -1699,7 +1701,7 @@ namespace pl::core { } // (parseType) Identifier[(parseMathematicalExpression)] - hlp::safe_unique_ptr Parser::parseMemberArrayVariable(const hlp::safe_shared_ptr &type, bool constant) { + hlp::safe_unique_ptr Parser::parseMemberArrayVariable(const hlp::safe_shared_ptr &type, bool constant) { auto name = getValue(-2).get(); auto memberIdentifier = std::get_if(&((m_curr[-2]).value)); @@ -1782,7 +1784,7 @@ namespace pl::core { } // (parseType) *Identifier : (parseType) - hlp::safe_unique_ptr Parser::parseMemberPointerVariable(const hlp::safe_shared_ptr &type) { + hlp::safe_unique_ptr Parser::parseMemberPointerVariable(const hlp::safe_shared_ptr &type) { auto name = getValue(-2).get(); auto memberIdentifier = std::get_if(&((m_curr[-2]).value)); @@ -1814,7 +1816,7 @@ namespace pl::core { } // (parseType) *Identifier[[(parseMathematicalExpression)]] : (parseType) - hlp::safe_unique_ptr Parser::parseMemberPointerArrayVariable(const hlp::safe_shared_ptr &type) { + hlp::safe_unique_ptr Parser::parseMemberPointerArrayVariable(const hlp::safe_shared_ptr &type) { auto name = getValue(-2).get(); auto memberIdentifier = std::get_if(&((m_curr[-2]).value)); @@ -2175,7 +2177,7 @@ namespace pl::core { member = create("$padding$", std::move(bitfieldSize)); } else if (peek(tkn::Literal::Identifier) || peek(tkn::ValueType::Any)) { - hlp::safe_unique_ptr type = nullptr; + hlp::safe_unique_ptr type = nullptr; if (sequence(tkn::ValueType::Any)) { const auto typeToken = getValue(-1); @@ -2184,7 +2186,7 @@ namespace pl::core { if (userDefinedTypeIdentifier != nullptr) userDefinedTypeIdentifier->setType(Token::Identifier::IdentifierType::UDT); } - type = create(Token::getTypeName(typeToken), create(typeToken)); + type = create(createShared(typeToken)); } else if (sequence(tkn::Literal::Identifier)) { const auto originalPosition = m_curr; auto name = parseNamespaceResolution(); @@ -2319,21 +2321,9 @@ namespace pl::core { return typeDecl; } - // using Identifier; - void Parser::parseForwardDeclaration() { - std::string typeName = getNamespacePrefixedNames(getValue(-1).get()).back(); - - auto userDefinedTypeIdentifier = std::get_if(&((m_curr[-1]).value)); - if (userDefinedTypeIdentifier != nullptr) - userDefinedTypeIdentifier->setType(Token::Identifier::IdentifierType::UDT); - if (this->m_types.contains(typeName)) - return; - - this->m_types.insert({ typeName, createShared(typeName) }); - } // (parseType) Identifier @ Integer - hlp::safe_unique_ptr Parser::parseVariablePlacement(const hlp::safe_shared_ptr &type) { + hlp::safe_unique_ptr Parser::parseVariablePlacement(const hlp::safe_shared_ptr &type) { bool inVariable = false; bool outVariable = false; @@ -2400,7 +2390,7 @@ namespace pl::core { } // (parseType) Identifier[[(parseMathematicalExpression)]] @ Integer - hlp::safe_unique_ptr Parser::parseArrayVariablePlacement(const hlp::safe_shared_ptr &type) { + hlp::safe_unique_ptr Parser::parseArrayVariablePlacement(const hlp::safe_shared_ptr &type) { auto name = getValue(-2).get(); auto typedefIdentifier = std::get_if(&((m_curr[-2]).value)); @@ -2461,7 +2451,7 @@ namespace pl::core { } // (parseType) *Identifier : (parseType) @ Integer - hlp::safe_unique_ptr Parser::parsePointerVariablePlacement(const hlp::safe_shared_ptr &type) { + hlp::safe_unique_ptr Parser::parsePointerVariablePlacement(const hlp::safe_shared_ptr &type) { auto name = getValue(-2).get(); auto typedefIdentifier = std::get_if(&((m_curr[-2]).value)); @@ -2492,7 +2482,7 @@ namespace pl::core { } // (parseType) *Identifier[[(parseMathematicalExpression)]] : (parseType) @ Integer - hlp::safe_unique_ptr Parser::parsePointerArrayVariablePlacement(const hlp::safe_shared_ptr &type) { + hlp::safe_unique_ptr Parser::parsePointerArrayVariablePlacement(const hlp::safe_shared_ptr &type) { auto name = getValue(-2).get(); auto placedIdentifier = std::get_if(&((m_curr[-2]).value)); @@ -2639,10 +2629,8 @@ namespace pl::core { statement = parseFunctionVariableAssignment("$"); else if (const auto identifierOffset = parseCompoundAssignment(tkn::Literal::Identifier); identifierOffset.has_value()) statement = parseFunctionVariableCompoundAssignment(getValue(*identifierOffset).get()); - else if (MATCHES(sequence(tkn::Keyword::Using, tkn::Literal::Identifier) && (peek(tkn::Operator::Assign) || peek(tkn::Operator::BoolLessThan)))) + else if (MATCHES(sequence(tkn::Keyword::Using, tkn::Literal::Identifier))) statement = parseUsingDeclaration(); - else if (sequence(tkn::Keyword::Using, tkn::Literal::Identifier)) - parseForwardDeclaration(); else if (sequence(tkn::Keyword::Import)) statement = parseImportStatement(); else if (peek(tkn::Keyword::BigEndian) || peek(tkn::Keyword::LittleEndian) || peek(tkn::ValueType::Any)) @@ -2717,17 +2705,19 @@ namespace pl::core { return std::nullopt; } - hlp::safe_shared_ptr Parser::addType(const std::string &name, hlp::safe_unique_ptr &&node, std::optional endian) { + hlp::safe_shared_ptr Parser::addType(const std::string &name, hlp::safe_unique_ptr &&node) { auto typeName = getNamespacePrefixedNames(name).back(); if (this->m_types.contains(typeName) && this->m_types.at(typeName)->isForwardDeclared()) { - this->m_types.at(typeName)->setType(std::move(node)); + if(node != nullptr) { + this->m_types.at(typeName)->setType(std::move(node)); + } return this->m_types.at(typeName); } if (!this->m_types.contains(typeName)) { - auto typeDecl = createShared(typeName, std::move(std::move(node).unwrapUnchecked()), endian); + auto typeDecl = createShared(typeName, std::move(std::move(node).unwrapUnchecked())); this->m_types.insert({typeName, typeDecl}); return typeDecl; @@ -2822,6 +2812,18 @@ namespace pl::core { } void Parser::reset() { + for (const auto &[_, type] : this->m_types) { + if (type != nullptr && type->isValid()) { + if (auto builtinType = dynamic_cast(type->getType().get()); builtinType != nullptr) { + if (builtinType->getType() != Token::ValueType::CustomType) { + type->setType(nullptr); + } + } else { + type->setType(nullptr); + } + } + } + this->m_types.clear(); this->m_currTemplateType.clear(); this->m_matchedOptionals.clear(); diff --git a/lib/source/pl/core/parser_manager.cpp b/lib/source/pl/core/parser_manager.cpp index 3aee99a5..e4367019 100644 --- a/lib/source/pl/core/parser_manager.cpp +++ b/lib/source/pl/core/parser_manager.cpp @@ -86,9 +86,9 @@ namespace pl::core { if (parameterCount.min != parameterCount.max) throw std::runtime_error("Types cannot have a variable amount of parameters"); - std::vector> templateParameters; + std::vector> templateParameters; for (u32 i = 0; i < parameterCount.max; i += 1) { - templateParameters.emplace_back(std::make_shared(fmt::format("$param{}$", i), nullptr)); + templateParameters.push_back(std::make_shared(Token::Identifier(fmt::format("$param{}$", i), Token::Identifier::IdentifierType::TemplateArgument), false)); } type->setTemplateParameters(std::move(templateParameters)); diff --git a/lib/source/pl/core/validator.cpp b/lib/source/pl/core/validator.cpp index 0dc10bf9..0af78364 100644 --- a/lib/source/pl/core/validator.cpp +++ b/lib/source/pl/core/validator.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -123,17 +124,38 @@ namespace pl::core { if (!this->validateNodes(multiVariableDecl->getVariables())) return false; } else if (const auto typeDeclNode = dynamic_cast(node); typeDeclNode != nullptr) { - if (!typeDeclNode->isForwardDeclared()) - if (!this->validateNode(typeDeclNode->getType())) + if (!typeDeclNode->isForwardDeclared()) { + std::unordered_set typeParameterIdentifiers; + std::unordered_set nonTypeParameterIdentifiers; + for (const auto & parameter : typeDeclNode->getTemplateParameters()) { + auto name = parameter->getName().get(); + auto isType = parameter->isType(); + if (isType && !typeParameterIdentifiers.insert(name).second) { + error("Redefinition of type template parameter '{}'", name); + return false; + } + if (!isType && !nonTypeParameterIdentifiers.insert(name).second) { + error("Redefinition of non-type template parameter '{}'", name); + return false; + } + } + + this->m_identifiers.push_back(std::move(nonTypeParameterIdentifiers)); + ON_SCOPE_EXIT { + this->m_identifiers.pop_back(); + }; + + if (!this->validateNode(typeDeclNode->getType(), false)) return false; + } } else if (const auto structNode = dynamic_cast(node); structNode != nullptr) { - if (!this->validateNodes(structNode->getMembers())) + if (!this->validateNodes(structNode->getMembers(), false)) return false; } else if (const auto unionNode = dynamic_cast(node); unionNode != nullptr) { - if (!this->validateNodes(unionNode->getMembers())) + if (!this->validateNodes(unionNode->getMembers(), false)) return false; } else if (const auto bitfieldNode = dynamic_cast(node); bitfieldNode != nullptr) { - if (!this->validateNodes(bitfieldNode->getEntries())) + if (!this->validateNodes(bitfieldNode->getEntries(), false)) return false; } else if (const auto enumNode = dynamic_cast(node); enumNode != nullptr) { std::unordered_set enumIdentifiers; @@ -164,6 +186,9 @@ namespace pl::core { return false; } } + } else if (const auto compoundNode = dynamic_cast(node); compoundNode != nullptr) { + if (!this->validateNodes(compoundNode->getStatements(), false)) + return false; } this->m_validatedNodes.insert(node); diff --git a/lib/source/pl/pattern_language.cpp b/lib/source/pl/pattern_language.cpp index 7308cc59..e6e3f93a 100644 --- a/lib/source/pl/pattern_language.cpp +++ b/lib/source/pl/pattern_language.cpp @@ -52,6 +52,9 @@ namespace pl { PatternLanguage::~PatternLanguage() { if (this->m_flattenThread.joinable()) this->m_flattenThread.join(); + this->m_parserManager.reset(); + if (this->m_internals.parser) + this->m_internals.parser->reset(); this->m_patterns.clear(); this->m_flattenedPatterns.clear(); this->m_flattenedPatternsValid = false; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 16791c5a..4e64663b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,6 +32,9 @@ set(AVAILABLE_TESTS PragmasFail Format RValuesAssignmentInStruct + TemplateParametersScope + TypeNameOf + CustomBuiltInType ) diff --git a/tests/include/test_patterns/test_pattern.hpp b/tests/include/test_patterns/test_pattern.hpp index cd8853de..eae9cb06 100644 --- a/tests/include/test_patterns/test_pattern.hpp +++ b/tests/include/test_patterns/test_pattern.hpp @@ -59,6 +59,10 @@ namespace pl::test { return true; } + [[nodiscard]] virtual size_t repeatTimes() const { + return 1; + } + private: std::vector> m_patterns; core::Evaluator *m_evaluator; diff --git a/tests/include/test_patterns/test_pattern_custom_builtin_type.hpp b/tests/include/test_patterns/test_pattern_custom_builtin_type.hpp new file mode 100644 index 00000000..8b2c5dc3 --- /dev/null +++ b/tests/include/test_patterns/test_pattern_custom_builtin_type.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "test_pattern.hpp" + +namespace pl::test { + + class TestPatternCustomBuiltinType : public TestPattern { + public: + TestPatternCustomBuiltinType(core::Evaluator *evaluator) : TestPattern(evaluator, "CustomBuiltInType") { + } + ~TestPatternCustomBuiltinType() override = default; + + virtual void setup() override{ + const pl::api::Namespace ns = { "custom_type" }; + m_runtime->addType(ns, "custom_type", pl::api::FunctionParameterCount::exactly(1), [](core::Evaluator *evaluator, auto params) -> std::unique_ptr { + auto pattern = std::make_unique(evaluator, 0, sizeof(u8), 0); + return pattern; + }); + }; + + [[nodiscard]] std::string getSourceCode() const override { + return R"( + custom_type::custom_type<1> test @ 0; + std::assert(test == 137, "test should be 137"); + )"; + } + + [[nodiscard]] size_t repeatTimes() const override { + return 2; + } + }; + +} \ No newline at end of file diff --git a/tests/include/test_patterns/test_pattern_template_parameters_scope.hpp b/tests/include/test_patterns/test_pattern_template_parameters_scope.hpp new file mode 100644 index 00000000..49238d66 --- /dev/null +++ b/tests/include/test_patterns/test_pattern_template_parameters_scope.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include "test_pattern.hpp" + +namespace pl::test { + + class TestPatternTemplateParametersScope : public TestPattern { + public: + TestPatternTemplateParametersScope(core::Evaluator *evaluator) : TestPattern(evaluator, "TemplateParametersScope") { + } + ~TestPatternTemplateParametersScope() override = default; + + [[nodiscard]] std::string getSourceCode() const override { + return R"( + struct Y { + try { + u8 a = x; + } catch { + u8 a = 2; + } + }; + struct T { + u8 value = x; + Y y; + }; + T<4> t @ 0; + std::assert(t.y.a == 2, "t.value should be 2"); + + struct U { + V v; + }; + struct S { + u8 j = 16; + U> t; + }; + S s @ 0 ; + std::assert(s.t.v.value == 16, "s.t.v.value should be 16"); + + struct W { + T t; + }; + struct R { + u8 j = 32; + W w; + }; + R r @ 0; + std::assert(r.w.t.value == 32, "r.w.t.value should be 32"); + + struct Z { + if(v > 0) { + Z, v-1> q; + } + u32 value = v; + }; + Z a @ 0; + + std::assert(a.q.q.q.q.q.value == 0, "a.q.q.q.q.q.value should be 0"); + + u32 b = 64; + using Alias = U>; + Alias alias @ 0; + std::assert(alias.v.value == 64, "alias.v.value should be 32"); + + using C = U>; + C<16> c @ 0; + + std::assert(c.v.value == 80, "c.v.value should be 80"); + + struct E { + u32 b = 128; + C c; + }; + E e @ 0; + std::assert(e.c.v.value == 192, "e.c.v.value should be 192"); + + using G; + struct H{ + G<66, u32> d; + }; + H h @0; + struct G { + c cc = b; + }; + std::assert(h.d.cc == 66, "f.x should be 66"); + + using I; + struct J { + if(value > 0) { + I i; + } + u32 j = value [[export]]; + }; + struct I { + J j; + u32 i = value [[export]]; + }; + I i @ 0; + std::assert(i.j.i.j.i.j.i.j.j == 0, "i.j.i.j.i.j.i.j.j should be 0"); + + struct K { + u32 e = v; + }; + using P = K; + struct Q { + u32 b = 1; + P<1> q; + }; + Q q @ 0; + std::assert(q.q.e == 65, "q.q.e should be 65"); + + using Fp; + struct FFp{ + Fp<1> fp; + }; + FFp ffp @ 0; + using Fp = P; + std::assert(ffp.fp.e == 129, "fp.e should be 129"); + )"; + } + }; + +} \ No newline at end of file diff --git a/tests/include/test_patterns/test_pattern_typenameof.hpp b/tests/include/test_patterns/test_pattern_typenameof.hpp new file mode 100644 index 00000000..51f9d6b6 --- /dev/null +++ b/tests/include/test_patterns/test_pattern_typenameof.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "test_pattern.hpp" + +namespace pl::test { + + class TestPatternTypeNameOf : public TestPattern { + public: + TestPatternTypeNameOf(core::Evaluator *evaluator) : TestPattern(evaluator, "TypeNameOf") { + } + ~TestPatternTypeNameOf() override = default; + + [[nodiscard]] std::string getSourceCode() const override { + return R"( + struct A { + + }; + + struct B { + + }; + + struct TypeName { + std::assert(typenameof(type) == typename, "type name should match"); + }; + + u32 P = 16; + TypeName a @ 0; + TypeName b @ 0; + TypeName, "B"> c @ 0; + TypeName, 2>, "B, 2>"> d @ 0; + TypeName , "TypeName"> e @ 0; + std::assert(typenameof(B, 2>) == "B, 2>", "type name should match"); + )"; + } + }; + +} \ No newline at end of file diff --git a/tests/source/main.cpp b/tests/source/main.cpp index c6d461b1..e070d1d4 100644 --- a/tests/source/main.cpp +++ b/tests/source/main.cpp @@ -108,20 +108,23 @@ int runTests(int argc, char **argv) { auto &test = testPatterns[testName]; test->m_runtime = &runtime; test->setup(); - auto result = runtime.executeString(test->getSourceCode()); - // Check if compilation succeeded - if (!result) { - fmt::print("Error during test!\n"); + for (size_t i = 0; i < test->repeatTimes(); i++) { + auto result = runtime.executeString(test->getSourceCode()); - if (auto error = runtime.getEvalError(); error.has_value()) - fmt::print("Error: {}:{} : {}\n", error->line, error->column, error->message); + // Check if compilation succeeded + if (!result) { + fmt::print("Error during test!\n"); - for (const auto& error : runtime.getCompileErrors()) { - fmt::print("{}", error.format()); - } + if (auto error = runtime.getEvalError(); error.has_value()) + fmt::print("Error: {}:{} : {}\n", error->line, error->column, error->message); - return failing ? EXIT_SUCCESS : EXIT_FAILURE; + for (const auto& error : runtime.getCompileErrors()) { + fmt::print("{}", error.format()); + } + + return failing ? EXIT_SUCCESS : EXIT_FAILURE; + } } const auto &evaluatedPatterns = runtime.getPatterns(); diff --git a/tests/source/tests.cpp b/tests/source/tests.cpp index 648611cd..36fb4e42 100644 --- a/tests/source/tests.cpp +++ b/tests/source/tests.cpp @@ -27,6 +27,9 @@ #include "test_patterns/test_pattern_pragmas_fail.hpp" #include "test_patterns/test_pattern_format.hpp" #include "test_patterns/test_pattern_rvalues_assignment_in_struct.hpp" +#include "test_patterns/test_pattern_template_parameters_scope.hpp" +#include "test_patterns/test_pattern_typenameof.hpp" +#include "test_patterns/test_pattern_custom_builtin_type.hpp" static pl::core::Evaluator s_evaluator; @@ -59,4 +62,7 @@ std::array Tests = { TEST(PragmasFail), TEST(Format), TEST(RValuesAssignmentInStruct), + TEST(TemplateParametersScope), + TEST(TypeNameOf), + TEST(CustomBuiltinType), };