| // Copyright 2023 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef MPACT_SIM_DECODER_TEMPLATE_EXPRESSION_H_ |
| #define MPACT_SIM_DECODER_TEMPLATE_EXPRESSION_H_ |
| |
| #include <cstddef> |
| #include <functional> |
| #include <string> |
| #include <utility> |
| #include <variant> |
| #include <vector> |
| |
| #include "absl/status/statusor.h" |
| |
| // This file contains classes that represent and can evaluate expressions |
| // consisting of literals, template parameters, and operations: unary minus, |
| // add, subtract, multiply and divide. The value of the expression is |
| // abstracted to an absl::variant type. Currently, the only type that is |
| // supported is int, but putting the variant in now makes it easier to add |
| // support for others later. |
| |
| namespace mpact { |
| namespace sim { |
| namespace machine_description { |
| namespace instruction_set { |
| |
| // Variant with possible value types of template parameters. |
| using TemplateValue = ::std::variant<int>; |
| |
| // A template formal parameter has a name and a position in the template |
| // argument list. |
| class TemplateFormal { |
| public: |
| TemplateFormal(std::string name, int position) |
| : name_(std::move(name)), position_(position) {} |
| |
| const std::string& name() const { return name_; } |
| size_t position() const { return position_; } |
| |
| private: |
| std::string name_; |
| size_t position_; |
| }; |
| |
| // Template instantiation arguments are represented as a vector of template |
| // argument expressions that match to the positions of the template formal |
| // parameters. |
| |
| class TemplateExpression; |
| using TemplateInstantiationArgs = std::vector<TemplateExpression*>; |
| |
| // Virtual base class for template expressions. |
| class TemplateExpression { |
| public: |
| virtual ~TemplateExpression() = default; |
| // Returns the value of the expression provided it can be computed without |
| // having to resolve any template parameters (i.e., the expression tree |
| // does not contain any template parameter nodes. |
| virtual absl::StatusOr<TemplateValue> GetValue() const = 0; |
| // Returns a new expression tree where any template parameters have been |
| // resolved against the argument expressions that are passed in. Constant |
| // subexpressions are collapsed into constant nodes wherever possible. Note |
| // that the argument expressions may themselves contain template parameters |
| // for the "surrounding" template, so it may not resolve to a constant value. |
| virtual absl::StatusOr<TemplateExpression*> Evaluate( |
| TemplateInstantiationArgs*) = 0; |
| // Returns true if the expression can be evaluated to a constant. |
| virtual bool IsConstant() const = 0; |
| virtual TemplateExpression* DeepCopy() const = 0; |
| }; |
| |
| // Constant value expression node. |
| class TemplateConstant : public TemplateExpression { |
| public: |
| explicit TemplateConstant(int val) : value_(val) {} |
| explicit TemplateConstant(TemplateValue val) : value_(val) {} |
| absl::StatusOr<TemplateValue> GetValue() const override { return value_; } |
| absl::StatusOr<TemplateExpression*> Evaluate( |
| TemplateInstantiationArgs*) override; |
| bool IsConstant() const override { return true; } |
| TemplateExpression* DeepCopy() const override; |
| |
| private: |
| TemplateValue value_; |
| }; |
| |
| // Using the "curiously recurring template pattern" to define a templated |
| // base class for binary expression node classes. Each binary operator class |
| // will inherit from this class, while passing itself as the template argument. |
| template <typename T> |
| class BinaryTemplateExpression : public TemplateExpression { |
| public: |
| TemplateExpression* DeepCopy() const final { |
| return new T(lhs_->DeepCopy(), rhs_->DeepCopy()); |
| } |
| absl::StatusOr<TemplateExpression*> Evaluate( |
| TemplateInstantiationArgs* args) final { |
| auto lhs = lhs_->Evaluate(args); |
| if (!lhs.ok()) return lhs.status(); |
| |
| auto rhs = rhs_->Evaluate(args); |
| if (!rhs.ok()) { |
| delete lhs.value(); |
| return rhs.status(); |
| } |
| // Return a constant node if the right and left subexpressions are constant. |
| if (lhs.value()->IsConstant() && rhs.value()->IsConstant()) { |
| auto result = |
| T::Operator(lhs.value()->GetValue(), rhs.value()->GetValue()); |
| delete lhs.value(); |
| delete rhs.value(); |
| if (result.ok()) { |
| return new TemplateConstant(result.value()); |
| } else { |
| return result.status(); |
| } |
| } else { |
| return new T(lhs.value(), rhs.value()); |
| } |
| } |
| |
| absl::StatusOr<TemplateValue> GetValue() const final { |
| return T::Operator(lhs_->GetValue(), rhs_->GetValue()); |
| } |
| |
| bool IsConstant() const final { |
| return lhs_->IsConstant() && rhs_->IsConstant(); |
| } |
| |
| protected: |
| BinaryTemplateExpression() = delete; |
| BinaryTemplateExpression(TemplateExpression* lhs, TemplateExpression* rhs) |
| : lhs_(lhs), rhs_(rhs) {} |
| ~BinaryTemplateExpression() override { |
| delete lhs_; |
| delete rhs_; |
| lhs_ = nullptr; |
| rhs_ = nullptr; |
| } |
| |
| private: |
| TemplateExpression* lhs_; |
| TemplateExpression* rhs_; |
| }; |
| |
| // Slot constant. |
| class SlotConstant : public TemplateExpression { |
| public: |
| explicit SlotConstant(TemplateExpression* expr) : expr_(expr) {} |
| ~SlotConstant() override; |
| absl::StatusOr<TemplateValue> GetValue() const override; |
| absl::StatusOr<TemplateExpression*> Evaluate( |
| TemplateInstantiationArgs* args) override; |
| bool IsConstant() const override { return expr_->IsConstant(); } |
| TemplateExpression* DeepCopy() const override; |
| |
| private: |
| TemplateExpression* expr_ = nullptr; |
| }; |
| |
| // Template formal parameter reference expression node. |
| class TemplateParam : public TemplateExpression { |
| public: |
| explicit TemplateParam(TemplateFormal* param) : param_(param) {} |
| absl::StatusOr<TemplateValue> GetValue() const override; |
| absl::StatusOr<TemplateExpression*> Evaluate( |
| TemplateInstantiationArgs* args) override; |
| bool IsConstant() const override { return false; } |
| TemplateExpression* DeepCopy() const override; |
| |
| private: |
| TemplateFormal* param_; |
| }; |
| |
| // Negate expression node. |
| class TemplateNegate : public TemplateExpression { |
| public: |
| explicit TemplateNegate(TemplateExpression* expr) : expr_(expr) {} |
| ~TemplateNegate() override; |
| absl::StatusOr<TemplateValue> GetValue() const override; |
| absl::StatusOr<TemplateExpression*> Evaluate( |
| TemplateInstantiationArgs* args) override; |
| bool IsConstant() const override { return expr_->IsConstant(); } |
| TemplateExpression* DeepCopy() const override; |
| |
| private: |
| TemplateExpression* expr_; |
| }; |
| |
| // Multiply expression node. |
| class TemplateMultiply : public BinaryTemplateExpression<TemplateMultiply> { |
| public: |
| TemplateMultiply(TemplateExpression* lhs, TemplateExpression* rhs) |
| : BinaryTemplateExpression(lhs, rhs) {} |
| static absl::StatusOr<TemplateValue> Operator( |
| const absl::StatusOr<TemplateValue>& lhs, |
| const absl::StatusOr<TemplateValue>& rhs); |
| }; |
| |
| // Divide expression node. |
| class TemplateDivide : public BinaryTemplateExpression<TemplateDivide> { |
| public: |
| TemplateDivide(TemplateExpression* lhs, TemplateExpression* rhs) |
| : BinaryTemplateExpression(lhs, rhs) {} |
| static absl::StatusOr<TemplateValue> Operator( |
| const absl::StatusOr<TemplateValue>& lhs, |
| const absl::StatusOr<TemplateValue>& rhs); |
| }; |
| |
| // Add expression node. |
| class TemplateAdd : public BinaryTemplateExpression<TemplateAdd> { |
| public: |
| TemplateAdd(TemplateExpression* lhs, TemplateExpression* rhs) |
| : BinaryTemplateExpression(lhs, rhs) {} |
| static absl::StatusOr<TemplateValue> Operator( |
| const absl::StatusOr<TemplateValue>& lhs, |
| const absl::StatusOr<TemplateValue>& rhs); |
| }; |
| |
| // Subtract expression node. |
| class TemplateSubtract : public BinaryTemplateExpression<TemplateSubtract> { |
| public: |
| TemplateSubtract(TemplateExpression* lhs, TemplateExpression* rhs) |
| : BinaryTemplateExpression(lhs, rhs) {} |
| static absl::StatusOr<TemplateValue> Operator( |
| const absl::StatusOr<TemplateValue>& lhs, |
| const absl::StatusOr<TemplateValue>& rhs); |
| }; |
| |
| // Function expression node. |
| class TemplateFunction : public TemplateExpression { |
| public: |
| using Evaluator = |
| std::function<absl::StatusOr<TemplateValue>(TemplateInstantiationArgs*)>; |
| TemplateFunction(Evaluator evaluator, TemplateInstantiationArgs* args) |
| : evaluator_(std::move(evaluator)), args_(args) {} |
| ~TemplateFunction() override; |
| absl::StatusOr<TemplateValue> GetValue() const override; |
| absl::StatusOr<TemplateExpression*> Evaluate( |
| TemplateInstantiationArgs* args) override; |
| bool IsConstant() const override; |
| TemplateExpression* DeepCopy() const override; |
| |
| private: |
| Evaluator evaluator_; |
| TemplateInstantiationArgs* args_; |
| }; |
| |
| } // namespace instruction_set |
| } // namespace machine_description |
| } // namespace sim |
| } // namespace mpact |
| |
| #endif // MPACT_SIM_DECODER_TEMPLATE_EXPRESSION_H_ |