diff --git a/lib/include/pl/patterns/pattern.hpp b/lib/include/pl/patterns/pattern.hpp index e2574e05..48a47f28 100644 --- a/lib/include/pl/patterns/pattern.hpp +++ b/lib/include/pl/patterns/pattern.hpp @@ -217,6 +217,8 @@ namespace pl::ptrn { [[nodiscard]] std::endian getEndian() const { if (this->m_evaluator == nullptr) return std::endian::native; + else if (!this->m_endian.has_value() && + (this->m_section == HeapSectionId || this->m_section == PatternLocalSectionId || this->m_section == InstantiationSectionId)) return std::endian::native; else return this->m_endian.value_or(this->m_evaluator->getDefaultEndian()); } virtual void setEndian(std::endian endian) { diff --git a/lib/source/pl/core/ast/ast_node_type_application.cpp b/lib/source/pl/core/ast/ast_node_type_application.cpp index 40ef1750..b5144387 100644 --- a/lib/source/pl/core/ast/ast_node_type_application.cpp +++ b/lib/source/pl/core/ast/ast_node_type_application.cpp @@ -37,7 +37,7 @@ namespace pl::core::ast { : m_type(std::move(type)) { }; ASTNodeTypeApplication::ASTNodeTypeApplication(const ASTNodeTypeApplication &other) - : ASTNode(other), m_type(other.m_type) { + : ASTNode(other), m_type(other.m_type), m_reference(other.m_reference), m_endian(other.m_endian), m_templateParameterIndex(other.m_templateParameterIndex) { for (const auto &arg : other.m_templateArguments) this->m_templateArguments.emplace_back(arg->clone()); }; @@ -71,6 +71,9 @@ namespace pl::core::ast { } evaluatedType->m_templateArguments = std::move(evaluatedTemplateArguments); + evaluatedType->m_reference = this->m_reference; + evaluatedType->m_endian = this->m_endian; + evaluatedType->m_templateParameterIndex = this->m_templateParameterIndex; evaluatedType->setLocation(this->getLocation()); evaluatedType->setShouldDocument(this->shouldDocument()); evaluatedType->setDocComment(this->getDocComment()); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 292b15f5..767160e5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -42,6 +42,7 @@ set(AVAILABLE_TESTS Format RValuesAssignmentInStruct TemplateParametersScope + TemplateEndian TypeNameOf CustomBuiltInType Using diff --git a/tests/include/test_patterns/test_pattern_template_endian.hpp b/tests/include/test_patterns/test_pattern_template_endian.hpp new file mode 100644 index 00000000..fbfa5418 --- /dev/null +++ b/tests/include/test_patterns/test_pattern_template_endian.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include "test_pattern.hpp" + +namespace pl::test { + + class TestPatternTemplateEndian : public TestPattern { + public: + TestPatternTemplateEndian(core::Evaluator *evaluator) : TestPattern(evaluator, "TemplateEndian") { + } + ~TestPatternTemplateEndian() override = default; + + [[nodiscard]] std::string getSourceCode() const override { + return R"( + struct EqBox { + V v; + }; + struct EqPayload { + u32 x; + }; + struct EqBodyBe { + be V v; + }; + struct EqStructPayload { + be u32 x; + }; + + be u32 eqPlainBe @ 0; + std::assert(eqPlainBe == 0x89504E47, "sanity: plain 'be u32' must read big endian"); + + u32 eqPlainDefault @ 0; + std::assert(eqPlainDefault == 0x474E5089, "sanity: default 'u32' must read little endian"); + + EqBox eqBoxBe @ 0; + std::assert(eqBoxBe.v == 0x89504E47, "'be' on a type template argument must be preserved"); + + EqBox eqBoxCustomBe @ 0; + std::assert(eqBoxCustomBe.v.x == 0x89504E47, "'be' on a custom type template argument must be preserved"); + + EqBox> eqBoxNestedBe @ 0; + std::assert(eqBoxNestedBe.v.v == 0x89504E47, "'be' in a nested template argument must be preserved"); + + using EqBoxAlias = EqBox; + EqBoxAlias eqAliasBe @ 0; + std::assert(eqAliasBe.v == 0x89504E47, "'be' in an alias template argument must be preserved"); + + using EqBoxAliasTemplate = EqBox; + EqBoxAliasTemplate eqAliasTemplateBe @ 0; + std::assert(eqAliasTemplateBe.v == 0x89504E47, "'be' passed through an alias template must be preserved"); + + using EqIdentity = V; + EqIdentity eqIdentityBe @ 0; + std::assert(eqIdentityBe == 0x89504E47, "'be' passed through an identity alias must be preserved"); + + EqBox eqBoxBeArray[2] @ 0; + std::assert(eqBoxBeArray[0].v == 0x89504E47, "'be' in an array of template instantiations must be preserved"); + std::assert(eqBoxBeArray[1].v == 0x0D0A1A0A, "'be' in an array of template instantiations must be preserved"); + + be EqBox eqOuterBe @ 0; + std::assert(eqOuterBe.v == 0x89504E47, "'be' on the outside of a template instantiation must still apply"); + + EqBodyBe eqBodyBe @ 0; + std::assert(eqBodyBe.v == 0x89504E47, "'be' applied to a template parameter inside the body must apply"); + + le EqBox eqInnerBeWins @ 4; + std::assert(eqInnerBeWins.v == 0x0D0A1A0A, "endian of the template argument must win over the outer default"); + + EqBox eqStructArg @ 0; + std::assert(eqStructArg.v.x == 0x89504E47, "a struct with 'be' members must stay big endian when used as a template argument"); + + struct AutoBox { + u32 f; + u32 a = t; + }; + + be AutoBox<5> autoBe @ 0; + std::assert(autoBe.f == 0x89504E47, "'be' instantiation must still read file data big endian"); + std::assert(autoBe.t == 5, "non-type template parameter must not be endian-swapped by an outer 'be'"); + std::assert(autoBe.a == 5, "member initialized from a non-type template parameter must keep its value"); + + le AutoBox<5> autoLe @ 4; + std::assert(autoLe.f == 0x0A1A0A0D, "'le' instantiation must read file data little endian"); + std::assert(autoLe.t == 5, "non-type template parameter must not be endian-swapped by an outer 'le'"); + + be AutoBox<5> autoBeLocal; + std::assert(autoBeLocal.t == 5, "non-type template parameter must not be endian-swapped by a local 'be' instantiation"); + std::assert(autoBeLocal.a == 5, "member initialized from a non-type template parameter must keep its value when local"); + + auto endianGlobal = 16909060; + struct AutoGlobal { + u32 a = endianGlobal; + }; + be AutoGlobal<5> autoGlobalBe; + std::assert(autoGlobalBe.a == 16909060, "a heap variable read under an outer 'be' must keep its value"); + )"; + } + }; + +} diff --git a/tests/source/tests.cpp b/tests/source/tests.cpp index 0e6510ef..75ceeca5 100644 --- a/tests/source/tests.cpp +++ b/tests/source/tests.cpp @@ -30,6 +30,7 @@ #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_template_endian.hpp" #include "test_patterns/test_pattern_typenameof.hpp" #include "test_patterns/test_pattern_custom_builtin_type.hpp" #include "test_patterns/test_pattern_using.hpp" @@ -85,6 +86,7 @@ std::array Tests = { TEST(Format), TEST(RValuesAssignmentInStruct), TEST(TemplateParametersScope), + TEST(TemplateEndian), TEST(TypeNameOf), TEST(CustomBuiltinType), TEST(Using),