Added support for creating a string outline of a bound script for debugging purposes
continuous-integration/drone/push Build was killed Details

This commit is contained in:
Deukhoofd 2019-09-02 20:48:52 +02:00
parent e0941a9db8
commit d21cfeaac8
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
11 changed files with 370 additions and 0 deletions

View File

@ -7,6 +7,7 @@
#include "../../ScriptTypes/ScriptType.hpp"
#include "../BoundOperators.hpp"
#include "../BoundVariables/BoundVariableKey.hpp"
#include "../../Utilities/StringUtils.hpp"
using namespace std;
@ -62,6 +63,8 @@ namespace Porygon::Binder {
inline unsigned int GetLength() const {
return _length;
}
virtual void GetTreeString(std::stringstream& stream, size_t indents) const = 0;
};
class BoundBadExpression : public BoundExpression {
@ -74,6 +77,12 @@ namespace Porygon::Binder {
inline BoundExpressionKind GetKind() const final {
return BoundExpressionKind::Bad;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "BadExpression";
}
};
class BoundLiteralIntegerExpression : public BoundExpression {
@ -93,6 +102,12 @@ namespace Porygon::Binder {
inline int64_t GetValue() const {
return _value;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "LiteralInteger: " << _value << " (" << GetType()->ToString() << ")";
}
};
class BoundLiteralFloatExpression : public BoundExpression {
@ -112,6 +127,12 @@ namespace Porygon::Binder {
inline double GetValue() const {
return _value;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "LiteralFloat: " << _value << " (" << GetType()->ToString() << ")";
}
};
class BoundLiteralStringExpression : public BoundExpression {
@ -132,6 +153,13 @@ namespace Porygon::Binder {
inline const u16string* GetValue() const {
return &_value;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "LiteralString: " << Utilities::StringUtils::FromUTF8(_value)
<< " (" << GetType()->ToString() << ")";
}
};
class BoundLiteralBoolExpression : public BoundExpression {
@ -151,6 +179,12 @@ namespace Porygon::Binder {
inline bool GetValue() const {
return _value;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "LiteralBool: " << _value << " (" << GetType()->ToString() << ")";
}
};
class BoundNilExpression : public BoundExpression {
@ -163,6 +197,12 @@ namespace Porygon::Binder {
inline BoundExpressionKind GetKind() const final {
return BoundExpressionKind::Nil;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "NilExpression" << " (" << GetType()->ToString() << ")";
}
};
class BoundVariableExpression : public BoundExpression {
@ -187,6 +227,13 @@ namespace Porygon::Binder {
inline const BoundVariableKey *GetKey() const {
return _key;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "VariableExpression: " << _key->GetIdentifier()->GetString().get()
<< " (" << GetType()->ToString() << ")";
}
};
class BoundBinaryExpression : public BoundExpression {
@ -227,6 +274,35 @@ namespace Porygon::Binder {
inline BoundBinaryOperation GetOperation() const {
return _operation;
}
static std::string GetOperationString(BoundBinaryOperation op){
switch (op){
case BoundBinaryOperation::Addition: return "addition";
case BoundBinaryOperation::Subtraction: return "subtraction";
case BoundBinaryOperation::Multiplication: return "multiplication";
case BoundBinaryOperation::Division: return "division";
case BoundBinaryOperation::Equality: return "equality";
case BoundBinaryOperation::Inequality: return "inequality";
case BoundBinaryOperation::LessThan: return "lessThan";
case BoundBinaryOperation::LessThanEquals: return "lessThanEquals";
case BoundBinaryOperation::GreaterThan: return "greaterThan";
case BoundBinaryOperation::GreaterThanEquals: return "greaterThanEquals";
case BoundBinaryOperation::LogicalAnd: return "logicalAnd";
case BoundBinaryOperation::LogicalOr: return "logicalOr";
case BoundBinaryOperation::Concatenation: return "concatenation";
}
throw exception();
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "BinaryExpression: " << GetOperationString(_operation)
<< " (" << GetType()->ToString() << ")" << endl;
_left->GetTreeString(stream, indents + 1);
_right->GetTreeString(stream, indents + 1);
}
};
class BoundUnaryExpression : public BoundExpression {
@ -258,6 +334,22 @@ namespace Porygon::Binder {
inline BoundUnaryOperation GetOperation() const {
return _operation;
}
static std::string GetOperationString(BoundUnaryOperation op){
switch (op){
case BoundUnaryOperation::Negation: return "negation";
case BoundUnaryOperation::LogicalNegation: return "logicalNegation";
}
throw exception();
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "UnaryExpression: " << GetOperationString(_operation)
<< " (" << GetType()->ToString() << ")" << endl;
_operand->GetTreeString(stream, indents + 1);
}
};
class BoundIndexExpression : public BoundExpression {
@ -289,6 +381,16 @@ namespace Porygon::Binder {
inline const BoundExpression *GetIndexExpression() const {
return _indexExpression;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "IndexExpression" << " (" << GetType()->ToString() << ")" << endl;
_indexableExpression->GetTreeString(stream, indents + 1);
stream << endl;
_indexExpression->GetTreeString(stream, indents + 1);
}
};
class BoundPeriodIndexExpression : public BoundExpression {
@ -319,6 +421,15 @@ namespace Porygon::Binder {
inline const Utilities::HashedString* GetIndex() const {
return &_index;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "PeriodIndex: " << _index.GetString().get() << " (" << GetType()->ToString() << ")" << endl;
stream << endl;
_indexableExpression->GetTreeString(stream, indents + 1);
}
};
class BoundNumericalTableExpression : public BoundExpression {
@ -344,6 +455,17 @@ namespace Porygon::Binder {
inline const vector<const BoundExpression *> *GetExpressions() const {
return &_expressions;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "NumericalTable" << " (" << GetType()->ToString() << ")" << endl;
for (auto _expression : _expressions){
stream << endl;
_expression->GetTreeString(stream, indents + 1);
}
}
};
class BoundCastExpression : public BoundExpression {
@ -366,6 +488,14 @@ namespace Porygon::Binder {
inline BoundExpressionKind GetKind() const final {
return BoundExpressionKind::Cast;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "CastExpression" << " (" << GetType()->ToString() << ")" << endl;
_expression->GetTreeString(stream, indents + 1);
}
};
}

View File

@ -42,6 +42,20 @@ namespace Porygon::Binder {
inline const Porygon::GenericFunctionOption *GetFunctionOption() const {
return _option;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "Function Call" << " (" << GetType()->ToString() << ")" << endl;
for (size_t i = 0; i < indents; i++)
stream << "\t";
if (!_parameters.empty()){
stream << "Parameters: " << endl;
for (auto p : _parameters){
p->GetTreeString(stream, indents + 1);
}
}
}
};
}

View File

@ -26,6 +26,12 @@ namespace Porygon::Binder {
inline BoundExpressionKind GetKind() const final {
return BoundExpressionKind::Require;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "Require" << " (" << GetType()->ToString() << ")";
}
};
}

View File

@ -29,6 +29,14 @@ namespace Porygon::Binder {
inline const BoundBlockStatement *GetBlock() const {
return _block;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "TableExpression" << " (" << GetType()->ToString() << ")" << endl;
_block->GetTreeString(stream, indents + 1);
}
};
}

View File

@ -40,6 +40,18 @@ namespace Porygon::Binder {
inline std::shared_ptr<const GenericFunctionScriptType> GetType() const {
return _type;
}
void GetTreeString(std::stringstream& stream, size_t indents) const override{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "FunctionDeclaration" << endl;
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "Key: " << _key->GetIdentifier()->GetString().get() << endl;
stream << "Type: " << _type->ToString() << endl;
_block->GetTreeString(stream, indents + 1);
}
};
}

View File

@ -32,6 +32,8 @@ namespace Porygon::Binder {
virtual BoundStatementKind GetKind() const = 0;
virtual ~BoundStatement() = default;
virtual void GetTreeString(std::stringstream& stream, size_t indents) const = 0;
};
class BoundBadStatement : public BoundStatement {
@ -40,6 +42,12 @@ namespace Porygon::Binder {
inline BoundStatementKind GetKind() const final {
return BoundStatementKind::Bad;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "BadStatement";
}
};
class BoundBreakStatement : public BoundStatement {
@ -48,6 +56,12 @@ namespace Porygon::Binder {
inline BoundStatementKind GetKind() const final {
return BoundStatementKind::Break;
}
void GetTreeString(std::stringstream& stream, size_t indents) const final{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "BreakStatement";
}
};
class BoundBlockStatement : public BoundStatement {
@ -72,6 +86,16 @@ namespace Porygon::Binder {
inline const vector<const BoundStatement *> *GetStatements() const {
return &_statements;
}
void GetTreeString(std::stringstream& stream, size_t indents) const override{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "BlockStatement";
for (auto s : _statements){
stream << endl;
s->GetTreeString(stream, indents + 1);
}
}
};
class BoundScriptStatement : public BoundBlockStatement {
@ -114,6 +138,13 @@ namespace Porygon::Binder {
inline const BoundExpression *GetExpression() const {
return _expression;
}
void GetTreeString(std::stringstream& stream, size_t indents) const override{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "ExpressionStatement" << endl;
_expression->GetTreeString(stream, indents + 1);
}
};
class BoundAssignmentStatement : public BoundStatement {
@ -143,6 +174,13 @@ namespace Porygon::Binder {
inline const BoundExpression *GetExpression() const {
return _expression;
}
void GetTreeString(std::stringstream& stream, size_t indents) const override{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "Assignment -> " << _key->GetIdentifier()->GetString() << endl;
_expression->GetTreeString(stream, indents + 1);
}
};
class BoundIndexAssignmentStatement : public BoundStatement {
@ -172,6 +210,15 @@ namespace Porygon::Binder {
inline const BoundExpression *GetValueExpression() const {
return _valueExpression;
}
void GetTreeString(std::stringstream& stream, size_t indents) const override{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "IndexAssignment" << endl;
_indexExpression->GetTreeString(stream, indents + 1);
stream << endl;
_valueExpression->GetTreeString(stream, indents + 1);
}
};
class BoundReturnStatement : public BoundStatement {
@ -194,6 +241,16 @@ namespace Porygon::Binder {
inline const BoundExpression *GetExpression() const {
return _expression;
}
void GetTreeString(std::stringstream& stream, size_t indents) const override{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "ReturnStatement" << endl;
if (_expression != nullptr){
_expression->GetTreeString(stream, indents + 1);
}
}
};
class BoundConditionalStatement : public BoundStatement {
@ -230,6 +287,26 @@ namespace Porygon::Binder {
inline const BoundStatement *GetElseStatement() const {
return _elseStatement;
}
void GetTreeString(std::stringstream& stream, size_t indents) const override{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "ConditionalStatement" << endl;
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "Condition:" << endl;
_condition->GetTreeString(stream, indents + 1);
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "If True:" << endl;
_block->GetTreeString(stream, indents + 1);
if (_elseStatement != nullptr){
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "Else:" << endl;
_elseStatement->GetTreeString(stream, indents + 1);
}
}
};
class BoundNumericalForStatement : public BoundStatement {
@ -283,6 +360,30 @@ namespace Porygon::Binder {
inline const BoundStatement* GetBlock() const{
return _block;
}
void GetTreeString(std::stringstream& stream, size_t indents) const override{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "NumericForLoopStatement" << endl;
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "Start:" << endl;
_start->GetTreeString(stream, indents + 1);
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "End:" << endl;
_end->GetTreeString(stream, indents + 1);
if (_step != nullptr){
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "Step:" << endl;
_step->GetTreeString(stream, indents + 1);
}
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "Do:" << endl;
_block->GetTreeString(stream, indents + 1);
}
};
class BoundGenericForStatement : public BoundStatement {
@ -329,6 +430,22 @@ namespace Porygon::Binder {
inline const BoundStatement* GetBlock() const{
return _block;
}
void GetTreeString(std::stringstream& stream, size_t indents) const override{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "GenericForLoopStatement" << endl;
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "Key: " << _keyIdentifier->GetIdentifier()->GetString().get() << endl;
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "Value: " << _valueIdentifier->GetIdentifier()->GetString().get() << endl;
stream << "Iterator: " << endl;
_iterator->GetTreeString(stream, indents + 1);
stream << endl;
_block->GetTreeString(stream, indents + 1);
}
};
class BoundWhileStatement : public BoundStatement {
@ -358,6 +475,20 @@ namespace Porygon::Binder {
inline const BoundStatement* GetBlock() const{
return _block;
}
void GetTreeString(std::stringstream& stream, size_t indents) const override{
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "ConditionalStatement" << endl;
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "Condition:" << endl;
_condition->GetTreeString(stream, indents + 1);
for (size_t i = 0; i < indents; i++)
stream << "\t";
stream << "While True:" << endl;
_block->GetTreeString(stream, indents + 1);
}
};
}

View File

@ -263,6 +263,7 @@ namespace Porygon::Evaluation {
case BoundExpressionKind::Cast:
return this -> EvaluateImplicitCastExpression(expression);
}
throw exception();
}
EvalValuePointer Evaluator::EvaluateBinary(const BoundBinaryExpression *expression){

View File

@ -26,6 +26,7 @@ namespace Porygon{
All,
};
class ScriptType{
TypeClass _class;
public:
@ -84,6 +85,26 @@ namespace Porygon{
return CastResult::InvalidCast;
return CastResult::InvalidCast;
}
static std::string ToString(TypeClass c){
switch (c){
case TypeClass::Error: return "error";
case TypeClass::Nil: return "nil";
case TypeClass::Number: return "number";
case TypeClass::Bool: return "bool";
case TypeClass::String: return "string";
case TypeClass::Function: return "function";
case TypeClass::UserData: return "userdata";
case TypeClass::Table: return "table";
case TypeClass::All: return "all";
}
throw exception();
}
[[nodiscard]] virtual std::string ToString() const{
return ToString(this->_class);
}
};
class NumericScriptType : public ScriptType{

View File

@ -110,6 +110,7 @@ namespace Porygon::StandardLibraries{
case TypeClass::Table: return new Evaluation::StringEvalValue(u"table");
case TypeClass::All: return new Evaluation::StringEvalValue(u"all");
}
throw exception();
}
static shared_ptr<GenericFunctionScriptType> GetTypeFuncType(){
return GetFuncType(StringScriptType::Dynamic,{{make_shared<ScriptType>(TypeClass::All)}});

29
tests/TreeStringTests.cpp Normal file
View File

@ -0,0 +1,29 @@
#ifdef TESTS_BUILD
#include <catch.hpp>
#include <sstream>
#include "../src/Binder/BoundStatements/BoundStatement.hpp"
using namespace Porygon::Binder;
TEST_CASE( "Bad Statement To String", "[BoundTreeString]" ) {
std::stringstream stream;
auto s = new BoundBadStatement();
s->GetTreeString(stream, 1);
REQUIRE(stream.str() == "\tBadStatement");
}
TEST_CASE( "Break Statement To String", "[BoundTreeString]" ) {
std::stringstream stream;
auto s = new BoundBreakStatement();
s->GetTreeString(stream, 1);
REQUIRE(stream.str() == "\tBreakStatement");
}
TEST_CASE( "Block Statement To String", "[BoundTreeString]" ) {
std::stringstream stream;
auto s = new BoundBlockStatement({new BoundBreakStatement(), new BoundBreakStatement()});
s->GetTreeString(stream, 1);
REQUIRE(stream.str() == "\tBlockStatement\n\t\tBreakStatement\n\t\tBreakStatement");
}
#endif

View File

@ -153,6 +153,23 @@ TEST_CASE( "5 >= 5 == true", "[integration]" ) {
delete script;
}
TEST_CASE( "nil == nil == true", "[integration]" ) {
auto script = Script::Create("nil == nil");
REQUIRE(!script->Diagnostics -> HasErrors());
auto result = script->Evaluate();
REQUIRE(result->EvaluateBool());
delete script;
}
TEST_CASE( "nil != nil == true", "[integration]" ) {
auto script = Script::Create("nil ~= nil");
REQUIRE(!script->Diagnostics -> HasErrors());
auto result = script->Evaluate();
REQUIRE(!result->EvaluateBool());
delete script;
}
#endif