Rework of memory handling in Evaluation
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Deukhoofd 2019-07-27 17:59:42 +02:00
parent 268f6b59fb
commit ccc6e297f2
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
32 changed files with 496 additions and 461 deletions

View File

@ -1,91 +0,0 @@
#include "../Script.hpp"
#include "EvaluationException.hpp"
#include "Evaluator.hpp"
#include "EvalValues/NumericEvalValue.hpp"
#include "EvalValues/StringEvalValue.hpp"
using namespace Porygon::Binder;
namespace Porygon::Evaluation {
shared_ptr<const NumericEvalValue> Evaluator::EvaluateIntegerBinary(const BoundBinaryExpression *expression) {
auto leftValue = this->EvaluateIntegerExpression(expression->GetLeft());
auto rightValue = this->EvaluateIntegerExpression(expression->GetRight());
switch (expression->GetOperation()) {
case BoundBinaryOperation::Addition:
return leftValue.get()->operator+(rightValue);
case BoundBinaryOperation::Subtraction:
return leftValue.get()->operator-(rightValue);
case BoundBinaryOperation::Multiplication:
return leftValue.get()->operator*(rightValue);
case BoundBinaryOperation::Division:
return leftValue.get()->operator/(rightValue);
default:
throw EvaluationException("Can't evaluate operation to numeric");
}
}
shared_ptr<const BooleanEvalValue> Evaluator::EvaluateBooleanBinary(const BoundBinaryExpression *expression) {
switch (expression->GetOperation()) {
case BoundBinaryOperation::Equality: {
auto leftValue = this->EvaluateExpression(expression->GetLeft());
auto rightValue = this->EvaluateExpression(expression->GetRight());
bool equals = leftValue.get()->operator==(rightValue.get());
return make_shared<BooleanEvalValue>(equals);
}
case BoundBinaryOperation::Inequality: {
auto leftValue = this->EvaluateExpression(expression->GetLeft());
auto rightValue = this->EvaluateExpression(expression->GetRight());
bool equals = leftValue.get()->operator!=(rightValue.get());
return make_shared<BooleanEvalValue>(equals);
}
case BoundBinaryOperation::LessThan: {
auto leftValue = this->EvaluateIntegerExpression(expression->GetLeft());
auto rightValue = this->EvaluateIntegerExpression(expression->GetRight());
return leftValue->operator<(rightValue);
}
case BoundBinaryOperation::LessThanEquals: {
auto leftValue = this->EvaluateIntegerExpression(expression->GetLeft());
auto rightValue = this->EvaluateIntegerExpression(expression->GetRight());
return leftValue->operator<=(rightValue);
}
case BoundBinaryOperation::GreaterThan: {
auto leftValue = this->EvaluateIntegerExpression(expression->GetLeft());
auto rightValue = this->EvaluateIntegerExpression(expression->GetRight());
return leftValue->operator>(rightValue);
}
case BoundBinaryOperation::GreaterThanEquals: {
auto leftValue = this->EvaluateIntegerExpression(expression->GetLeft());
auto rightValue = this->EvaluateIntegerExpression(expression->GetRight());
return leftValue->operator>=(rightValue);
}
case BoundBinaryOperation::LogicalAnd: {
auto leftValue = this->EvaluateBoolExpression(expression->GetLeft());
if (!leftValue->EvaluateBool()) return leftValue;
auto rightValue = this->EvaluateBoolExpression(expression->GetRight());
return rightValue;
}
case BoundBinaryOperation::LogicalOr: {
auto leftValue = this->EvaluateBoolExpression(expression->GetLeft());
if (leftValue->EvaluateBool()) return leftValue;
auto rightValue = this->EvaluateBoolExpression(expression->GetRight());
return rightValue;
}
default:
throw EvaluationException("Can't evaluate operation to boolean");
}
}
shared_ptr<const StringEvalValue> Evaluator::EvaluateStringBinary(const BoundBinaryExpression *expression) {
if (expression->GetOperation() != BoundBinaryOperation::Concatenation)
throw;
std::basic_ostringstream<char16_t> stringStream;
auto left = this->EvaluateStringExpression(expression->GetLeft());
stringStream << left->EvaluateString();
auto right = this->EvaluateExpression(expression->GetRight());
stringStream << right->EvaluateString();
return make_shared<StringEvalValue>(stringStream.str());
}
}

View File

@ -0,0 +1 @@
#include "EvalValuePointer.hpp"

View File

@ -0,0 +1,85 @@
#ifndef PORYGONLANG_EVALVALUEPOINTER_HPP
#define PORYGONLANG_EVALVALUEPOINTER_HPP
#include "EvalValues/EvalValue.hpp"
namespace Porygon::Evaluation {
class EvalValuePointer {
const EvalValue *_ptr;
public:
EvalValuePointer(const EvalValue* p) :_ptr(p){};
EvalValuePointer(const EvalValuePointer& b){
if (b._ptr == nullptr){
_ptr = nullptr;
} else{
_ptr = b._ptr->Clone();
}
};
EvalValuePointer(){
_ptr = nullptr;
};
~EvalValuePointer(){
delete _ptr;
}
[[nodiscard]]
inline const EvalValue* Get() const{
return _ptr;
}
[[nodiscard]]
inline const EvalValue* Clone() const{
if (_ptr == nullptr){
return nullptr;
}
return _ptr->Clone();
}
inline const EvalValue* Take(){
auto p = _ptr;
_ptr = nullptr;
return p;
}
inline void ClearAssign(const EvalValue* n){
delete _ptr;
_ptr = n;
}
inline const bool HasValue() const{
return _ptr == nullptr;
}
inline const EvalValue* operator ->() const{
return Get();
}
inline bool operator == (const EvalValuePointer& b) const{
if (!_ptr){
return !b._ptr;
}
if (!b._ptr) return false;
return _ptr->operator==(b._ptr);
}
inline bool operator != (const EvalValuePointer& b) const{
if (!_ptr){
return b._ptr;
}
if (!b._ptr) return false;
return _ptr->operator!=(b._ptr);
}
EvalValuePointer& operator =(const EvalValuePointer& a){
if (a._ptr == nullptr){
_ptr = nullptr;
} else{
_ptr = a._ptr->Clone();
}
return *this;
};
};
}
#endif //PORYGONLANG_EVALVALUEPOINTER_HPP

View File

@ -64,9 +64,9 @@ TEST_CASE( "Evaluate String", "[integration]" ) {
auto script = Porygon::Script::Create(*sc); auto script = Porygon::Script::Create(*sc);
REQUIRE(!script->Diagnostics -> HasErrors()); REQUIRE(!script->Diagnostics -> HasErrors());
auto result = script->Evaluate(); auto result = script->Evaluate();
size_t size = GetEvalValueStringLength(result.get()); size_t size = GetEvalValueStringLength(result.Get());
auto dst = new char16_t[size + 1]{'\0'}; auto dst = new char16_t[size + 1]{'\0'};
EvaluateEvalValueString(result.get(), dst, size); EvaluateEvalValueString(result.Get(), dst, size);
auto s = u16string(dst); auto s = u16string(dst);
REQUIRE(s == u"foo bar"); REQUIRE(s == u"foo bar");
delete[] dst; delete[] dst;

View File

@ -12,6 +12,7 @@ namespace Porygon::Evaluation{
class Iterator; class Iterator;
} }
#include "../Iterator/Iterator.hpp" #include "../Iterator/Iterator.hpp"
#include "../../Binder/BoundOperators.hpp"
namespace Porygon::Evaluation { namespace Porygon::Evaluation {
@ -33,7 +34,7 @@ namespace Porygon::Evaluation {
} }
[[nodiscard]] [[nodiscard]]
virtual shared_ptr<const EvalValue> Clone() const = 0; virtual EvalValue* Clone() const = 0;
[[nodiscard]] [[nodiscard]]
virtual long EvaluateInteger() const { virtual long EvaluateInteger() const {
@ -59,16 +60,16 @@ namespace Porygon::Evaluation {
virtual std::size_t GetHashCode() const = 0; virtual std::size_t GetHashCode() const = 0;
[[nodiscard]] [[nodiscard]]
virtual shared_ptr<const EvalValue> IndexValue(const EvalValue *val) const { virtual const EvalValue* IndexValue(const EvalValue *val) const {
throw EvaluationException("Can't index this EvalValue"); throw EvaluationException("Can't index this EvalValue");
} }
[[nodiscard]] [[nodiscard]]
virtual shared_ptr<const EvalValue> IndexValue(uint32_t hash) const { virtual const EvalValue* IndexValue(uint32_t hash) const {
throw EvaluationException("Can't index this EvalValue"); throw EvaluationException("Can't index this EvalValue");
} }
virtual void SetIndexValue(const EvalValue *key, const shared_ptr<const EvalValue> &value) const { virtual void SetIndexValue(const EvalValue *key, const EvalValue* value) const {
throw EvaluationException("Can't index this EvalValue"); throw EvaluationException("Can't index this EvalValue");
} }
@ -76,6 +77,16 @@ namespace Porygon::Evaluation {
virtual Iterator * GetKeyIterator() const{ virtual Iterator * GetKeyIterator() const{
throw EvaluationException("Can't iterate over this EvalValue"); throw EvaluationException("Can't iterate over this EvalValue");
} }
[[nodiscard]]
virtual EvalValue* BinaryOperation(Binder::BoundBinaryOperation operation, const EvalValue* b) const{
throw EvaluationException("Binary operations are not implemented for this type.");
}
[[nodiscard]]
virtual EvalValue* UnaryOperation(Binder::BoundUnaryOperation operation) const{
throw EvaluationException("Unary operations are not implemented for this type.");
}
}; };
class BooleanEvalValue : public EvalValue { class BooleanEvalValue : public EvalValue {
@ -86,8 +97,8 @@ namespace Porygon::Evaluation {
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> Clone() const final { inline EvalValue* Clone() const final {
return make_shared<BooleanEvalValue>(_value); return new BooleanEvalValue(_value);
} }
[[nodiscard]] [[nodiscard]]
@ -111,6 +122,25 @@ namespace Porygon::Evaluation {
inline std::size_t GetHashCode() const final { inline std::size_t GetHashCode() const final {
return _value; return _value;
} }
[[nodiscard]]
inline EvalValue* BinaryOperation(Binder::BoundBinaryOperation operation, const EvalValue* b) const final{
auto bVal = b -> EvaluateBool();
switch (operation){
case Binder::BoundBinaryOperation::LogicalAnd: return new BooleanEvalValue(_value && bVal);
case Binder::BoundBinaryOperation::LogicalOr: return new BooleanEvalValue(_value || bVal);
default:
throw;
}
}
[[nodiscard]]
EvalValue* UnaryOperation(Binder::BoundUnaryOperation operation) const final{
switch (operation){
case Binder::BoundUnaryOperation::LogicalNegation: return new BooleanEvalValue(!_value);
default: throw;
}
}
}; };
} }

View File

@ -15,8 +15,8 @@ namespace Porygon::Evaluation{
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> Clone() const final{ inline EvalValue* Clone() const final{
return make_shared<NilEvalValue>(); return new NilEvalValue();
} }
[[nodiscard]] [[nodiscard]]

View File

@ -143,4 +143,70 @@ namespace Porygon::Evaluation {
} }
} }
} }
EvalValue *IntegerEvalValue::BinaryOperation(Binder::BoundBinaryOperation operation, const EvalValue *b) const {
auto right = dynamic_cast<const NumericEvalValue*>(b);
if (right->IsFloat()){
auto rightVal = right->EvaluateFloat();
switch (operation){
case Binder::BoundBinaryOperation::Addition: return new FloatEvalValue((double)_value + rightVal);
case Binder::BoundBinaryOperation::Subtraction: return new FloatEvalValue((double)_value - rightVal);
case Binder::BoundBinaryOperation::Multiplication: return new FloatEvalValue((double)_value * rightVal);
case Binder::BoundBinaryOperation::Division: return new FloatEvalValue((double)_value / rightVal);
case Binder::BoundBinaryOperation::LessThan: return new BooleanEvalValue((double)_value < rightVal);
case Binder::BoundBinaryOperation::LessThanEquals: return new BooleanEvalValue((double)_value <= rightVal);
case Binder::BoundBinaryOperation::GreaterThan: return new BooleanEvalValue((double)_value > rightVal);
case Binder::BoundBinaryOperation::GreaterThanEquals: return new BooleanEvalValue((double)_value >= rightVal);
default:
throw;
}
} else{
auto rightVal = right->EvaluateInteger();
switch (operation){
case Binder::BoundBinaryOperation::Addition: return new IntegerEvalValue(_value + rightVal);
case Binder::BoundBinaryOperation::Subtraction: return new IntegerEvalValue(_value - rightVal);
case Binder::BoundBinaryOperation::Multiplication: return new IntegerEvalValue(_value * rightVal);
case Binder::BoundBinaryOperation::Division: return new IntegerEvalValue(_value / rightVal);
case Binder::BoundBinaryOperation::LessThan: return new BooleanEvalValue(_value < rightVal);
case Binder::BoundBinaryOperation::LessThanEquals: return new BooleanEvalValue(_value <= rightVal);
case Binder::BoundBinaryOperation::GreaterThan: return new BooleanEvalValue(_value > rightVal);
case Binder::BoundBinaryOperation::GreaterThanEquals: return new BooleanEvalValue(_value >= rightVal);
default:
throw;
}
}
}
EvalValue *FloatEvalValue::BinaryOperation(Binder::BoundBinaryOperation operation, const EvalValue *b) const {
auto right = dynamic_cast<const NumericEvalValue*>(b);
if (right->IsFloat()){
auto rightVal = right->EvaluateFloat();
switch (operation){
case Binder::BoundBinaryOperation::Addition: return new FloatEvalValue(_value + rightVal);
case Binder::BoundBinaryOperation::Subtraction: return new FloatEvalValue(_value - rightVal);
case Binder::BoundBinaryOperation::Multiplication: return new FloatEvalValue(_value * rightVal);
case Binder::BoundBinaryOperation::Division: return new FloatEvalValue(_value / rightVal);
case Binder::BoundBinaryOperation::LessThan: return new BooleanEvalValue(_value < rightVal);
case Binder::BoundBinaryOperation::LessThanEquals: return new BooleanEvalValue(_value <= rightVal);
case Binder::BoundBinaryOperation::GreaterThan: return new BooleanEvalValue(_value > rightVal);
case Binder::BoundBinaryOperation::GreaterThanEquals: return new BooleanEvalValue(_value >= rightVal);
default:
throw;
}
} else{
auto rightVal = right->EvaluateInteger();
switch (operation){
case Binder::BoundBinaryOperation::Addition: return new IntegerEvalValue((long)_value + rightVal);
case Binder::BoundBinaryOperation::Subtraction: return new IntegerEvalValue((long)_value - rightVal);
case Binder::BoundBinaryOperation::Multiplication: return new IntegerEvalValue((long)_value * rightVal);
case Binder::BoundBinaryOperation::Division: return new IntegerEvalValue((long)_value / rightVal);
case Binder::BoundBinaryOperation::LessThan: return new BooleanEvalValue(_value < rightVal);
case Binder::BoundBinaryOperation::LessThanEquals: return new BooleanEvalValue(_value <= rightVal);
case Binder::BoundBinaryOperation::GreaterThan: return new BooleanEvalValue(_value > rightVal);
case Binder::BoundBinaryOperation::GreaterThanEquals: return new BooleanEvalValue(_value >= rightVal);
default:
throw;
}
}
}
} }

View File

@ -74,14 +74,25 @@ namespace Porygon::Evaluation {
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> Clone() const final { inline EvalValue* Clone() const final {
return make_shared<IntegerEvalValue>(_value); return new IntegerEvalValue(_value);
} }
[[nodiscard]] [[nodiscard]]
inline std::size_t GetHashCode() const final { inline std::size_t GetHashCode() const final {
return std::hash<long>{}(_value); return std::hash<long>{}(_value);
} }
[[nodiscard]]
EvalValue* BinaryOperation(Binder::BoundBinaryOperation operation, const EvalValue* b) const final;
[[nodiscard]]
EvalValue* UnaryOperation(Binder::BoundUnaryOperation operation) const final{
switch (operation){
case Binder::BoundUnaryOperation::Negation: return new IntegerEvalValue(-_value);
default: throw;
}
}
}; };
class FloatEvalValue : public NumericEvalValue { class FloatEvalValue : public NumericEvalValue {
@ -112,14 +123,25 @@ namespace Porygon::Evaluation {
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> Clone() const final { inline EvalValue* Clone() const final {
return make_shared<FloatEvalValue>(_value); return new FloatEvalValue(_value);
} }
[[nodiscard]] [[nodiscard]]
inline std::size_t GetHashCode() const final { inline std::size_t GetHashCode() const final {
return std::hash<double>{}(_value); return std::hash<double>{}(_value);
} }
[[nodiscard]]
inline EvalValue* BinaryOperation(Binder::BoundBinaryOperation operation, const EvalValue* b) const final;
[[nodiscard]]
EvalValue* UnaryOperation(Binder::BoundUnaryOperation operation) const final{
switch (operation){
case Binder::BoundUnaryOperation::Negation: return new FloatEvalValue(-_value);
default: throw;
}
}
}; };
} }

View File

@ -4,3 +4,9 @@
inline Porygon::Evaluation::Iterator *Porygon::Evaluation::NumericalTableEvalValue::GetKeyIterator() const { inline Porygon::Evaluation::Iterator *Porygon::Evaluation::NumericalTableEvalValue::GetKeyIterator() const {
return new NumericalKeyIterator(this); return new NumericalKeyIterator(this);
} }
Porygon::Evaluation::NumericalTableEvalValue::NumericalTableEvalValue(shared_ptr<vector<EvalValuePointer>> table) :
_table(std::move(table)),
_hash(rand())
{
}

View File

@ -5,26 +5,23 @@
#include <utility> #include <utility>
#include <map> #include <map>
#include "EvalValue.hpp" #include "EvalValue.hpp"
#include "../EvalValuePointer.hpp"
using namespace std; using namespace std;
namespace Porygon::Evaluation { namespace Porygon::Evaluation {
class NumericalTableEvalValue : public EvalValue { class NumericalTableEvalValue : public EvalValue {
const shared_ptr<vector<shared_ptr<const EvalValue>>> _table; const shared_ptr<vector<EvalValuePointer>> _table;
const size_t _hash; const size_t _hash;
explicit NumericalTableEvalValue(shared_ptr<vector<shared_ptr<const EvalValue>>> table, size_t hash) explicit NumericalTableEvalValue(shared_ptr<vector<EvalValuePointer>> table, size_t hash)
: _table(std::move(table)), : _table(std::move(table)),
_hash(hash) _hash(hash)
{ {
} }
public: public:
explicit NumericalTableEvalValue(shared_ptr<vector<shared_ptr<const EvalValue>>> table) : explicit NumericalTableEvalValue(shared_ptr<vector<EvalValuePointer>> table);
_table(std::move(table)),
_hash(rand())
{
}
[[nodiscard]] [[nodiscard]]
inline TypeClass GetTypeClass() const final { inline TypeClass GetTypeClass() const final {
@ -42,22 +39,22 @@ namespace Porygon::Evaluation {
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> Clone() const final { inline EvalValue* Clone() const final {
return shared_ptr<EvalValue>(new NumericalTableEvalValue(_table, _hash)); return new NumericalTableEvalValue(_table, _hash);
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> IndexValue(const EvalValue *val) const final { inline const EvalValue* IndexValue(const EvalValue *val) const final {
const auto index = val->EvaluateInteger() - 1; const auto index = val->EvaluateInteger() - 1;
return this->_table->at(index); return this->_table->at(index).Clone();
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> IndexValue(uint32_t hash) const final { inline EvalValue* IndexValue(uint32_t hash) const final {
return this->_table->at(hash - 1); return this->_table->at(hash - 1)-> Clone();
} }
inline void SetIndexValue(const EvalValue *key, const shared_ptr<const EvalValue> &value) const final { inline void SetIndexValue(const EvalValue *key, const EvalValue* value) const final {
auto index = key->EvaluateInteger(); auto index = key->EvaluateInteger();
this->_table->at(index - 1) = value; this->_table->at(index - 1) = value;
} }
@ -66,7 +63,7 @@ namespace Porygon::Evaluation {
Iterator * GetKeyIterator() const final; Iterator * GetKeyIterator() const final;
[[nodiscard]] [[nodiscard]]
inline shared_ptr<vector<shared_ptr<const EvalValue>>> GetTable() const{ inline shared_ptr<vector<EvalValuePointer>> GetTable() const{
return _table; return _table;
}; };
}; };

View File

@ -42,15 +42,15 @@ namespace Porygon::Evaluation {
protected: protected:
const shared_ptr<const GenericFunctionScriptType> _type; const shared_ptr<const GenericFunctionScriptType> _type;
const size_t _hash; const size_t _hash;
vector<shared_ptr<GenericFunctionOption>>* _options; shared_ptr<vector<shared_ptr<GenericFunctionOption>>> _options;
GenericFunctionEvalValue(shared_ptr<const GenericFunctionScriptType> type, size_t hash,
shared_ptr<vector<shared_ptr<GenericFunctionOption>>> options)
:_type(std::move(type)), _hash(hash), _options(std::move(options))
{}
public: public:
GenericFunctionEvalValue(shared_ptr<const GenericFunctionScriptType> type, size_t hash) GenericFunctionEvalValue(shared_ptr<const GenericFunctionScriptType> type, size_t hash)
: _type(move(type)), : _type(move(type)),
_hash(hash), _options(new vector<shared_ptr<GenericFunctionOption>>()){ _hash(hash), _options(make_shared<vector<shared_ptr<GenericFunctionOption>>>()){
}
~GenericFunctionEvalValue() final{
delete _options;
} }
GenericFunctionEvalValue(const GenericFunctionEvalValue& _) = delete; GenericFunctionEvalValue(const GenericFunctionEvalValue& _) = delete;
@ -58,19 +58,16 @@ namespace Porygon::Evaluation {
GenericFunctionEvalValue& operator =(GenericFunctionEvalValue v) = delete; GenericFunctionEvalValue& operator =(GenericFunctionEvalValue v) = delete;
[[nodiscard]] [[nodiscard]]
shared_ptr<const EvalValue> Clone() const final { EvalValue* Clone() const final {
auto t = make_shared<GenericFunctionEvalValue>(_type, _hash); return new GenericFunctionEvalValue(_type, _hash, _options);
for (const auto& o: *_options){
t->_options->push_back(o);
}
return t;
} }
inline void RegisterOption(GenericFunctionOption* option) const{ inline void RegisterOption(GenericFunctionOption* option) const{
_options->push_back(shared_ptr<GenericFunctionOption>(option)); _options->push_back(shared_ptr<GenericFunctionOption>(option));
} }
inline std::shared_ptr<const ScriptType> GetType() const { [[nodiscard]]
inline std::shared_ptr<const GenericFunctionScriptType> GetType() const {
return _type; return _type;
} }

View File

@ -34,20 +34,31 @@ namespace Porygon::Evaluation {
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> Clone() const final { inline EvalValue* Clone() const final {
return make_shared<StringEvalValue>(_value); return new StringEvalValue(_value);
} }
shared_ptr<const EvalValue> IndexValue(const EvalValue *val) const final { EvalValue* IndexValue(const EvalValue *val) const final {
// Porygon is 1-indexed, so we convert to that. // Porygon is 1-indexed, so we convert to that.
auto l = val->EvaluateInteger() - 1; auto l = val->EvaluateInteger() - 1;
return make_shared<const StringEvalValue>(u16string(1, _value[l])); return new StringEvalValue(u16string(1, _value[l]));
} }
[[nodiscard]] [[nodiscard]]
inline std::size_t GetHashCode() const final { inline std::size_t GetHashCode() const final {
return _hash; return _hash;
} }
[[nodiscard]]
inline EvalValue* BinaryOperation(Binder::BoundBinaryOperation operation, const EvalValue* b) const final{
if (operation != Binder::BoundBinaryOperation::Concatenation){
throw EvaluationException("Binary operation not supported for strings.");
}
std::basic_ostringstream<char16_t> stringStream;
stringStream << _value;
stringStream << b->EvaluateString();
return new StringEvalValue(stringStream.str());
}
}; };
} }

View File

@ -5,22 +5,23 @@
#include <map> #include <map>
#include "EvalValue.hpp" #include "EvalValue.hpp"
#include "../../Utilities/Random.hpp" #include "../../Utilities/Random.hpp"
#include "../EvalValuePointer.hpp"
using namespace std; using namespace std;
namespace Porygon::Evaluation { namespace Porygon::Evaluation {
class TableEvalValue : public EvalValue { class TableEvalValue : public EvalValue {
const shared_ptr<map<Utilities::HashedString, shared_ptr<const EvalValue>>> _table; const shared_ptr<map<Utilities::HashedString, EvalValuePointer>> _table;
const size_t _hash; const size_t _hash;
explicit TableEvalValue(shared_ptr<map<Utilities::HashedString, shared_ptr<const EvalValue>>> table, size_t hash) explicit TableEvalValue(shared_ptr<map<Utilities::HashedString, EvalValuePointer>> table, size_t hash)
: _table(std::move(table)), : _table(std::move(table)),
_hash(hash) _hash(hash)
{ {
} }
public: public:
explicit TableEvalValue(shared_ptr<map<Utilities::HashedString, shared_ptr<const EvalValue>>> table) : explicit TableEvalValue(shared_ptr<map<Utilities::HashedString, EvalValuePointer>> table) :
_table(std::move(table)), _table(std::move(table)),
_hash(Utilities::Random::Get()) _hash(Utilities::Random::Get())
{ {
@ -42,41 +43,41 @@ namespace Porygon::Evaluation {
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> Clone() const final { inline EvalValue* Clone() const final {
return shared_ptr<EvalValue>(new TableEvalValue(_table, _hash)); return new TableEvalValue(_table, _hash);
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> IndexValue(const EvalValue *val) const final { inline EvalValue* IndexValue(const EvalValue *val) const final {
const auto stringKey = val->EvaluateString(); const auto stringKey = val->EvaluateString();
return this->_table->at(Utilities::HashedString::CreateLookup(stringKey)); return this->_table->at(Utilities::HashedString::CreateLookup(stringKey))->Clone();
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> IndexValue(uint32_t hash) const final { inline EvalValue* IndexValue(uint32_t hash) const final {
return this->_table->at(Utilities::HashedString::CreateLookup(hash)); return this->_table->at(Utilities::HashedString::CreateLookup(hash))->Clone();
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> IndexValue(const char *val) const { inline const EvalValue* IndexValue(const char *val) const {
auto hash = Utilities::HashedString::ConstHash(val); auto hash = Utilities::HashedString::ConstHash(val);
return this->_table->at(Utilities::HashedString::CreateLookup(hash)); return this->_table->at(Utilities::HashedString::CreateLookup(hash)).Clone();
} }
inline void SetIndexValue(const EvalValue *key, const shared_ptr<const EvalValue> &value) const final { inline void SetIndexValue(const EvalValue *key, const EvalValue* value) const final {
auto hash = key->GetHashCode(); auto hash = key->GetHashCode();
this->_table->at(Utilities::HashedString::CreateLookup(hash)) = value; this->_table->at(Utilities::HashedString::CreateLookup(hash)).ClearAssign(value);
} }
[[nodiscard]] [[nodiscard]]
Iterator * GetKeyIterator() const final; Iterator * GetKeyIterator() const final;
[[nodiscard]] [[nodiscard]]
inline _Rb_tree_const_iterator<pair<const Utilities::HashedString, shared_ptr<const EvalValue>>> GetTableIterator() const{ inline _Rb_tree_const_iterator<pair<const Utilities::HashedString, EvalValuePointer>> GetTableIterator() const{
return _table->cbegin(); return _table->cbegin();
}; };
[[nodiscard]] [[nodiscard]]
inline _Rb_tree_const_iterator<pair<const Utilities::HashedString, shared_ptr<const EvalValue>>> GetTableIteratorEnd() const{ inline _Rb_tree_const_iterator<pair<const Utilities::HashedString, EvalValuePointer>> GetTableIteratorEnd() const{
return _table->cend(); return _table->cend();
}; };
}; };

View File

@ -4,38 +4,39 @@
#include <memory> #include <memory>
namespace Porygon::Evaluation { namespace Porygon::Evaluation {
EvaluationScope::EvaluationScope(map<Utilities::HashedString, shared_ptr<const EvalValue>> *scriptVariables) EvaluationScope::EvaluationScope(map<Utilities::HashedString, EvalValuePointer> *scriptVariables)
: _scriptScope(scriptVariables), : _scriptScope(scriptVariables),
_localScope(map<uint64_t, shared_ptr<const EvalValue>>()) { _localScope(map<uint64_t, EvalValuePointer>()) {
} }
void EvaluationScope::CreateVariable(const BoundVariableKey *key, const shared_ptr<const EvalValue>& value) { void EvaluationScope::CreateVariable(const BoundVariableKey *key, EvalValuePointer value) {
if (key->GetScopeId() == 0) { if (key->GetScopeId() == 0) {
_scriptScope->at(*key->GetIdentifier()) = value; _scriptScope->at(*key->GetIdentifier()).ClearAssign(value.Take());
} else { } else {
auto insert = _localScope.insert({key->GetHash(), value}); auto val = value.Clone();
auto insert = _localScope.insert({key->GetHash(), val});
if (!insert.second) { if (!insert.second) {
_localScope[key->GetHash()] = value; _localScope[key->GetHash()].ClearAssign(value.Take());
} }
} }
} }
void EvaluationScope::SetVariable(const BoundVariableKey *key, const shared_ptr<const EvalValue> &value) { void EvaluationScope::SetVariable(const BoundVariableKey *key, EvalValuePointer value) {
if (key->GetScopeId() == 0) { if (key->GetScopeId() == 0) {
_scriptScope->at(*key->GetIdentifier()) = value; _scriptScope->at(*key->GetIdentifier()).ClearAssign(value.Take());
} else { } else {
_localScope[key->GetHash()] = value; _localScope[key->GetHash()].ClearAssign(value.Take());
} }
} }
shared_ptr<const EvalValue> EvaluationScope::GetVariable(const BoundVariableKey *key) { EvalValuePointer EvaluationScope::GetVariable(const BoundVariableKey *key) {
auto scopeId = key -> GetScopeId(); auto scopeId = key -> GetScopeId();
if (scopeId== 0) { if (scopeId== 0) {
return _scriptScope->at(*key->GetIdentifier()); return _scriptScope->at(*key->GetIdentifier())->Clone();
} else if(scopeId == -2){ } else if(scopeId == -2){
return StandardLibraries::StaticScope::GetVariable(*key->GetIdentifier()); return StandardLibraries::StaticScope::GetVariable(*key->GetIdentifier()).Clone();
} else { } else {
return _localScope[key->GetHash()]; return _localScope[key->GetHash()]->Clone();
} }
} }
} }

View File

@ -5,22 +5,26 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include "../EvalValues/EvalValue.hpp" #include "../EvalValues/EvalValue.hpp"
#include "../EvalValuePointer.hpp"
using namespace Porygon::Binder; using namespace Porygon::Binder;
namespace Porygon::Evaluation { namespace Porygon::Evaluation {
class EvaluationScope { class EvaluationScope {
map<Utilities::HashedString, shared_ptr<const EvalValue>> *_scriptScope; map<Utilities::HashedString, EvalValuePointer> *_scriptScope;
map<uint64_t, shared_ptr<const EvalValue>> _localScope; map<uint64_t, EvalValuePointer> _localScope;
public: public:
explicit EvaluationScope(map<Utilities::HashedString, shared_ptr<const EvalValue>> *scriptVariables); explicit EvaluationScope(map<Utilities::HashedString, EvalValuePointer> *scriptVariables);
~EvaluationScope() = default; ~EvaluationScope(){
_localScope.clear();
};
void CreateVariable(const BoundVariableKey *key, const shared_ptr<const EvalValue>&value); void CreateVariable(const BoundVariableKey *key, EvalValuePointer value);
void SetVariable(const BoundVariableKey *key, const shared_ptr<const EvalValue> &value); void SetVariable(const BoundVariableKey *key, EvalValuePointer value);
shared_ptr<const EvalValue> GetVariable(const BoundVariableKey *key); EvalValuePointer GetVariable(const BoundVariableKey *key);
}; };
} }

View File

@ -15,15 +15,18 @@ using namespace std;
using namespace Porygon::Binder; using namespace Porygon::Binder;
namespace Porygon::Evaluation { namespace Porygon::Evaluation {
shared_ptr<const EvalValue> Evaluator::Evaluate(const BoundScriptStatement *statement) { const EvalValue* Evaluator::Evaluate(const BoundScriptStatement *statement) {
this->_evaluationScope = make_shared<EvaluationScope>(this->_scriptVariables); this->_evaluationScope = make_shared<EvaluationScope>(this->_scriptVariables);
auto statements = statement->GetStatements(); auto statements = statement->GetStatements();
if (statements -> size() == 1 && statements->at(0)->GetKind() == BoundStatementKind::Expression){ if (statements -> size() == 1 && statements->at(0)->GetKind() == BoundStatementKind::Expression){
auto expStatement = (BoundExpressionStatement*) statements -> at(0); auto expStatement = (BoundExpressionStatement*) statements -> at(0);
return this -> EvaluateExpression(expStatement -> GetExpression()); return this -> EvaluateExpression(expStatement -> GetExpression()).Clone();
} }
EvaluateBlockStatement(statement); EvaluateBlockStatement(statement);
return this->_returnValue; if (this->_returnValue.Get() == nullptr){
return nullptr;
}
return this->_returnValue.Clone();
} }
void Evaluator::EvaluateStatement(const BoundStatement *statement) { void Evaluator::EvaluateStatement(const BoundStatement *statement) {
@ -78,9 +81,9 @@ namespace Porygon::Evaluation {
auto value = this->EvaluateExpression(statement->GetExpression()); auto value = this->EvaluateExpression(statement->GetExpression());
auto key = statement->GetKey(); auto key = statement->GetKey();
if (key->IsCreation()) { if (key->IsCreation()) {
this->_evaluationScope->CreateVariable(key, value); this->_evaluationScope->CreateVariable(key, value.Clone());
} else { } else {
this->_evaluationScope->SetVariable(key, value); this->_evaluationScope->SetVariable(key, value.Clone());
} }
} }
@ -90,7 +93,7 @@ namespace Porygon::Evaluation {
auto index = ((BoundIndexExpression *) indexExpression); auto index = ((BoundIndexExpression *) indexExpression);
auto table = this->EvaluateExpression(index->GetIndexableExpression()); auto table = this->EvaluateExpression(index->GetIndexableExpression());
auto key = this->EvaluateExpression(index->GetIndexExpression()); auto key = this->EvaluateExpression(index->GetIndexExpression());
table->SetIndexValue(key.get(), value); table->SetIndexValue(key.Get(), value.Take());
} }
void Evaluator::EvaluateFunctionDeclarationStatement(const BoundFunctionDeclarationStatement *statement) { void Evaluator::EvaluateFunctionDeclarationStatement(const BoundFunctionDeclarationStatement *statement) {
@ -100,13 +103,14 @@ namespace Porygon::Evaluation {
auto option = new Evaluation::EvaluationScriptFunctionOption(block, this->_evaluationScope); auto option = new Evaluation::EvaluationScriptFunctionOption(block, this->_evaluationScope);
if (key->IsCreation()) { if (key->IsCreation()) {
auto value = make_shared<GenericFunctionEvalValue>(type, Utilities::Random::Get()); auto p = new GenericFunctionEvalValue(type, Utilities::Random::Get());
value->RegisterOption(option); p->RegisterOption(option);
auto value = EvalValuePointer(p);
this->_evaluationScope->CreateVariable(key, value); this->_evaluationScope->CreateVariable(key, value);
} else { } else {
auto var = dynamic_pointer_cast<const GenericFunctionEvalValue>(this -> _evaluationScope ->GetVariable(key)); auto var = (GenericFunctionEvalValue*)this -> _evaluationScope ->GetVariable(key).Get();
var->RegisterOption(option); var->RegisterOption(option);
this->_evaluationScope->SetVariable(key, var); //this->_evaluationScope->SetVariable(key, var);
} }
} }
@ -114,17 +118,17 @@ namespace Porygon::Evaluation {
auto expression = statement->GetExpression(); auto expression = statement->GetExpression();
if (expression == nullptr) { if (expression == nullptr) {
this->_hasReturned = true; this->_hasReturned = true;
this -> _returnValue = nullptr; this -> _returnValue.ClearAssign(nullptr);
return; return;
} }
auto value = this->EvaluateExpression(expression); auto value = this->EvaluateExpression(expression).Take();
this->_hasReturned = true; this->_hasReturned = true;
this->_returnValue = value; this->_returnValue.ClearAssign(value);
} }
void Evaluator::EvaluateConditionalStatement(const BoundConditionalStatement *statement) { void Evaluator::EvaluateConditionalStatement(const BoundConditionalStatement *statement) {
auto condition = statement->GetCondition(); auto condition = statement->GetCondition();
if (EvaluateBoolExpression(condition)->EvaluateBool()) { if (EvaluateExpression(condition)->EvaluateBool()) {
this->EvaluateStatement(statement->GetBlock()); this->EvaluateStatement(statement->GetBlock());
} else { } else {
auto elseStatement = statement->GetElseStatement(); auto elseStatement = statement->GetElseStatement();
@ -135,12 +139,12 @@ namespace Porygon::Evaluation {
} }
void Evaluator::EvaluateNumericalForStatement(const BoundNumericalForStatement *statement) { void Evaluator::EvaluateNumericalForStatement(const BoundNumericalForStatement *statement) {
long start = this->EvaluateIntegerExpression(statement -> GetStart()) -> EvaluateInteger(); long start = this->EvaluateExpression(statement -> GetStart()) -> EvaluateInteger();
long end = this->EvaluateIntegerExpression(statement -> GetEnd()) -> EvaluateInteger(); long end = this->EvaluateExpression(statement -> GetEnd()) -> EvaluateInteger();
long step = 1; long step = 1;
auto stepExp = statement -> GetStep(); auto stepExp = statement -> GetStep();
if (stepExp != nullptr){ if (stepExp != nullptr){
step = this -> EvaluateIntegerExpression(stepExp) -> EvaluateInteger(); step = this -> EvaluateExpression(stepExp) -> EvaluateInteger();
} }
auto identifier = statement -> GetIdentifier(); auto identifier = statement -> GetIdentifier();
this -> _evaluationScope -> CreateVariable(identifier, nullptr); this -> _evaluationScope -> CreateVariable(identifier, nullptr);
@ -148,7 +152,7 @@ namespace Porygon::Evaluation {
auto statements = *block -> GetStatements(); auto statements = *block -> GetStatements();
if (step >= 0){ if (step >= 0){
for (long i = start; i <= end; i += step){ for (long i = start; i <= end; i += step){
this -> _evaluationScope -> SetVariable(identifier, make_shared<IntegerEvalValue>(i)); this -> _evaluationScope -> SetVariable(identifier, new IntegerEvalValue(i));
for (auto s: statements) { for (auto s: statements) {
this->EvaluateStatement(s); this->EvaluateStatement(s);
if (this->_hasReturned || this -> _hasBroken) if (this->_hasReturned || this -> _hasBroken)
@ -159,7 +163,7 @@ namespace Porygon::Evaluation {
} }
} else{ } else{
for (long i = start; i >= end; i += step){ for (long i = start; i >= end; i += step){
this -> _evaluationScope -> SetVariable(identifier, make_shared<IntegerEvalValue>(i)); this -> _evaluationScope -> SetVariable(identifier, new IntegerEvalValue(i));
for (auto s: statements) { for (auto s: statements) {
this->EvaluateStatement(s); this->EvaluateStatement(s);
if (this->_hasReturned || this -> _hasBroken) if (this->_hasReturned || this -> _hasBroken)
@ -184,10 +188,10 @@ namespace Porygon::Evaluation {
auto block = (BoundBlockStatement*)statement -> GetBlock(); auto block = (BoundBlockStatement*)statement -> GetBlock();
auto statements = *block -> GetStatements(); auto statements = *block -> GetStatements();
while (iterator->MoveNext()){ while (iterator->MoveNext()){
auto currentKey = iterator->GetCurrent(); auto currentKey = EvalValuePointer(iterator->GetCurrent());
this -> _evaluationScope -> SetVariable(keyVariable, currentKey); this -> _evaluationScope -> SetVariable(keyVariable, currentKey);
if (valueVariable != nullptr){ if (valueVariable != nullptr){
auto currentValue = iteratorVal -> IndexValue(currentKey.get()); auto currentValue = EvalValuePointer(iteratorVal -> IndexValue(currentKey.Get()));
this -> _evaluationScope -> SetVariable(valueVariable, currentValue); this -> _evaluationScope -> SetVariable(valueVariable, currentValue);
} }
for (auto s: statements) { for (auto s: statements) {
@ -206,7 +210,7 @@ namespace Porygon::Evaluation {
auto condition = statement -> GetCondition(); auto condition = statement -> GetCondition();
auto block = (BoundBlockStatement*)statement -> GetBlock(); auto block = (BoundBlockStatement*)statement -> GetBlock();
auto statements = *block -> GetStatements(); auto statements = *block -> GetStatements();
while (this->EvaluateBoolExpression(condition)->EvaluateBool()){ while (this->EvaluateExpression(condition)->EvaluateBool()){
for (auto s: statements) { for (auto s: statements) {
this->EvaluateStatement(s); this->EvaluateStatement(s);
if (this->_hasReturned || this -> _hasBroken) if (this->_hasReturned || this -> _hasBroken)
@ -222,161 +226,75 @@ namespace Porygon::Evaluation {
// Expressions // // Expressions //
///////////////// /////////////////
shared_ptr<const EvalValue> Evaluator::EvaluateExpression(const BoundExpression *expression) { EvalValuePointer Evaluator::EvaluateExpression(const BoundExpression *expression) {
auto type = expression->GetType(); switch (expression->GetKind()){
switch (type->GetClass()) {
case TypeClass::Number:
return this->EvaluateIntegerExpression(expression);
case TypeClass::Bool:
return this->EvaluateBoolExpression(expression);
case TypeClass::String:
return this->EvaluateStringExpression(expression);
case TypeClass::Function:
return this->EvaluateFunctionExpression(expression);
case TypeClass::Nil:
return this->EvaluateNilExpression(expression);
case TypeClass::Table:
return this->EvaluateTableExpression(expression);
case TypeClass::UserData:
return this->EvaluateUserDataExpression(expression);
default:
throw;
}
}
shared_ptr<const EvalValue> Evaluator::GetVariable(const BoundVariableExpression *expression) { case BoundExpressionKind::Bad: throw;
auto variable = this->_evaluationScope->GetVariable(expression->GetKey());
if (variable == nullptr) {
throw EvaluationException("Variable not found");
}
return variable->Clone();
}
shared_ptr<const NumericEvalValue> Evaluator::EvaluateIntegerExpression(const BoundExpression *expression) {
switch (expression->GetKind()) {
case BoundExpressionKind::LiteralInteger: case BoundExpressionKind::LiteralInteger:
return make_shared<IntegerEvalValue>(((BoundLiteralIntegerExpression *) expression)->GetValue()); return new IntegerEvalValue(((BoundLiteralIntegerExpression *) expression)->GetValue());
case BoundExpressionKind::LiteralFloat: case BoundExpressionKind::LiteralFloat:
return make_shared<FloatEvalValue>(((BoundLiteralFloatExpression *) expression)->GetValue()); return new FloatEvalValue(((BoundLiteralFloatExpression *) expression)->GetValue());
case BoundExpressionKind::Unary:
return this->EvaluateIntegerUnary((BoundUnaryExpression *) expression);
case BoundExpressionKind::Binary:
return this->EvaluateIntegerBinary((BoundBinaryExpression *) expression);
case BoundExpressionKind::Variable:
return dynamic_pointer_cast<const NumericEvalValue>(
this->GetVariable((BoundVariableExpression *) expression));
case BoundExpressionKind::FunctionCall:
return dynamic_pointer_cast<const NumericEvalValue>(this->EvaluateFunctionCallExpression(expression));
case BoundExpressionKind::Index:
return dynamic_pointer_cast<const NumericEvalValue>(this->EvaluateIndexExpression(expression));
case BoundExpressionKind::PeriodIndex:
return dynamic_pointer_cast<const NumericEvalValue>(this->EvaluatePeriodIndexExpression(expression));
default:
throw;
}
}
shared_ptr<const BooleanEvalValue> Evaluator::EvaluateBoolExpression(const BoundExpression *expression) {
switch (expression->GetKind()) {
case BoundExpressionKind::LiteralBool:
return make_shared<BooleanEvalValue>(((BoundLiteralBoolExpression *) expression)->GetValue());
case BoundExpressionKind::Unary:
return this->EvaluateBooleanUnary((BoundUnaryExpression *) expression);
case BoundExpressionKind::Binary:
return this->EvaluateBooleanBinary((BoundBinaryExpression *) expression);
case BoundExpressionKind::Variable:
return dynamic_pointer_cast<const BooleanEvalValue>(
this->GetVariable((BoundVariableExpression *) expression));
case BoundExpressionKind::FunctionCall:
return dynamic_pointer_cast<const BooleanEvalValue>(this->EvaluateFunctionCallExpression(expression));
case BoundExpressionKind::Index:
return dynamic_pointer_cast<const BooleanEvalValue>(this->EvaluateIndexExpression(expression));
case BoundExpressionKind::PeriodIndex:
return dynamic_pointer_cast<const BooleanEvalValue>(this->EvaluatePeriodIndexExpression(expression));
default:
throw;
}
}
shared_ptr<const StringEvalValue> Evaluator::EvaluateStringExpression(const BoundExpression *expression) {
switch (expression->GetKind()) {
case BoundExpressionKind::LiteralString: case BoundExpressionKind::LiteralString:
return make_shared<StringEvalValue>(*((BoundLiteralStringExpression *) expression)->GetValue()); return new StringEvalValue(*((BoundLiteralStringExpression *) expression)->GetValue());
case BoundExpressionKind::LiteralBool:
return new BooleanEvalValue(((BoundLiteralBoolExpression *) expression)->GetValue());
case BoundExpressionKind::Variable:
return this -> GetVariable((BoundVariableExpression*)expression);
case BoundExpressionKind::Unary:
return this->EvaluateUnary((BoundUnaryExpression *) expression);
case BoundExpressionKind::Binary: case BoundExpressionKind::Binary:
return this->EvaluateStringBinary((BoundBinaryExpression *) expression); return this->EvaluateBinary((BoundBinaryExpression *) expression);
case BoundExpressionKind::Variable:
return dynamic_pointer_cast<const StringEvalValue>(this->GetVariable((BoundVariableExpression *) expression));
case BoundExpressionKind::FunctionCall: case BoundExpressionKind::FunctionCall:
return dynamic_pointer_cast<const StringEvalValue>(this->EvaluateFunctionCallExpression(expression)); return this->EvaluateFunctionCallExpression(expression);
case BoundExpressionKind::Index: case BoundExpressionKind::Index:
return dynamic_pointer_cast<const StringEvalValue>(this->EvaluateIndexExpression(expression)); return this->EvaluateIndexExpression(expression).Take();
case BoundExpressionKind::PeriodIndex:
return dynamic_pointer_cast<const StringEvalValue>(this->EvaluatePeriodIndexExpression(expression));
default:
throw;
}
}
shared_ptr<const EvalValue> Evaluator::EvaluateFunctionExpression(const BoundExpression *expression) {
switch (expression->GetKind()) {
case BoundExpressionKind::Variable:
return this->GetVariable((BoundVariableExpression *) expression);
case BoundExpressionKind::Index:
return this->EvaluateIndexExpression(expression);
case BoundExpressionKind::PeriodIndex: case BoundExpressionKind::PeriodIndex:
return this->EvaluatePeriodIndexExpression(expression); return this->EvaluatePeriodIndexExpression(expression);
default:
throw;
}
}
shared_ptr<const EvalValue> Evaluator::EvaluateNilExpression(const BoundExpression *expression) {
switch (expression->GetKind()) {
case BoundExpressionKind::FunctionCall:
return this->EvaluateFunctionCallExpression(expression);
default:
return nullptr;
}
}
shared_ptr<const EvalValue> Evaluator::EvaluateTableExpression(const BoundExpression *expression) {
switch (expression->GetKind()) {
case BoundExpressionKind::FunctionCall:
return this->EvaluateFunctionCallExpression(expression);
case BoundExpressionKind::Variable:
return this->GetVariable((BoundVariableExpression *) expression);
case BoundExpressionKind::Index:
return this->EvaluateIndexExpression(expression);
case BoundExpressionKind::NumericalTable: case BoundExpressionKind::NumericalTable:
return this->EvaluateNumericTableExpression(expression); return this->EvaluateNumericTableExpression(expression);
case BoundExpressionKind::Table: case BoundExpressionKind::Table:
return this->EvaluateComplexTableExpression(expression); return this->EvaluateComplexTableExpression(expression);
case BoundExpressionKind::PeriodIndex:
return this->EvaluatePeriodIndexExpression(expression);
default:
throw;
} }
} }
EvalValuePointer Evaluator::EvaluateBinary(const BoundBinaryExpression *expression){
auto leftValue = this -> EvaluateExpression(expression->GetLeft());
auto rightValue = this -> EvaluateExpression(expression->GetRight());
auto operation = expression->GetOperation();
if (operation == BoundBinaryOperation::Equality){
return new BooleanEvalValue(leftValue == rightValue);
} else if (operation == BoundBinaryOperation::Inequality){
return new BooleanEvalValue(leftValue != rightValue);
}
return leftValue->BinaryOperation(operation, rightValue.Get());
}
shared_ptr<const EvalValue> Evaluator::EvaluateFunctionCallExpression(const BoundExpression *expression) { EvalValuePointer Evaluator::EvaluateUnary(const BoundUnaryExpression *expression) {
auto exp = expression->GetOperand();
auto val = EvaluateExpression(exp);
return val->UnaryOperation(expression->GetOperation());
}
EvalValuePointer Evaluator::GetVariable(const BoundVariableExpression *expression) {
auto variable = this->_evaluationScope->GetVariable(expression->GetKey());
if (variable.Get() == nullptr) {
throw EvaluationException("Variable not found");
}
return variable;
}
EvalValuePointer Evaluator::EvaluateFunctionCallExpression(const BoundExpression *expression) {
auto functionCall = (BoundFunctionCallExpression *) expression; auto functionCall = (BoundFunctionCallExpression *) expression;
auto function = dynamic_pointer_cast<const GenericFunctionEvalValue>( auto function = (GenericFunctionEvalValue*)this->EvaluateExpression(functionCall->GetFunctionExpression()).Clone();
this->EvaluateExpression(functionCall->GetFunctionExpression()));
auto boundParameters = functionCall->GetParameters(); auto boundParameters = functionCall->GetParameters();
auto parameters = vector<shared_ptr<const EvalValue>>(boundParameters->size()); auto parameters = vector<EvalValuePointer>(boundParameters->size());
for (size_t i = 0; i < boundParameters->size(); i++) { for (size_t i = 0; i < boundParameters->size(); i++) {
parameters[i] = this->EvaluateExpression(boundParameters->at(i)); parameters[i] = this->EvaluateExpression(boundParameters->at(i));
} }
auto type = std::dynamic_pointer_cast<const GenericFunctionScriptType>(function->GetType()); auto type = std::dynamic_pointer_cast<const GenericFunctionScriptType>(function->GetType());
auto func = dynamic_pointer_cast<const GenericFunctionEvalValue>(function); auto func = function;
auto option = functionCall ->GetFunctionOption(); auto option = functionCall ->GetFunctionOption();
auto opt = func->GetOption(option->GetOptionId()); auto opt = func->GetOption(option->GetOptionId());
if (option -> IsScriptFunction()){ if (option -> IsScriptFunction()){
@ -390,28 +308,30 @@ namespace Porygon::Evaluation {
for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++) { for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++) {
auto parameter = parameters[i]; auto parameter = parameters[i];
auto key = parameterKeys.at(i); auto key = parameterKeys.at(i);
this->_evaluationScope->CreateVariable(key.get(), parameter->Clone()); this->_evaluationScope->CreateVariable(key.get(), parameter.Clone());
} }
this->EvaluateBlockStatement(scriptOption->GetInnerBlock().get()); this->EvaluateBlockStatement(scriptOption->GetInnerBlock().get());
this->_evaluationScope = originalScope; this->_evaluationScope = originalScope;
this->_hasReturned = false; this->_hasReturned = false;
auto r = this->_returnValue; auto r = this->_returnValue;
this->_returnValue = nullptr; this->_returnValue.ClearAssign(nullptr);
delete function;
return r; return r;
} else{ } else{
auto scriptOption = dynamic_pointer_cast<const UserData::UserDataFunction>(opt); auto scriptOption = dynamic_pointer_cast<const UserData::UserDataFunction>(opt);
const EvalValue* arr[parameters.size()]; const EvalValue* arr[parameters.size()];
for (size_t i = 0; i < parameters.size(); i++){ for (size_t i = 0; i < parameters.size(); i++){
arr[i] = parameters[i].get(); arr[i] = parameters[i].Get();
} }
return shared_ptr<const EvalValue>(scriptOption -> Call(arr, parameters.size())); delete function;
return scriptOption -> Call(arr, parameters.size());
} }
} }
shared_ptr<const EvalValue> Evaluator::EvaluateFunction(const GenericFunctionEvalValue *function, const EvalValue* Evaluator::EvaluateFunction(const GenericFunctionEvalValue *function,
const vector<EvalValue *> &parameters) { const vector<EvalValue *> &parameters) {
auto type = std::dynamic_pointer_cast<const GenericFunctionScriptType>(function->GetType()); auto type = function->GetType();
auto option = dynamic_cast<const ScriptFunctionOption*>(type->GetFirstOption()); auto option = dynamic_cast<const ScriptFunctionOption*>(type->GetFirstOption());
auto parameterTypes = option->GetParameterTypes(); auto parameterTypes = option->GetParameterTypes();
@ -429,42 +349,43 @@ namespace Porygon::Evaluation {
this->EvaluateBlockStatement(scriptOption->GetInnerBlock().get()); this->EvaluateBlockStatement(scriptOption->GetInnerBlock().get());
this->_evaluationScope = originalScope; this->_evaluationScope = originalScope;
this->_hasReturned = false; this->_hasReturned = false;
auto r = this->_returnValue; auto r = this->_returnValue.Take();
this->_returnValue = nullptr; delete function;
return r; return r;
} }
shared_ptr<const EvalValue> Evaluator::EvaluateIndexExpression(const BoundExpression *expression) { EvalValuePointer Evaluator::EvaluateIndexExpression(const BoundExpression *expression) {
auto indexExpression = (BoundIndexExpression *) expression; auto indexExpression = (BoundIndexExpression *) expression;
auto index = this->EvaluateExpression(indexExpression->GetIndexExpression()); auto index = this->EvaluateExpression(indexExpression->GetIndexExpression());
auto indexable = this->EvaluateExpression(indexExpression->GetIndexableExpression()); auto indexable = this->EvaluateExpression(indexExpression->GetIndexableExpression());
return indexable->IndexValue(index.get()); return indexable->IndexValue(index.Get());
} }
shared_ptr<const EvalValue> Evaluator::EvaluatePeriodIndexExpression(const BoundExpression *expression) { EvalValuePointer Evaluator::EvaluatePeriodIndexExpression(const BoundExpression *expression) {
auto indexExpression = (BoundPeriodIndexExpression *) expression; auto indexExpression = (BoundPeriodIndexExpression *) expression;
auto index = indexExpression->GetIndex()->GetHash(); auto index = indexExpression->GetIndex()->GetHash();
auto indexable = this->EvaluateExpression(indexExpression->GetIndexableExpression()); auto indexable = this->EvaluateExpression(indexExpression->GetIndexableExpression());
return indexable->IndexValue(index)->Clone(); return indexable->IndexValue(index);
} }
shared_ptr<const EvalValue> Evaluator::EvaluateNumericTableExpression(const BoundExpression *expression) { EvalValuePointer Evaluator::EvaluateNumericTableExpression(const BoundExpression *expression) {
auto tableExpression = (BoundNumericalTableExpression *) expression; auto tableExpression = (BoundNumericalTableExpression *) expression;
auto valueExpressions = tableExpression->GetExpressions(); auto valueExpressions = tableExpression->GetExpressions();
auto values = new vector<shared_ptr<const EvalValue>>(valueExpressions->size()); auto values = new vector<EvalValuePointer>(valueExpressions->size());
for (size_t i = 0; i < valueExpressions->size(); i++) { for (size_t i = 0; i < valueExpressions->size(); i++) {
auto val = this->EvaluateExpression(valueExpressions->at(i)); auto val = this->EvaluateExpression(valueExpressions->at(i));
values->at(i) = val; values->at(i) = val.Take();
} }
auto valuesPointer = shared_ptr<vector<shared_ptr<const EvalValue>>>(values); auto valuesPointer = shared_ptr<vector<EvalValuePointer>>(values);
return make_shared<NumericalTableEvalValue>(valuesPointer); return new NumericalTableEvalValue(valuesPointer);
} }
shared_ptr<const EvalValue> Evaluator::EvaluateComplexTableExpression(const BoundExpression *expression) { EvalValuePointer Evaluator::EvaluateComplexTableExpression(const BoundExpression *expression) {
auto tableExpression = (BoundTableExpression *) expression; auto tableExpression = (BoundTableExpression *) expression;
auto type = dynamic_pointer_cast<const TableScriptType>(tableExpression->GetType()); const auto& baseType = tableExpression -> GetType();
auto type = dynamic_pointer_cast<const TableScriptType>(baseType);
auto declaredVars = type->GetValues(); auto declaredVars = type->GetValues();
auto variables = make_shared<map<Utilities::HashedString, shared_ptr<const EvalValue>>>(); auto variables = make_shared<map<Utilities::HashedString, EvalValuePointer>>();
for (const auto& i : *declaredVars) { for (const auto& i : *declaredVars) {
variables->insert({i.first, nullptr}); variables->insert({i.first, nullptr});
} }
@ -473,17 +394,6 @@ namespace Porygon::Evaluation {
this->_evaluationScope = evaluator; this->_evaluationScope = evaluator;
this->EvaluateBlockStatement(tableExpression->GetBlock()); this->EvaluateBlockStatement(tableExpression->GetBlock());
this->_evaluationScope = currentEvaluator; this->_evaluationScope = currentEvaluator;
return make_shared<TableEvalValue>(variables); return new TableEvalValue(variables);
}
shared_ptr<const EvalValue> Evaluator::EvaluateUserDataExpression(const BoundExpression *expression) {
switch (expression->GetKind()) {
case BoundExpressionKind::Variable:
return this->GetVariable((BoundVariableExpression *) expression);
case BoundExpressionKind::Index:
return this->EvaluateIndexExpression(expression);
default:
throw;
}
} }
} }

View File

@ -10,13 +10,14 @@
#include "EvalValues/StringEvalValue.hpp" #include "EvalValues/StringEvalValue.hpp"
#include "EvalValues/ScriptFunctionEvalValue.hpp" #include "EvalValues/ScriptFunctionEvalValue.hpp"
#include "EvaluationScope/EvaluationScope.hpp" #include "EvaluationScope/EvaluationScope.hpp"
#include "EvalValuePointer.hpp"
using namespace std; using namespace std;
namespace Porygon::Evaluation{ namespace Porygon::Evaluation{
class Evaluator { class Evaluator {
shared_ptr<const EvalValue> _returnValue; EvalValuePointer _returnValue;
map<Utilities::HashedString, shared_ptr<const EvalValue>>* _scriptVariables; map<Utilities::HashedString, EvalValuePointer>* _scriptVariables;
bool _hasReturned; bool _hasReturned;
bool _hasBroken; bool _hasBroken;
@ -35,36 +36,25 @@ namespace Porygon::Evaluation{
void EvaluateGenericForStatement(const BoundGenericForStatement *statement); void EvaluateGenericForStatement(const BoundGenericForStatement *statement);
void EvaluateWhileStatement(const BoundWhileStatement *statement); void EvaluateWhileStatement(const BoundWhileStatement *statement);
shared_ptr<const EvalValue> EvaluateExpression(const BoundExpression *expression); EvalValuePointer EvaluateExpression(const BoundExpression *expression);
shared_ptr<const NumericEvalValue> EvaluateIntegerExpression(const BoundExpression *expression); EvalValuePointer EvaluateBinary(const BoundBinaryExpression *expression);
shared_ptr<const BooleanEvalValue> EvaluateBoolExpression(const BoundExpression *expression); EvalValuePointer EvaluateUnary(const BoundUnaryExpression *expression);
shared_ptr<const StringEvalValue> EvaluateStringExpression(const BoundExpression *expression);
shared_ptr<const EvalValue> EvaluateFunctionExpression(const BoundExpression *expression);
shared_ptr<const EvalValue> EvaluateNilExpression(const BoundExpression *expression);
shared_ptr<const EvalValue> EvaluateTableExpression(const BoundExpression *expression);
shared_ptr<const NumericEvalValue> EvaluateIntegerBinary(const BoundBinaryExpression *expression); EvalValuePointer EvaluateFunctionCallExpression(const BoundExpression *expression);
shared_ptr<const BooleanEvalValue> EvaluateBooleanBinary(const BoundBinaryExpression *expression); EvalValuePointer EvaluateIndexExpression(const BoundExpression *expression);
shared_ptr<const StringEvalValue> EvaluateStringBinary(const BoundBinaryExpression *expression); EvalValuePointer EvaluatePeriodIndexExpression(const BoundExpression *expression);
EvalValuePointer EvaluateNumericTableExpression(const BoundExpression *expression);
EvalValuePointer EvaluateComplexTableExpression(const BoundExpression *expression);
shared_ptr<const NumericEvalValue> EvaluateIntegerUnary(const BoundUnaryExpression *expression); EvalValuePointer GetVariable(const BoundVariableExpression *expression);
shared_ptr<const BooleanEvalValue> EvaluateBooleanUnary(const BoundUnaryExpression *expression);
shared_ptr<const EvalValue> EvaluateFunctionCallExpression(const BoundExpression *expression);
shared_ptr<const EvalValue> EvaluateIndexExpression(const BoundExpression *expression);
shared_ptr<const EvalValue> EvaluatePeriodIndexExpression(const BoundExpression *expression);
shared_ptr<const EvalValue> EvaluateNumericTableExpression(const BoundExpression *expression);
shared_ptr<const EvalValue> EvaluateUserDataExpression(const BoundExpression *expression);
shared_ptr<const EvalValue> EvaluateComplexTableExpression(const BoundExpression *expression);
shared_ptr<const EvalValue> GetVariable(const BoundVariableExpression *expression);
public: public:
explicit Evaluator(map<Utilities::HashedString, shared_ptr<const EvalValue>>* scriptVariables) explicit Evaluator(map<Utilities::HashedString, EvalValuePointer>* scriptVariables)
: _scriptVariables(scriptVariables), _hasReturned(false), _hasBroken(false), _returnValue(nullptr), : _scriptVariables(scriptVariables), _hasReturned(false), _hasBroken(false), _returnValue(nullptr),
_evaluationScope(nullptr){ _evaluationScope(nullptr){
} }
shared_ptr<const EvalValue> Evaluate(const BoundScriptStatement* statement); const EvalValue* Evaluate(const BoundScriptStatement* statement);
shared_ptr<const EvalValue> EvaluateFunction(const GenericFunctionEvalValue *function, const EvalValue* EvaluateFunction(const GenericFunctionEvalValue *function,
const vector<EvalValue *> &parameters); const vector<EvalValue *> &parameters);
}; };

View File

@ -10,7 +10,7 @@ using namespace std;
namespace Porygon::Evaluation{ namespace Porygon::Evaluation{
class Iterator { class Iterator {
public: public:
virtual shared_ptr<EvalValue> GetCurrent() = 0; virtual EvalValue* GetCurrent() = 0;
virtual bool MoveNext() = 0; virtual bool MoveNext() = 0;
virtual void Reset() = 0; virtual void Reset() = 0;
virtual ~Iterator(){} virtual ~Iterator(){}

View File

@ -9,15 +9,15 @@
namespace Porygon::Evaluation{ namespace Porygon::Evaluation{
class NumericalKeyIterator : public Iterator{ class NumericalKeyIterator : public Iterator{
const shared_ptr<vector<shared_ptr<const EvalValue>>> _vec; const shared_ptr<vector<EvalValuePointer>> _vec;
const size_t _size; const size_t _size;
long _position = 0; long _position = 0;
public: public:
explicit NumericalKeyIterator(const NumericalTableEvalValue* table) explicit NumericalKeyIterator(const NumericalTableEvalValue* table)
: _vec(table->GetTable()), _size(_vec->size() + 1){} : _vec(table->GetTable()), _size(_vec->size() + 1){}
inline shared_ptr<EvalValue> GetCurrent() final{ inline EvalValue* GetCurrent() final{
return make_shared<IntegerEvalValue>(_position); return new IntegerEvalValue(_position);
} }
inline bool MoveNext() final{ inline bool MoveNext() final{

View File

@ -8,15 +8,15 @@
namespace Porygon::Evaluation{ namespace Porygon::Evaluation{
class TableKeyIterator : public Iterator{ class TableKeyIterator : public Iterator{
_Rb_tree_const_iterator<pair<const Utilities::HashedString, shared_ptr<const EvalValue>>> _iterator; _Rb_tree_const_iterator<pair<const Utilities::HashedString, EvalValuePointer>> _iterator;
_Rb_tree_const_iterator<pair<const Utilities::HashedString, shared_ptr<const EvalValue>>> _end; _Rb_tree_const_iterator<pair<const Utilities::HashedString, EvalValuePointer>> _end;
bool _hasStarted = false; bool _hasStarted = false;
public: public:
explicit TableKeyIterator(const TableEvalValue* table) explicit TableKeyIterator(const TableEvalValue* table)
: _iterator(table->GetTableIterator()), _end(table->GetTableIteratorEnd()){} : _iterator(table->GetTableIterator()), _end(table->GetTableIteratorEnd()){}
inline shared_ptr<EvalValue> GetCurrent() final{ inline EvalValue* GetCurrent() final{
return make_shared<StringEvalValue>(*_iterator->first.GetString()); return new StringEvalValue(*_iterator->first.GetString());
} }
bool MoveNext() final{ bool MoveNext() final{

View File

@ -1,36 +0,0 @@
#include "EvalValues/NumericEvalValue.hpp"
#include "Evaluator.hpp"
#include "EvaluationException.hpp"
#include "../Script.hpp"
namespace Porygon::Evaluation {
shared_ptr<const NumericEvalValue> Evaluator::EvaluateIntegerUnary(const BoundUnaryExpression *expression) {
switch (expression->GetOperation()) {
case BoundUnaryOperation::Negation: {
auto operandValue = EvaluateIntegerExpression(expression->GetOperand());
if (operandValue->IsFloat()) {
double f = operandValue->EvaluateFloat();
return make_shared<FloatEvalValue>(-f);
} else {
long l = operandValue->EvaluateInteger();
return make_shared<IntegerEvalValue>(-l);
}
}
default:
throw;
}
}
shared_ptr<const BooleanEvalValue> Evaluator::EvaluateBooleanUnary(const BoundUnaryExpression *expression) {
switch (expression->GetOperation()) {
case BoundUnaryOperation::LogicalNegation: {
auto val = EvaluateBoolExpression(expression->GetOperand());
bool b = val->EvaluateBool();
return make_shared<BooleanEvalValue>(!b);
}
default:
throw;
}
}
}

View File

@ -24,13 +24,13 @@ Porygon::Script *Porygon::Script::Create(const string &script) {
Porygon::Script::Script(const u16string& s) Porygon::Script::Script(const u16string& s)
: Diagnostics(make_shared<Diagnostics::DiagnosticsHolder>(s)), : Diagnostics(make_shared<Diagnostics::DiagnosticsHolder>(s)),
_boundScript(nullptr), _boundScript(nullptr),
_scriptVariables(new map<Utilities::HashedString, shared_ptr<const EvalValue>>()) _scriptVariables(new map<Utilities::HashedString, EvalValuePointer>())
{ {
_evaluator = new Evaluator(this -> _scriptVariables); _evaluator = new Evaluator(this -> _scriptVariables);
this -> Parse(s); this -> Parse(s);
} }
shared_ptr<const EvalValue> Porygon::Script::Evaluate() { EvalValuePointer Porygon::Script::Evaluate() {
return _evaluator->Evaluate(_boundScript.get()); return _evaluator->Evaluate(_boundScript.get());
} }
@ -62,8 +62,8 @@ void Porygon::Script::Parse(const u16string& script) {
delete parseResult; delete parseResult;
} }
const EvalValue *Porygon::Script::GetVariable(const u16string &key) { const EvalValue* Porygon::Script::GetVariable(const u16string &key) {
return _scriptVariables -> at(HashedString::CreateLookup(key)).get(); return _scriptVariables -> at(HashedString::CreateLookup(key)).Clone();
} }
bool Porygon::Script::HasVariable(const u16string &key) { bool Porygon::Script::HasVariable(const u16string &key) {
@ -80,7 +80,7 @@ bool Porygon::Script::HasFunction(const u16string &key) {
return f != _scriptVariables->end() && f.operator->()->second->GetTypeClass() == TypeClass ::Function; return f != _scriptVariables->end() && f.operator->()->second->GetTypeClass() == TypeClass ::Function;
} }
shared_ptr<const EvalValue> Porygon::Script::CallFunction(const u16string &key, const vector<EvalValue *>& variables) { const EvalValue* Porygon::Script::CallFunction(const u16string &key, const vector<EvalValue *>& variables) {
auto var = (GenericFunctionEvalValue*)GetVariable(key); auto var = (GenericFunctionEvalValue*)GetVariable(key);
return this->_evaluator->EvaluateFunction(var, variables); return this->_evaluator->EvaluateFunction(var, variables);
} }
@ -98,7 +98,7 @@ Porygon::Script::Script(shared_ptr<BoundScriptStatement> boundScript,
shared_ptr<Porygon::Diagnostics::DiagnosticsHolder> diagnostics) shared_ptr<Porygon::Diagnostics::DiagnosticsHolder> diagnostics)
: _boundScript(std::move(boundScript)), : _boundScript(std::move(boundScript)),
Diagnostics(std::move(diagnostics)), Diagnostics(std::move(diagnostics)),
_scriptVariables(new map<Utilities::HashedString, shared_ptr<const EvalValue>>()) _scriptVariables(new map<Utilities::HashedString, EvalValuePointer>())
{ {
_evaluator = new Evaluator(_scriptVariables); _evaluator = new Evaluator(_scriptVariables);
} }
@ -111,8 +111,7 @@ extern "C" {
const EvalValue* EvaluateScript(Porygon::Script* script){ const EvalValue* EvaluateScript(Porygon::Script* script){
auto result = script -> Evaluate(); auto result = script -> Evaluate();
auto resultPtr = result.get(); return result.Clone();
return resultPtr;
} }
bool HasVariable(Porygon::Script* script, const char16_t* key){ bool HasVariable(Porygon::Script* script, const char16_t* key){
@ -129,6 +128,6 @@ extern "C" {
const EvalValue* CallFunction(Porygon::Script* script, const char16_t* key, EvalValue* parameters[], int parameterCount){ const EvalValue* CallFunction(Porygon::Script* script, const char16_t* key, EvalValue* parameters[], int parameterCount){
std::vector<EvalValue*> v(parameters, parameters + parameterCount); std::vector<EvalValue*> v(parameters, parameters + parameterCount);
return script->CallFunction(key, v).get(); return script->CallFunction(key, v);
} }
} }

View File

@ -17,7 +17,7 @@ using namespace Porygon::Evaluation;
namespace Porygon{ namespace Porygon{
class Script { class Script {
Evaluator* _evaluator; Evaluator* _evaluator;
map<Utilities::HashedString, shared_ptr<const EvalValue>>* _scriptVariables; map<Utilities::HashedString, EvalValuePointer>* _scriptVariables;
shared_ptr<Binder::BoundScriptStatement> _boundScript; shared_ptr<Binder::BoundScriptStatement> _boundScript;
shared_ptr<const ScriptType> _returnType; shared_ptr<const ScriptType> _returnType;
@ -41,14 +41,12 @@ namespace Porygon{
_returnType = t; _returnType = t;
} }
shared_ptr<const EvalValue> Evaluate(); EvalValuePointer Evaluate();
//const EvalValue* GetLastValue();
const EvalValue* GetVariable(const u16string& key); const EvalValue* GetVariable(const u16string& key);
bool HasVariable(const u16string& key); bool HasVariable(const u16string& key);
shared_ptr<const EvalValue> CallFunction(const u16string& key, const vector<EvalValue*>& variables); const EvalValue* CallFunction(const u16string& key, const vector<EvalValue*>& variables);
bool HasFunction(const u16string& key); bool HasFunction(const u16string& key);
}; };

View File

@ -74,10 +74,10 @@ namespace Porygon::StandardLibraries{
} }
static shared_ptr<Evaluation::EvalValue> GetFuncEvalValue( static Evaluation::EvalValue* GetFuncEvalValue(
const Evaluation::EvalValue* (*func)(void* obj, const Evaluation::EvalValue* parameters[], int parameterCount), const Evaluation::EvalValue* (*func)(void* obj, const Evaluation::EvalValue* parameters[], int parameterCount),
const shared_ptr<GenericFunctionScriptType>& type, size_t optionLength){ const shared_ptr<GenericFunctionScriptType>& type, size_t optionLength){
auto f = make_shared<Evaluation::GenericFunctionEvalValue>(type, rand()); auto f = new Evaluation::GenericFunctionEvalValue(type, rand());
for (size_t i = 0; i < optionLength; i++){ for (size_t i = 0; i < optionLength; i++){
auto funcOption = new UserData::UserDataFunction(func, nullptr); auto funcOption = new UserData::UserDataFunction(func, nullptr);
f->RegisterOption(funcOption); f->RegisterOption(funcOption);
@ -88,7 +88,7 @@ namespace Porygon::StandardLibraries{
public: public:
static void RegisterVariables(std::map<Utilities::HashedString, Binder::BoundVariable *>* bound, static void RegisterVariables(std::map<Utilities::HashedString, Binder::BoundVariable *>* bound,
std::map<Utilities::HashedString, shared_ptr<Evaluation::EvalValue>>* values){ std::map<Utilities::HashedString, Evaluation::EvalValue*>* values){
// Register error function // Register error function
auto errorFuncType = BasicLibrary::GetErrorFuncType(); auto errorFuncType = BasicLibrary::GetErrorFuncType();
auto errorLookup = Utilities::HashedString::CreateLookup(u"error"); auto errorLookup = Utilities::HashedString::CreateLookup(u"error");

View File

@ -19,7 +19,7 @@ namespace Porygon::StandardLibraries{
class InternalScope{ class InternalScope{
public: public:
map<Utilities::HashedString, Binder::BoundVariable *> _boundVariables; map<Utilities::HashedString, Binder::BoundVariable *> _boundVariables;
map<Utilities::HashedString, shared_ptr<Evaluation::EvalValue>> _variables; map<Utilities::HashedString, Evaluation::EvalValue*> _variables;
InternalScope(){ InternalScope(){
BasicLibrary::RegisterVariables(&_boundVariables, &_variables); BasicLibrary::RegisterVariables(&_boundVariables, &_variables);
@ -29,6 +29,9 @@ namespace Porygon::StandardLibraries{
for (const auto& b: _boundVariables){ for (const auto& b: _boundVariables){
delete b.second; delete b.second;
} }
for (const auto& v: _variables){
delete v.second;
}
} }
}; };
@ -36,7 +39,7 @@ namespace Porygon::StandardLibraries{
public: public:
static void RegisterVariable(const Utilities::HashedString& identifier, shared_ptr<ScriptType> type, Evaluation::EvalValue* value){ static void RegisterVariable(const Utilities::HashedString& identifier, shared_ptr<ScriptType> type, Evaluation::EvalValue* value){
_internal._boundVariables.insert({identifier, new Binder::BoundVariable(std::move(type))}); _internal._boundVariables.insert({identifier, new Binder::BoundVariable(std::move(type))});
_internal._variables.insert({identifier, shared_ptr<Evaluation::EvalValue>(value)}); _internal._variables.insert({identifier, value});
} }
static Binder::BoundVariable* GetBoundVariable(const Utilities::HashedString &identifier){ static Binder::BoundVariable* GetBoundVariable(const Utilities::HashedString &identifier){
@ -47,8 +50,8 @@ namespace Porygon::StandardLibraries{
return nullptr; return nullptr;
} }
inline static shared_ptr<Evaluation::EvalValue> GetVariable(const Utilities::HashedString &identifier){ inline static Evaluation::EvalValuePointer GetVariable(const Utilities::HashedString &identifier){
return _internal._variables[identifier]; return _internal._variables[identifier]->Clone();
} }
}; };
} }

View File

@ -34,8 +34,8 @@ namespace Porygon::UserData {
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> Clone() const final { inline Evaluation::EvalValue* Clone() const final {
return make_shared<UserDataValue>(_userData, _obj); return new UserDataValue(_userData, _obj);
} }
[[nodiscard]] [[nodiscard]]
@ -43,22 +43,23 @@ namespace Porygon::UserData {
return reinterpret_cast<intptr_t>(_obj); return reinterpret_cast<intptr_t>(_obj);
} }
shared_ptr<const EvalValue> IndexValue(const EvalValue *val) const final { const Evaluation::EvalValue* IndexValue(const EvalValue *val) const final {
auto fieldId = val->GetHashCode(); auto fieldId = val->GetHashCode();
auto field = _userData->GetField(fieldId); auto field = _userData->GetField(fieldId);
return shared_ptr<const EvalValue>(field->Get(_obj)); return field->Get(_obj);
} }
[[nodiscard]] [[nodiscard]]
inline shared_ptr<const EvalValue> IndexValue(uint32_t hash) const final { inline const EvalValue* IndexValue(uint32_t hash) const final {
auto field = _userData->GetField(hash); auto field = _userData->GetField(hash);
return shared_ptr<const EvalValue>(field->Get(_obj)); return field->Get(_obj);
} }
void SetIndexValue(const EvalValue *key, const shared_ptr<const EvalValue> &value) const final { void SetIndexValue(const EvalValue *key, const EvalValue* value) const final {
auto fieldId = key->GetHashCode(); auto fieldId = key->GetHashCode();
auto field = _userData->GetField(fieldId); auto field = _userData->GetField(fieldId);
field->Set(_obj, value.get()); field->Set(_obj, value);
delete value;
} }
inline void* GetObjectPointer(){ inline void* GetObjectPointer(){

View File

@ -14,6 +14,7 @@ TEST_CASE( "Basic conditional", "[integration]" ) {
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
REQUIRE(variable->EvaluateBool()); REQUIRE(variable->EvaluateBool());
delete script; delete script;
delete variable;
} }
TEST_CASE( "If then, else", "[integration]" ) { TEST_CASE( "If then, else", "[integration]" ) {
@ -26,6 +27,7 @@ TEST_CASE( "If then, else", "[integration]" ) {
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
REQUIRE(variable->EvaluateBool()); REQUIRE(variable->EvaluateBool());
delete script; delete script;
delete variable;
} }
TEST_CASE( "If then, else if", "[integration]" ) { TEST_CASE( "If then, else if", "[integration]" ) {
@ -38,6 +40,7 @@ TEST_CASE( "If then, else if", "[integration]" ) {
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
REQUIRE(variable->EvaluateBool()); REQUIRE(variable->EvaluateBool());
delete script; delete script;
delete variable;
} }

View File

@ -12,6 +12,7 @@ TEST_CASE( "Define script function", "[integration]" ) {
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
REQUIRE(variable->GetTypeClass() == TypeClass::Function); REQUIRE(variable->GetTypeClass() == TypeClass::Function);
delete script; delete script;
delete variable;
} }
TEST_CASE( "Define script function and call", "[integration]" ) { TEST_CASE( "Define script function and call", "[integration]" ) {
@ -25,6 +26,8 @@ TEST_CASE( "Define script function and call", "[integration]" ) {
REQUIRE(result->GetTypeClass() == TypeClass::Number); REQUIRE(result->GetTypeClass() == TypeClass::Number);
REQUIRE(result->EvaluateInteger() == 3); REQUIRE(result->EvaluateInteger() == 3);
delete script; delete script;
delete variable;
delete result;
} }
TEST_CASE( "Define script function and call multiple times", "[integration]" ) { TEST_CASE( "Define script function and call multiple times", "[integration]" ) {
@ -38,6 +41,8 @@ TEST_CASE( "Define script function and call multiple times", "[integration]" ) {
REQUIRE(result->GetTypeClass() == TypeClass::Number); REQUIRE(result->GetTypeClass() == TypeClass::Number);
REQUIRE(result->EvaluateInteger() == 5); REQUIRE(result->EvaluateInteger() == 5);
delete script; delete script;
delete variable;
delete result;
} }
TEST_CASE( "Define script function and call from extern", "[integration]" ) { TEST_CASE( "Define script function and call from extern", "[integration]" ) {
@ -57,6 +62,7 @@ TEST_CASE( "Define script function and call from extern", "[integration]" ) {
REQUIRE(result->GetTypeClass() == TypeClass::Number); REQUIRE(result->GetTypeClass() == TypeClass::Number);
REQUIRE(result->EvaluateInteger() == 11); REQUIRE(result->EvaluateInteger() == 11);
delete script; delete script;
delete result;
} }
TEST_CASE( "Define script function and return", "[integration]" ) { TEST_CASE( "Define script function and return", "[integration]" ) {
@ -84,6 +90,8 @@ TEST_CASE( "Define script function and return", "[integration]" ) {
REQUIRE(variable->EvaluateInteger() == 0); REQUIRE(variable->EvaluateInteger() == 0);
delete script; delete script;
delete variable;
delete result;
} }
TEST_CASE( "Functions can call themselves", "[integration]" ) { TEST_CASE( "Functions can call themselves", "[integration]" ) {
@ -106,6 +114,7 @@ end
REQUIRE(variable->EvaluateInteger() == 5); REQUIRE(variable->EvaluateInteger() == 5);
delete script; delete script;
delete variable;
} }
TEST_CASE( "Functions respect scope", "[integration]" ) { TEST_CASE( "Functions respect scope", "[integration]" ) {
@ -134,6 +143,7 @@ test()
REQUIRE(variable->EvaluateInteger() == 50); REQUIRE(variable->EvaluateInteger() == 50);
delete script; delete script;
delete variable;
} }
TEST_CASE( "Return doesn't parse next line expression", "[integration]" ) { TEST_CASE( "Return doesn't parse next line expression", "[integration]" ) {
@ -174,8 +184,9 @@ stringResult = add('foo', 'bar')
REQUIRE(stringVar != nullptr); REQUIRE(stringVar != nullptr);
CHECK(stringVar->EvaluateString() == u"foobar"); CHECK(stringVar->EvaluateString() == u"foobar");
delete script; delete script;
delete intVar;
delete stringVar;
} }

View File

@ -15,6 +15,7 @@ end
auto var = script->GetVariable(u"result"); auto var = script->GetVariable(u"result");
REQUIRE(var->EvaluateInteger() == 33); REQUIRE(var->EvaluateInteger() == 33);
delete script; delete script;
delete var;
} }
TEST_CASE( "Numerical for loop with step", "[integration]" ) { TEST_CASE( "Numerical for loop with step", "[integration]" ) {
@ -29,6 +30,7 @@ end
auto var = script->GetVariable(u"result"); auto var = script->GetVariable(u"result");
REQUIRE(var->EvaluateInteger() == 12); REQUIRE(var->EvaluateInteger() == 12);
delete script; delete script;
delete var;
} }
TEST_CASE( "Numerical for loop with negative step", "[integration]" ) { TEST_CASE( "Numerical for loop with negative step", "[integration]" ) {
@ -43,6 +45,7 @@ end
auto var = script->GetVariable(u"result"); auto var = script->GetVariable(u"result");
REQUIRE(var->EvaluateInteger() == 33); REQUIRE(var->EvaluateInteger() == 33);
delete script; delete script;
delete var;
} }
@ -58,6 +61,7 @@ end
auto var = script->GetVariable(u"result"); auto var = script->GetVariable(u"result");
REQUIRE(var->EvaluateInteger() == 15); REQUIRE(var->EvaluateInteger() == 15);
delete script; delete script;
delete var;
} }
TEST_CASE( "Numerical for loop, break", "[integration]" ) { TEST_CASE( "Numerical for loop, break", "[integration]" ) {
@ -73,6 +77,7 @@ end
auto var = script->GetVariable(u"result"); auto var = script->GetVariable(u"result");
REQUIRE(var->EvaluateInteger() == 6); REQUIRE(var->EvaluateInteger() == 6);
delete script; delete script;
delete var;
} }
@ -89,6 +94,7 @@ end
auto var = script->GetVariable(u"result"); auto var = script->GetVariable(u"result");
REQUIRE(var->EvaluateInteger() == 15); REQUIRE(var->EvaluateInteger() == 15);
delete script; delete script;
delete var;
} }
TEST_CASE( "Generic for loop over simple numerical table, get values", "[integration]" ) { TEST_CASE( "Generic for loop over simple numerical table, get values", "[integration]" ) {
@ -104,6 +110,7 @@ end
auto var = script->GetVariable(u"result"); auto var = script->GetVariable(u"result");
REQUIRE(var->EvaluateInteger() == 25); REQUIRE(var->EvaluateInteger() == 25);
delete script; delete script;
delete var;
} }
TEST_CASE( "Generic for loop over simple numerical table, break", "[integration]" ) { TEST_CASE( "Generic for loop over simple numerical table, break", "[integration]" ) {
@ -120,6 +127,7 @@ end
auto var = script->GetVariable(u"result"); auto var = script->GetVariable(u"result");
REQUIRE(var->EvaluateInteger() == 9); REQUIRE(var->EvaluateInteger() == 9);
delete script; delete script;
delete var;
} }
TEST_CASE( "While loop", "[integration]" ) { TEST_CASE( "While loop", "[integration]" ) {
@ -134,6 +142,7 @@ end
auto var = script->GetVariable(u"result"); auto var = script->GetVariable(u"result");
REQUIRE(var->EvaluateInteger() == 5); REQUIRE(var->EvaluateInteger() == 5);
delete script; delete script;
delete var;
} }
TEST_CASE( "While loop break", "[integration]" ) { TEST_CASE( "While loop break", "[integration]" ) {
@ -149,6 +158,7 @@ end
auto var = script->GetVariable(u"result"); auto var = script->GetVariable(u"result");
REQUIRE(var->EvaluateInteger() == 5); REQUIRE(var->EvaluateInteger() == 5);
delete script; delete script;
delete var;
} }
#endif #endif

View File

@ -11,6 +11,7 @@ TEST_CASE( "Create empty table", "[integration]" ) {
auto variable = script->GetVariable(u"table"); auto variable = script->GetVariable(u"table");
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
delete script; delete script;
delete variable;
} }
TEST_CASE( "Create simple integer table", "[integration]" ) { TEST_CASE( "Create simple integer table", "[integration]" ) {
@ -20,6 +21,7 @@ TEST_CASE( "Create simple integer table", "[integration]" ) {
auto variable = script->GetVariable(u"table"); auto variable = script->GetVariable(u"table");
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
delete script; delete script;
delete variable;
} }
TEST_CASE( "Create simple string table", "[integration]" ) { TEST_CASE( "Create simple string table", "[integration]" ) {
@ -29,6 +31,7 @@ TEST_CASE( "Create simple string table", "[integration]" ) {
auto variable = script->GetVariable(u"table"); auto variable = script->GetVariable(u"table");
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
delete script; delete script;
delete variable;
} }
TEST_CASE( "Index string table", "[integration]" ) { TEST_CASE( "Index string table", "[integration]" ) {
@ -39,7 +42,7 @@ return table[3]
)"); )");
REQUIRE(!script->Diagnostics -> HasErrors()); REQUIRE(!script->Diagnostics -> HasErrors());
auto variable = script->Evaluate(); auto variable = script->Evaluate();
REQUIRE(variable != nullptr); REQUIRE(variable.Get() != nullptr);
REQUIRE(variable->EvaluateString() == u"foo"); REQUIRE(variable->EvaluateString() == u"foo");
delete script; delete script;
} }
@ -57,9 +60,14 @@ table = {
auto variable = script->GetVariable(u"table"); auto variable = script->GetVariable(u"table");
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
auto table = (TableEvalValue*)variable; auto table = (TableEvalValue*)variable;
CHECK(table->IndexValue("foo")->EvaluateString() == u"test"); auto res = table->IndexValue("foo");
CHECK(table->IndexValue("bar")->EvaluateInteger() == 100); auto res2 = table->IndexValue("bar");
CHECK(res->EvaluateString() == u"test");
CHECK(res2->EvaluateInteger() == 100);
delete script; delete script;
delete table;
delete res;
delete res2;
} }
TEST_CASE( "Complex table with function", "[integration]" ) { TEST_CASE( "Complex table with function", "[integration]" ) {
@ -75,7 +83,7 @@ return table["getFoo"]()
)"); )");
REQUIRE(!script->Diagnostics -> HasErrors()); REQUIRE(!script->Diagnostics -> HasErrors());
auto variable = script->Evaluate(); auto variable = script->Evaluate();
REQUIRE(variable != nullptr); REQUIRE(variable.Get() != nullptr);
delete script; delete script;
} }

View File

@ -54,6 +54,7 @@ end
delete par; delete par;
delete parameter; delete parameter;
delete script; delete script;
delete variable;
UserDataStorage::ClearTypes(); UserDataStorage::ClearTypes();
} }
@ -92,6 +93,7 @@ end
delete script; delete script;
delete obj; delete obj;
delete parameter; delete parameter;
delete result;
UserDataStorage::ClearTypes(); UserDataStorage::ClearTypes();
} }
@ -111,6 +113,7 @@ end
delete script; delete script;
delete obj; delete obj;
delete parameter; delete parameter;
delete result;
UserDataStorage::ClearTypes(); UserDataStorage::ClearTypes();
} }

View File

@ -13,6 +13,7 @@ TEST_CASE( "Create script variable", "[integration]" ) {
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
REQUIRE(variable->EvaluateBool()); REQUIRE(variable->EvaluateBool());
delete script; delete script;
delete variable;
} }
TEST_CASE( "Create local variable", "[integration]" ) { TEST_CASE( "Create local variable", "[integration]" ) {
@ -32,6 +33,7 @@ TEST_CASE( "Create script variable and use", "[integration]" ) {
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
CHECK(variable->EvaluateBool()); CHECK(variable->EvaluateBool());
delete script; delete script;
delete variable;
} }
TEST_CASE( "Create local variable and use", "[integration]" ) { TEST_CASE( "Create local variable and use", "[integration]" ) {
@ -43,6 +45,7 @@ TEST_CASE( "Create local variable and use", "[integration]" ) {
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
CHECK(variable->EvaluateBool()); CHECK(variable->EvaluateBool());
delete script; delete script;
delete variable;
} }
TEST_CASE( "Local variables in upmost scope persist", "[integration]" ) { TEST_CASE( "Local variables in upmost scope persist", "[integration]" ) {
@ -62,6 +65,7 @@ end
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
CHECK(variable->EvaluateInteger() == 2); CHECK(variable->EvaluateInteger() == 2);
delete script; delete script;
delete variable;
} }
TEST_CASE( "Able to use emoji", "[integration]" ) { TEST_CASE( "Able to use emoji", "[integration]" ) {
@ -75,6 +79,7 @@ TEST_CASE( "Able to use emoji", "[integration]" ) {
REQUIRE(variable != nullptr); REQUIRE(variable != nullptr);
CHECK(variable->EvaluateString() == u"LJ"); CHECK(variable->EvaluateString() == u"LJ");
delete script; delete script;
delete variable;
} }
#endif #endif