diff --git a/lib/include/pl/core/ast/ast_node_lvalue_assignment.hpp b/lib/include/pl/core/ast/ast_node_lvalue_assignment.hpp index 0f58ba9d..921485c5 100644 --- a/lib/include/pl/core/ast/ast_node_lvalue_assignment.hpp +++ b/lib/include/pl/core/ast/ast_node_lvalue_assignment.hpp @@ -37,6 +37,7 @@ namespace pl::core::ast { private: std::string m_lvalueName; std::unique_ptr m_rvalue; + mutable std::shared_ptr m_cachedVariable; }; } \ No newline at end of file diff --git a/lib/include/pl/core/ast/ast_node_rvalue.hpp b/lib/include/pl/core/ast/ast_node_rvalue.hpp index bfa5d5f2..f3e5b402 100644 --- a/lib/include/pl/core/ast/ast_node_rvalue.hpp +++ b/lib/include/pl/core/ast/ast_node_rvalue.hpp @@ -25,6 +25,8 @@ namespace pl::core::ast { private: Path m_path; + bool m_canCache = false; + mutable std::shared_ptr m_evaluatedPattern; }; } \ No newline at end of file diff --git a/lib/source/pl/core/ast/ast_node_attribute.cpp b/lib/source/pl/core/ast/ast_node_attribute.cpp index 0b2e0467..c744a158 100644 --- a/lib/source/pl/core/ast/ast_node_attribute.cpp +++ b/lib/source/pl/core/ast/ast_node_attribute.cpp @@ -175,6 +175,9 @@ namespace pl::core::ast { if (attributable == nullptr) err::E0008.throwError("Attributes cannot be applied to this statement.", {}, node->getLocation()); + if (attributable->getAttributes().empty()) + return; + if (attributable->hasAttribute("inline", false)) { auto inlinable = dynamic_cast(pattern.get()); @@ -389,6 +392,9 @@ namespace pl::core::ast { if (attributable == nullptr) err::E0008.throwError("Attributes cannot be applied to this statement.", {}, node->getLocation()); + if (attributable->getAttributes().empty()) + return; + auto endOffset = evaluator->getBitwiseReadOffset(); evaluator->setReadOffset(pattern->getOffset()); ON_SCOPE_EXIT { diff --git a/lib/source/pl/core/ast/ast_node_lvalue_assignment.cpp b/lib/source/pl/core/ast/ast_node_lvalue_assignment.cpp index 864d16a8..bd3a856e 100644 --- a/lib/source/pl/core/ast/ast_node_lvalue_assignment.cpp +++ b/lib/source/pl/core/ast/ast_node_lvalue_assignment.cpp @@ -29,20 +29,24 @@ namespace pl::core::ast { if (literal == nullptr) err::E0010.throwError("Cannot assign void expression to variable.", {}, this->getLocation()); - auto value = literal->getValue(); + const auto &value = literal->getValue(); if (this->getLValueName() == "$") evaluator->setReadOffset(u64(value.toUnsigned())); else { - auto variable = evaluator->getVariableByName(this->getLValueName()); - applyVariableAttributes(evaluator, this, variable); + if (m_cachedVariable == nullptr) { + m_cachedVariable = evaluator->getVariableByName(this->getLValueName()); + applyTypeAttributes(evaluator, this, m_cachedVariable); + } if (value.isPattern()) { auto decayedValue = value.toPattern()->getValue(); if (!decayedValue.isPattern()) - value = std::move(decayedValue); + evaluator->setVariable(m_cachedVariable, decayedValue); + else + evaluator->setVariable(m_cachedVariable, value); + } else { + evaluator->setVariable(m_cachedVariable, value); } - - evaluator->setVariable(this->getLValueName(), value); } return {}; diff --git a/lib/source/pl/core/ast/ast_node_rvalue.cpp b/lib/source/pl/core/ast/ast_node_rvalue.cpp index 67dce489..9ed4893a 100644 --- a/lib/source/pl/core/ast/ast_node_rvalue.cpp +++ b/lib/source/pl/core/ast/ast_node_rvalue.cpp @@ -24,7 +24,14 @@ namespace pl::core::ast { - ASTNodeRValue::ASTNodeRValue(Path &&path) : m_path(std::move(path)) { } + ASTNodeRValue::ASTNodeRValue(Path &&path) : m_path(std::move(path)) { + for (auto &part : m_path) { + if (std::holds_alternative>(part)) { + m_canCache = false; + return; + } + } + } ASTNodeRValue::ASTNodeRValue(const ASTNodeRValue &other) : ASTNode(other) { for (auto &part : other.m_path) { @@ -33,6 +40,7 @@ namespace pl::core::ast { else if (auto nodePart = std::get_if>(&part); nodePart != nullptr) this->m_path.emplace_back((*nodePart)->clone()); } + this->m_canCache = other.m_canCache; } static void readVariable(Evaluator *evaluator, auto &value, ptrn::Pattern *variablePattern) { @@ -52,102 +60,109 @@ namespace pl::core::ast { [[nodiscard]] std::unique_ptr ASTNodeRValue::evaluate(Evaluator *evaluator) const { [[maybe_unused]] auto context = evaluator->updateRuntime(this); - if (this->getPath().size() == 1) { - if (auto name = std::get_if(&this->getPath().front()); name != nullptr) { - if (*name == "$") return std::make_unique(u128(evaluator->getReadOffset())); - else if (*name == "null") return std::make_unique( - std::make_shared(evaluator, 0, 0, getLocation().line)); - - auto parameterPack = evaluator->getScope(0).parameterPack; - if (parameterPack && *name == parameterPack->name) - return std::make_unique(std::move(parameterPack->values)); - } - } else if (this->getPath().size() == 2) { - if (auto name = std::get_if(this->getPath().data()); name != nullptr) { - if (*name == "$") { - if (auto arraySegment = std::get_if>(&this->getPath()[1]); arraySegment != nullptr) { - auto offsetNode = (*arraySegment)->evaluate(evaluator); - auto offsetLiteral = dynamic_cast(offsetNode.get()); - if (offsetLiteral != nullptr) { - auto offset = u64(offsetLiteral->getValue().toUnsigned()); - - u8 byte = 0x00; - evaluator->readData(offset, &byte, 1, ptrn::Pattern::MainSectionId); - return std::make_unique(u128(byte)); + std::shared_ptr pattern; + if (!m_canCache || m_evaluatedPattern == nullptr) { + if (this->getPath().size() == 1) { + if (auto name = std::get_if(&this->getPath().front()); name != nullptr) { + if (*name == "$") return std::make_unique(u128(evaluator->getReadOffset())); + else if (*name == "null") return std::make_unique( + std::make_shared(evaluator, 0, 0, getLocation().line)); + + auto parameterPack = evaluator->getScope(0).parameterPack; + if (parameterPack && *name == parameterPack->name) + return std::make_unique(std::move(parameterPack->values)); + } + } else if (this->getPath().size() == 2) { + if (auto name = std::get_if(this->getPath().data()); name != nullptr) { + if (*name == "$") { + if (auto arraySegment = std::get_if>(&this->getPath()[1]); arraySegment != nullptr) { + auto offsetNode = (*arraySegment)->evaluate(evaluator); + auto offsetLiteral = dynamic_cast(offsetNode.get()); + if (offsetLiteral != nullptr) { + auto offset = u64(offsetLiteral->getValue().toUnsigned()); + + u8 byte = 0x00; + evaluator->readData(offset, &byte, 1, ptrn::Pattern::MainSectionId); + return std::make_unique(u128(byte)); + } } } } } - } - std::shared_ptr pattern; - { - std::vector> referencedPatterns; - this->createPatterns(evaluator, referencedPatterns); + { + std::vector> referencedPatterns; + this->createPatterns(evaluator, referencedPatterns); - pattern = std::move(referencedPatterns.front()); + pattern = std::move(referencedPatterns.front()); + } + + if (m_canCache) + m_evaluatedPattern = pattern; + } else { + pattern = m_evaluatedPattern; } - Token::Literal literal; + std::unique_ptr literal; if (dynamic_cast(pattern.get()) != nullptr) { u128 value = 0; readVariable(evaluator, value, pattern.get()); - literal = value; + literal = std::make_unique(value); } else if (dynamic_cast(pattern.get()) != nullptr) { i128 value = 0; readVariable(evaluator, value, pattern.get()); value = hlp::signExtend(pattern->getSize() * 8, value); - literal = value; + literal = std::make_unique(value); } else if (dynamic_cast(pattern.get()) != nullptr) { if (pattern->getSize() == sizeof(u16)) { u16 value = 0; readVariable(evaluator, value, pattern.get()); - literal = double(hlp::float16ToFloat32(value)); + literal = std::make_unique(double(hlp::float16ToFloat32(value))); } else if (pattern->getSize() == sizeof(float)) { float value = 0; readVariable(evaluator, value, pattern.get()); - literal = double(value); + literal = std::make_unique(double(value)); } else if (pattern->getSize() == sizeof(double)) { double value = 0; readVariable(evaluator, value, pattern.get()); - literal = value; + literal = std::make_unique(value); } else err::E0001.throwError("Invalid floating point type."); } else if (dynamic_cast(pattern.get()) != nullptr) { char value = 0; readVariable(evaluator, value, pattern.get()); - literal = value; + literal = std::make_unique(value); } else if (dynamic_cast(pattern.get()) != nullptr) { bool value = false; readVariable(evaluator, value, pattern.get()); - literal = value; + literal = std::make_unique(value); } else if (dynamic_cast(pattern.get()) != nullptr) { std::string value; readVariable(evaluator, value, pattern.get()); - literal = value; + literal = std::make_unique(value); } else if (auto bitfieldFieldPatternBoolean = dynamic_cast(pattern.get()); bitfieldFieldPatternBoolean != nullptr) { - literal = bool(bitfieldFieldPatternBoolean->readValue()); + literal = std::make_unique(bool(bitfieldFieldPatternBoolean->readValue())); } else if (auto bitfieldFieldPatternSigned = dynamic_cast(pattern.get()); bitfieldFieldPatternSigned != nullptr) { - literal = hlp::signExtend(bitfieldFieldPatternSigned->getBitSize(), i128(bitfieldFieldPatternSigned->readValue())); + literal = std::make_unique(hlp::signExtend(bitfieldFieldPatternSigned->getBitSize(), i128(bitfieldFieldPatternSigned->readValue()))); } else if (auto bitfieldFieldPatternEnum = dynamic_cast(pattern.get()); bitfieldFieldPatternEnum != nullptr) { - literal = pattern; + literal = std::make_unique(pattern); } else if (auto bitfieldFieldPattern = dynamic_cast(pattern.get()); bitfieldFieldPattern != nullptr) { - literal = bitfieldFieldPattern->readValue(); + literal = std::make_unique(bitfieldFieldPattern->readValue()); } else { - literal = pattern; + literal = std::make_unique(pattern); } if (auto transformFunc = evaluator->findFunction(pattern->getTransformFunction()); transformFunc.has_value()) { auto oldPatternName = pattern->getVariableName(); - auto result = transformFunc->func(evaluator, { std::move(literal) }); + auto result = transformFunc->func(evaluator, { literal->getValue() }); pattern->setVariableName(oldPatternName); if (!result.has_value()) err::E0009.throwError("Transform function did not return a value.", "Try adding a 'return ;' statement in all code paths.", this->getLocation()); - literal = std::move(result.value()); + literal = std::make_unique(std::move(result.value())); } - return std::unique_ptr(new ASTNodeLiteral(std::move(literal))); + return literal; } void ASTNodeRValue::createPatterns(Evaluator *evaluator, std::vector> &resultPatterns) const {