Added namespaces to most classes, general cleanup
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Deukhoofd 2019-06-17 18:35:12 +02:00
parent 21d3329c55
commit fde102d954
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
66 changed files with 4301 additions and 3909 deletions

File diff suppressed because it is too large Load Diff

View File

@ -8,36 +8,54 @@
#include "../Parser/ParsedExpressions/ParsedTableExpression.hpp" #include "../Parser/ParsedExpressions/ParsedTableExpression.hpp"
using namespace std; using namespace std;
using namespace Porygon::Parser;
class Binder { namespace Porygon::Binder {
Script* _scriptData; class Binder {
BoundScope* _scope; Porygon::Script *_scriptData;
shared_ptr<FunctionScriptType> _currentFunction; BoundScope *_scope;
shared_ptr<FunctionScriptType> _currentFunction;
~Binder(); ~Binder();
BoundStatement *BindStatement(const ParsedStatement *statement); BoundStatement *BindStatement(const ParsedStatement *statement);
BoundStatement *BindBlockStatement(const ParsedStatement *statement);
BoundStatement *BindExpressionStatement(const ParsedStatement *statement);
BoundStatement *BindAssignmentStatement(const ParsedStatement *statement);
BoundStatement *BindIndexAssignmentStatement(const ParsedStatement *statement);
BoundStatement *BindFunctionDeclarationStatement(const ParsedStatement * statement);
BoundStatement *BindReturnStatement(const ParsedStatement *statement);
BoundStatement *BindConditionalStatement(const ParsedStatement *statement);
BoundExpression *BindExpression(const ParsedExpression *expression); BoundStatement *BindBlockStatement(const ParsedStatement *statement);
BoundExpression *BindVariableExpression(const VariableExpression *expression);
BoundExpression *BindBinaryOperator(const BinaryExpression *expression);
BoundExpression *BindUnaryOperator(const UnaryExpression *expression);
BoundExpression *BindFunctionCall(const FunctionCallExpression *expression);
BoundExpression *BindIndexExpression(const IndexExpression *expression, bool setter);
BoundExpression *BindNumericalTableExpression(const ParsedNumericalTableExpression *expression);
BoundExpression *BindTableExpression(const ParsedTableExpression * expression);
public:
static BoundScriptStatement* Bind(Script* script, const ParsedScriptStatement* s, BoundScope* scriptScope);
BoundExpression *BindPeriodIndexExpression(const PeriodIndexExpression *expression, bool setter); BoundStatement *BindExpressionStatement(const ParsedStatement *statement);
};
BoundStatement *BindAssignmentStatement(const ParsedStatement *statement);
BoundStatement *BindIndexAssignmentStatement(const ParsedStatement *statement);
BoundStatement *BindFunctionDeclarationStatement(const ParsedStatement *statement);
BoundStatement *BindReturnStatement(const ParsedStatement *statement);
BoundStatement *BindConditionalStatement(const ParsedStatement *statement);
BoundExpression *BindExpression(const ParsedExpression *expression);
BoundExpression *BindVariableExpression(const VariableExpression *expression);
BoundExpression *BindBinaryOperator(const BinaryExpression *expression);
BoundExpression *BindUnaryOperator(const UnaryExpression *expression);
BoundExpression *BindFunctionCall(const FunctionCallExpression *expression);
BoundExpression *BindIndexExpression(const IndexExpression *expression, bool setter);
BoundExpression *BindNumericalTableExpression(const ParsedNumericalTableExpression *expression);
BoundExpression *BindTableExpression(const ParsedTableExpression *expression);
public:
static BoundScriptStatement *
Bind(Porygon::Script *script, const ParsedScriptStatement *s, BoundScope *scriptScope);
BoundExpression *BindPeriodIndexExpression(const PeriodIndexExpression *expression, bool setter);
};
}
#endif //PORYGONLANG_BINDER_HPP #endif //PORYGONLANG_BINDER_HPP

View File

@ -10,322 +10,330 @@
using namespace std; using namespace std;
enum class BoundExpressionKind{ namespace Porygon::Binder {
Bad, enum class BoundExpressionKind {
Bad,
LiteralInteger, LiteralInteger,
LiteralFloat, LiteralFloat,
LiteralString, LiteralString,
LiteralBool, LiteralBool,
Variable, Variable,
Unary, Unary,
Binary, Binary,
FunctionCall, FunctionCall,
Index, Index,
PeriodIndex, PeriodIndex,
NumericalTable, NumericalTable,
Table, Table,
};
class BoundExpression{
const unsigned int _start;
const unsigned int _length;
const shared_ptr<ScriptType> _type;
public:
BoundExpression(unsigned int start, unsigned int length, shared_ptr<ScriptType> type)
: _start(start),
_length(length),
_type(std::move(type))
{
}
virtual ~BoundExpression() = default;
virtual const BoundExpressionKind GetKind() const = 0;
virtual const std::shared_ptr<ScriptType>& GetType() const{
return _type;
}; };
const unsigned int GetStartPosition() const{ class BoundExpression {
return _start; const unsigned int _start;
} const unsigned int _length;
const unsigned int GetLength() const{ const shared_ptr<ScriptType> _type;
return _length; public:
} BoundExpression(unsigned int start, unsigned int length, shared_ptr<ScriptType> type)
const unsigned int GetEndPosition() const{ : _start(start),
return _start + _length - 1; _length(length),
} _type(std::move(type)) {
};
class BoundBadExpression : public BoundExpression{
public:
BoundBadExpression(unsigned int start, unsigned int length) : BoundExpression(start, length, make_shared<ScriptType>(TypeClass::Error)){}
const BoundExpressionKind GetKind() const final{
return BoundExpressionKind ::Bad;
}
};
class BoundLiteralIntegerExpression : public BoundExpression{
const long _value;
public:
BoundLiteralIntegerExpression(long value, unsigned int start, unsigned int length)
: BoundExpression(start, length, make_shared<NumericScriptType>(true, false)),
_value(value)
{
}
const BoundExpressionKind GetKind() const final{
return BoundExpressionKind ::LiteralInteger;
}
const long GetValue() const{
return _value;
}
};
class BoundLiteralFloatExpression : public BoundExpression{
const double _value;
public:
BoundLiteralFloatExpression(double value, unsigned int start, unsigned int length)
: BoundExpression(start, length, make_shared<NumericScriptType>(true, true)),
_value(value)
{
}
const BoundExpressionKind GetKind() const final{
return BoundExpressionKind ::LiteralFloat;
}
const double GetValue() const{
return _value;
}
};
class BoundLiteralStringExpression : public BoundExpression{
const u16string _value;
public:
BoundLiteralStringExpression(const u16string& value, unsigned int start, unsigned int length)
: BoundExpression(start, length, make_shared<StringScriptType>(true, HashedString::ConstHash(value.c_str()))),
_value(value)
{
}
const BoundExpressionKind GetKind() const final{
return BoundExpressionKind ::LiteralString;
}
const u16string GetValue() const{
return _value;
}
};
class BoundLiteralBoolExpression : public BoundExpression{
const bool _value;
public:
BoundLiteralBoolExpression(bool value, unsigned int start, unsigned int length)
: BoundExpression(start, length, make_shared<ScriptType>(TypeClass::Bool)),
_value(value)
{
}
const BoundExpressionKind GetKind() const final{
return BoundExpressionKind ::LiteralBool;
}
const bool GetValue() const{
return _value;
}
};
class BoundVariableExpression : public BoundExpression{
const BoundVariableKey* _key;
public:
BoundVariableExpression(BoundVariableKey* key, shared_ptr<ScriptType> type, unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(type)),
_key(key)
{
}
~BoundVariableExpression() override{
delete _key;
}
const BoundExpressionKind GetKind() const final{
return BoundExpressionKind ::Variable;
}
const BoundVariableKey* GetKey() const{
return _key;
}
};
class BoundBinaryExpression : public BoundExpression {
const BoundExpression* _left;
const BoundExpression* _right;
const BoundBinaryOperation _operation;
public:
BoundBinaryExpression(BoundExpression* left, BoundExpression* right, BoundBinaryOperation op, shared_ptr<ScriptType> result,
unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(result)),
_left(left),
_right(right),
_operation(op)
{
}
~BoundBinaryExpression() final{
delete _left;
delete _right;
}
const BoundExpressionKind GetKind() const final{
return BoundExpressionKind ::Binary;
}
const BoundExpression* GetLeft() const{
return _left;
}
const BoundExpression* GetRight() const{
return _right;
}
const BoundBinaryOperation GetOperation() const{
return _operation;
}
};
class BoundUnaryExpression : public BoundExpression {
const BoundExpression* _operand;
const BoundUnaryOperation _operation;
public:
BoundUnaryExpression(BoundExpression* operand, BoundUnaryOperation op, shared_ptr<ScriptType> result, unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(result)),
_operand(operand),
_operation(op)
{
}
~BoundUnaryExpression() final{
delete _operand;
}
const BoundExpressionKind GetKind() const final{
return BoundExpressionKind ::Unary;
}
const BoundExpression* GetOperand() const{
return _operand;
}
const BoundUnaryOperation GetOperation() const{
return _operation;
}
};
class BoundFunctionCallExpression : public BoundExpression {
const BoundExpression* _functionExpression;
const vector<BoundExpression*> _parameters;
public:
BoundFunctionCallExpression(BoundExpression *functionExpression, vector<BoundExpression *> parameters, shared_ptr<ScriptType> result,
unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(result)), _functionExpression(functionExpression), _parameters(std::move(parameters)) {}
~BoundFunctionCallExpression() final{
delete _functionExpression;
for (auto p : _parameters){
delete p;
} }
}
const BoundExpressionKind GetKind() const final{ virtual ~BoundExpression() = default;
return BoundExpressionKind ::FunctionCall;
}
const BoundExpression* GetFunctionExpression() const{ virtual const BoundExpressionKind GetKind() const = 0;
return _functionExpression;
}
const vector<BoundExpression*>* GetParameters() const{ virtual const std::shared_ptr<ScriptType> &GetType() const {
return &_parameters; return _type;
} };
};
class BoundIndexExpression : public BoundExpression { const unsigned int GetStartPosition() const {
const BoundExpression* _indexableExpression; return _start;
const BoundExpression* _indexExpression;
public:
BoundIndexExpression(BoundExpression* indexableExpression, BoundExpression* indexExpression, shared_ptr<ScriptType> result,
unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(result)), _indexableExpression(indexableExpression), _indexExpression(indexExpression) {}
~BoundIndexExpression() final{
delete _indexableExpression;
delete _indexExpression;
}
const BoundExpressionKind GetKind() const final{
return BoundExpressionKind ::Index;
}
const BoundExpression* GetIndexableExpression() const{
return _indexableExpression;
}
const BoundExpression* GetIndexExpression() const{
return _indexExpression;
}
};
class BoundPeriodIndexExpression : public BoundExpression {
const BoundExpression* _indexableExpression;
const HashedString _index;
public:
BoundPeriodIndexExpression(BoundExpression* indexableExpression, HashedString index, shared_ptr<ScriptType> result,
unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(result)), _indexableExpression(indexableExpression), _index(index) {}
~BoundPeriodIndexExpression() final{
delete _indexableExpression;
}
const BoundExpressionKind GetKind() const final{
return BoundExpressionKind ::PeriodIndex;
}
const BoundExpression* GetIndexableExpression() const{
return _indexableExpression;
}
const HashedString GetIndex() const{
return _index;
}
};
class BoundNumericalTableExpression : public BoundExpression{
const vector<const BoundExpression*> _expressions;
public:
BoundNumericalTableExpression(vector<const BoundExpression*> expressions, shared_ptr<ScriptType> type, unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(type)),
_expressions(std::move(expressions))
{}
~BoundNumericalTableExpression() final{
for (auto e: _expressions){
delete e;
} }
}
const BoundExpressionKind GetKind() const final{ const unsigned int GetLength() const {
return BoundExpressionKind ::NumericalTable; return _length;
} }
const vector<const BoundExpression*>* GetExpressions() const{ const unsigned int GetEndPosition() const {
return &_expressions; return _start + _length - 1;
} }
}; };
class BoundBadExpression : public BoundExpression {
public:
BoundBadExpression(unsigned int start, unsigned int length) : BoundExpression(start, length,
make_shared<ScriptType>(
TypeClass::Error)) {}
const BoundExpressionKind GetKind() const final {
return BoundExpressionKind::Bad;
}
};
class BoundLiteralIntegerExpression : public BoundExpression {
const long _value;
public:
BoundLiteralIntegerExpression(long value, unsigned int start, unsigned int length)
: BoundExpression(start, length, make_shared<NumericScriptType>(true, false)),
_value(value) {
}
const BoundExpressionKind GetKind() const final {
return BoundExpressionKind::LiteralInteger;
}
const long GetValue() const {
return _value;
}
};
class BoundLiteralFloatExpression : public BoundExpression {
const double _value;
public:
BoundLiteralFloatExpression(double value, unsigned int start, unsigned int length)
: BoundExpression(start, length, make_shared<NumericScriptType>(true, true)),
_value(value) {
}
const BoundExpressionKind GetKind() const final {
return BoundExpressionKind::LiteralFloat;
}
const double GetValue() const {
return _value;
}
};
class BoundLiteralStringExpression : public BoundExpression {
const u16string _value;
public:
BoundLiteralStringExpression(const u16string &value, unsigned int start, unsigned int length)
: BoundExpression(start, length,
make_shared<StringScriptType>(true, Utilities::HashedString::ConstHash(value.c_str()))),
_value(value) {
}
const BoundExpressionKind GetKind() const final {
return BoundExpressionKind::LiteralString;
}
const u16string GetValue() const {
return _value;
}
};
class BoundLiteralBoolExpression : public BoundExpression {
const bool _value;
public:
BoundLiteralBoolExpression(bool value, unsigned int start, unsigned int length)
: BoundExpression(start, length, make_shared<ScriptType>(TypeClass::Bool)),
_value(value) {
}
const BoundExpressionKind GetKind() const final {
return BoundExpressionKind::LiteralBool;
}
const bool GetValue() const {
return _value;
}
};
class BoundVariableExpression : public BoundExpression {
const BoundVariableKey *_key;
public:
BoundVariableExpression(BoundVariableKey *key, shared_ptr<ScriptType> type, unsigned int start,
unsigned int length)
: BoundExpression(start, length, std::move(type)),
_key(key) {
}
~BoundVariableExpression() override {
delete _key;
}
const BoundExpressionKind GetKind() const final {
return BoundExpressionKind::Variable;
}
const BoundVariableKey *GetKey() const {
return _key;
}
};
class BoundBinaryExpression : public BoundExpression {
const BoundExpression *_left;
const BoundExpression *_right;
const BoundBinaryOperation _operation;
public:
BoundBinaryExpression(BoundExpression *left, BoundExpression *right, BoundBinaryOperation op,
shared_ptr<ScriptType> result,
unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(result)),
_left(left),
_right(right),
_operation(op) {
}
~BoundBinaryExpression() final {
delete _left;
delete _right;
}
const BoundExpressionKind GetKind() const final {
return BoundExpressionKind::Binary;
}
const BoundExpression *GetLeft() const {
return _left;
}
const BoundExpression *GetRight() const {
return _right;
}
const BoundBinaryOperation GetOperation() const {
return _operation;
}
};
class BoundUnaryExpression : public BoundExpression {
const BoundExpression *_operand;
const BoundUnaryOperation _operation;
public:
BoundUnaryExpression(BoundExpression *operand, BoundUnaryOperation op, shared_ptr<ScriptType> result,
unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(result)),
_operand(operand),
_operation(op) {
}
~BoundUnaryExpression() final {
delete _operand;
}
const BoundExpressionKind GetKind() const final {
return BoundExpressionKind::Unary;
}
const BoundExpression *GetOperand() const {
return _operand;
}
const BoundUnaryOperation GetOperation() const {
return _operation;
}
};
class BoundFunctionCallExpression : public BoundExpression {
const BoundExpression *_functionExpression;
const vector<BoundExpression *> _parameters;
public:
BoundFunctionCallExpression(BoundExpression *functionExpression, vector<BoundExpression *> parameters,
shared_ptr<ScriptType> result,
unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(result)), _functionExpression(functionExpression),
_parameters(std::move(parameters)) {}
~BoundFunctionCallExpression() final {
delete _functionExpression;
for (auto p : _parameters) {
delete p;
}
}
const BoundExpressionKind GetKind() const final {
return BoundExpressionKind::FunctionCall;
}
const BoundExpression *GetFunctionExpression() const {
return _functionExpression;
}
const vector<BoundExpression *> *GetParameters() const {
return &_parameters;
}
};
class BoundIndexExpression : public BoundExpression {
const BoundExpression *_indexableExpression;
const BoundExpression *_indexExpression;
public:
BoundIndexExpression(BoundExpression *indexableExpression, BoundExpression *indexExpression,
shared_ptr<ScriptType> result,
unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(result)), _indexableExpression(indexableExpression),
_indexExpression(indexExpression) {}
~BoundIndexExpression() final {
delete _indexableExpression;
delete _indexExpression;
}
const BoundExpressionKind GetKind() const final {
return BoundExpressionKind::Index;
}
const BoundExpression *GetIndexableExpression() const {
return _indexableExpression;
}
const BoundExpression *GetIndexExpression() const {
return _indexExpression;
}
};
class BoundPeriodIndexExpression : public BoundExpression {
const BoundExpression *_indexableExpression;
const Utilities::HashedString _index;
public:
BoundPeriodIndexExpression(BoundExpression *indexableExpression, Utilities::HashedString index,
shared_ptr<ScriptType> result,
unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(result)), _indexableExpression(indexableExpression),
_index(index) {}
~BoundPeriodIndexExpression() final {
delete _indexableExpression;
}
const BoundExpressionKind GetKind() const final {
return BoundExpressionKind::PeriodIndex;
}
const BoundExpression *GetIndexableExpression() const {
return _indexableExpression;
}
const Utilities::HashedString GetIndex() const {
return _index;
}
};
class BoundNumericalTableExpression : public BoundExpression {
const vector<const BoundExpression *> _expressions;
public:
BoundNumericalTableExpression(vector<const BoundExpression *> expressions, shared_ptr<ScriptType> type,
unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(type)),
_expressions(std::move(expressions)) {}
~BoundNumericalTableExpression() final {
for (auto e: _expressions) {
delete e;
}
}
const BoundExpressionKind GetKind() const final {
return BoundExpressionKind::NumericalTable;
}
const vector<const BoundExpression *> *GetExpressions() const {
return &_expressions;
}
};
}
#endif //PORYGONLANG_BOUNDEXPRESSION_HPP #endif //PORYGONLANG_BOUNDEXPRESSION_HPP

View File

@ -6,26 +6,29 @@
#include "../BoundStatements/BoundStatement.hpp" #include "../BoundStatements/BoundStatement.hpp"
class BoundTableExpression : public BoundExpression{ namespace Porygon::Binder {
const BoundBlockStatement* _block; class BoundTableExpression : public BoundExpression {
public: const BoundBlockStatement *_block;
BoundTableExpression(BoundBlockStatement* block, shared_ptr<ScriptType> type, unsigned int start, unsigned int length) public:
: BoundExpression(start, length, std::move(type)){ BoundTableExpression(BoundBlockStatement *block, shared_ptr<ScriptType> type, unsigned int start,
_block = block; unsigned int length)
} : BoundExpression(start, length, std::move(type)) {
_block = block;
}
~BoundTableExpression() final{ ~BoundTableExpression() final {
delete _block; delete _block;
} }
const BoundExpressionKind GetKind() const final { const BoundExpressionKind GetKind() const final {
return BoundExpressionKind ::Table; return BoundExpressionKind::Table;
} }
const BoundBlockStatement* GetBlock() const { const BoundBlockStatement *GetBlock() const {
return _block; return _block;
} }
}; };
}
#include "BoundExpression.hpp" #include "BoundExpression.hpp"

View File

@ -2,26 +2,28 @@
#ifndef PORYGONLANG_BOUNDOPERATORS_HPP #ifndef PORYGONLANG_BOUNDOPERATORS_HPP
#define PORYGONLANG_BOUNDOPERATORS_HPP #define PORYGONLANG_BOUNDOPERATORS_HPP
enum class BoundBinaryOperation{ namespace Porygon::Binder {
Addition, enum class BoundBinaryOperation {
Subtraction, Addition,
Multiplication, Subtraction,
Division, Multiplication,
Equality, Division,
Inequality, Equality,
LessThan, Inequality,
LessThanEquals, LessThan,
GreaterThan, LessThanEquals,
GreaterThanEquals, GreaterThan,
GreaterThanEquals,
LogicalAnd, LogicalAnd,
LogicalOr, LogicalOr,
Concatenation Concatenation
}; };
enum class BoundUnaryOperation{ enum class BoundUnaryOperation {
Negation, Negation,
LogicalNegation, LogicalNegation,
}; };
}
#endif //PORYGONLANG_BOUNDOPERATORS_HPP #endif //PORYGONLANG_BOUNDOPERATORS_HPP

View File

@ -7,36 +7,38 @@
#include <memory> #include <memory>
#include "BoundStatement.hpp" #include "BoundStatement.hpp"
class BoundFunctionDeclarationStatement : public BoundStatement{ namespace Porygon::Binder {
const BoundVariableKey* _key; class BoundFunctionDeclarationStatement : public BoundStatement {
const std::shared_ptr<BoundBlockStatement> _block; const BoundVariableKey *_key;
const std::shared_ptr<FunctionScriptType> _type; const std::shared_ptr<BoundBlockStatement> _block;
public: const std::shared_ptr<FunctionScriptType> _type;
BoundFunctionDeclarationStatement(std::shared_ptr<FunctionScriptType> type, BoundVariableKey* key, BoundBlockStatement* block) public:
:_key(key), _block(block), _type(std::move(type)) BoundFunctionDeclarationStatement(std::shared_ptr<FunctionScriptType> type, BoundVariableKey *key,
{ BoundBlockStatement *block)
} : _key(key), _block(block), _type(std::move(type)) {
}
~BoundFunctionDeclarationStatement() final{ ~BoundFunctionDeclarationStatement() final {
delete _key; delete _key;
} }
const BoundStatementKind GetKind() const final{ const BoundStatementKind GetKind() const final {
return BoundStatementKind ::FunctionDeclaration; return BoundStatementKind::FunctionDeclaration;
} }
const BoundVariableKey* GetKey() const{ const BoundVariableKey *GetKey() const {
return _key; return _key;
} }
const std::shared_ptr<BoundBlockStatement> GetBlock() const{ const std::shared_ptr<BoundBlockStatement> GetBlock() const {
return _block; return _block;
} }
const std::shared_ptr<FunctionScriptType> GetType() const{ const std::shared_ptr<FunctionScriptType> GetType() const {
return _type; return _type;
} }
}; };
}
#include "BoundStatement.hpp" #include "BoundStatement.hpp"

View File

@ -12,198 +12,197 @@
using namespace std; using namespace std;
enum class BoundStatementKind{ namespace Porygon::Binder {
Bad, enum class BoundStatementKind {
Script, Bad,
Block, Script,
Expression, Block,
Assignment, Expression,
IndexAssignment, Assignment,
FunctionDeclaration, IndexAssignment,
Return, FunctionDeclaration,
Conditional, Return,
}; Conditional,
};
class BoundStatement{ class BoundStatement {
public: public:
virtual const BoundStatementKind GetKind() const = 0; virtual const BoundStatementKind GetKind() const = 0;
virtual ~BoundStatement() = default;
};
class BoundBadStatement : public BoundStatement{ virtual ~BoundStatement() = default;
public: };
const BoundStatementKind GetKind() const final{
return BoundStatementKind ::Bad;
}
};
class BoundBlockStatement : public BoundStatement{ class BoundBadStatement : public BoundStatement {
const vector<BoundStatement*> _statements; public:
public: const BoundStatementKind GetKind() const final {
explicit BoundBlockStatement(vector<BoundStatement*> statements) return BoundStatementKind::Bad;
: _statements(std::move(statements))
{
}
~BoundBlockStatement() override {
for (auto s : _statements){
delete s;
} }
} };
const BoundStatementKind GetKind() const override { class BoundBlockStatement : public BoundStatement {
return BoundStatementKind ::Block; const vector<BoundStatement *> _statements;
} public:
explicit BoundBlockStatement(vector<BoundStatement *> statements)
: _statements(std::move(statements)) {
}
const vector<BoundStatement*>* GetStatements() const{ ~BoundBlockStatement() override {
return &_statements; for (auto s : _statements) {
} delete s;
}; }
}
class BoundScriptStatement : public BoundBlockStatement{ const BoundStatementKind GetKind() const override {
const int _localVariableCount; return BoundStatementKind::Block;
public: }
explicit BoundScriptStatement(vector<BoundStatement*> statements, int localVariableCount)
: BoundBlockStatement(std::move(statements)),
_localVariableCount(localVariableCount)
{
}
const BoundStatementKind GetKind() const final{ const vector<BoundStatement *> *GetStatements() const {
return BoundStatementKind ::Script; return &_statements;
} }
};
const int GetLocalVariableCount() const{ class BoundScriptStatement : public BoundBlockStatement {
return _localVariableCount; const int _localVariableCount;
} public:
}; explicit BoundScriptStatement(vector<BoundStatement *> statements, int localVariableCount)
: BoundBlockStatement(std::move(statements)),
_localVariableCount(localVariableCount) {
}
class BoundExpressionStatement : public BoundStatement{ const BoundStatementKind GetKind() const final {
const BoundExpression* _expression; return BoundStatementKind::Script;
public: }
explicit BoundExpressionStatement(BoundExpression* expression)
: _expression(expression)
{
_expression = expression;
}
~BoundExpressionStatement() final{
delete _expression;
}
const BoundStatementKind GetKind() const final{ const int GetLocalVariableCount() const {
return BoundStatementKind ::Expression; return _localVariableCount;
} }
};
const BoundExpression* GetExpression() const{ class BoundExpressionStatement : public BoundStatement {
return _expression; const BoundExpression *_expression;
} public:
}; explicit BoundExpressionStatement(BoundExpression *expression)
: _expression(expression) {
_expression = expression;
}
class BoundAssignmentStatement : public BoundStatement{ ~BoundExpressionStatement() final {
const BoundVariableKey* _key; delete _expression;
const BoundExpression* _expression; }
public:
BoundAssignmentStatement(BoundVariableKey* key, BoundExpression* expression)
: _key(key), _expression(expression)
{
}
~BoundAssignmentStatement() final{ const BoundStatementKind GetKind() const final {
delete _key; return BoundStatementKind::Expression;
delete _expression; }
}
const BoundStatementKind GetKind() const final{ const BoundExpression *GetExpression() const {
return BoundStatementKind ::Assignment; return _expression;
} }
};
const BoundVariableKey* GetKey() const { class BoundAssignmentStatement : public BoundStatement {
return _key; const BoundVariableKey *_key;
} const BoundExpression *_expression;
public:
BoundAssignmentStatement(BoundVariableKey *key, BoundExpression *expression)
: _key(key), _expression(expression) {
}
const BoundExpression* GetExpression() const { ~BoundAssignmentStatement() final {
return _expression; delete _key;
} delete _expression;
}; }
class BoundIndexAssignmentStatement : public BoundStatement{ const BoundStatementKind GetKind() const final {
const BoundExpression* _indexExpression; return BoundStatementKind::Assignment;
const BoundExpression* _valueExpression; }
public:
BoundIndexAssignmentStatement(const BoundExpression* index, BoundExpression* value)
: _indexExpression(index), _valueExpression(value)
{
}
~BoundIndexAssignmentStatement() final{ const BoundVariableKey *GetKey() const {
delete _indexExpression; return _key;
delete _valueExpression; }
}
const BoundStatementKind GetKind() const final{ const BoundExpression *GetExpression() const {
return BoundStatementKind ::IndexAssignment; return _expression;
} }
};
const BoundExpression* GetIndexExpression() const { class BoundIndexAssignmentStatement : public BoundStatement {
return _indexExpression; const BoundExpression *_indexExpression;
} const BoundExpression *_valueExpression;
public:
BoundIndexAssignmentStatement(const BoundExpression *index, BoundExpression *value)
: _indexExpression(index), _valueExpression(value) {
}
const BoundExpression* GetValueExpression() const { ~BoundIndexAssignmentStatement() final {
return _valueExpression; delete _indexExpression;
} delete _valueExpression;
}; }
class BoundReturnStatement : public BoundStatement{ const BoundStatementKind GetKind() const final {
const BoundExpression* _expression; return BoundStatementKind::IndexAssignment;
public: }
explicit BoundReturnStatement(BoundExpression* expression)
: _expression(expression)
{
}
~BoundReturnStatement() final{
delete _expression;
}
const BoundStatementKind GetKind() const final{ const BoundExpression *GetIndexExpression() const {
return BoundStatementKind ::Return; return _indexExpression;
} }
const BoundExpression* GetExpression() const{ const BoundExpression *GetValueExpression() const {
return _expression; return _valueExpression;
} }
}; };
class BoundConditionalStatement : public BoundStatement{ class BoundReturnStatement : public BoundStatement {
const BoundExpression* _condition; const BoundExpression *_expression;
const BoundStatement* _block; public:
const BoundStatement* _elseStatement; explicit BoundReturnStatement(BoundExpression *expression)
public: : _expression(expression) {
explicit BoundConditionalStatement(BoundExpression* condition, BoundStatement* block, BoundStatement* next) }
:_condition(condition), _block(block), _elseStatement(next)
{
}
~BoundConditionalStatement() final{ ~BoundReturnStatement() final {
delete _condition; delete _expression;
delete _block; }
delete _elseStatement;
}
const BoundStatementKind GetKind() const final{ const BoundStatementKind GetKind() const final {
return BoundStatementKind ::Conditional; return BoundStatementKind::Return;
} }
const BoundExpression* GetCondition() const{ const BoundExpression *GetExpression() const {
return _condition; return _expression;
} }
};
const BoundStatement* GetBlock() const{ class BoundConditionalStatement : public BoundStatement {
return _block; const BoundExpression *_condition;
} const BoundStatement *_block;
const BoundStatement *_elseStatement;
public:
explicit BoundConditionalStatement(BoundExpression *condition, BoundStatement *block, BoundStatement *next)
: _condition(condition), _block(block), _elseStatement(next) {
}
const BoundStatement* GetElseStatement() const{ ~BoundConditionalStatement() final {
return _elseStatement; delete _condition;
} delete _block;
}; delete _elseStatement;
}
const BoundStatementKind GetKind() const final {
return BoundStatementKind::Conditional;
}
const BoundExpression *GetCondition() const {
return _condition;
}
const BoundStatement *GetBlock() const {
return _block;
}
const BoundStatement *GetElseStatement() const {
return _elseStatement;
}
};
}
#include "BoundFunctionDeclarationStatement.hpp" #include "BoundFunctionDeclarationStatement.hpp"

View File

@ -3,95 +3,98 @@
#include "BoundScope.hpp" #include "BoundScope.hpp"
BoundScope::BoundScope(unordered_map<uint32_t, BoundVariable *> *tableScope) { namespace Porygon::Binder {
_tableScope = tableScope; BoundScope::BoundScope(unordered_map<uint32_t, BoundVariable *> *tableScope) {
_currentScope = 1; _tableScope = tableScope;
_lastCreatedScope = 1; _currentScope = 1;
auto localUpmostScope = new unordered_map<uint32_t, BoundVariable*>(); _lastCreatedScope = 1;
_localScope.push_back(localUpmostScope); auto localUpmostScope = new unordered_map<uint32_t, BoundVariable *>();
} _localScope.push_back(localUpmostScope);
}
BoundScope::~BoundScope() { BoundScope::~BoundScope() {
for (auto scope : _localScope){ for (auto scope : _localScope) {
for (auto v : *scope){ for (auto v : *scope) {
delete v.second;
}
delete scope;
}
}
void BoundScope::GoInnerScope() {
_lastCreatedScope++;
_currentScope = _lastCreatedScope;
if (_localScope.size() < _currentScope) {
auto innerScope = new unordered_map<uint32_t, BoundVariable *>();
_localScope.push_back(innerScope);
}
}
void BoundScope::GoOuterScope() {
auto scope = _localScope[_currentScope - 1];
for (auto v : *scope) {
delete v.second; delete v.second;
} }
delete scope; scope->clear();
_currentScope--;
} }
}
void BoundScope::GoInnerScope() { int BoundScope::Exists(int key) {
_lastCreatedScope++; auto found = this->_tableScope->find(key);
_currentScope = _lastCreatedScope; if (found != _tableScope->end()) {
if (_localScope.size() < _currentScope){ return 0;
auto innerScope = new unordered_map<uint32_t, BoundVariable*>(); }
_localScope.push_back(innerScope); for (int i = _currentScope - 1; i >= 0; i--) {
auto scope = _localScope.at(i);
found = scope->find(key);
if (found != scope->end()) {
return i + 1;
}
}
return -1;
} }
}
void BoundScope::GoOuterScope() { BoundVariable *BoundScope::GetVariable(uint32_t scope, uint32_t identifier) {
auto scope = _localScope[_currentScope - 1]; if (scope == 0) {
for (auto v : *scope){ auto find = this->_tableScope->find(identifier);
delete v.second; if (find != _tableScope->end()) {
} return find->second;
scope->clear(); }
_currentScope--; return nullptr;
} } else {
auto s = this->_localScope.at(scope - 1);
int BoundScope::Exists(int key) { auto find = s->find(identifier);
auto found = this -> _tableScope -> find(key); if (find != s->end()) {
if (found != _tableScope -> end()){ return find->second;
return 0; }
} return nullptr;
for (int i = _currentScope - 1; i >= 0; i--){
auto scope = _localScope.at(i);
found = scope -> find(key);
if (found != scope -> end()){
return i + 1;
} }
} }
return -1;
}
BoundVariable *BoundScope::GetVariable(uint32_t scope, uint32_t identifier) { VariableAssignment BoundScope::CreateExplicitLocal(uint32_t identifier, std::shared_ptr<ScriptType> type) {
if (scope == 0){ auto scope = this->_localScope.at(this->_currentScope - 1);
auto find = this -> _tableScope->find(identifier); if (scope->find(identifier) != scope->end()) {
if (find != _tableScope->end()){ return VariableAssignment(VariableAssignmentResult::ExplicitLocalVariableExists, nullptr);
return find -> second;
} }
return nullptr; scope->insert({identifier, new BoundVariable(std::move(type))});
} else{ return VariableAssignment(VariableAssignmentResult::Ok,
auto s = this->_localScope.at(scope - 1); new BoundVariableKey(identifier, this->_currentScope, true));
auto find = s -> find(identifier);
if (find != s -> end()){
return find -> second;
}
return nullptr;
} }
}
VariableAssignment BoundScope::CreateExplicitLocal(uint32_t identifier, std::shared_ptr<ScriptType> type) { VariableAssignment BoundScope::AssignVariable(uint32_t identifier, const std::shared_ptr<ScriptType> &type) {
auto scope = this->_localScope.at(this->_currentScope - 1); int exists = this->Exists(identifier);
if (scope -> find(identifier) != scope -> end()){ if (exists == -1) {
return VariableAssignment(VariableAssignmentResult::ExplicitLocalVariableExists, nullptr); // Creation
} _tableScope->insert({identifier, new BoundVariable(type)});
scope -> insert({identifier, new BoundVariable(std::move(type))}); return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, 0, true));
return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, this->_currentScope, true)); } else {
} // Assigning
auto var = this->GetVariable(exists, identifier);
VariableAssignment BoundScope::AssignVariable(uint32_t identifier, const std::shared_ptr<ScriptType>& type) { if (var->GetType().get()->operator!=(type.get())) {
int exists = this->Exists(identifier); return VariableAssignment(VariableAssignmentResult::VariableDefinedWithDifferentType, nullptr);
if (exists == -1){ }
// Creation return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, exists, false));
_tableScope->insert({identifier, new BoundVariable(type)});
return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, 0, true));
} else{
// Assigning
auto var = this->GetVariable(exists, identifier);
if (var->GetType().get()->operator!=(type.get())){
return VariableAssignment(VariableAssignmentResult::VariableDefinedWithDifferentType, nullptr);
} }
return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, exists, false));
} }
} }

View File

@ -13,31 +13,38 @@
using namespace std; using namespace std;
class BoundScope { namespace Porygon::Binder {
unordered_map<uint32_t, BoundVariable*>* _tableScope; class BoundScope {
vector<unordered_map<uint32_t, BoundVariable*>*> _localScope; unordered_map<uint32_t, BoundVariable *> *_tableScope;
int _currentScope; vector<unordered_map<uint32_t, BoundVariable *> *> _localScope;
int _lastCreatedScope; int _currentScope;
public: int _lastCreatedScope;
explicit BoundScope(unordered_map<uint32_t, BoundVariable*> *tableScope); public:
~BoundScope(); explicit BoundScope(unordered_map<uint32_t, BoundVariable *> *tableScope);
void GoInnerScope(); ~BoundScope();
void GoOuterScope();
int Exists(int key); void GoInnerScope();
BoundVariable* GetVariable(uint32_t scope, uint32_t identifier);
VariableAssignment CreateExplicitLocal(uint32_t identifier, std::shared_ptr<ScriptType> type);
VariableAssignment AssignVariable(uint32_t identifier, const std::shared_ptr<ScriptType>& type);
size_t GetLocalVariableCount(){ void GoOuterScope();
return _localScope.size();
}
int GetCurrentScope(){ int Exists(int key);
return _currentScope;
} BoundVariable *GetVariable(uint32_t scope, uint32_t identifier);
};
VariableAssignment CreateExplicitLocal(uint32_t identifier, std::shared_ptr<ScriptType> type);
VariableAssignment AssignVariable(uint32_t identifier, const std::shared_ptr<ScriptType> &type);
size_t GetLocalVariableCount() {
return _localScope.size();
}
int GetCurrentScope() {
return _currentScope;
}
};
}
#endif //PORYGONLANG_BOUNDSCOPE_HPP #endif //PORYGONLANG_BOUNDSCOPE_HPP

View File

@ -9,15 +9,17 @@
using namespace std; using namespace std;
class BoundVariable{ namespace Porygon::Binder {
std::shared_ptr<ScriptType> _type; class BoundVariable {
public: std::shared_ptr<ScriptType> _type;
explicit BoundVariable(std::shared_ptr<ScriptType> type) : _type(std::move(type)){ public:
} explicit BoundVariable(std::shared_ptr<ScriptType> type) : _type(std::move(type)) {
}
std::shared_ptr<ScriptType> GetType(){ std::shared_ptr<ScriptType> GetType() {
return _type; return _type;
} }
}; };
}
#endif //PORYGONLANG_BOUNDVARIABLE_HPP #endif //PORYGONLANG_BOUNDVARIABLE_HPP

View File

@ -4,42 +4,43 @@
#include <string> #include <string>
class BoundVariableKey{ namespace Porygon::Binder {
const int _identifier; class BoundVariableKey {
const unsigned int _scopeId; const int _identifier;
const bool _isCreation; const unsigned int _scopeId;
const uint64_t _hash; const bool _isCreation;
const uint64_t _hash;
static uint64_t KnuthsHash(unsigned int i1, unsigned int i2) static uint64_t KnuthsHash(unsigned int i1, unsigned int i2) {
{ uint64_t ret = i1;
uint64_t ret = i1; ret *= 2654435761U;
ret *= 2654435761U; return ret ^ i2;
return ret ^ i2; }
}
public: public:
BoundVariableKey(int id, unsigned int scope, bool creation) BoundVariableKey(int id, unsigned int scope, bool creation)
: _identifier(id), : _identifier(id),
_scopeId(scope), _scopeId(scope),
_isCreation(creation), _isCreation(creation),
_hash(KnuthsHash(id, scope)) _hash(KnuthsHash(id, scope)) {}
{}
const int GetIdentifier() const{ const int GetIdentifier() const {
return _identifier; return _identifier;
} }
const unsigned int GetScopeId() const{ const unsigned int GetScopeId() const {
return _scopeId; return _scopeId;
} }
const bool IsCreation() const{ const bool IsCreation() const {
return _isCreation; return _isCreation;
} }
const uint64_t GetHash() const{ const uint64_t GetHash() const {
return _hash; return _hash;
} }
}; };
}
#endif //PORYGONLANG_BOUNDVARIABLEKEY_HPP #endif //PORYGONLANG_BOUNDVARIABLEKEY_HPP

View File

@ -4,28 +4,30 @@
#include "BoundVariableKey.hpp" #include "BoundVariableKey.hpp"
enum class VariableAssignmentResult{ namespace Porygon::Binder {
Ok, enum class VariableAssignmentResult {
ExplicitLocalVariableExists, Ok,
VariableDefinedWithDifferentType ExplicitLocalVariableExists,
}; VariableDefinedWithDifferentType
};
class VariableAssignment{ class VariableAssignment {
VariableAssignmentResult _result; VariableAssignmentResult _result;
BoundVariableKey* _key; BoundVariableKey *_key;
public: public:
VariableAssignment(VariableAssignmentResult result, BoundVariableKey *key) { VariableAssignment(VariableAssignmentResult result, BoundVariableKey *key) {
_result = result; _result = result;
_key = key; _key = key;
} }
VariableAssignmentResult GetResult(){ VariableAssignmentResult GetResult() {
return _result; return _result;
} }
BoundVariableKey* GetKey(){ BoundVariableKey *GetKey() {
return _key; return _key;
} }
}; };
}
#endif //PORYGONLANG_VARIABLEASSIGMENTRESULT_HPP #endif //PORYGONLANG_VARIABLEASSIGMENTRESULT_HPP

View File

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

View File

@ -3,42 +3,45 @@
#include "StringEvalValue.hpp" #include "StringEvalValue.hpp"
#include <cstring> #include <cstring>
extern "C" { namespace Porygon::Evaluation {
TypeClass GetEvalValueTypeClass(EvalValue* v){
extern "C" {
Porygon::TypeClass GetEvalValueTypeClass(EvalValue *v) {
return v->GetTypeClass(); return v->GetTypeClass();
} }
int64_t EvaluateEvalValueInteger(EvalValue* v){ int64_t EvaluateEvalValueInteger(EvalValue *v) {
return v->EvaluateInteger(); return v->EvaluateInteger();
} }
double EvaluateEvalValueFloat(EvalValue* v){ double EvaluateEvalValueFloat(EvalValue *v) {
return v->EvaluateFloat(); return v->EvaluateFloat();
} }
bool EvaluateEvalValueBool(EvalValue* v){ bool EvaluateEvalValueBool(EvalValue *v) {
return v->EvaluateBool(); return v->EvaluateBool();
} }
const char16_t * EvaluateEvalValueString(EvalValue* v){ const char16_t *EvaluateEvalValueString(EvalValue *v) {
return v->EvaluateString() -> c_str(); return v->EvaluateString()->c_str();
} }
EvalValue* CreateIntegerEvalValue(long l){ EvalValue *CreateIntegerEvalValue(long l) {
return new IntegerEvalValue(l); return new IntegerEvalValue(l);
} }
EvalValue* CreateFloatEvalValue(double d){ EvalValue *CreateFloatEvalValue(double d) {
return new FloatEvalValue(d); return new FloatEvalValue(d);
} }
EvalValue* CreateBoolEvalValue(bool b){ EvalValue *CreateBoolEvalValue(bool b) {
return new BooleanEvalValue(b); return new BooleanEvalValue(b);
} }
EvalValue* CreateStringEvalValue(const char16_t * s){ EvalValue *CreateStringEvalValue(const char16_t *s) {
return new StringEvalValue(s); return new StringEvalValue(s);
} }
}
} }
#ifdef TESTS_BUILD #ifdef TESTS_BUILD
@ -47,7 +50,7 @@ extern "C" {
TEST_CASE( "Evaluate String", "[integration]" ) { TEST_CASE( "Evaluate String", "[integration]" ) {
auto script = Script::Create(u"\"foo bar\""); auto script = Porygon::Script::Create(u"\"foo bar\"");
REQUIRE(!script->Diagnostics -> HasErrors()); REQUIRE(!script->Diagnostics -> HasErrors());
script->Evaluate(); script->Evaluate();
auto lastValue = script->GetLastValue(); auto lastValue = script->GetLastValue();

View File

@ -8,77 +8,83 @@
#include <sstream> #include <sstream>
#include <memory> #include <memory>
class EvalValue{ namespace Porygon::Evaluation {
public: class EvalValue {
EvalValue() = default; public:
virtual ~EvalValue() = default; EvalValue() = default;
virtual const TypeClass GetTypeClass() const = 0;
virtual const bool operator ==(EvalValue* b) const = 0; virtual ~EvalValue() = default;
virtual const bool operator !=(EvalValue*b) const{ virtual const TypeClass GetTypeClass() const = 0;
return ! (this->operator==(b));
}
virtual const shared_ptr<EvalValue> Clone() const = 0; virtual const bool operator==(EvalValue *b) const = 0;
virtual const long EvaluateInteger() const{ virtual const bool operator!=(EvalValue *b) const {
throw EvaluationException("Can't evaluate this EvalValue as integer."); return !(this->operator==(b));
} }
virtual const double EvaluateFloat() const{
throw EvaluationException("Can't evaluate this EvalValue as float.");
}
virtual const bool EvaluateBool() const{
throw EvaluationException("Can't evaluate this EvalValue as bool.");
}
virtual const std::u16string* EvaluateString() const {
throw EvaluationException("Can't evaluate this EvalValue as string.");
}
virtual const std::size_t GetHashCode() const = 0; virtual const shared_ptr<EvalValue> Clone() const = 0;
virtual const shared_ptr<EvalValue> IndexValue(EvalValue* val) const{ virtual const long EvaluateInteger() const {
throw EvaluationException("Can't index this EvalValue"); throw EvaluationException("Can't evaluate this EvalValue as integer.");
} }
virtual const shared_ptr<EvalValue> IndexValue(uint32_t hash) const{ virtual const double EvaluateFloat() const {
throw EvaluationException("Can't index this EvalValue"); throw EvaluationException("Can't evaluate this EvalValue as float.");
} }
virtual void SetIndexValue(EvalValue *key, const shared_ptr<EvalValue>& value) const{ virtual const bool EvaluateBool() const {
throw EvaluationException("Can't index this EvalValue"); throw EvaluationException("Can't evaluate this EvalValue as bool.");
} }
};
class BooleanEvalValue : public EvalValue{ virtual const std::u16string *EvaluateString() const {
const bool _value; throw EvaluationException("Can't evaluate this EvalValue as string.");
public: }
explicit BooleanEvalValue(bool val)
: _value(val)
{
}
const shared_ptr<EvalValue> Clone() const final{ virtual const std::size_t GetHashCode() const = 0;
return make_shared<BooleanEvalValue>(_value);
}
const TypeClass GetTypeClass() const final{ virtual const shared_ptr<EvalValue> IndexValue(EvalValue *val) const {
return TypeClass ::Bool; throw EvaluationException("Can't index this EvalValue");
} }
const bool EvaluateBool() const final{ virtual const shared_ptr<EvalValue> IndexValue(uint32_t hash) const {
return _value; throw EvaluationException("Can't index this EvalValue");
} }
const bool operator ==(EvalValue* b) const final{ virtual void SetIndexValue(EvalValue *key, const shared_ptr<EvalValue> &value) const {
if (b->GetTypeClass() != TypeClass::Bool) throw EvaluationException("Can't index this EvalValue");
return false; }
return this->EvaluateBool() == b->EvaluateBool();
}; };
const std::size_t GetHashCode() const final{ class BooleanEvalValue : public EvalValue {
return _value; const bool _value;
} public:
}; explicit BooleanEvalValue(bool val)
: _value(val) {
}
const shared_ptr<EvalValue> Clone() const final {
return make_shared<BooleanEvalValue>(_value);
}
const TypeClass GetTypeClass() const final {
return TypeClass::Bool;
}
const bool EvaluateBool() const final {
return _value;
}
const bool operator==(EvalValue *b) const final {
if (b->GetTypeClass() != TypeClass::Bool)
return false;
return this->EvaluateBool() == b->EvaluateBool();
};
const std::size_t GetHashCode() const final {
return _value;
}
};
}
#endif //PORYGONLANG_EVALVALUE_HPP #endif //PORYGONLANG_EVALVALUE_HPP

View File

@ -1,144 +1,146 @@
#include "NumericEvalValue.hpp" #include "NumericEvalValue.hpp"
const shared_ptr<NumericEvalValue> NumericEvalValue::operator+(const shared_ptr<NumericEvalValue>& b) const { namespace Porygon::Evaluation {
if (this->IsFloat()){ const shared_ptr<NumericEvalValue> NumericEvalValue::operator+(const shared_ptr<NumericEvalValue> &b) const {
if (b->IsFloat()){ if (this->IsFloat()) {
return make_shared<FloatEvalValue>(this->GetFloatValue() + b->GetFloatValue()); if (b->IsFloat()) {
} else{ return make_shared<FloatEvalValue>(this->GetFloatValue() + b->GetFloatValue());
return make_shared<FloatEvalValue>(this->GetFloatValue() + b->GetIntegerValue()); } else {
} return make_shared<FloatEvalValue>(this->GetFloatValue() + b->GetIntegerValue());
} else { }
if (b->IsFloat()){ } else {
return make_shared<FloatEvalValue>(this->GetIntegerValue() + b->GetFloatValue()); if (b->IsFloat()) {
} else{ return make_shared<FloatEvalValue>(this->GetIntegerValue() + b->GetFloatValue());
return make_shared<IntegerEvalValue>(this->GetIntegerValue() + b->GetIntegerValue()); } else {
return make_shared<IntegerEvalValue>(this->GetIntegerValue() + b->GetIntegerValue());
}
} }
} }
}
const shared_ptr<NumericEvalValue> NumericEvalValue::operator-(const shared_ptr<NumericEvalValue>& b) const { const shared_ptr<NumericEvalValue> NumericEvalValue::operator-(const shared_ptr<NumericEvalValue> &b) const {
if (this->IsFloat()){ if (this->IsFloat()) {
if (b->IsFloat()){ if (b->IsFloat()) {
return make_shared<FloatEvalValue>(this->GetFloatValue() - b->GetFloatValue()); return make_shared<FloatEvalValue>(this->GetFloatValue() - b->GetFloatValue());
} else{ } else {
return make_shared<FloatEvalValue>(this->GetFloatValue() - b->GetIntegerValue()); return make_shared<FloatEvalValue>(this->GetFloatValue() - b->GetIntegerValue());
} }
} else { } else {
if (b->IsFloat()){ if (b->IsFloat()) {
return make_shared<FloatEvalValue>(this->GetIntegerValue() - b->GetFloatValue()); return make_shared<FloatEvalValue>(this->GetIntegerValue() - b->GetFloatValue());
} else{ } else {
return make_shared<IntegerEvalValue>(this->GetIntegerValue() - b->GetIntegerValue()); return make_shared<IntegerEvalValue>(this->GetIntegerValue() - b->GetIntegerValue());
}
} }
} }
}
const shared_ptr<NumericEvalValue> NumericEvalValue::operator*(const shared_ptr<NumericEvalValue>& b) const { const shared_ptr<NumericEvalValue> NumericEvalValue::operator*(const shared_ptr<NumericEvalValue> &b) const {
if (this->IsFloat()){ if (this->IsFloat()) {
if (b->IsFloat()){ if (b->IsFloat()) {
return make_shared<FloatEvalValue>(this->GetFloatValue() * b->GetFloatValue()); return make_shared<FloatEvalValue>(this->GetFloatValue() * b->GetFloatValue());
} else{ } else {
return make_shared<FloatEvalValue>(this->GetFloatValue() * b->GetIntegerValue()); return make_shared<FloatEvalValue>(this->GetFloatValue() * b->GetIntegerValue());
} }
} else { } else {
if (b->IsFloat()){ if (b->IsFloat()) {
return make_shared<FloatEvalValue>(this->GetIntegerValue() * b->GetFloatValue()); return make_shared<FloatEvalValue>(this->GetIntegerValue() * b->GetFloatValue());
} else{ } else {
return make_shared<IntegerEvalValue>(this->GetIntegerValue() * b->GetIntegerValue()); return make_shared<IntegerEvalValue>(this->GetIntegerValue() * b->GetIntegerValue());
}
} }
} }
}
const shared_ptr<NumericEvalValue> NumericEvalValue::operator/(const shared_ptr<NumericEvalValue>& b) const { const shared_ptr<NumericEvalValue> NumericEvalValue::operator/(const shared_ptr<NumericEvalValue> &b) const {
if (this->IsFloat()){ if (this->IsFloat()) {
if (b->IsFloat()){ if (b->IsFloat()) {
return make_shared<FloatEvalValue>(this->GetFloatValue() / b->GetFloatValue()); return make_shared<FloatEvalValue>(this->GetFloatValue() / b->GetFloatValue());
} else{ } else {
return make_shared<FloatEvalValue>(this->GetFloatValue() / b->GetIntegerValue()); return make_shared<FloatEvalValue>(this->GetFloatValue() / b->GetIntegerValue());
} }
} else { } else {
if (b->IsFloat()){ if (b->IsFloat()) {
return make_shared<FloatEvalValue>(this->GetIntegerValue() / b->GetFloatValue()); return make_shared<FloatEvalValue>(this->GetIntegerValue() / b->GetFloatValue());
} else{ } else {
return make_shared<IntegerEvalValue>(this->GetIntegerValue() / b->GetIntegerValue()); return make_shared<IntegerEvalValue>(this->GetIntegerValue() / b->GetIntegerValue());
}
} }
} }
}
const bool NumericEvalValue::operator==(EvalValue *b) const { const bool NumericEvalValue::operator==(EvalValue *b) const {
if (b->GetTypeClass() != TypeClass::Number) if (b->GetTypeClass() != TypeClass::Number)
return false; return false;
auto numVal = (NumericEvalValue*)b; auto numVal = (NumericEvalValue *) b;
if (this->IsFloat() != numVal->IsFloat()) if (this->IsFloat() != numVal->IsFloat())
return false; return false;
if (this->IsFloat()){ if (this->IsFloat()) {
return this->EvaluateFloat() == numVal->EvaluateFloat(); return this->EvaluateFloat() == numVal->EvaluateFloat();
} else{ } else {
return this->EvaluateInteger() == numVal->EvaluateInteger(); return this->EvaluateInteger() == numVal->EvaluateInteger();
}
}
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator<(const shared_ptr<NumericEvalValue>& b) const {
if (this->IsFloat()){
if (b->IsFloat()){
return make_shared<BooleanEvalValue>(this->GetFloatValue() < b->GetFloatValue());
} else{
return make_shared<BooleanEvalValue>(this->GetFloatValue() < b->GetIntegerValue());
}
} else {
if (b->IsFloat()){
return make_shared<BooleanEvalValue>(this->GetIntegerValue() < b->GetFloatValue());
} else{
return make_shared<BooleanEvalValue>(this->GetIntegerValue() < b->GetIntegerValue());
} }
} }
}
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator<=(const shared_ptr<NumericEvalValue>& b) const { const shared_ptr<BooleanEvalValue> NumericEvalValue::operator<(const shared_ptr<NumericEvalValue> &b) const {
if (this->IsFloat()){ if (this->IsFloat()) {
if (b->IsFloat()){ if (b->IsFloat()) {
return make_shared<BooleanEvalValue>(this->GetFloatValue() <= b->GetFloatValue()); return make_shared<BooleanEvalValue>(this->GetFloatValue() < b->GetFloatValue());
} else{ } else {
return make_shared<BooleanEvalValue>(this->GetFloatValue() <= b->GetIntegerValue()); return make_shared<BooleanEvalValue>(this->GetFloatValue() < b->GetIntegerValue());
} }
} else { } else {
if (b->IsFloat()){ if (b->IsFloat()) {
return make_shared<BooleanEvalValue>(this->GetIntegerValue() <= b->GetFloatValue()); return make_shared<BooleanEvalValue>(this->GetIntegerValue() < b->GetFloatValue());
} else{ } else {
return make_shared<BooleanEvalValue>(this->GetIntegerValue() <= b->GetIntegerValue()); return make_shared<BooleanEvalValue>(this->GetIntegerValue() < b->GetIntegerValue());
}
} }
} }
}
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator>(const shared_ptr<NumericEvalValue>& b) const { const shared_ptr<BooleanEvalValue> NumericEvalValue::operator<=(const shared_ptr<NumericEvalValue> &b) const {
if (this->IsFloat()){ if (this->IsFloat()) {
if (b->IsFloat()){ if (b->IsFloat()) {
return make_shared<BooleanEvalValue>(this->GetFloatValue() > b->GetFloatValue()); return make_shared<BooleanEvalValue>(this->GetFloatValue() <= b->GetFloatValue());
} else{ } else {
return make_shared<BooleanEvalValue>(this->GetFloatValue() > b->GetIntegerValue()); return make_shared<BooleanEvalValue>(this->GetFloatValue() <= b->GetIntegerValue());
} }
} else { } else {
if (b->IsFloat()){ if (b->IsFloat()) {
return make_shared<BooleanEvalValue>(this->GetIntegerValue() > b->GetFloatValue()); return make_shared<BooleanEvalValue>(this->GetIntegerValue() <= b->GetFloatValue());
} else{ } else {
return make_shared<BooleanEvalValue>(this->GetIntegerValue() > b->GetIntegerValue()); return make_shared<BooleanEvalValue>(this->GetIntegerValue() <= b->GetIntegerValue());
}
} }
} }
}
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator>=(const shared_ptr<NumericEvalValue>& b) const { const shared_ptr<BooleanEvalValue> NumericEvalValue::operator>(const shared_ptr<NumericEvalValue> &b) const {
if (this->IsFloat()){ if (this->IsFloat()) {
if (b->IsFloat()){ if (b->IsFloat()) {
return make_shared<BooleanEvalValue>(this->GetFloatValue() >= b->GetFloatValue()); return make_shared<BooleanEvalValue>(this->GetFloatValue() > b->GetFloatValue());
} else{ } else {
return make_shared<BooleanEvalValue>(this->GetFloatValue() >= b->GetIntegerValue()); return make_shared<BooleanEvalValue>(this->GetFloatValue() > b->GetIntegerValue());
} }
} else { } else {
if (b->IsFloat()){ if (b->IsFloat()) {
return make_shared<BooleanEvalValue>(this->GetIntegerValue() >= b->GetFloatValue()); return make_shared<BooleanEvalValue>(this->GetIntegerValue() > b->GetFloatValue());
} else{ } else {
return make_shared<BooleanEvalValue>(this->GetIntegerValue() >= b->GetIntegerValue()); return make_shared<BooleanEvalValue>(this->GetIntegerValue() > b->GetIntegerValue());
}
} }
} }
}
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator>=(const shared_ptr<NumericEvalValue> &b) const {
if (this->IsFloat()) {
if (b->IsFloat()) {
return make_shared<BooleanEvalValue>(this->GetFloatValue() >= b->GetFloatValue());
} else {
return make_shared<BooleanEvalValue>(this->GetFloatValue() >= b->GetIntegerValue());
}
} else {
if (b->IsFloat()) {
return make_shared<BooleanEvalValue>(this->GetIntegerValue() >= b->GetFloatValue());
} else {
return make_shared<BooleanEvalValue>(this->GetIntegerValue() >= b->GetIntegerValue());
}
}
}
}

View File

@ -4,76 +4,98 @@
#include <sstream> #include <sstream>
#include "EvalValue.hpp" #include "EvalValue.hpp"
namespace Porygon::Evaluation {
class NumericEvalValue : public EvalValue {
class NumericEvalValue : public EvalValue{ virtual const long GetIntegerValue() const = 0;
virtual const long GetIntegerValue() const = 0; virtual const double GetFloatValue() const = 0;
virtual const double GetFloatValue() const = 0;
public: public:
virtual const bool IsFloat() const = 0; virtual const bool IsFloat() const = 0;
const TypeClass GetTypeClass() const final{ const TypeClass GetTypeClass() const final {
return TypeClass ::Number; return TypeClass::Number;
} }
const shared_ptr<NumericEvalValue> operator +(const shared_ptr<NumericEvalValue>& b) const; const shared_ptr<NumericEvalValue> operator+(const shared_ptr<NumericEvalValue> &b) const;
const shared_ptr<NumericEvalValue> operator -(const shared_ptr<NumericEvalValue>& b) const ;
const shared_ptr<NumericEvalValue> operator *(const shared_ptr<NumericEvalValue>& b) const ;
const shared_ptr<NumericEvalValue> operator /(const shared_ptr<NumericEvalValue>& b) const ;
const shared_ptr<BooleanEvalValue> operator <(const shared_ptr<NumericEvalValue>& b) const ;
const shared_ptr<BooleanEvalValue> operator <=(const shared_ptr<NumericEvalValue>& b)const ;
const shared_ptr<BooleanEvalValue> operator >(const shared_ptr<NumericEvalValue>& b) const ;
const shared_ptr<BooleanEvalValue> operator >=(const shared_ptr<NumericEvalValue>& b) const ;
const bool operator ==(EvalValue* b) const final;
};
class IntegerEvalValue : public NumericEvalValue{ const shared_ptr<NumericEvalValue> operator-(const shared_ptr<NumericEvalValue> &b) const;
const long _value;
const long GetIntegerValue() const final{return _value;}
const double GetFloatValue() const final{ throw EvaluationException("Attempting to retrieve float from int eval value."); }
public:
explicit IntegerEvalValue(long value) :_value(value){
}
const bool IsFloat() const final{
return false;
}
const long EvaluateInteger() const final{ const shared_ptr<NumericEvalValue> operator*(const shared_ptr<NumericEvalValue> &b) const;
return _value;
}
const shared_ptr<EvalValue> Clone() const final{ const shared_ptr<NumericEvalValue> operator/(const shared_ptr<NumericEvalValue> &b) const;
return make_shared<IntegerEvalValue>(_value);
}
const std::size_t GetHashCode() const final{ const shared_ptr<BooleanEvalValue> operator<(const shared_ptr<NumericEvalValue> &b) const;
return std::hash<long>{}(_value);
}
};
class FloatEvalValue : public NumericEvalValue{ const shared_ptr<BooleanEvalValue> operator<=(const shared_ptr<NumericEvalValue> &b) const;
const double _value;
const long GetIntegerValue() const final{ throw EvaluationException("Attempting to retrieve float from int eval value."); }
const double GetFloatValue() const final{return _value;}
public:
explicit FloatEvalValue(double value) :_value(value){
}
const bool IsFloat() const final{
return true;
}
const double EvaluateFloat() const final{ const shared_ptr<BooleanEvalValue> operator>(const shared_ptr<NumericEvalValue> &b) const;
return _value;
}
const shared_ptr<EvalValue> Clone() const final{ const shared_ptr<BooleanEvalValue> operator>=(const shared_ptr<NumericEvalValue> &b) const;
return make_shared<FloatEvalValue>(_value);
}
const std::size_t GetHashCode() const final{ const bool operator==(EvalValue *b) const final;
return std::hash<double >{}(_value); };
}
}; class IntegerEvalValue : public NumericEvalValue {
const long _value;
const long GetIntegerValue() const final { return _value; }
const double GetFloatValue() const final {
throw EvaluationException("Attempting to retrieve float from int eval value.");
}
public:
explicit IntegerEvalValue(long value) : _value(value) {
}
const bool IsFloat() const final {
return false;
}
const long EvaluateInteger() const final {
return _value;
}
const shared_ptr<EvalValue> Clone() const final {
return make_shared<IntegerEvalValue>(_value);
}
const std::size_t GetHashCode() const final {
return std::hash<long>{}(_value);
}
};
class FloatEvalValue : public NumericEvalValue {
const double _value;
const long GetIntegerValue() const final {
throw EvaluationException("Attempting to retrieve float from int eval value.");
}
const double GetFloatValue() const final { return _value; }
public:
explicit FloatEvalValue(double value) : _value(value) {
}
const bool IsFloat() const final {
return true;
}
const double EvaluateFloat() const final {
return _value;
}
const shared_ptr<EvalValue> Clone() const final {
return make_shared<FloatEvalValue>(_value);
}
const std::size_t GetHashCode() const final {
return std::hash<double>{}(_value);
}
};
}
#endif //PORYGONLANG_NUMERICEVALVALUE_HPP #endif //PORYGONLANG_NUMERICEVALVALUE_HPP

View File

@ -11,63 +11,65 @@
#include "../Evaluator.hpp" #include "../Evaluator.hpp"
#include "../EvaluationScope/EvaluationScope.hpp" #include "../EvaluationScope/EvaluationScope.hpp"
namespace Porygon::Evaluation {
class ScriptFunctionEvalValue : public EvalValue {
const std::shared_ptr<BoundBlockStatement> _innerBlock;
const std::shared_ptr<FunctionScriptType> _type;
const std::shared_ptr<EvaluationScope> _scope;
const std::size_t _hash;
class ScriptFunctionEvalValue : public EvalValue{ explicit ScriptFunctionEvalValue(std::shared_ptr<BoundBlockStatement> innerBlock,
const std::shared_ptr<BoundBlockStatement> _innerBlock; std::shared_ptr<EvaluationScope> scope,
const std::shared_ptr<FunctionScriptType> _type; std::shared_ptr<FunctionScriptType> type, size_t hash)
const std::shared_ptr<EvaluationScope> _scope; : _type(std::move(type)),
const std::size_t _hash; _innerBlock(std::move(innerBlock)),
explicit ScriptFunctionEvalValue(std::shared_ptr<BoundBlockStatement> innerBlock, std::shared_ptr<EvaluationScope> scope, _scope(std::move(scope)),
std::shared_ptr<FunctionScriptType> type, size_t hash) _hash(hash) {
: _type(std::move(type)), }
_innerBlock(std::move(innerBlock)),
_scope(std::move(scope)),
_hash(hash)
{
}
public: public:
explicit ScriptFunctionEvalValue(std::shared_ptr<BoundBlockStatement> innerBlock, std::shared_ptr<EvaluationScope> scope, explicit ScriptFunctionEvalValue(std::shared_ptr<BoundBlockStatement> innerBlock,
std::shared_ptr<FunctionScriptType> type) std::shared_ptr<EvaluationScope> scope,
: _type(std::move(type)), std::shared_ptr<FunctionScriptType> type)
_innerBlock(std::move(innerBlock)), : _type(std::move(type)),
_scope(std::move(scope)), _innerBlock(std::move(innerBlock)),
_hash(rand()) _scope(std::move(scope)),
{ _hash(rand()) {
} }
const std::shared_ptr<ScriptType> GetType() const{ const std::shared_ptr<ScriptType> GetType() const {
return _type; return _type;
} }
const TypeClass GetTypeClass() const final{ const TypeClass GetTypeClass() const final {
return TypeClass ::Function; return TypeClass::Function;
} }
const shared_ptr<EvalValue> Clone() const final{ const shared_ptr<EvalValue> Clone() const final {
// We don't run make_shared here as it can't call private constructors // We don't run make_shared here as it can't call private constructors
return shared_ptr<ScriptFunctionEvalValue>(new ScriptFunctionEvalValue(_innerBlock, _scope, _type, _hash)); return shared_ptr<ScriptFunctionEvalValue>(new ScriptFunctionEvalValue(_innerBlock, _scope, _type, _hash));
} }
const bool operator ==(EvalValue* b) const final{ const bool operator==(EvalValue *b) const final {
if (b->GetTypeClass() != TypeClass::Function) if (b->GetTypeClass() != TypeClass::Function)
return false; return false;
return this->_hash == ((ScriptFunctionEvalValue*)b)->_hash; return this->_hash == ((ScriptFunctionEvalValue *) b)->_hash;
};
const std::shared_ptr<BoundBlockStatement> &GetInnerBlock() const {
return _innerBlock;
}
const std::size_t GetHashCode() const final {
return _hash;
}
const std::shared_ptr<EvaluationScope> &GetScope() const {
return _scope;
}
}; };
}
const std::shared_ptr<BoundBlockStatement>& GetInnerBlock() const{
return _innerBlock;
}
const std::size_t GetHashCode() const final{
return _hash;
}
const std::shared_ptr<EvaluationScope>& GetScope() const{
return _scope;
}
};
#endif //PORYGONLANG_SCRIPTFUNCTIONEVALVALUE_HPP #endif //PORYGONLANG_SCRIPTFUNCTIONEVALVALUE_HPP

View File

@ -8,43 +8,44 @@
using namespace std; using namespace std;
class StringEvalValue : public EvalValue{ namespace Porygon::Evaluation {
u16string _value; class StringEvalValue : public EvalValue {
size_t _hash; u16string _value;
public: size_t _hash;
explicit StringEvalValue(u16string s){ public:
_value = move(s); explicit StringEvalValue(u16string s) {
_hash = HashedString::ConstHash (_value.c_str()); _value = move(s);
} _hash = Utilities::HashedString::ConstHash(_value.c_str());
}
const TypeClass GetTypeClass() const final{ const TypeClass GetTypeClass() const final {
return TypeClass ::String; return TypeClass::String;
} }
const bool operator ==(EvalValue* b) const final{ const bool operator==(EvalValue *b) const final {
if (b->GetTypeClass() != TypeClass::String) if (b->GetTypeClass() != TypeClass::String)
return false; return false;
return this->_hash == b->GetHashCode(); return this->_hash == b->GetHashCode();
};
const u16string *EvaluateString() const final {
return &_value;
}
const shared_ptr<EvalValue> Clone() const final {
return make_shared<StringEvalValue>(_value);
}
const shared_ptr<EvalValue> IndexValue(EvalValue *val) const final {
// Porygon is 1-indexed, so we convert to that.
auto l = val->EvaluateInteger() - 1;
return make_shared<StringEvalValue>(u16string(1, _value[l]));
}
const std::size_t GetHashCode() const final {
return _hash;
}
}; };
}
const u16string* EvaluateString() const final{
return &_value;
}
const shared_ptr<EvalValue> Clone() const final{
return make_shared<StringEvalValue>(_value);
}
const shared_ptr<EvalValue> IndexValue(EvalValue* val) const final{
// Porygon is 1-indexed, so we convert to that.
auto l = val->EvaluateInteger() - 1;
return make_shared<StringEvalValue>(u16string(1, _value[l]));
}
const std::size_t GetHashCode() const final{
return _hash;
}
};
#endif //PORYGONLANG_STRINGEVALVALUE_HPP #endif //PORYGONLANG_STRINGEVALVALUE_HPP

View File

@ -6,55 +6,57 @@
using namespace std; using namespace std;
class TableEvalValue : public EvalValue { namespace Porygon::Evaluation {
shared_ptr<unordered_map<uint32_t, shared_ptr<EvalValue>>> _table; class TableEvalValue : public EvalValue {
size_t _hash; shared_ptr<unordered_map<uint32_t, shared_ptr<EvalValue>>> _table;
size_t _hash;
explicit TableEvalValue(shared_ptr<unordered_map<uint32_t, shared_ptr<EvalValue>>> table, size_t hash){ explicit TableEvalValue(shared_ptr<unordered_map<uint32_t, shared_ptr<EvalValue>>> table, size_t hash) {
_table = std::move(table); _table = std::move(table);
_hash = hash; _hash = hash;
} }
public:
explicit TableEvalValue(shared_ptr<unordered_map<uint32_t, shared_ptr<EvalValue>>> table){
_table = std::move(table);
_hash = rand();
}
const TypeClass GetTypeClass() const final{ public:
return TypeClass ::Table; explicit TableEvalValue(shared_ptr<unordered_map<uint32_t, shared_ptr<EvalValue>>> table) {
} _table = std::move(table);
_hash = rand();
}
const size_t GetHashCode() const final{ const TypeClass GetTypeClass() const final {
return _hash; return TypeClass::Table;
} }
const bool operator ==(EvalValue* b) const final{ const size_t GetHashCode() const final {
return this -> _hash == b->GetHashCode(); return _hash;
} }
const shared_ptr<EvalValue> Clone() const final{ const bool operator==(EvalValue *b) const final {
return shared_ptr<EvalValue>(new TableEvalValue(_table, _hash)); return this->_hash == b->GetHashCode();
} }
const shared_ptr<EvalValue> IndexValue(EvalValue* val) const final{ const shared_ptr<EvalValue> Clone() const final {
auto hash = val->GetHashCode(); return shared_ptr<EvalValue>(new TableEvalValue(_table, _hash));
return this -> _table->at(hash); }
}
const shared_ptr<EvalValue> IndexValue(uint32_t hash) const final{ const shared_ptr<EvalValue> IndexValue(EvalValue *val) const final {
return this -> _table->at(hash); auto hash = val->GetHashCode();
} return this->_table->at(hash);
}
const shared_ptr<EvalValue> IndexValue(const char* val) const { const shared_ptr<EvalValue> IndexValue(uint32_t hash) const final {
auto hash = HashedString::ConstHash(val); return this->_table->at(hash);
return this -> _table -> at(hash); }
}
void SetIndexValue(EvalValue *key, const shared_ptr<EvalValue>& value) const final{ const shared_ptr<EvalValue> IndexValue(const char *val) const {
auto hash = key->GetHashCode(); auto hash = Utilities::HashedString::ConstHash(val);
this -> _table->at(hash) = value; return this->_table->at(hash);
} }
};
void SetIndexValue(EvalValue *key, const shared_ptr<EvalValue> &value) const final {
auto hash = key->GetHashCode();
this->_table->at(hash) = value;
}
};
}
#endif //PORYGONLANG_TABLEEVALVALUE_HPP #endif //PORYGONLANG_TABLEEVALVALUE_HPP

View File

@ -7,18 +7,20 @@
#include <string> #include <string>
using namespace std; using namespace std;
class EvaluationException : public std::exception { namespace Porygon::Evaluation {
string _message; class EvaluationException : public std::exception {
public: string _message;
explicit EvaluationException(string message){ public:
_message = std::move(message); explicit EvaluationException(string message) {
} _message = std::move(message);
}
const string defaultErrorText = "An evaluation exception occurred: "; const string defaultErrorText = "An evaluation exception occurred: ";
const char* what() const noexcept final{
return (defaultErrorText + _message).c_str();
}
};
const char *what() const noexcept final {
return (defaultErrorText + _message).c_str();
}
};
}
#endif //PORYGONLANG_EVALUATIONEXCEPTION_HPP #endif //PORYGONLANG_EVALUATIONEXCEPTION_HPP

View File

@ -2,34 +2,37 @@
#include "EvaluationScope.hpp" #include "EvaluationScope.hpp"
#include <memory> #include <memory>
EvaluationScope::EvaluationScope(unordered_map<uint32_t, shared_ptr<EvalValue>> *scriptVariables, int localVariableCount) { namespace Porygon::Evaluation {
_scriptScope = scriptVariables; EvaluationScope::EvaluationScope(unordered_map<uint32_t, shared_ptr<EvalValue>> *scriptVariables,
_localScope = unordered_map<uint64_t, shared_ptr<EvalValue>>(localVariableCount); int localVariableCount) {
} _scriptScope = scriptVariables;
_localScope = unordered_map<uint64_t, shared_ptr<EvalValue>>(localVariableCount);
}
void EvaluationScope::CreateVariable(const BoundVariableKey* key, const shared_ptr<EvalValue> &value) { void EvaluationScope::CreateVariable(const BoundVariableKey *key, const shared_ptr<EvalValue> &value) {
if (key->GetScopeId() == 0){ if (key->GetScopeId() == 0) {
_scriptScope -> at(key->GetIdentifier()) = value; _scriptScope->at(key->GetIdentifier()) = value;
} else{ } else {
auto insert = _localScope.insert({key->GetHash(), value}); auto insert = _localScope.insert({key->GetHash(), value});
if (!insert.second){ if (!insert.second) {
_localScope[key->GetHash()] = value;
}
}
}
void EvaluationScope::SetVariable(const BoundVariableKey *key, const shared_ptr<EvalValue> &value) {
if (key->GetScopeId() == 0) {
_scriptScope->at(key->GetIdentifier()) = value;
} else {
_localScope[key->GetHash()] = value; _localScope[key->GetHash()] = value;
} }
} }
}
void EvaluationScope::SetVariable(const BoundVariableKey* key, const shared_ptr<EvalValue> &value) { shared_ptr<EvalValue> EvaluationScope::GetVariable(const BoundVariableKey *key) {
if (key->GetScopeId() == 0){ if (key->GetScopeId() == 0) {
_scriptScope -> at(key->GetIdentifier()) = value; return _scriptScope->at(key->GetIdentifier());
} else{ } else {
_localScope[key->GetHash()] = value; return _localScope[key->GetHash()];
} }
}
shared_ptr<EvalValue> EvaluationScope::GetVariable(const BoundVariableKey* key) {
if (key->GetScopeId() == 0){
return _scriptScope -> at(key->GetIdentifier());
} else{
return _localScope[key->GetHash()];
} }
} }

View File

@ -5,18 +5,24 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "../EvalValues/EvalValue.hpp" #include "../EvalValues/EvalValue.hpp"
using namespace Porygon::Binder;
class EvaluationScope { namespace Porygon::Evaluation {
unordered_map<uint32_t, shared_ptr<EvalValue>>* _scriptScope; class EvaluationScope {
unordered_map<uint64_t, shared_ptr<EvalValue>> _localScope; unordered_map<uint32_t, shared_ptr<EvalValue>> *_scriptScope;
public: unordered_map<uint64_t, shared_ptr<EvalValue>> _localScope;
explicit EvaluationScope(unordered_map<uint32_t, shared_ptr<EvalValue>>* scriptVariables, int deepestScope); public:
~EvaluationScope() = default; explicit EvaluationScope(unordered_map<uint32_t, shared_ptr<EvalValue>> *scriptVariables, int deepestScope);
void CreateVariable(const BoundVariableKey* key, const shared_ptr<EvalValue>& value); ~EvaluationScope() = default;
void SetVariable(const BoundVariableKey* key, const shared_ptr<EvalValue>& value);
shared_ptr<EvalValue> GetVariable(const BoundVariableKey* key); void CreateVariable(const BoundVariableKey *key, const shared_ptr<EvalValue> &value);
};
void SetVariable(const BoundVariableKey *key, const shared_ptr<EvalValue> &value);
shared_ptr<EvalValue> GetVariable(const BoundVariableKey *key);
};
}
#endif //PORYGONLANG_EVALUATIONSCOPE_HPP #endif //PORYGONLANG_EVALUATIONSCOPE_HPP

View File

@ -11,317 +11,369 @@
#include "../TableScriptType.hpp" #include "../TableScriptType.hpp"
using namespace std; using namespace std;
using namespace Porygon::Binder;
EvalValue* Evaluator::Evaluate(const BoundScriptStatement *statement) { namespace Porygon::Evaluation {
this->_evaluationScope = make_shared<EvaluationScope>(this->_scriptData->_scriptVariables, statement->GetLocalVariableCount()); EvalValue *Evaluator::Evaluate(const BoundScriptStatement *statement) {
EvaluateBlockStatement(statement); this->_evaluationScope = make_shared<EvaluationScope>(this->_scriptVariables,
return this -> _returnValue.get(); statement->GetLocalVariableCount());
} EvaluateBlockStatement(statement);
return this->_returnValue.get();
void Evaluator::EvaluateStatement(const BoundStatement *statement) {
if (this->_hasReturned)
return;
switch (statement->GetKind()){
case BoundStatementKind ::Script: throw; // Should never happen
case BoundStatementKind ::Block: return this->EvaluateBlockStatement((BoundBlockStatement *) statement);
case BoundStatementKind ::Expression: return this -> EvaluateExpressionStatement((BoundExpressionStatement*)statement);
case BoundStatementKind ::Assignment: return this -> EvaluateAssignmentStatement((BoundAssignmentStatement*)statement);
case BoundStatementKind::IndexAssignment:
return this -> EvaluateIndexAssignmentStatement((BoundIndexAssignmentStatement*)statement);
case BoundStatementKind ::FunctionDeclaration: return this->EvaluateFunctionDeclarationStatement((BoundFunctionDeclarationStatement*)statement);
case BoundStatementKind::Return: return this -> EvaluateReturnStatement((BoundReturnStatement*)statement);
case BoundStatementKind::Conditional: return this -> EvaluateConditionalStatement((BoundConditionalStatement*)statement);
case BoundStatementKind::Bad:
throw;
} }
}
void Evaluator::EvaluateBlockStatement(const BoundBlockStatement *statement) { void Evaluator::EvaluateStatement(const BoundStatement *statement) {
for (auto s: *statement->GetStatements()){
this -> EvaluateStatement(s);
if (this->_hasReturned) if (this->_hasReturned)
break; return;
} switch (statement->GetKind()) {
} case BoundStatementKind::Script:
throw; // Should never happen
case BoundStatementKind::Block:
return this->EvaluateBlockStatement((BoundBlockStatement *) statement);
case BoundStatementKind::Expression:
return this->EvaluateExpressionStatement((BoundExpressionStatement *) statement);
case BoundStatementKind::Assignment:
return this->EvaluateAssignmentStatement((BoundAssignmentStatement *) statement);
case BoundStatementKind::IndexAssignment:
return this->EvaluateIndexAssignmentStatement((BoundIndexAssignmentStatement *) statement);
case BoundStatementKind::FunctionDeclaration:
return this->EvaluateFunctionDeclarationStatement((BoundFunctionDeclarationStatement *) statement);
case BoundStatementKind::Return:
return this->EvaluateReturnStatement((BoundReturnStatement *) statement);
case BoundStatementKind::Conditional:
return this->EvaluateConditionalStatement((BoundConditionalStatement *) statement);
void Evaluator::EvaluateExpressionStatement(const BoundExpressionStatement *statement) { case BoundStatementKind::Bad:
// Save new value throw;
this->_lastValue = this -> EvaluateExpression(statement->GetExpression());
}
void Evaluator::EvaluateAssignmentStatement(const BoundAssignmentStatement *statement) {
auto value = this -> EvaluateExpression(statement->GetExpression());
auto key = statement->GetKey();
if (key->IsCreation()){
this->_evaluationScope->CreateVariable(key, value);
} else{
this->_evaluationScope->SetVariable(key, value);
}
}
void Evaluator::EvaluateIndexAssignmentStatement(const BoundIndexAssignmentStatement *statement) {
auto indexExpression = statement -> GetIndexExpression();
auto value = this -> EvaluateExpression(statement -> GetValueExpression());
auto index = ((BoundIndexExpression*)indexExpression);
auto table = this -> EvaluateExpression(index -> GetIndexableExpression());
auto key = this -> EvaluateExpression(index->GetIndexExpression());
table -> SetIndexValue(key.get(), value);
}
void Evaluator::EvaluateFunctionDeclarationStatement(const BoundFunctionDeclarationStatement *statement) {
auto type = statement->GetType();
auto key = statement->GetKey();
auto block = statement->GetBlock();
auto value = make_shared<ScriptFunctionEvalValue>(block, this->_evaluationScope, type);
if (key->IsCreation()){
this->_evaluationScope->CreateVariable(key, value);
} else{
this->_evaluationScope->SetVariable(key, value);
}
}
void Evaluator::EvaluateReturnStatement(const BoundReturnStatement* statement){
auto expression = statement->GetExpression();
if (expression == nullptr){
this->_hasReturned = true;
return;
}
auto value = this -> EvaluateExpression(expression);
this->_hasReturned = true;
this -> _returnValue = value;
}
void Evaluator::EvaluateConditionalStatement(const BoundConditionalStatement *statement) {
auto condition = statement->GetCondition();
if (EvaluateBoolExpression(condition) -> EvaluateBool()){
this -> EvaluateStatement(statement->GetBlock());
} else{
auto elseStatement = statement -> GetElseStatement();
if (elseStatement != nullptr){
this->EvaluateStatement(elseStatement);
} }
} }
}
const shared_ptr<EvalValue> Evaluator::EvaluateExpression(const BoundExpression *expression) { void Evaluator::EvaluateBlockStatement(const BoundBlockStatement *statement) {
auto type = expression -> GetType(); for (auto s: *statement->GetStatements()) {
switch (type->GetClass()){ this->EvaluateStatement(s);
case TypeClass ::Number: return this -> EvaluateIntegerExpression(expression); if (this->_hasReturned)
case TypeClass ::Bool: return this -> EvaluateBoolExpression(expression); break;
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;
}
}
const shared_ptr<EvalValue> Evaluator::GetVariable(const BoundVariableExpression *expression){
auto variable = this->_evaluationScope->GetVariable(expression->GetKey());
if (variable == nullptr){
throw EvaluationException("Variable not found");
}
return variable->Clone();
}
const shared_ptr<NumericEvalValue> Evaluator::EvaluateIntegerExpression(const BoundExpression *expression) {
switch (expression->GetKind()){
case BoundExpressionKind ::LiteralInteger: return make_shared<IntegerEvalValue>(((BoundLiteralIntegerExpression*)expression)->GetValue());
case BoundExpressionKind ::LiteralFloat: return make_shared<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<NumericEvalValue>(this->GetVariable((BoundVariableExpression*)expression));
case BoundExpressionKind ::FunctionCall: return dynamic_pointer_cast<NumericEvalValue>(this->EvaluateFunctionCallExpression(expression));
case BoundExpressionKind ::Index: return dynamic_pointer_cast<NumericEvalValue>(this->EvaluateIndexExpression(expression));
case BoundExpressionKind ::PeriodIndex: return dynamic_pointer_cast<NumericEvalValue>(this->EvaluatePeriodIndexExpression(expression));
case BoundExpressionKind ::LiteralString:
case BoundExpressionKind ::LiteralBool:
case BoundExpressionKind ::Bad:
case BoundExpressionKind::NumericalTable:
case BoundExpressionKind::Table:
throw;
}
}
const shared_ptr<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<BooleanEvalValue>(this->GetVariable((BoundVariableExpression*)expression));
case BoundExpressionKind ::FunctionCall: return dynamic_pointer_cast<BooleanEvalValue>(this->EvaluateFunctionCallExpression(expression));
case BoundExpressionKind ::Index: return dynamic_pointer_cast<BooleanEvalValue>(this->EvaluateIndexExpression(expression));
case BoundExpressionKind ::PeriodIndex: return dynamic_pointer_cast<BooleanEvalValue>(this->EvaluatePeriodIndexExpression(expression));
case BoundExpressionKind::Bad:
case BoundExpressionKind::LiteralInteger:
case BoundExpressionKind::LiteralFloat:
case BoundExpressionKind::LiteralString:
case BoundExpressionKind::NumericalTable:
case BoundExpressionKind::Table:
throw;
}
}
const shared_ptr<StringEvalValue> Evaluator::EvaluateStringExpression(const BoundExpression *expression) {
switch (expression->GetKind()) {
case BoundExpressionKind ::LiteralString:
return make_shared<StringEvalValue>(((BoundLiteralStringExpression*)expression)->GetValue());
case BoundExpressionKind::Binary:
return this -> EvaluateStringBinary((BoundBinaryExpression*)expression);
case BoundExpressionKind::Variable: return dynamic_pointer_cast<StringEvalValue>(this->GetVariable((BoundVariableExpression*)expression));
case BoundExpressionKind ::FunctionCall: return dynamic_pointer_cast<StringEvalValue>(this->EvaluateFunctionCallExpression(expression));
case BoundExpressionKind ::Index: return dynamic_pointer_cast<StringEvalValue>(this->EvaluateIndexExpression(expression));
case BoundExpressionKind ::PeriodIndex: return dynamic_pointer_cast<StringEvalValue>(this->EvaluatePeriodIndexExpression(expression));
case BoundExpressionKind::Bad:
case BoundExpressionKind::LiteralInteger:
case BoundExpressionKind::LiteralFloat:
case BoundExpressionKind::LiteralBool:
case BoundExpressionKind::Unary:
case BoundExpressionKind::NumericalTable:
case BoundExpressionKind::Table:
throw;
}
}
const shared_ptr<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: return this->EvaluatePeriodIndexExpression(expression);
default: throw;
}
}
const shared_ptr<EvalValue> Evaluator::EvaluateNilExpression(const BoundExpression *expression){
switch (expression->GetKind()){
case BoundExpressionKind ::FunctionCall:
return this->EvaluateFunctionCallExpression(expression);
default:
return nullptr;
}
}
const shared_ptr<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: return this-> EvaluateNumericTableExpression(expression);
case BoundExpressionKind ::Table: return this -> EvaluateComplexTableExpression(expression);
case BoundExpressionKind ::PeriodIndex: return this->EvaluatePeriodIndexExpression(expression);
default:
throw;
}
}
const shared_ptr<EvalValue> Evaluator::EvaluateFunctionCallExpression(const BoundExpression *expression){
auto functionCall = (BoundFunctionCallExpression*)expression;
auto function = dynamic_pointer_cast<ScriptFunctionEvalValue>(this->EvaluateExpression(functionCall->GetFunctionExpression()));
auto boundParameters = functionCall->GetParameters();
auto parameters = vector<shared_ptr<EvalValue>>(boundParameters->size());
for (int i = 0; i < boundParameters->size(); i++){
parameters[i] = this->EvaluateExpression(boundParameters->at(i));
} }
auto type = std::dynamic_pointer_cast<FunctionScriptType>(function->GetType()); void Evaluator::EvaluateExpressionStatement(const BoundExpressionStatement *statement) {
auto parameterTypes = type->GetParameterTypes(); // Save new value
auto parameterKeys = type->GetParameterKeys(); this->_lastValue = this->EvaluateExpression(statement->GetExpression());
auto originalScope = this->_evaluationScope;
this->_evaluationScope = function->GetScope();
for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++){
auto parameter = parameters[i];
auto key = parameterKeys.at(i);
this->_evaluationScope->CreateVariable(key.get(), parameter->Clone());
} }
this->EvaluateBlockStatement(function->GetInnerBlock().get());
this->_evaluationScope = originalScope;
this->_hasReturned = false; void Evaluator::EvaluateAssignmentStatement(const BoundAssignmentStatement *statement) {
auto r = this -> _returnValue; auto value = this->EvaluateExpression(statement->GetExpression());
this -> _returnValue = nullptr; auto key = statement->GetKey();
return r; if (key->IsCreation()) {
} this->_evaluationScope->CreateVariable(key, value);
} else {
const shared_ptr<EvalValue> Evaluator::EvaluateFunction(const ScriptFunctionEvalValue *function, this->_evaluationScope->SetVariable(key, value);
const vector<EvalValue *> &parameters) { }
auto type = std::dynamic_pointer_cast<FunctionScriptType>(function->GetType());
auto parameterTypes = type->GetParameterTypes();
auto parameterKeys = type->GetParameterKeys();
auto originalScope = this->_evaluationScope;
this->_evaluationScope = function->GetScope();
for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++){
auto parameter = parameters[i];
auto key = parameterKeys.at(i);
this->_evaluationScope->CreateVariable(key.get(), parameter->Clone());
} }
this->EvaluateBlockStatement(function->GetInnerBlock().get());
this->_evaluationScope = originalScope;
this->_hasReturned = false;
auto r = this -> _returnValue;
this -> _returnValue = nullptr;
return r;
}
const shared_ptr<EvalValue> Evaluator::EvaluateIndexExpression(const BoundExpression *expression) { void Evaluator::EvaluateIndexAssignmentStatement(const BoundIndexAssignmentStatement *statement) {
auto indexExpression = (BoundIndexExpression*)expression; auto indexExpression = statement->GetIndexExpression();
auto index = this -> EvaluateExpression(indexExpression->GetIndexExpression()); auto value = this->EvaluateExpression(statement->GetValueExpression());
auto indexable = this -> EvaluateExpression(indexExpression->GetIndexableExpression()); auto index = ((BoundIndexExpression *) indexExpression);
return indexable -> IndexValue(index.get()) -> Clone(); auto table = this->EvaluateExpression(index->GetIndexableExpression());
} auto key = this->EvaluateExpression(index->GetIndexExpression());
table->SetIndexValue(key.get(), value);
const shared_ptr<EvalValue> Evaluator::EvaluatePeriodIndexExpression(const BoundExpression *expression) {
auto indexExpression = (BoundPeriodIndexExpression*)expression;
auto index = indexExpression -> GetIndex().GetHash();
auto indexable = this -> EvaluateExpression(indexExpression->GetIndexableExpression());
return indexable -> IndexValue(index) -> Clone();
}
const shared_ptr<EvalValue> Evaluator::EvaluateNumericTableExpression(const BoundExpression *expression) {
auto tableExpression = (BoundNumericalTableExpression*)expression;
auto valueExpressions = tableExpression->GetExpressions();
auto values = new unordered_map<uint32_t, shared_ptr<EvalValue>>(valueExpressions->size());
for (int i = 0; i < valueExpressions->size(); i++){
auto val = this -> EvaluateExpression(valueExpressions -> at(i));
values -> insert({i + 1, val});
} }
auto valuesPointer = shared_ptr<unordered_map<uint32_t, shared_ptr<EvalValue>>>(values);
return make_shared<TableEvalValue>(valuesPointer);
}
const shared_ptr<EvalValue> Evaluator::EvaluateComplexTableExpression(const BoundExpression *expression) { void Evaluator::EvaluateFunctionDeclarationStatement(const BoundFunctionDeclarationStatement *statement) {
auto tableExpression = (BoundTableExpression*)expression; auto type = statement->GetType();
auto type = dynamic_pointer_cast<TableScriptType>(tableExpression->GetType()); auto key = statement->GetKey();
auto declaredVars = type -> GetValues(); auto block = statement->GetBlock();
auto variables = make_shared<unordered_map<uint32_t, shared_ptr<EvalValue>>>(declaredVars->size()); auto value = make_shared<ScriptFunctionEvalValue>(block, this->_evaluationScope, type);
for (auto i : *declaredVars){ if (key->IsCreation()) {
variables->insert({i.first, nullptr}); this->_evaluationScope->CreateVariable(key, value);
} else {
this->_evaluationScope->SetVariable(key, value);
}
} }
auto evaluator = make_shared<EvaluationScope>(variables.get(), type -> GetLocalVariableCount());
auto currentEvaluator = this -> _evaluationScope;
this -> _evaluationScope = evaluator;
this->EvaluateBlockStatement(tableExpression->GetBlock());
this -> _evaluationScope = currentEvaluator;
return make_shared<TableEvalValue>(variables);
}
const shared_ptr<EvalValue> Evaluator::EvaluateUserDataExpression(const BoundExpression *expression) { void Evaluator::EvaluateReturnStatement(const BoundReturnStatement *statement) {
switch (expression->GetKind()){ auto expression = statement->GetExpression();
case BoundExpressionKind ::Variable: return this->GetVariable((BoundVariableExpression*)expression); if (expression == nullptr) {
case BoundExpressionKind ::Index: return this -> EvaluateIndexExpression(expression); this->_hasReturned = true;
default: throw; return;
}
auto value = this->EvaluateExpression(expression);
this->_hasReturned = true;
this->_returnValue = value;
} }
}
void Evaluator::EvaluateConditionalStatement(const BoundConditionalStatement *statement) {
auto condition = statement->GetCondition();
if (EvaluateBoolExpression(condition)->EvaluateBool()) {
this->EvaluateStatement(statement->GetBlock());
} else {
auto elseStatement = statement->GetElseStatement();
if (elseStatement != nullptr) {
this->EvaluateStatement(elseStatement);
}
}
}
const shared_ptr<EvalValue> Evaluator::EvaluateExpression(const BoundExpression *expression) {
auto type = expression->GetType();
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;
}
}
const shared_ptr<EvalValue> Evaluator::GetVariable(const BoundVariableExpression *expression) {
auto variable = this->_evaluationScope->GetVariable(expression->GetKey());
if (variable == nullptr) {
throw EvaluationException("Variable not found");
}
return variable->Clone();
}
const shared_ptr<NumericEvalValue> Evaluator::EvaluateIntegerExpression(const BoundExpression *expression) {
switch (expression->GetKind()) {
case BoundExpressionKind::LiteralInteger:
return make_shared<IntegerEvalValue>(((BoundLiteralIntegerExpression *) expression)->GetValue());
case BoundExpressionKind::LiteralFloat:
return make_shared<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<NumericEvalValue>(
this->GetVariable((BoundVariableExpression *) expression));
case BoundExpressionKind::FunctionCall:
return dynamic_pointer_cast<NumericEvalValue>(this->EvaluateFunctionCallExpression(expression));
case BoundExpressionKind::Index:
return dynamic_pointer_cast<NumericEvalValue>(this->EvaluateIndexExpression(expression));
case BoundExpressionKind::PeriodIndex:
return dynamic_pointer_cast<NumericEvalValue>(this->EvaluatePeriodIndexExpression(expression));
case BoundExpressionKind::LiteralString:
case BoundExpressionKind::LiteralBool:
case BoundExpressionKind::Bad:
case BoundExpressionKind::NumericalTable:
case BoundExpressionKind::Table:
throw;
}
}
const shared_ptr<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<BooleanEvalValue>(
this->GetVariable((BoundVariableExpression *) expression));
case BoundExpressionKind::FunctionCall:
return dynamic_pointer_cast<BooleanEvalValue>(this->EvaluateFunctionCallExpression(expression));
case BoundExpressionKind::Index:
return dynamic_pointer_cast<BooleanEvalValue>(this->EvaluateIndexExpression(expression));
case BoundExpressionKind::PeriodIndex:
return dynamic_pointer_cast<BooleanEvalValue>(this->EvaluatePeriodIndexExpression(expression));
case BoundExpressionKind::Bad:
case BoundExpressionKind::LiteralInteger:
case BoundExpressionKind::LiteralFloat:
case BoundExpressionKind::LiteralString:
case BoundExpressionKind::NumericalTable:
case BoundExpressionKind::Table:
throw;
}
}
const shared_ptr<StringEvalValue> Evaluator::EvaluateStringExpression(const BoundExpression *expression) {
switch (expression->GetKind()) {
case BoundExpressionKind::LiteralString:
return make_shared<StringEvalValue>(((BoundLiteralStringExpression *) expression)->GetValue());
case BoundExpressionKind::Binary:
return this->EvaluateStringBinary((BoundBinaryExpression *) expression);
case BoundExpressionKind::Variable:
return dynamic_pointer_cast<StringEvalValue>(this->GetVariable((BoundVariableExpression *) expression));
case BoundExpressionKind::FunctionCall:
return dynamic_pointer_cast<StringEvalValue>(this->EvaluateFunctionCallExpression(expression));
case BoundExpressionKind::Index:
return dynamic_pointer_cast<StringEvalValue>(this->EvaluateIndexExpression(expression));
case BoundExpressionKind::PeriodIndex:
return dynamic_pointer_cast<StringEvalValue>(this->EvaluatePeriodIndexExpression(expression));
case BoundExpressionKind::Bad:
case BoundExpressionKind::LiteralInteger:
case BoundExpressionKind::LiteralFloat:
case BoundExpressionKind::LiteralBool:
case BoundExpressionKind::Unary:
case BoundExpressionKind::NumericalTable:
case BoundExpressionKind::Table:
throw;
}
}
const shared_ptr<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:
return this->EvaluatePeriodIndexExpression(expression);
default:
throw;
}
}
const shared_ptr<EvalValue> Evaluator::EvaluateNilExpression(const BoundExpression *expression) {
switch (expression->GetKind()) {
case BoundExpressionKind::FunctionCall:
return this->EvaluateFunctionCallExpression(expression);
default:
return nullptr;
}
}
const shared_ptr<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:
return this->EvaluateNumericTableExpression(expression);
case BoundExpressionKind::Table:
return this->EvaluateComplexTableExpression(expression);
case BoundExpressionKind::PeriodIndex:
return this->EvaluatePeriodIndexExpression(expression);
default:
throw;
}
}
const shared_ptr<EvalValue> Evaluator::EvaluateFunctionCallExpression(const BoundExpression *expression) {
auto functionCall = (BoundFunctionCallExpression *) expression;
auto function = dynamic_pointer_cast<ScriptFunctionEvalValue>(
this->EvaluateExpression(functionCall->GetFunctionExpression()));
auto boundParameters = functionCall->GetParameters();
auto parameters = vector<shared_ptr<EvalValue>>(boundParameters->size());
for (int i = 0; i < boundParameters->size(); i++) {
parameters[i] = this->EvaluateExpression(boundParameters->at(i));
}
auto type = std::dynamic_pointer_cast<FunctionScriptType>(function->GetType());
auto parameterTypes = type->GetParameterTypes();
auto parameterKeys = type->GetParameterKeys();
auto originalScope = this->_evaluationScope;
this->_evaluationScope = function->GetScope();
for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++) {
auto parameter = parameters[i];
auto key = parameterKeys.at(i);
this->_evaluationScope->CreateVariable(key.get(), parameter->Clone());
}
this->EvaluateBlockStatement(function->GetInnerBlock().get());
this->_evaluationScope = originalScope;
this->_hasReturned = false;
auto r = this->_returnValue;
this->_returnValue = nullptr;
return r;
}
const shared_ptr<EvalValue> Evaluator::EvaluateFunction(const ScriptFunctionEvalValue *function,
const vector<EvalValue *> &parameters) {
auto type = std::dynamic_pointer_cast<FunctionScriptType>(function->GetType());
auto parameterTypes = type->GetParameterTypes();
auto parameterKeys = type->GetParameterKeys();
auto originalScope = this->_evaluationScope;
this->_evaluationScope = function->GetScope();
for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++) {
auto parameter = parameters[i];
auto key = parameterKeys.at(i);
this->_evaluationScope->CreateVariable(key.get(), parameter->Clone());
}
this->EvaluateBlockStatement(function->GetInnerBlock().get());
this->_evaluationScope = originalScope;
this->_hasReturned = false;
auto r = this->_returnValue;
this->_returnValue = nullptr;
return r;
}
const shared_ptr<EvalValue> Evaluator::EvaluateIndexExpression(const BoundExpression *expression) {
auto indexExpression = (BoundIndexExpression *) expression;
auto index = this->EvaluateExpression(indexExpression->GetIndexExpression());
auto indexable = this->EvaluateExpression(indexExpression->GetIndexableExpression());
return indexable->IndexValue(index.get())->Clone();
}
const shared_ptr<EvalValue> Evaluator::EvaluatePeriodIndexExpression(const BoundExpression *expression) {
auto indexExpression = (BoundPeriodIndexExpression *) expression;
auto index = indexExpression->GetIndex().GetHash();
auto indexable = this->EvaluateExpression(indexExpression->GetIndexableExpression());
return indexable->IndexValue(index)->Clone();
}
const shared_ptr<EvalValue> Evaluator::EvaluateNumericTableExpression(const BoundExpression *expression) {
auto tableExpression = (BoundNumericalTableExpression *) expression;
auto valueExpressions = tableExpression->GetExpressions();
auto values = new unordered_map<uint32_t, shared_ptr<EvalValue>>(valueExpressions->size());
for (int i = 0; i < valueExpressions->size(); i++) {
auto val = this->EvaluateExpression(valueExpressions->at(i));
values->insert({i + 1, val});
}
auto valuesPointer = shared_ptr<unordered_map<uint32_t, shared_ptr<EvalValue>>>(values);
return make_shared<TableEvalValue>(valuesPointer);
}
const shared_ptr<EvalValue> Evaluator::EvaluateComplexTableExpression(const BoundExpression *expression) {
auto tableExpression = (BoundTableExpression *) expression;
auto type = dynamic_pointer_cast<TableScriptType>(tableExpression->GetType());
auto declaredVars = type->GetValues();
auto variables = make_shared<unordered_map<uint32_t, shared_ptr<EvalValue>>>(declaredVars->size());
for (auto i : *declaredVars) {
variables->insert({i.first, nullptr});
}
auto evaluator = make_shared<EvaluationScope>(variables.get(), type->GetLocalVariableCount());
auto currentEvaluator = this->_evaluationScope;
this->_evaluationScope = evaluator;
this->EvaluateBlockStatement(tableExpression->GetBlock());
this->_evaluationScope = currentEvaluator;
return make_shared<TableEvalValue>(variables);
}
const shared_ptr<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

@ -4,7 +4,6 @@
#include <string> #include <string>
#include "../Binder/BoundStatements/BoundStatement.hpp" #include "../Binder/BoundStatements/BoundStatement.hpp"
#include "../Script.hpp"
#include "EvalValues/EvalValue.hpp" #include "EvalValues/EvalValue.hpp"
#include "EvalValues/NumericEvalValue.hpp" #include "EvalValues/NumericEvalValue.hpp"
#include "EvalValues/StringEvalValue.hpp" #include "EvalValues/StringEvalValue.hpp"
@ -14,62 +13,65 @@
using namespace std; using namespace std;
class Evaluator { namespace Porygon::Evaluation{
shared_ptr<EvalValue> _returnValue; class Evaluator {
bool _hasReturned; shared_ptr<EvalValue> _returnValue;
shared_ptr<EvalValue> _lastValue; unordered_map<uint32_t, shared_ptr<EvalValue>>* _scriptVariables;
bool _hasReturned;
shared_ptr<EvalValue> _lastValue;
Script* _scriptData; //Porygon::Script* _scriptData;
shared_ptr<EvaluationScope> _evaluationScope; shared_ptr<EvaluationScope> _evaluationScope;
void EvaluateStatement(const BoundStatement* statement); void EvaluateStatement(const BoundStatement* statement);
void EvaluateBlockStatement(const BoundBlockStatement *statement); void EvaluateBlockStatement(const BoundBlockStatement *statement);
void EvaluateExpressionStatement(const BoundExpressionStatement* statement); void EvaluateExpressionStatement(const BoundExpressionStatement* statement);
void EvaluateAssignmentStatement(const BoundAssignmentStatement* statement); void EvaluateAssignmentStatement(const BoundAssignmentStatement* statement);
void EvaluateIndexAssignmentStatement(const BoundIndexAssignmentStatement* statement); void EvaluateIndexAssignmentStatement(const BoundIndexAssignmentStatement* statement);
void EvaluateFunctionDeclarationStatement(const BoundFunctionDeclarationStatement *statement); void EvaluateFunctionDeclarationStatement(const BoundFunctionDeclarationStatement *statement);
void EvaluateReturnStatement(const BoundReturnStatement *statement); void EvaluateReturnStatement(const BoundReturnStatement *statement);
void EvaluateConditionalStatement(const BoundConditionalStatement *statement); void EvaluateConditionalStatement(const BoundConditionalStatement *statement);
const shared_ptr<EvalValue> EvaluateExpression(const BoundExpression *expression); const shared_ptr<EvalValue> EvaluateExpression(const BoundExpression *expression);
const shared_ptr<NumericEvalValue> EvaluateIntegerExpression(const BoundExpression *expression); const shared_ptr<NumericEvalValue> EvaluateIntegerExpression(const BoundExpression *expression);
const shared_ptr<BooleanEvalValue> EvaluateBoolExpression(const BoundExpression *expression); const shared_ptr<BooleanEvalValue> EvaluateBoolExpression(const BoundExpression *expression);
const shared_ptr<StringEvalValue> EvaluateStringExpression(const BoundExpression *expression); const shared_ptr<StringEvalValue> EvaluateStringExpression(const BoundExpression *expression);
const shared_ptr<EvalValue> EvaluateFunctionExpression(const BoundExpression *expression); const shared_ptr<EvalValue> EvaluateFunctionExpression(const BoundExpression *expression);
const shared_ptr<EvalValue> EvaluateNilExpression(const BoundExpression *expression); const shared_ptr<EvalValue> EvaluateNilExpression(const BoundExpression *expression);
const shared_ptr<EvalValue> EvaluateTableExpression(const BoundExpression *expression); const shared_ptr<EvalValue> EvaluateTableExpression(const BoundExpression *expression);
const shared_ptr<NumericEvalValue> EvaluateIntegerBinary(const BoundBinaryExpression *expression); const shared_ptr<NumericEvalValue> EvaluateIntegerBinary(const BoundBinaryExpression *expression);
const shared_ptr<BooleanEvalValue> EvaluateBooleanBinary(const BoundBinaryExpression *expression); const shared_ptr<BooleanEvalValue> EvaluateBooleanBinary(const BoundBinaryExpression *expression);
const shared_ptr<StringEvalValue> EvaluateStringBinary(const BoundBinaryExpression *expression); const shared_ptr<StringEvalValue> EvaluateStringBinary(const BoundBinaryExpression *expression);
const shared_ptr<NumericEvalValue> EvaluateIntegerUnary(const BoundUnaryExpression *expression); const shared_ptr<NumericEvalValue> EvaluateIntegerUnary(const BoundUnaryExpression *expression);
const shared_ptr<BooleanEvalValue> EvaluateBooleanUnary(const BoundUnaryExpression *expression); const shared_ptr<BooleanEvalValue> EvaluateBooleanUnary(const BoundUnaryExpression *expression);
const shared_ptr<EvalValue> EvaluateFunctionCallExpression(const BoundExpression *expression); const shared_ptr<EvalValue> EvaluateFunctionCallExpression(const BoundExpression *expression);
const shared_ptr<EvalValue> EvaluateIndexExpression(const BoundExpression *expression); const shared_ptr<EvalValue> EvaluateIndexExpression(const BoundExpression *expression);
const shared_ptr<EvalValue> EvaluatePeriodIndexExpression(const BoundExpression *expression); const shared_ptr<EvalValue> EvaluatePeriodIndexExpression(const BoundExpression *expression);
const shared_ptr<EvalValue> EvaluateNumericTableExpression(const BoundExpression *expression); const shared_ptr<EvalValue> EvaluateNumericTableExpression(const BoundExpression *expression);
const shared_ptr<EvalValue> EvaluateComplexTableExpression(const BoundExpression *expression); const shared_ptr<EvalValue> EvaluateComplexTableExpression(const BoundExpression *expression);
const shared_ptr<EvalValue> EvaluateUserDataExpression(const BoundExpression *expression); const shared_ptr<EvalValue> EvaluateUserDataExpression(const BoundExpression *expression);
const shared_ptr<EvalValue> GetVariable(const BoundVariableExpression *expression); const shared_ptr<EvalValue> GetVariable(const BoundVariableExpression *expression);
public: public:
explicit Evaluator(Script* script){ explicit Evaluator(unordered_map<uint32_t, shared_ptr<EvalValue>>* scriptVariables){
_scriptData = script; _scriptVariables = scriptVariables;
_hasReturned = false; _hasReturned = false;
_returnValue = nullptr; _returnValue = nullptr;
_evaluationScope = nullptr; _evaluationScope = nullptr;
} }
EvalValue* Evaluate(const BoundScriptStatement* statement); EvalValue* Evaluate(const BoundScriptStatement* statement);
const shared_ptr<EvalValue> EvaluateFunction(const ScriptFunctionEvalValue *function, const shared_ptr<EvalValue> EvaluateFunction(const ScriptFunctionEvalValue *function,
const vector<EvalValue *> &parameters); const vector<EvalValue *> &parameters);
EvalValue* GetLastValue(){ EvalValue* GetLastValue(){
return _lastValue.get(); return _lastValue.get();
} }
}; };
}

View File

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

View File

@ -1,23 +1,26 @@
#ifndef PORYGONLANG_BINARYOPERATORKIND_HPP #ifndef PORYGONLANG_BINARYOPERATORKIND_HPP
#define PORYGONLANG_BINARYOPERATORKIND_HPP #define PORYGONLANG_BINARYOPERATORKIND_HPP
enum class BinaryOperatorKind{
// Math
Addition,
Subtraction,
Multiplication,
Division,
// Equality namespace Porygon::Parser {
Equality, enum class BinaryOperatorKind {
Inequality, // Math
Less, Addition,
LessOrEquals, Subtraction,
Greater, Multiplication,
GreaterOrEquals, Division,
// Logical // Equality
LogicalAnd, Equality,
LogicalOr, Inequality,
}; Less,
LessOrEquals,
Greater,
GreaterOrEquals,
// Logical
LogicalAnd,
LogicalOr,
};
}
#endif //PORYGONLANG_BINARYOPERATORKIND_HPP #endif //PORYGONLANG_BINARYOPERATORKIND_HPP

View File

@ -5,270 +5,313 @@
#include "Lexer.hpp" #include "Lexer.hpp"
Lexer::Lexer(const u16string& scriptString, class Script* script) namespace Porygon::Parser {
: _scriptString(scriptString) Lexer::Lexer(const u16string &scriptString, Porygon::Script *script)
{ : _scriptString(scriptString) {
this->_scriptSize = scriptString.size(); this->_scriptSize = scriptString.size();
this -> ScriptData = script; this->ScriptData = script;
this -> _position = 0; this->_position = 0;
}
vector<const IToken*> Lexer::Lex() {
vector<const IToken*> tokens;
while (true){
IToken* next = this -> LexNext(this -> Next());
auto nextKind = next -> GetKind();
if (nextKind != TokenKind::WhiteSpace)
tokens.push_back(next);
else
delete next;
if (nextKind == TokenKind::EndOfFile)
break;
} }
return tokens;
}
char16_t Lexer::Peek(){
if (Lexer::_position >= this -> _scriptSize)
return '\0';
return this -> _scriptString.at(Lexer::_position);
}
char16_t Lexer::Next(){ vector<const IToken *> Lexer::Lex() {
char16_t next = Peek(); vector<const IToken *> tokens;
Lexer::_position++; while (true) {
return next; IToken *next = this->LexNext(this->Next());
} auto nextKind = next->GetKind();
if (nextKind != TokenKind::WhiteSpace)
tokens.push_back(next);
else
delete next;
if (nextKind == TokenKind::EndOfFile)
break;
}
return tokens;
}
IToken* Lexer::LexNext(char16_t c){ char16_t Lexer::Peek() {
switch (c) { if (Lexer::_position >= this->_scriptSize)
case '\0': return '\0';
return new SimpleToken(TokenKind::EndOfFile, this -> _position - 1, 1); return this->_scriptString.at(Lexer::_position);
case ' ': case '\t': case '\n': case '\r': case '\v': case '\f': }
return new SimpleToken(TokenKind::WhiteSpace, this -> _position - 1, 1);
case '+': char16_t Lexer::Next() {
return new SimpleToken(TokenKind::PlusToken, this -> _position - 1, 1); char16_t next = Peek();
case '-': Lexer::_position++;
return new SimpleToken(TokenKind::MinusToken, this -> _position - 1, 1); return next;
case '/': }
return new SimpleToken(TokenKind::SlashToken, this -> _position - 1, 1);
case '*': IToken *Lexer::LexNext(char16_t c) {
return new SimpleToken(TokenKind::StarToken, this -> _position - 1, 1); switch (c) {
case '(': case '\0':
return new SimpleToken(TokenKind::OpenParenthesis, this -> _position - 1, 1); return new SimpleToken(TokenKind::EndOfFile, this->_position - 1, 1);
case ')': case ' ':
return new SimpleToken(TokenKind::CloseParenthesis, this -> _position - 1, 1); case '\t':
case '[': case '\n':
return new SimpleToken(TokenKind::OpenSquareBracket, this -> _position - 1, 1); case '\r':
case ']': case '\v':
return new SimpleToken(TokenKind::CloseSquareBracket, this -> _position - 1, 1); case '\f':
case '{': return new SimpleToken(TokenKind::WhiteSpace, this->_position - 1, 1);
return new SimpleToken(TokenKind::OpenCurlyBracket, this -> _position - 1, 1); case '+':
case '}': return new SimpleToken(TokenKind::PlusToken, this->_position - 1, 1);
return new SimpleToken(TokenKind::CloseCurlyBracket, this -> _position - 1, 1); case '-':
case ',': return new SimpleToken(TokenKind::MinusToken, this->_position - 1, 1);
return new SimpleToken(TokenKind::CommaToken, this -> _position - 1, 1); case '/':
case '.': return new SimpleToken(TokenKind::SlashToken, this->_position - 1, 1);
return new SimpleToken(TokenKind::PeriodToken, this -> _position - 1, 1); case '*':
case '=': return new SimpleToken(TokenKind::StarToken, this->_position - 1, 1);
if (Lexer::Peek() == '='){ case '(':
Lexer::Next(); return new SimpleToken(TokenKind::OpenParenthesis, this->_position - 1, 1);
return new SimpleToken(TokenKind::EqualityToken, this -> _position - 2, 2); case ')':
} return new SimpleToken(TokenKind::CloseParenthesis, this->_position - 1, 1);
return new SimpleToken(TokenKind::AssignmentToken, this -> _position - 1, 1); case '[':
case '<': return new SimpleToken(TokenKind::OpenSquareBracket, this->_position - 1, 1);
if (Lexer::Peek() == '='){ case ']':
Lexer::Next(); return new SimpleToken(TokenKind::CloseSquareBracket, this->_position - 1, 1);
return new SimpleToken(TokenKind::LessEquals, this -> _position - 2, 2); case '{':
} return new SimpleToken(TokenKind::OpenCurlyBracket, this->_position - 1, 1);
return new SimpleToken(TokenKind::Less, this -> _position - 1, 1); case '}':
case '>': return new SimpleToken(TokenKind::CloseCurlyBracket, this->_position - 1, 1);
if (Lexer::Peek() == '='){ case ',':
Lexer::Next(); return new SimpleToken(TokenKind::CommaToken, this->_position - 1, 1);
return new SimpleToken(TokenKind::GreaterEquals, this -> _position - 2, 2); case '.':
} return new SimpleToken(TokenKind::PeriodToken, this->_position - 1, 1);
return new SimpleToken(TokenKind::Greater, this -> _position - 1, 1); case '=':
case '~': if (Lexer::Peek() == '=') {
if (Lexer::Peek() == '='){ Lexer::Next();
Lexer::Next(); return new SimpleToken(TokenKind::EqualityToken, this->_position - 2, 2);
return new SimpleToken(TokenKind::InequalityToken, this -> _position - 2, 2); }
} return new SimpleToken(TokenKind::AssignmentToken, this->_position - 1, 1);
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedCharacter, this -> _position - 1, 1); case '<':
return new SimpleToken(TokenKind::BadToken, this -> _position - 1, 1); if (Lexer::Peek() == '=') {
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': Lexer::Next();
return LexNumber(c); return new SimpleToken(TokenKind::LessEquals, this->_position - 2, 2);
case '"': }
return LexString(c); return new SimpleToken(TokenKind::Less, this->_position - 1, 1);
case '\'': case '>':
return LexString(c); if (Lexer::Peek() == '=') {
case '_': Lexer::Next();
return LexIdentifierOrKeyword(); return new SimpleToken(TokenKind::GreaterEquals, this->_position - 2, 2);
default: }
if (isalpha(c) || c > 255){ return new SimpleToken(TokenKind::Greater, this->_position - 1, 1);
case '~':
if (Lexer::Peek() == '=') {
Lexer::Next();
return new SimpleToken(TokenKind::InequalityToken, this->_position - 2, 2);
}
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedCharacter, this->_position - 1, 1);
return new SimpleToken(TokenKind::BadToken, this->_position - 1, 1);
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return LexNumber(c);
case '"':
return LexString(c);
case '\'':
return LexString(c);
case '_':
return LexIdentifierOrKeyword(); return LexIdentifierOrKeyword();
} default:
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedCharacter, this -> _position - 1, 1); if (isalpha(c) || c > 255) {
return new SimpleToken(TokenKind::BadToken, this -> _position - 1, 1); return LexIdentifierOrKeyword();
} }
} this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedCharacter, this->_position - 1, 1);
return new SimpleToken(TokenKind::BadToken, this->_position - 1, 1);
int CharToInt(char16_t c){
switch (c){
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
default: return -1;
}
}
IToken* Lexer::LexNumber(char16_t c){
long int_value = CharToInt(c);
double float_value = 0;
short decimal_index = 0;
bool has_point = false;
bool is_searching = true;
unsigned int start = this -> _position - 1;
unsigned int length = 1;
while (is_searching){
char16_t next = this -> Peek();
int next_val = CharToInt(next);
if (next_val == -1){
switch (next){
case '_':
this -> Next();
length++;
continue;
case '.':
this -> Next();
has_point = true;
decimal_index = 0;
float_value = int_value;
length++;
continue;
default:
is_searching = false;
continue;
}
}
else{
this -> Next();
length++;
if (has_point){
decimal_index++;
float_value += next_val / pow(10, decimal_index);
}
else {
int_value *= 10;
int_value += next_val;
}
} }
} }
if (has_point){
return new FloatToken(float_value, start, length);
}
else{
return new IntegerToken(int_value, start, length);
}
}
IToken * Lexer::LexIdentifierOrKeyword() { int CharToInt(char16_t c) {
auto start = this -> _position - 1; switch (c) {
auto end = start; case '0':
while (true){ return 0;
char16_t next = this -> Peek(); case '1':
if (next == '\0') break; return 1;
if (isalpha(next) || next == '_' || next > 255){ case '2':
this -> Next(); return 2;
case '3':
return 3;
case '4':
return 4;
case '5':
return 5;
case '6':
return 6;
case '7':
return 7;
case '8':
return 8;
case '9':
return 9;
default:
return -1;
}
}
IToken *Lexer::LexNumber(char16_t c) {
long int_value = CharToInt(c);
double float_value = 0;
short decimal_index = 0;
bool has_point = false;
bool is_searching = true;
unsigned int start = this->_position - 1;
unsigned int length = 1;
while (is_searching) {
char16_t next = this->Peek();
int next_val = CharToInt(next);
if (next_val == -1) {
switch (next) {
case '_':
this->Next();
length++;
continue;
case '.':
this->Next();
has_point = true;
decimal_index = 0;
float_value = int_value;
length++;
continue;
default:
is_searching = false;
continue;
}
} else {
this->Next();
length++;
if (has_point) {
decimal_index++;
float_value += next_val / pow(10, decimal_index);
} else {
int_value *= 10;
int_value += next_val;
}
}
}
if (has_point) {
return new FloatToken(float_value, start, length);
} else {
return new IntegerToken(int_value, start, length);
}
}
IToken *Lexer::LexIdentifierOrKeyword() {
auto start = this->_position - 1;
auto end = start;
while (true) {
char16_t next = this->Peek();
if (next == '\0') break;
if (isalpha(next) || next == '_' || next > 255) {
this->Next();
end++;
} else {
break;
}
}
u16string s = this->_scriptString.substr(start, end - start + 1);
switch (HashedString::ConstHash(s.c_str())) {
case HashedString::ConstHash("and"):
return new SimpleToken(TokenKind::AndKeyword, start, 3);
case HashedString::ConstHash("break"):
return new SimpleToken(TokenKind::BreakKeyword, start, 5);
case HashedString::ConstHash("do"):
return new SimpleToken(TokenKind::DoKeyword, start, 2);
case HashedString::ConstHash("else"):
return new SimpleToken(TokenKind::ElseKeyword, start, 4);
case HashedString::ConstHash("elseif"):
return new SimpleToken(TokenKind::ElseIfKeyword, start, 6);
case HashedString::ConstHash("end"):
return new SimpleToken(TokenKind::EndKeyword, start, 3);
case HashedString::ConstHash("false"):
return new SimpleToken(TokenKind::FalseKeyword, start, 5);
case HashedString::ConstHash("for"):
return new SimpleToken(TokenKind::ForKeyword, start, 3);
case HashedString::ConstHash("function"):
return new SimpleToken(TokenKind::FunctionKeyword, start, 8);
case HashedString::ConstHash("if"):
return new SimpleToken(TokenKind::IfKeyword, start, 2);
case HashedString::ConstHash("in"):
return new SimpleToken(TokenKind::InKeyword, start, 2);
case HashedString::ConstHash("local"):
return new SimpleToken(TokenKind::LocalKeyword, start, 5);
case HashedString::ConstHash("nil"):
return new SimpleToken(TokenKind::NilKeyword, start, 3);
case HashedString::ConstHash("not"):
return new SimpleToken(TokenKind::NotKeyword, start, 3);
case HashedString::ConstHash("or"):
return new SimpleToken(TokenKind::OrKeyword, start, 2);
case HashedString::ConstHash("return"):
return new SimpleToken(TokenKind::ReturnKeyword, start, 6);
case HashedString::ConstHash("then"):
return new SimpleToken(TokenKind::ThenKeyword, start, 4);
case HashedString::ConstHash("true"):
return new SimpleToken(TokenKind::TrueKeyword, start, 4);
case HashedString::ConstHash("while"):
return new SimpleToken(TokenKind::WhileKeyword, start, 5);
default:
return new IdentifierToken(HashedString(s), start, s.length());
}
}
const unordered_map<char16_t, char16_t> ControlCharacters{ // NOLINT(cert-err58-cpp)
{'0', '\0'},
{'a', '\a'},
{'b', '\b'},
{'t', '\t'},
{'n', '\n'},
{'v', '\v'},
{'f', '\f'},
{'r', '\r'},
{'"', '\"'},
{'\'', '\''},
{'\?', '\?'},
{'\\', '\\'},
};
IToken *Lexer::LexString(char16_t c) {
auto start = this->_position - 1;
auto end = start;
char16_t last = c;
while (true) {
char16_t next = this->Peek();
if (next == '\0') break;
if (next == c && last != '\\') break;
this->Next();
end++; end++;
last = next;
} }
else{ auto closeToken = this->Next();
break; if (closeToken != c) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedCharacter, this->_position - 1, 1);
return new SimpleToken(TokenKind::BadToken, start, end - start + 1);
} }
}
u16string s = this -> _scriptString.substr(start, end - start + 1); u16string s = this->_scriptString.substr(start + 1, end - start);
switch (HashedString::ConstHash(s.c_str())){ std::basic_ostringstream<char16_t> stream;
case HashedString::ConstHash("and"): return new SimpleToken(TokenKind::AndKeyword, start, 3); for (int i = 0; i < s.size(); i++) {
case HashedString::ConstHash("break"): return new SimpleToken(TokenKind::BreakKeyword, start, 5);
case HashedString::ConstHash("do"): return new SimpleToken(TokenKind::DoKeyword, start, 2);
case HashedString::ConstHash("else"): return new SimpleToken(TokenKind::ElseKeyword, start, 4);
case HashedString::ConstHash("elseif"): return new SimpleToken(TokenKind::ElseIfKeyword, start, 6);
case HashedString::ConstHash("end"): return new SimpleToken(TokenKind::EndKeyword, start, 3);
case HashedString::ConstHash("false"): return new SimpleToken(TokenKind::FalseKeyword, start, 5);
case HashedString::ConstHash("for"): return new SimpleToken(TokenKind::ForKeyword, start, 3);
case HashedString::ConstHash("function"): return new SimpleToken(TokenKind::FunctionKeyword, start, 8);
case HashedString::ConstHash("if"): return new SimpleToken(TokenKind::IfKeyword, start, 2);
case HashedString::ConstHash("in"): return new SimpleToken(TokenKind::InKeyword, start, 2);
case HashedString::ConstHash("local"): return new SimpleToken(TokenKind::LocalKeyword, start, 5);
case HashedString::ConstHash("nil"): return new SimpleToken(TokenKind::NilKeyword, start, 3);
case HashedString::ConstHash("not"): return new SimpleToken(TokenKind::NotKeyword, start, 3);
case HashedString::ConstHash("or"): return new SimpleToken(TokenKind::OrKeyword, start, 2);
case HashedString::ConstHash("return"): return new SimpleToken(TokenKind::ReturnKeyword, start, 6);
case HashedString::ConstHash("then"): return new SimpleToken(TokenKind::ThenKeyword, start, 4);
case HashedString::ConstHash("true"): return new SimpleToken(TokenKind::TrueKeyword, start, 4);
case HashedString::ConstHash("while"): return new SimpleToken(TokenKind::WhileKeyword, start, 5);
default: return new IdentifierToken(HashedString(s), start, s.length());
}
}
const unordered_map<char16_t, char16_t> ControlCharacters{ // NOLINT(cert-err58-cpp)
{'0', '\0'},
{'a', '\a'},
{'b', '\b'},
{'t', '\t'},
{'n', '\n'},
{'v', '\v'},
{'f', '\f'},
{'r', '\r'},
{'"', '\"'},
{'\'', '\''},
{'\?', '\?'},
{'\\', '\\'},
};
IToken* Lexer::LexString(char16_t c){
auto start = this -> _position - 1;
auto end = start;
char16_t last = c;
while (true){
char16_t next = this -> Peek();
if (next == '\0') break;
if (next == c && last != '\\') break;
this -> Next();
end++;
last = next;
}
auto closeToken = this -> Next();
if (closeToken != c){
this -> ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedCharacter, this->_position - 1, 1);
return new SimpleToken(TokenKind::BadToken, start, end -start + 1);
}
u16string s = this -> _scriptString.substr(start + 1, end - start);
std::basic_ostringstream<char16_t > stream;
for (int i = 0; i < s.size(); i++){
c = s[i];
if (c == '\\'){
i++;
c = s[i]; c = s[i];
if (ControlCharacters.find(c) != ControlCharacters.end()) { if (c == '\\') {
stream << ControlCharacters.at(c); i++;
} else{ c = s[i];
this -> ScriptData->Diagnostics->LogError(DiagnosticCode::InvalidStringControlCharacter, start + 1 + i, 1); if (ControlCharacters.find(c) != ControlCharacters.end()) {
stream << ControlCharacters.at(c);
} else {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::InvalidStringControlCharacter,
start + 1 + i, 1);
stream << c;
}
} else {
stream << c; stream << c;
} }
} else{
stream << c;
} }
return new StringToken(stream.str(), start, end - start);
} }
return new StringToken(stream.str(), start, end - start );
}
}

View File

@ -7,26 +7,28 @@
using namespace std; using namespace std;
class Lexer { namespace Porygon::Parser{
const u16string& _scriptString; class Lexer {
const u16string& _scriptString;
#ifdef TESTS_BUILD #ifdef TESTS_BUILD
public: public:
#endif #endif
unsigned int _position; unsigned int _position;
unsigned int _scriptSize; unsigned int _scriptSize;
char16_t Peek(); char16_t Peek();
char16_t Next(); char16_t Next();
IToken* LexNext(char16_t c); IToken* LexNext(char16_t c);
IToken* LexNumber(char16_t c); IToken* LexNumber(char16_t c);
IToken* LexIdentifierOrKeyword(); IToken* LexIdentifierOrKeyword();
IToken* LexString(char16_t c); IToken* LexString(char16_t c);
public: public:
Script* ScriptData; Porygon::Script* ScriptData;
vector<const IToken*> Lex(); vector<const IToken*> Lex();
explicit Lexer(const u16string& scriptString, class Script* script); explicit Lexer(const u16string& scriptString, Porygon::Script* script);
}; };
}
#endif //PORYGONLANG_LEXER_HPP #endif //PORYGONLANG_LEXER_HPP

View File

@ -11,333 +11,332 @@
#include "../BinaryOperatorKind.hpp" #include "../BinaryOperatorKind.hpp"
#include "../../Utilities/HashedString.hpp" #include "../../Utilities/HashedString.hpp"
enum class ParsedExpressionKind{ namespace Porygon::Parser {
Bad, enum class ParsedExpressionKind {
Bad,
LiteralInteger, LiteralInteger,
LiteralFloat, LiteralFloat,
LiteralString, LiteralString,
LiteralBool, LiteralBool,
Variable, Variable,
Unary, Unary,
Binary, Binary,
Parenthesized, Parenthesized,
FunctionCall, FunctionCall,
Indexer, Indexer,
PeriodIndexer, PeriodIndexer,
NumericalTable, NumericalTable,
Table, Table,
}; };
class ParsedExpression { class ParsedExpression {
const unsigned int _position; const unsigned int _position;
const unsigned int _length; const unsigned int _length;
public: public:
ParsedExpression(unsigned int position, unsigned int length) ParsedExpression(unsigned int position, unsigned int length)
: _position(position), : _position(position),
_length(length) _length(length) {
{
}
virtual ~ParsedExpression() = default;
virtual const ParsedExpressionKind GetKind() const = 0;
const unsigned int GetStartPosition() const{
return _position;
}
const unsigned int GetEndPosition() const{
return _position + _length - 1;
}
const unsigned int GetLength() const{
return _length;
}
};
class BadExpression : public ParsedExpression{
public:
BadExpression(unsigned int position, unsigned int length) : ParsedExpression(position, length){}
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::Bad;
}
};
class LiteralIntegerExpression : public ParsedExpression{
const long _value;
public:
const ParsedExpressionKind GetKind() const final{
return ParsedExpressionKind::LiteralInteger;
}
explicit LiteralIntegerExpression(IntegerToken* token)
: ParsedExpression(token -> GetStartPosition(), token -> GetLength()),
_value(token -> GetValue())
{
}
const long GetValue() const{
return _value;
}
};
class LiteralFloatExpression : public ParsedExpression{
const double _value;
public:
const ParsedExpressionKind GetKind() const final{
return ParsedExpressionKind::LiteralFloat;
}
explicit LiteralFloatExpression(FloatToken* token)
: ParsedExpression(token -> GetStartPosition(), token -> GetLength()),
_value(token -> GetValue())
{
}
const double GetValue() const{
return _value;
}
};
class LiteralStringExpression : public ParsedExpression{
const u16string _value;
public:
const ParsedExpressionKind GetKind() const final{
return ParsedExpressionKind::LiteralString;
}
explicit LiteralStringExpression(StringToken* token)
: ParsedExpression(token -> GetStartPosition(), token -> GetLength()),
_value(std::move(token -> GetValue()))
{
}
const u16string& GetValue() const{
return _value;
}
};
class LiteralBoolExpression : public ParsedExpression{
const bool _value;
public:
const ParsedExpressionKind GetKind() const final{
return ParsedExpressionKind::LiteralBool;
}
explicit LiteralBoolExpression(const IToken* token)
: ParsedExpression(token -> GetStartPosition(), token -> GetLength()),
_value(token -> GetKind() == TokenKind::TrueKeyword)
{
}
const bool GetValue() const{
return _value;
}
};
class VariableExpression : public ParsedExpression{
const HashedString _value;
public:
const ParsedExpressionKind GetKind() const final{
return ParsedExpressionKind::Variable;
}
explicit VariableExpression(IdentifierToken* token) : ParsedExpression(token -> GetStartPosition(), token -> GetLength())
, _value(HashedString(token -> GetValue()))
{
}
const HashedString GetValue() const{
return _value;
}
};
class ParenthesizedExpression : public ParsedExpression{
const ParsedExpression* _expression;
public:
~ParenthesizedExpression() override {
delete _expression;
}
const ParsedExpressionKind GetKind() const final{
return ParsedExpressionKind::Parenthesized;
}
explicit ParenthesizedExpression(ParsedExpression* innerExpression, unsigned int start, unsigned int length)
: ParsedExpression(start, length), _expression(innerExpression){
}
const ParsedExpression* GetInnerExpression() const{
return _expression;
}
};
class UnaryExpression : public ParsedExpression{
const UnaryOperatorKind _kind;
const ParsedExpression* _operand;
public:
~UnaryExpression() override {
delete _operand;
}
const ParsedExpressionKind GetKind() const final{
return ParsedExpressionKind::Unary;
}
UnaryExpression(UnaryOperatorKind kind, ParsedExpression* operand, unsigned int start, unsigned int length)
: ParsedExpression(start, length),
_kind(kind), _operand(operand)
{
}
const UnaryOperatorKind GetOperatorKind() const{
return _kind;
}
const ParsedExpression* GetOperand() const{
return _operand;
}
};
class BinaryExpression : public ParsedExpression{
const BinaryOperatorKind _kind;
const ParsedExpression* _left;
const ParsedExpression* _right;
public:
~BinaryExpression() override {
delete _left;
delete _right;
}
const ParsedExpressionKind GetKind() const final{
return ParsedExpressionKind::Binary;
}
BinaryExpression(BinaryOperatorKind kind, ParsedExpression* left, ParsedExpression* right, unsigned int start,
unsigned int length)
: ParsedExpression(start, length),
_kind(kind), _left(left), _right(right)
{
}
const BinaryOperatorKind GetOperatorKind() const{
return _kind;
}
const ParsedExpression* GetLeft() const{
return _left;
}
const ParsedExpression* GetRight() const{
return _right;
}
};
class FunctionCallExpression : public ParsedExpression{
const std::unique_ptr<ParsedExpression> _function;
const vector<const ParsedExpression*> _parameters;
public:
FunctionCallExpression(ParsedExpression* function, vector<const ParsedExpression*> parameters, unsigned int start, unsigned int length)
: ParsedExpression(start, length),
_function(function), _parameters(std::move(parameters))
{
}
~FunctionCallExpression() final{
for (auto p : _parameters){
delete p;
} }
}
const ParsedExpressionKind GetKind() const final{ virtual ~ParsedExpression() = default;
return ParsedExpressionKind::FunctionCall;
}
const ParsedExpression* GetFunction() const{ virtual const ParsedExpressionKind GetKind() const = 0;
return _function.get();
}
const vector<const ParsedExpression*>* GetParameters() const{
return &_parameters;
}
};
class IndexExpression : public ParsedExpression{ const unsigned int GetStartPosition() const {
const ParsedExpression* _indexerExpression; return _position;
const ParsedExpression* _indexExpression;
public:
IndexExpression(ParsedExpression* indexer, ParsedExpression* index, unsigned int start, unsigned int length)
:ParsedExpression(start, length),
_indexerExpression(indexer), _indexExpression(index)
{
}
~IndexExpression() final{
delete _indexerExpression;
delete _indexExpression;
}
const ParsedExpressionKind GetKind() const final{
return ParsedExpressionKind::Indexer;
}
const ParsedExpression* GetIndexer() const{
return _indexerExpression;
}
const ParsedExpression* GetIndex() const{
return _indexExpression;
}
};
class PeriodIndexExpression : public ParsedExpression{
const ParsedExpression* _indexerExpression;
const HashedString _index;
public:
PeriodIndexExpression(ParsedExpression* indexer, HashedString index, unsigned int start, unsigned int length)
:ParsedExpression(start, length),
_indexerExpression(indexer), _index(index)
{
}
~PeriodIndexExpression() final{
delete _indexerExpression;
}
const ParsedExpressionKind GetKind() const final{
return ParsedExpressionKind::PeriodIndexer;
}
const ParsedExpression* GetIndexer() const{
return _indexerExpression;
}
const HashedString& GetIndex() const{
return _index;
}
};
class ParsedNumericalTableExpression : public ParsedExpression{
vector<const ParsedExpression*> _expressions;
public:
ParsedNumericalTableExpression(vector<const ParsedExpression*> expressions, unsigned int start, unsigned int length)
: ParsedExpression(start, length){
_expressions = std::move(expressions);
}
~ParsedNumericalTableExpression() final{
for (auto s: _expressions){
delete s;
} }
}
const vector<const ParsedExpression*>* GetExpressions() const{ const unsigned int GetEndPosition() const {
return &_expressions; return _position + _length - 1;
} }
const ParsedExpressionKind GetKind() const final{ const unsigned int GetLength() const {
return ParsedExpressionKind::NumericalTable; return _length;
} }
}; };
class BadExpression : public ParsedExpression {
public:
BadExpression(unsigned int position, unsigned int length) : ParsedExpression(position, length) {}
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::Bad;
}
};
class LiteralIntegerExpression : public ParsedExpression {
const long _value;
public:
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::LiteralInteger;
}
explicit LiteralIntegerExpression(IntegerToken *token)
: ParsedExpression(token->GetStartPosition(), token->GetLength()),
_value(token->GetValue()) {
}
const long GetValue() const {
return _value;
}
};
class LiteralFloatExpression : public ParsedExpression {
const double _value;
public:
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::LiteralFloat;
}
explicit LiteralFloatExpression(FloatToken *token)
: ParsedExpression(token->GetStartPosition(), token->GetLength()),
_value(token->GetValue()) {
}
const double GetValue() const {
return _value;
}
};
class LiteralStringExpression : public ParsedExpression {
const u16string _value;
public:
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::LiteralString;
}
explicit LiteralStringExpression(StringToken *token)
: ParsedExpression(token->GetStartPosition(), token->GetLength()),
_value(std::move(token->GetValue())) {
}
const u16string &GetValue() const {
return _value;
}
};
class LiteralBoolExpression : public ParsedExpression {
const bool _value;
public:
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::LiteralBool;
}
explicit LiteralBoolExpression(const IToken *token)
: ParsedExpression(token->GetStartPosition(), token->GetLength()),
_value(token->GetKind() == TokenKind::TrueKeyword) {
}
const bool GetValue() const {
return _value;
}
};
class VariableExpression : public ParsedExpression {
const HashedString _value;
public:
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::Variable;
}
explicit VariableExpression(IdentifierToken *token) : ParsedExpression(token->GetStartPosition(),
token->GetLength()),
_value(HashedString(token->GetValue())) {
}
const HashedString GetValue() const {
return _value;
}
};
class ParenthesizedExpression : public ParsedExpression {
const ParsedExpression *_expression;
public:
~ParenthesizedExpression() override {
delete _expression;
}
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::Parenthesized;
}
explicit ParenthesizedExpression(ParsedExpression *innerExpression, unsigned int start, unsigned int length)
: ParsedExpression(start, length), _expression(innerExpression) {
}
const ParsedExpression *GetInnerExpression() const {
return _expression;
}
};
class UnaryExpression : public ParsedExpression {
const UnaryOperatorKind _kind;
const ParsedExpression *_operand;
public:
~UnaryExpression() override {
delete _operand;
}
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::Unary;
}
UnaryExpression(UnaryOperatorKind kind, ParsedExpression *operand, unsigned int start, unsigned int length)
: ParsedExpression(start, length),
_kind(kind), _operand(operand) {
}
const UnaryOperatorKind GetOperatorKind() const {
return _kind;
}
const ParsedExpression *GetOperand() const {
return _operand;
}
};
class BinaryExpression : public ParsedExpression {
const BinaryOperatorKind _kind;
const ParsedExpression *_left;
const ParsedExpression *_right;
public:
~BinaryExpression() override {
delete _left;
delete _right;
}
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::Binary;
}
BinaryExpression(BinaryOperatorKind kind, ParsedExpression *left, ParsedExpression *right, unsigned int start,
unsigned int length)
: ParsedExpression(start, length),
_kind(kind), _left(left), _right(right) {
}
const BinaryOperatorKind GetOperatorKind() const {
return _kind;
}
const ParsedExpression *GetLeft() const {
return _left;
}
const ParsedExpression *GetRight() const {
return _right;
}
};
class FunctionCallExpression : public ParsedExpression {
const std::unique_ptr<ParsedExpression> _function;
const vector<const ParsedExpression *> _parameters;
public:
FunctionCallExpression(ParsedExpression *function, vector<const ParsedExpression *> parameters,
unsigned int start, unsigned int length)
: ParsedExpression(start, length),
_function(function), _parameters(std::move(parameters)) {
}
~FunctionCallExpression() final {
for (auto p : _parameters) {
delete p;
}
}
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::FunctionCall;
}
const ParsedExpression *GetFunction() const {
return _function.get();
}
const vector<const ParsedExpression *> *GetParameters() const {
return &_parameters;
}
};
class IndexExpression : public ParsedExpression {
const ParsedExpression *_indexerExpression;
const ParsedExpression *_indexExpression;
public:
IndexExpression(ParsedExpression *indexer, ParsedExpression *index, unsigned int start, unsigned int length)
: ParsedExpression(start, length),
_indexerExpression(indexer), _indexExpression(index) {
}
~IndexExpression() final {
delete _indexerExpression;
delete _indexExpression;
}
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::Indexer;
}
const ParsedExpression *GetIndexer() const {
return _indexerExpression;
}
const ParsedExpression *GetIndex() const {
return _indexExpression;
}
};
class PeriodIndexExpression : public ParsedExpression {
const ParsedExpression *_indexerExpression;
const HashedString _index;
public:
PeriodIndexExpression(ParsedExpression *indexer, HashedString index, unsigned int start, unsigned int length)
: ParsedExpression(start, length),
_indexerExpression(indexer), _index(index) {
}
~PeriodIndexExpression() final {
delete _indexerExpression;
}
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::PeriodIndexer;
}
const ParsedExpression *GetIndexer() const {
return _indexerExpression;
}
const HashedString &GetIndex() const {
return _index;
}
};
class ParsedNumericalTableExpression : public ParsedExpression {
vector<const ParsedExpression *> _expressions;
public:
ParsedNumericalTableExpression(vector<const ParsedExpression *> expressions, unsigned int start,
unsigned int length)
: ParsedExpression(start, length) {
_expressions = std::move(expressions);
}
~ParsedNumericalTableExpression() final {
for (auto s: _expressions) {
delete s;
}
}
const vector<const ParsedExpression *> *GetExpressions() const {
return &_expressions;
}
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::NumericalTable;
}
};
}
#endif //PORYGONLANG_PARSEDEXPRESSION_HPP #endif //PORYGONLANG_PARSEDEXPRESSION_HPP

View File

@ -5,27 +5,27 @@
#include "ParsedExpression.hpp" #include "ParsedExpression.hpp"
#include "../ParsedStatements/ParsedStatement.hpp" #include "../ParsedStatements/ParsedStatement.hpp"
class ParsedTableExpression : public ParsedExpression{ namespace Porygon::Parser {
const ParsedBlockStatement* _block; class ParsedTableExpression : public ParsedExpression {
public: const ParsedBlockStatement *_block;
ParsedTableExpression(ParsedBlockStatement* block, unsigned int start, unsigned int length) public:
: ParsedExpression(start, length), _block(block) ParsedTableExpression(ParsedBlockStatement *block, unsigned int start, unsigned int length)
{ : ParsedExpression(start, length), _block(block) {
} }
~ParsedTableExpression() final{ ~ParsedTableExpression() final {
delete _block; delete _block;
} }
const ParsedBlockStatement* GetBlock() const{ const ParsedBlockStatement *GetBlock() const {
return _block; return _block;
} }
const ParsedExpressionKind GetKind() const final{
return ParsedExpressionKind::Table;
}
};
const ParsedExpressionKind GetKind() const final {
return ParsedExpressionKind::Table;
}
};
}
#include "ParsedExpression.hpp" #include "ParsedExpression.hpp"
#endif //PORYGONLANG_PARSEDTABLEEXPRESSION_HPP #endif //PORYGONLANG_PARSEDTABLEEXPRESSION_HPP

View File

@ -13,263 +13,270 @@
#include "../../Utilities/HashedString.hpp" #include "../../Utilities/HashedString.hpp"
#include "../TypedVariableIdentifier.hpp" #include "../TypedVariableIdentifier.hpp"
enum class ParsedStatementKind{ namespace Porygon::Parser {
Bad, enum class ParsedStatementKind {
Script, Bad,
Block, Script,
Expression, Block,
Assignment, Expression,
IndexAssignment, Assignment,
FunctionDeclaration, IndexAssignment,
Return, FunctionDeclaration,
Conditional Return,
}; Conditional
};
class ParsedStatement { class ParsedStatement {
const unsigned int _start; const unsigned int _start;
const unsigned int _length; const unsigned int _length;
public: public:
ParsedStatement(unsigned int start, unsigned int length) ParsedStatement(unsigned int start, unsigned int length)
:_start(start), _length(length) : _start(start), _length(length) {
{
}
virtual ~ParsedStatement() = default;
virtual const ParsedStatementKind GetKind() const = 0;
const unsigned int GetStartPosition() const {
return _start;
}
const unsigned int GetLength() const {
return _length;
}
const unsigned int GetEndPosition() const {
return _start + _length - 1;
}
};
class ParsedBadStatement : public ParsedStatement{
public:
ParsedBadStatement(unsigned int start, unsigned int length) : ParsedStatement(start, length){};
const ParsedStatementKind GetKind() const final{
return ParsedStatementKind ::Bad;
}
};
class ParsedBlockStatement : public ParsedStatement{
const std::vector<const ParsedStatement*> _statements;
public:
explicit ParsedBlockStatement(std::vector<const ParsedStatement*> statements)
: ParsedStatement(statements.front()->GetStartPosition(), statements.back()->GetEndPosition() - statements.front()->GetStartPosition()),
_statements(statements)
{}
ParsedBlockStatement(std::vector<const ParsedStatement*> statements, unsigned int start) : ParsedStatement(start, 0),
_statements(std::move(statements))
{
}
~ParsedBlockStatement() override {
for (auto s: _statements){
delete s;
} }
}
const ParsedStatementKind GetKind() const override { virtual ~ParsedStatement() = default;
return ParsedStatementKind ::Block;
}
const std::vector<const ParsedStatement*>* GetStatements() const{ virtual const ParsedStatementKind GetKind() const = 0;
return &_statements;
}
};
class ParsedScriptStatement : public ParsedBlockStatement{ const unsigned int GetStartPosition() const {
public: return _start;
explicit ParsedScriptStatement(vector<const ParsedStatement*> statements) : ParsedBlockStatement(move(statements)){}
const ParsedStatementKind GetKind() const final{
return ParsedStatementKind ::Script;
}
};
class ParsedExpressionStatement : public ParsedStatement{
const ParsedExpression* _expression;
public:
explicit ParsedExpressionStatement(ParsedExpression* expression)
: ParsedStatement(expression->GetStartPosition(), expression->GetLength()),
_expression(expression)
{
}
~ParsedExpressionStatement() override {
delete _expression;
}
const ParsedStatementKind GetKind() const final{
return ParsedStatementKind ::Expression;
}
const ParsedExpression* GetExpression() const{
return _expression;
}
};
class ParsedFunctionDeclarationStatement : public ParsedStatement{
const HashedString _identifier;
const vector<TypedVariableIdentifier*> _parameters;
const ParsedBlockStatement* _block;
public:
ParsedFunctionDeclarationStatement(HashedString identifier, vector<TypedVariableIdentifier*> parameters, ParsedBlockStatement* block,
unsigned int start, unsigned int length)
: ParsedStatement(start, length), _identifier(identifier), _parameters(std::move(parameters)), _block(block){};
~ParsedFunctionDeclarationStatement() override {
for (auto v : _parameters){
delete v;
} }
delete _block;
}
const ParsedStatementKind GetKind() const final{ const unsigned int GetLength() const {
return ParsedStatementKind ::FunctionDeclaration; return _length;
} }
const HashedString GetIdentifier() const{ const unsigned int GetEndPosition() const {
return _identifier; return _start + _length - 1;
} }
};
const vector<TypedVariableIdentifier*>* GetParameters() const{ class ParsedBadStatement : public ParsedStatement {
return &_parameters; public:
} ParsedBadStatement(unsigned int start, unsigned int length) : ParsedStatement(start, length) {};
const ParsedBlockStatement* GetBlock() const{ const ParsedStatementKind GetKind() const final {
return _block; return ParsedStatementKind::Bad;
} }
}; };
class ParsedAssignmentStatement : public ParsedStatement{ class ParsedBlockStatement : public ParsedStatement {
const bool _local; const std::vector<const ParsedStatement *> _statements;
const HashedString _identifier; public:
const ParsedExpression* _expression; explicit ParsedBlockStatement(std::vector<const ParsedStatement *> statements)
public: : ParsedStatement(statements.front()->GetStartPosition(),
ParsedAssignmentStatement(bool local, const HashedString identifier, ParsedExpression* expression, unsigned int start, unsigned int length) statements.back()->GetEndPosition() - statements.front()->GetStartPosition()),
: ParsedStatement(start, length), _local(local), _identifier(identifier), _expression(expression) _statements(statements) {}
{
}
~ParsedAssignmentStatement() final{ ParsedBlockStatement(std::vector<const ParsedStatement *> statements, unsigned int start) : ParsedStatement(
delete _expression; start, 0),
} _statements(
std::move(
statements)) {
}
const ParsedStatementKind GetKind() const final{
return ParsedStatementKind ::Assignment;
}
const bool IsLocal() const{ ~ParsedBlockStatement() override {
return _local; for (auto s: _statements) {
} delete s;
}
}
const HashedString GetIdentifier() const{ const ParsedStatementKind GetKind() const override {
return _identifier; return ParsedStatementKind::Block;
} }
const ParsedExpression* GetExpression() const{ const std::vector<const ParsedStatement *> *GetStatements() const {
return _expression; return &_statements;
} }
}; };
class ParsedIndexAssignmentStatement : public ParsedStatement{ class ParsedScriptStatement : public ParsedBlockStatement {
const ParsedExpression* _indexExpression; public:
const ParsedExpression* _valueExpression; explicit ParsedScriptStatement(vector<const ParsedStatement *> statements) : ParsedBlockStatement(
public: move(statements)) {}
ParsedIndexAssignmentStatement(ParsedExpression* indexExpression, ParsedExpression* valueExpression, unsigned int start,
const ParsedStatementKind GetKind() const final {
return ParsedStatementKind::Script;
}
};
class ParsedExpressionStatement : public ParsedStatement {
const ParsedExpression *_expression;
public:
explicit ParsedExpressionStatement(ParsedExpression *expression)
: ParsedStatement(expression->GetStartPosition(), expression->GetLength()),
_expression(expression) {
}
~ParsedExpressionStatement() override {
delete _expression;
}
const ParsedStatementKind GetKind() const final {
return ParsedStatementKind::Expression;
}
const ParsedExpression *GetExpression() const {
return _expression;
}
};
class ParsedFunctionDeclarationStatement : public ParsedStatement {
const HashedString _identifier;
const vector<TypedVariableIdentifier *> _parameters;
const ParsedBlockStatement *_block;
public:
ParsedFunctionDeclarationStatement(HashedString identifier, vector<TypedVariableIdentifier *> parameters,
ParsedBlockStatement *block,
unsigned int start, unsigned int length)
: ParsedStatement(start, length), _identifier(identifier), _parameters(std::move(parameters)),
_block(block) {};
~ParsedFunctionDeclarationStatement() override {
for (auto v : _parameters) {
delete v;
}
delete _block;
}
const ParsedStatementKind GetKind() const final {
return ParsedStatementKind::FunctionDeclaration;
}
const HashedString GetIdentifier() const {
return _identifier;
}
const vector<TypedVariableIdentifier *> *GetParameters() const {
return &_parameters;
}
const ParsedBlockStatement *GetBlock() const {
return _block;
}
};
class ParsedAssignmentStatement : public ParsedStatement {
const bool _local;
const HashedString _identifier;
const ParsedExpression *_expression;
public:
ParsedAssignmentStatement(bool local, const HashedString identifier, ParsedExpression *expression,
unsigned int start, unsigned int length)
: ParsedStatement(start, length), _local(local), _identifier(identifier), _expression(expression) {
}
~ParsedAssignmentStatement() final {
delete _expression;
}
const ParsedStatementKind GetKind() const final {
return ParsedStatementKind::Assignment;
}
const bool IsLocal() const {
return _local;
}
const HashedString GetIdentifier() const {
return _identifier;
}
const ParsedExpression *GetExpression() const {
return _expression;
}
};
class ParsedIndexAssignmentStatement : public ParsedStatement {
const ParsedExpression *_indexExpression;
const ParsedExpression *_valueExpression;
public:
ParsedIndexAssignmentStatement(ParsedExpression *indexExpression, ParsedExpression *valueExpression,
unsigned int start,
unsigned int length)
: ParsedStatement(start, length),
_indexExpression(indexExpression), _valueExpression(valueExpression) {}
~ParsedIndexAssignmentStatement() final {
delete _indexExpression;
delete _valueExpression;
}
const ParsedStatementKind GetKind() const final {
return ParsedStatementKind::IndexAssignment;
}
const ParsedExpression *GetIndexExpression() const {
return _indexExpression;
}
const ParsedExpression *GetValueExpression() const {
return _valueExpression;
}
};
class ParsedReturnStatement : public ParsedStatement {
const ParsedExpression *_expression;
public:
ParsedReturnStatement(ParsedExpression *expression, unsigned int start, unsigned int length)
: ParsedStatement(start, length),
_expression(expression) {
}
~ParsedReturnStatement() final {
delete _expression;
}
const ParsedStatementKind GetKind() const final {
return ParsedStatementKind::Return;
}
const ParsedExpression *GetExpression() const {
return _expression;
}
};
class ParsedConditionalStatement : public ParsedStatement {
const ParsedExpression *_condition;
const ParsedStatement *_block;
// This can be either else if or else
const ParsedStatement *_elseStatement;
public:
ParsedConditionalStatement(ParsedExpression *condition, ParsedStatement *block, unsigned int start,
unsigned int length) unsigned int length)
: ParsedStatement(start, length), : ParsedStatement(start, length), _condition(condition), _block(block), _elseStatement(nullptr) {
_indexExpression(indexExpression), _valueExpression(valueExpression){} }
~ParsedIndexAssignmentStatement() final{ ParsedConditionalStatement(ParsedExpression *condition, ParsedStatement *block, ParsedStatement *nextStatement,
delete _indexExpression; unsigned int start, unsigned int length)
delete _valueExpression; : ParsedStatement(start, length), _condition(condition), _block(block), _elseStatement(nextStatement) {
} _condition = condition;
_block = block;
_elseStatement = nextStatement;
}
const ParsedStatementKind GetKind() const final{ ~ParsedConditionalStatement() final {
return ParsedStatementKind ::IndexAssignment; delete _condition;
} delete _block;
delete _elseStatement;
}
const ParsedExpression* GetIndexExpression() const{ const ParsedStatementKind GetKind() const final {
return _indexExpression; return ParsedStatementKind::Conditional;
} }
const ParsedExpression* GetValueExpression() const{ const ParsedExpression *GetCondition() const {
return _valueExpression; return _condition;
} }
};
class ParsedReturnStatement : public ParsedStatement{ const ParsedStatement *GetBlock() const {
const ParsedExpression* _expression; return _block;
public: }
ParsedReturnStatement(ParsedExpression* expression, unsigned int start, unsigned int length)
: ParsedStatement(start, length),
_expression(expression)
{
}
~ParsedReturnStatement() final{
delete _expression;
}
const ParsedStatementKind GetKind() const final{
return ParsedStatementKind ::Return;
}
const ParsedExpression* GetExpression() const{
return _expression;
}
};
class ParsedConditionalStatement : public ParsedStatement{
const ParsedExpression* _condition;
const ParsedStatement* _block;
// This can be either else if or else
const ParsedStatement* _elseStatement;
public:
ParsedConditionalStatement(ParsedExpression* condition, ParsedStatement* block, unsigned int start, unsigned int length)
: ParsedStatement(start, length), _condition(condition), _block(block), _elseStatement(nullptr)
{
}
ParsedConditionalStatement(ParsedExpression* condition, ParsedStatement* block, ParsedStatement* nextStatement, unsigned int start, unsigned int length)
: ParsedStatement(start, length), _condition(condition), _block(block), _elseStatement(nextStatement)
{
_condition = condition;
_block = block;
_elseStatement = nextStatement;
}
~ParsedConditionalStatement() final{
delete _condition;
delete _block;
delete _elseStatement;
}
const ParsedStatementKind GetKind() const final{
return ParsedStatementKind ::Conditional;
}
const ParsedExpression* GetCondition() const {
return _condition;
}
const ParsedStatement* GetBlock() const {
return _block;
}
const ParsedStatement* GetElseStatement() const {
return _elseStatement;
}
};
const ParsedStatement *GetElseStatement() const {
return _elseStatement;
}
};
}
#endif //PORYGONLANG_PARSEDSTATEMENT_HPP #endif //PORYGONLANG_PARSEDSTATEMENT_HPP

View File

@ -7,426 +7,496 @@
#include "TypedVariableIdentifier.hpp" #include "TypedVariableIdentifier.hpp"
#include "ParsedExpressions/ParsedTableExpression.hpp" #include "ParsedExpressions/ParsedTableExpression.hpp"
namespace Porygon::Parser {
ParsedScriptStatement* Parser::Parse() { ParsedScriptStatement *Parser::Parse() {
vector<const ParsedStatement*> statements; vector<const ParsedStatement *> statements;
while (this->_position < this->_tokens.size()){ while (this->_position < this->_tokens.size()) {
auto next = this -> Next(); auto next = this->Next();
if (next->GetKind() == TokenKind::EndOfFile){ if (next->GetKind() == TokenKind::EndOfFile) {
break; break;
}
statements.push_back(this->ParseStatement(next));
} }
statements.push_back(this -> ParseStatement(next)); return new ParsedScriptStatement(statements);
}
return new ParsedScriptStatement(statements);
}
const IToken *Parser::Peek() {
return this -> _tokens[_position];
}
const IToken *Parser::PeekAt(int offset) {
return this -> _tokens[_position + offset];
}
const IToken *Parser::Next() {
this -> _position++;
return this -> _tokens[_position - 1];
}
ParsedStatement* Parser::ParseStatement(const IToken* current){
auto currentKind = current->GetKind();
switch (currentKind){
case TokenKind ::LocalKeyword: return this->ParseVariableAssignment(current);
case TokenKind ::FunctionKeyword: return this -> ParseFunctionDeclaration(current);
case TokenKind ::ReturnKeyword: return this->ParseReturnStatement(current);
case TokenKind ::IfKeyword: return this -> ParseIfStatement(current);
default: break;
}
if (this->Peek()->GetKind() == TokenKind::AssignmentToken){
return ParseVariableAssignment(current);
}
auto expression = this -> ParseExpression(current);
auto expKind = expression -> GetKind();
if ((expKind == ParsedExpressionKind::Indexer || expKind == ParsedExpressionKind::PeriodIndexer)
&& this -> Peek()->GetKind() == TokenKind::AssignmentToken){
return this -> ParseIndexAssignment(expression);
}
return new ParsedExpressionStatement(expression);
}
ParsedStatement *Parser::ParseVariableAssignment(const IToken *current) {
bool isLocal = false;
const IToken* identifier;
if (current -> GetKind() == TokenKind::LocalKeyword){
isLocal = true;
identifier = this -> Next();
} else{
identifier = current;
}
auto assignmentToken = this->Next();
auto expression = this -> ParseExpression(this -> Next());
if (identifier -> GetKind() != TokenKind::Identifier){
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(), identifier->GetLength());
return new ParsedBadStatement(identifier->GetStartPosition(), identifier->GetLength());
}
if (assignmentToken -> GetKind() != TokenKind::AssignmentToken){
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(), identifier->GetLength());
return new ParsedBadStatement(identifier->GetStartPosition(), identifier->GetLength());
} }
auto start = current -> GetStartPosition(); const IToken *Parser::Peek() {
return new ParsedAssignmentStatement(isLocal, ((IdentifierToken*)identifier) -> GetValue(), expression, start, expression->GetEndPosition() - start); return this->_tokens[_position];
} }
ParsedStatement *Parser::ParseIndexAssignment(ParsedExpression *indexer) { const IToken *Parser::PeekAt(int offset) {
this -> Next(); // Consume assignment token return this->_tokens[_position + offset];
auto valueExpression = this -> ParseExpression(this -> Next()); }
auto start = indexer->GetStartPosition();
return new ParsedIndexAssignmentStatement(indexer, valueExpression, start, valueExpression->GetEndPosition() - start);
}
const IToken *Parser::Next() {
this->_position++;
return this->_tokens[_position - 1];
}
ParsedStatement *Parser::ParseBlock(const vector<TokenKind>& endTokens, const vector<const ParsedStatement*>& openStatements) { ParsedStatement *Parser::ParseStatement(const IToken *current) {
auto statements = openStatements; auto currentKind = current->GetKind();
auto start = this->_position; switch (currentKind) {
while (this->_position < this->_tokens.size()){ case TokenKind::LocalKeyword:
auto next = this -> Next(); return this->ParseVariableAssignment(current);
auto nextKind = next->GetKind(); case TokenKind::FunctionKeyword:
if (std::find(endTokens.begin(), endTokens.end(), nextKind) != endTokens.end()){ return this->ParseFunctionDeclaration(current);
break; case TokenKind::ReturnKeyword:
return this->ParseReturnStatement(current);
case TokenKind::IfKeyword:
return this->ParseIfStatement(current);
default:
break;
} }
if (nextKind == TokenKind::EndOfFile){ if (this->Peek()->GetKind() == TokenKind::AssignmentToken) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(), next->GetLength()); return ParseVariableAssignment(current);
break;
} }
statements.push_back(this -> ParseStatement(next)); auto expression = this->ParseExpression(current);
} auto expKind = expression->GetKind();
if (statements.empty()){ if ((expKind == ParsedExpressionKind::Indexer || expKind == ParsedExpressionKind::PeriodIndexer)
return new ParsedBlockStatement(statements,start); && this->Peek()->GetKind() == TokenKind::AssignmentToken) {
} return this->ParseIndexAssignment(expression);
return new ParsedBlockStatement(statements);
}
ParsedStatement *Parser::ParseFunctionDeclaration(const IToken *current) {
auto functionIdentifierToken = this->Next();
auto openParenthesis = this->Next();
vector<TypedVariableIdentifier*> parameters;
bool hasErrors = false;
if (functionIdentifierToken->GetKind() != TokenKind::Identifier){
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, functionIdentifierToken->GetStartPosition(), functionIdentifierToken->GetLength());
hasErrors = true;
}
if (openParenthesis->GetKind() != TokenKind::OpenParenthesis && !hasErrors){
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, openParenthesis->GetStartPosition(), openParenthesis->GetLength());
hasErrors = true;
}
while (this -> _position < this->_tokens.size()){
auto type = this->Next();
if (type->GetKind() == TokenKind::CloseParenthesis){
break;
}
auto identifier = this->Next();
auto next = this->Next();
if (type->GetKind() != TokenKind::Identifier &&!hasErrors){
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, type->GetStartPosition(), type->GetLength());
hasErrors = true;
continue;
}
if (identifier->GetKind() != TokenKind::Identifier &&!hasErrors){
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(), identifier->GetLength());
hasErrors = true;
continue;
}
if (type->GetKind() != TokenKind::Identifier || identifier->GetKind() != TokenKind::Identifier){
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, type->GetStartPosition(), type->GetLength());
hasErrors = true;
continue;
}
auto typeToken = (IdentifierToken*)type;
auto identifierToken = (IdentifierToken*)identifier;
parameters.push_back(new TypedVariableIdentifier(typeToken->GetValue(), identifierToken->GetValue()));
auto nextKind = next->GetKind();
if (nextKind == TokenKind::CloseParenthesis || nextKind == TokenKind::EndOfFile){
break;
} else if (nextKind != TokenKind::CommaToken && !hasErrors){
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(), next->GetLength());
hasErrors = true;
} }
return new ParsedExpressionStatement(expression);
} }
auto block = this -> ParseBlock({TokenKind ::EndKeyword});
auto start = current->GetStartPosition(); ParsedStatement *Parser::ParseVariableAssignment(const IToken *current) {
if (hasErrors){ bool isLocal = false;
return new ParsedBadStatement(start, block->GetEndPosition() - start); const IToken *identifier;
} if (current->GetKind() == TokenKind::LocalKeyword) {
if (block->GetKind() == ParsedStatementKind::Bad){ isLocal = true;
return new ParsedBadStatement(start, block->GetEndPosition() - start); identifier = this->Next();
}
auto functionIdentifier = ((IdentifierToken*) functionIdentifierToken)->GetValue();
return new ParsedFunctionDeclarationStatement(HashedString(functionIdentifier), parameters, (ParsedBlockStatement*)block, start, block->GetEndPosition() - start);
}
ParsedStatement* Parser::ParseReturnStatement(const IToken* current){
//TODO: if next token is on a different line, don't parse it as return expression.
auto expression = this->ParseExpression(this->Next());
auto start = current->GetStartPosition();
return new ParsedReturnStatement(expression, start, expression->GetEndPosition() - start);
}
ParsedStatement* Parser::ParseIfStatement(const IToken* current){
auto condition = this->ParseExpression(this->Next());
auto next = this -> Next();
if (next->GetKind() != TokenKind::ThenKeyword){
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(), next->GetLength());
return new ParsedBadStatement(next->GetStartPosition(), next->GetLength());
}
auto block = this -> ParseBlock({TokenKind ::EndKeyword, TokenKind ::ElseKeyword, TokenKind ::ElseIfKeyword});
auto closeToken = this->PeekAt(-1);
auto start = current->GetStartPosition();
if (closeToken->GetKind() == TokenKind::ElseIfKeyword){
auto elseIfStatement = this -> ParseIfStatement(closeToken);
return new ParsedConditionalStatement(condition, block, elseIfStatement, start, elseIfStatement->GetEndPosition() - start);
} else if (closeToken->GetKind() == TokenKind::ElseKeyword){
auto elseStatement = this -> ParseBlock({TokenKind ::EndKeyword});
return new ParsedConditionalStatement(condition, block, elseStatement, start, elseStatement->GetEndPosition() - start);
}
return new ParsedConditionalStatement(condition, block, start, block->GetEndPosition() - start);
}
ParsedExpression* Parser::ParseExpression(const IToken* current){
auto expression = this -> ParseBinaryExpression(current, OperatorPrecedence::No);
auto peekKind = this->Peek()->GetKind();
while (peekKind == TokenKind::OpenParenthesis ||
peekKind == TokenKind::OpenSquareBracket ||
peekKind == TokenKind::PeriodToken){
if (peekKind == TokenKind::OpenParenthesis){
expression = this->ParseFunctionCallExpression(expression);
} else if (peekKind == TokenKind::OpenSquareBracket){
expression = this->ParseIndexExpression(expression);
} else { } else {
expression = this -> ParsePeriodIndexExpression(expression); identifier = current;
} }
if (this -> _position >= this->_tokens.size()) auto assignmentToken = this->Next();
break; auto expression = this->ParseExpression(this->Next());
peekKind = this->Peek()->GetKind();
}
return expression;
}
OperatorPrecedence GetUnaryPrecedence(TokenKind kind){ if (identifier->GetKind() != TokenKind::Identifier) {
switch (kind){ this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(),
case TokenKind::PlusToken: identifier->GetLength());
case TokenKind::MinusToken: return new ParsedBadStatement(identifier->GetStartPosition(), identifier->GetLength());
case TokenKind::NotKeyword:
return OperatorPrecedence::Unary;
default:
return OperatorPrecedence::No;
}
}
UnaryOperatorKind GetUnaryOperatorKind(TokenKind kind){
switch (kind){
case TokenKind::PlusToken: return UnaryOperatorKind::Identity;
case TokenKind::MinusToken: return UnaryOperatorKind::Negation;
case TokenKind::NotKeyword: return UnaryOperatorKind::LogicalNegation;
default: // This should never trigger, so throw.
throw;
}
}
BinaryOperatorKind GetBinaryOperatorKind(TokenKind kind){
switch (kind){
// Math operators
case TokenKind::PlusToken: return BinaryOperatorKind ::Addition;
case TokenKind::MinusToken: return BinaryOperatorKind ::Subtraction;
case TokenKind::StarToken: return BinaryOperatorKind ::Multiplication;
case TokenKind::SlashToken: return BinaryOperatorKind ::Division;
// Equality operators
case TokenKind::EqualityToken: return BinaryOperatorKind ::Equality;
case TokenKind::InequalityToken: return BinaryOperatorKind ::Inequality;
case TokenKind ::Less: return BinaryOperatorKind ::Less;
case TokenKind ::LessEquals: return BinaryOperatorKind ::LessOrEquals;
case TokenKind ::Greater: return BinaryOperatorKind ::Greater;
case TokenKind ::GreaterEquals: return BinaryOperatorKind ::GreaterOrEquals;
// logical operators
case TokenKind::AndKeyword: return BinaryOperatorKind ::LogicalAnd;
case TokenKind::OrKeyword: return BinaryOperatorKind ::LogicalOr;
default: // This should never trigger, so throw.
throw;
}
}
OperatorPrecedence GetBinaryPrecedence(TokenKind kind){
switch (kind){
// Math
case TokenKind::PlusToken: return OperatorPrecedence ::Additive;
case TokenKind::MinusToken: return OperatorPrecedence ::Additive;
case TokenKind::StarToken: return OperatorPrecedence ::Multiplication;
case TokenKind::SlashToken: return OperatorPrecedence ::Multiplication;
// Equality
case TokenKind::EqualityToken: return OperatorPrecedence ::Equality;
case TokenKind::InequalityToken: return OperatorPrecedence ::Equality;
case TokenKind ::Less: return OperatorPrecedence ::Equality;
case TokenKind ::LessEquals: return OperatorPrecedence ::Equality;
case TokenKind ::Greater: return OperatorPrecedence ::Equality;
case TokenKind ::GreaterEquals: return OperatorPrecedence ::Equality;
// Logical
case TokenKind::AndKeyword: return OperatorPrecedence ::LogicalAnd;
case TokenKind::OrKeyword: return OperatorPrecedence ::LogicalOr;
default:
return OperatorPrecedence::No;
}
}
ParsedExpression* Parser::ParseBinaryExpression(const IToken* current, OperatorPrecedence parentPrecedence){
OperatorPrecedence unaryPrecedence = GetUnaryPrecedence(current -> GetKind());
ParsedExpression* left;
if (unaryPrecedence != OperatorPrecedence::No && unaryPrecedence >= parentPrecedence){
UnaryOperatorKind operatorKind = GetUnaryOperatorKind(current -> GetKind());
auto next = this -> Next();
auto operand = this -> ParseBinaryExpression(next, unaryPrecedence);
auto startPos = current -> GetStartPosition();
left = new UnaryExpression(operatorKind, operand, startPos, operand -> GetEndPosition() - startPos);
} else{
left = this -> ParsePrimaryExpression(current);
}
while (true){
auto next = this -> Peek();
OperatorPrecedence binaryPrecedence = GetBinaryPrecedence(next -> GetKind());
if (binaryPrecedence == OperatorPrecedence::No || binaryPrecedence <= parentPrecedence){
break;
} }
auto operatorKind = GetBinaryOperatorKind(next -> GetKind()); if (assignmentToken->GetKind() != TokenKind::AssignmentToken) {
this -> Next(); this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(),
auto right = this -> ParseBinaryExpression(this -> Next(), binaryPrecedence); identifier->GetLength());
auto startPos = left -> GetStartPosition(); return new ParsedBadStatement(identifier->GetStartPosition(), identifier->GetLength());
left = new BinaryExpression(operatorKind, left, right, startPos, right -> GetEndPosition() - startPos);
}
return left;
}
ParsedExpression *Parser::ParsePrimaryExpression(const IToken *current) {
switch (current -> GetKind()){
case TokenKind ::Integer: return new LiteralIntegerExpression((IntegerToken*)current);
case TokenKind ::Float: return new LiteralFloatExpression((FloatToken*)current);
case TokenKind ::String: return new LiteralStringExpression((StringToken*)current);
case TokenKind ::TrueKeyword: return new LiteralBoolExpression(current);
case TokenKind ::FalseKeyword: return new LiteralBoolExpression(current);
case TokenKind ::Identifier: return new VariableExpression((IdentifierToken*)current);
case TokenKind ::OpenParenthesis: return this -> ParseParenthesizedExpression(current);
case TokenKind ::OpenCurlyBracket: return this -> ParseTableExpression(current);
// If we find a bad token here, we should have already logged it in the lexer, so don't log another error.
case TokenKind ::BadToken: return new BadExpression(current->GetStartPosition(), current->GetLength());
default:
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, current->GetStartPosition(), current->GetLength());
return new BadExpression(current->GetStartPosition(), current->GetLength());
}
}
ParsedExpression *Parser::ParseParenthesizedExpression(const IToken *current) {
auto next = this -> Next();
auto expression = this -> ParseExpression(next);
auto closeToken = this -> Next();
if (closeToken -> GetKind() != TokenKind::CloseParenthesis){
this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, closeToken->GetStartPosition(), closeToken->GetLength());
return new BadExpression(closeToken->GetStartPosition(), closeToken->GetLength());
}
auto start = current -> GetStartPosition();
return new ParenthesizedExpression(expression, start, closeToken->GetEndPosition() - start);
}
ParsedExpression *Parser::ParseFunctionCallExpression(ParsedExpression* functionExpression) {
this -> Next(); // consume the open parenthesis
vector<const ParsedExpression*> parameters;
auto peeked = this -> Peek();
auto peekedKind = peeked->GetKind();
if (peekedKind == TokenKind::CloseParenthesis){
this->Next();
} else{
while (peekedKind != TokenKind::CloseParenthesis){
if (peekedKind == TokenKind ::EndOfFile){
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, peeked->GetStartPosition(), peeked->GetLength());
return new BadExpression(peeked->GetStartPosition(), peeked->GetLength());
}
parameters.push_back(this->ParseExpression(this->Next()));
peeked = this -> Next() ;
peekedKind = peeked->GetKind();
if (peekedKind != TokenKind::CloseParenthesis && peekedKind != TokenKind::CommaToken){
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, peeked->GetStartPosition(), peeked->GetLength());
return new BadExpression(peeked->GetStartPosition(), peeked->GetLength());
}
} }
}
auto start = functionExpression->GetStartPosition();
return new FunctionCallExpression(functionExpression, parameters, start, peeked->GetEndPosition() - start);
}
ParsedExpression* Parser::ParseIndexExpression(ParsedExpression* indexingExpression){
this->Next(); // consume '[' token
auto indexExpression = this -> ParseExpression(this -> Next());
auto closeBracket = this->Next();
if (closeBracket->GetKind() != TokenKind::CloseSquareBracket){
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, closeBracket->GetStartPosition(), closeBracket->GetLength());
return new BadExpression(closeBracket->GetStartPosition(), closeBracket->GetLength());
}
auto start = indexingExpression->GetStartPosition();
return new IndexExpression(indexingExpression, indexExpression, start, closeBracket->GetEndPosition() - start);
}
ParsedExpression* Parser::ParsePeriodIndexExpression(ParsedExpression* indexingExpression){
this->Next(); // consume '.' token
auto identifier = this -> Next();
if (identifier->GetKind() != TokenKind::Identifier){
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(), identifier->GetLength());
return new BadExpression(indexingExpression->GetStartPosition(), identifier->GetEndPosition() - indexingExpression->GetStartPosition());
}
auto start = indexingExpression->GetStartPosition();
return new PeriodIndexExpression(indexingExpression, ((IdentifierToken*)identifier)->GetValue(), start, identifier->GetEndPosition() - start);
}
ParsedExpression* Parser::ParseTableExpression(const IToken* current){
if (this -> Peek() -> GetKind() == TokenKind::CloseCurlyBracket){
this -> Next();
auto start = current->GetStartPosition(); auto start = current->GetStartPosition();
return new ParsedNumericalTableExpression({}, start, this -> Peek()->GetEndPosition() - start); return new ParsedAssignmentStatement(isLocal, ((IdentifierToken *) identifier)->GetValue(), expression, start,
expression->GetEndPosition() - start);
} }
auto start = current->GetStartPosition();
auto firstItem = this->ParseStatement(this -> Next()); ParsedStatement *Parser::ParseIndexAssignment(ParsedExpression *indexer) {
// If the first item is an expression, and is followed by a comma, we're dealing with a simple {1, 2, 3} kind of array this->Next(); // Consume assignment token
if (firstItem->GetKind() == ParsedStatementKind::Expression && auto valueExpression = this->ParseExpression(this->Next());
(this->Peek()->GetKind() == TokenKind::CommaToken )){ auto start = indexer->GetStartPosition();
auto expr = ((ParsedExpressionStatement*)firstItem)->GetExpression(); return new ParsedIndexAssignmentStatement(indexer, valueExpression, start,
auto expressions = vector<const ParsedExpression*>{expr}; valueExpression->GetEndPosition() - start);
auto n = this -> Next(); // consume the comma }
ParsedStatement *
Parser::ParseBlock(const vector<TokenKind> &endTokens, const vector<const ParsedStatement *> &openStatements) {
auto statements = openStatements;
auto start = this->_position;
while (this->_position < this->_tokens.size()) {
auto next = this->Next();
auto nextKind = next->GetKind();
if (std::find(endTokens.begin(), endTokens.end(), nextKind) != endTokens.end()) {
break;
}
if (nextKind == TokenKind::EndOfFile) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(),
next->GetLength());
break;
}
statements.push_back(this->ParseStatement(next));
}
if (statements.empty()) {
return new ParsedBlockStatement(statements, start);
}
return new ParsedBlockStatement(statements);
}
ParsedStatement *Parser::ParseFunctionDeclaration(const IToken *current) {
auto functionIdentifierToken = this->Next();
auto openParenthesis = this->Next();
vector<TypedVariableIdentifier *> parameters;
bool hasErrors = false; bool hasErrors = false;
while (n->GetKind() != TokenKind::CloseCurlyBracket){ if (functionIdentifierToken->GetKind() != TokenKind::Identifier) {
auto expression = this->ParseExpression(this->Next()); this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken,
expressions.push_back(expression); functionIdentifierToken->GetStartPosition(),
n = this->Next(); functionIdentifierToken->GetLength());
if (n->GetKind() != TokenKind::CommaToken && n->GetKind() != TokenKind ::CloseCurlyBracket && !hasErrors){ hasErrors = true;
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, n->GetStartPosition(), n->GetLength()); }
if (openParenthesis->GetKind() != TokenKind::OpenParenthesis && !hasErrors) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken,
openParenthesis->GetStartPosition(), openParenthesis->GetLength());
hasErrors = true;
}
while (this->_position < this->_tokens.size()) {
auto type = this->Next();
if (type->GetKind() == TokenKind::CloseParenthesis) {
break;
}
auto identifier = this->Next();
auto next = this->Next();
if (type->GetKind() != TokenKind::Identifier && !hasErrors) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, type->GetStartPosition(),
type->GetLength());
hasErrors = true;
continue;
}
if (identifier->GetKind() != TokenKind::Identifier && !hasErrors) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(),
identifier->GetLength());
hasErrors = true;
continue;
}
if (type->GetKind() != TokenKind::Identifier || identifier->GetKind() != TokenKind::Identifier) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, type->GetStartPosition(),
type->GetLength());
hasErrors = true;
continue;
}
auto typeToken = (IdentifierToken *) type;
auto identifierToken = (IdentifierToken *) identifier;
parameters.push_back(new TypedVariableIdentifier(typeToken->GetValue(), identifierToken->GetValue()));
auto nextKind = next->GetKind();
if (nextKind == TokenKind::CloseParenthesis || nextKind == TokenKind::EndOfFile) {
break;
} else if (nextKind != TokenKind::CommaToken && !hasErrors) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(),
next->GetLength());
hasErrors = true; hasErrors = true;
} }
} }
if (hasErrors){ auto block = this->ParseBlock({TokenKind::EndKeyword});
return new BadExpression(start, n->GetEndPosition() - start);
}
return new ParsedNumericalTableExpression(expressions, start, n->GetEndPosition() - start);
}
// Otherwise we have a more complex table, which can be defined by a block
else {
auto block = (ParsedBlockStatement*)this -> ParseBlock({TokenKind ::CloseCurlyBracket}, {firstItem});
auto closeToken = this -> PeekAt(-1);
return new ParsedTableExpression(block, start, closeToken->GetEndPosition() - start);
}
}
auto start = current->GetStartPosition();
if (hasErrors) {
return new ParsedBadStatement(start, block->GetEndPosition() - start);
}
if (block->GetKind() == ParsedStatementKind::Bad) {
return new ParsedBadStatement(start, block->GetEndPosition() - start);
}
auto functionIdentifier = ((IdentifierToken *) functionIdentifierToken)->GetValue();
return new ParsedFunctionDeclarationStatement(HashedString(functionIdentifier), parameters,
(ParsedBlockStatement *) block, start,
block->GetEndPosition() - start);
}
ParsedStatement *Parser::ParseReturnStatement(const IToken *current) {
//TODO: if next token is on a different line, don't parse it as return expression.
auto expression = this->ParseExpression(this->Next());
auto start = current->GetStartPosition();
return new ParsedReturnStatement(expression, start, expression->GetEndPosition() - start);
}
ParsedStatement *Parser::ParseIfStatement(const IToken *current) {
auto condition = this->ParseExpression(this->Next());
auto next = this->Next();
if (next->GetKind() != TokenKind::ThenKeyword) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, next->GetStartPosition(),
next->GetLength());
return new ParsedBadStatement(next->GetStartPosition(), next->GetLength());
}
auto block = this->ParseBlock({TokenKind::EndKeyword, TokenKind::ElseKeyword, TokenKind::ElseIfKeyword});
auto closeToken = this->PeekAt(-1);
auto start = current->GetStartPosition();
if (closeToken->GetKind() == TokenKind::ElseIfKeyword) {
auto elseIfStatement = this->ParseIfStatement(closeToken);
return new ParsedConditionalStatement(condition, block, elseIfStatement, start,
elseIfStatement->GetEndPosition() - start);
} else if (closeToken->GetKind() == TokenKind::ElseKeyword) {
auto elseStatement = this->ParseBlock({TokenKind::EndKeyword});
return new ParsedConditionalStatement(condition, block, elseStatement, start,
elseStatement->GetEndPosition() - start);
}
return new ParsedConditionalStatement(condition, block, start, block->GetEndPosition() - start);
}
ParsedExpression *Parser::ParseExpression(const IToken *current) {
auto expression = this->ParseBinaryExpression(current, OperatorPrecedence::No);
auto peekKind = this->Peek()->GetKind();
while (peekKind == TokenKind::OpenParenthesis ||
peekKind == TokenKind::OpenSquareBracket ||
peekKind == TokenKind::PeriodToken) {
if (peekKind == TokenKind::OpenParenthesis) {
expression = this->ParseFunctionCallExpression(expression);
} else if (peekKind == TokenKind::OpenSquareBracket) {
expression = this->ParseIndexExpression(expression);
} else {
expression = this->ParsePeriodIndexExpression(expression);
}
if (this->_position >= this->_tokens.size())
break;
peekKind = this->Peek()->GetKind();
}
return expression;
}
OperatorPrecedence GetUnaryPrecedence(TokenKind kind) {
switch (kind) {
case TokenKind::PlusToken:
case TokenKind::MinusToken:
case TokenKind::NotKeyword:
return OperatorPrecedence::Unary;
default:
return OperatorPrecedence::No;
}
}
UnaryOperatorKind GetUnaryOperatorKind(TokenKind kind) {
switch (kind) {
case TokenKind::PlusToken:
return UnaryOperatorKind::Identity;
case TokenKind::MinusToken:
return UnaryOperatorKind::Negation;
case TokenKind::NotKeyword:
return UnaryOperatorKind::LogicalNegation;
default: // This should never trigger, so throw.
throw;
}
}
BinaryOperatorKind GetBinaryOperatorKind(TokenKind kind) {
switch (kind) {
// Math operators
case TokenKind::PlusToken:
return BinaryOperatorKind::Addition;
case TokenKind::MinusToken:
return BinaryOperatorKind::Subtraction;
case TokenKind::StarToken:
return BinaryOperatorKind::Multiplication;
case TokenKind::SlashToken:
return BinaryOperatorKind::Division;
// Equality operators
case TokenKind::EqualityToken:
return BinaryOperatorKind::Equality;
case TokenKind::InequalityToken:
return BinaryOperatorKind::Inequality;
case TokenKind::Less:
return BinaryOperatorKind::Less;
case TokenKind::LessEquals:
return BinaryOperatorKind::LessOrEquals;
case TokenKind::Greater:
return BinaryOperatorKind::Greater;
case TokenKind::GreaterEquals:
return BinaryOperatorKind::GreaterOrEquals;
// logical operators
case TokenKind::AndKeyword:
return BinaryOperatorKind::LogicalAnd;
case TokenKind::OrKeyword:
return BinaryOperatorKind::LogicalOr;
default: // This should never trigger, so throw.
throw;
}
}
OperatorPrecedence GetBinaryPrecedence(TokenKind kind) {
switch (kind) {
// Math
case TokenKind::PlusToken:
return OperatorPrecedence::Additive;
case TokenKind::MinusToken:
return OperatorPrecedence::Additive;
case TokenKind::StarToken:
return OperatorPrecedence::Multiplication;
case TokenKind::SlashToken:
return OperatorPrecedence::Multiplication;
// Equality
case TokenKind::EqualityToken:
return OperatorPrecedence::Equality;
case TokenKind::InequalityToken:
return OperatorPrecedence::Equality;
case TokenKind::Less:
return OperatorPrecedence::Equality;
case TokenKind::LessEquals:
return OperatorPrecedence::Equality;
case TokenKind::Greater:
return OperatorPrecedence::Equality;
case TokenKind::GreaterEquals:
return OperatorPrecedence::Equality;
// Logical
case TokenKind::AndKeyword:
return OperatorPrecedence::LogicalAnd;
case TokenKind::OrKeyword:
return OperatorPrecedence::LogicalOr;
default:
return OperatorPrecedence::No;
}
}
ParsedExpression *Parser::ParseBinaryExpression(const IToken *current, OperatorPrecedence parentPrecedence) {
OperatorPrecedence unaryPrecedence = GetUnaryPrecedence(current->GetKind());
ParsedExpression *left;
if (unaryPrecedence != OperatorPrecedence::No && unaryPrecedence >= parentPrecedence) {
UnaryOperatorKind operatorKind = GetUnaryOperatorKind(current->GetKind());
auto next = this->Next();
auto operand = this->ParseBinaryExpression(next, unaryPrecedence);
auto startPos = current->GetStartPosition();
left = new UnaryExpression(operatorKind, operand, startPos, operand->GetEndPosition() - startPos);
} else {
left = this->ParsePrimaryExpression(current);
}
while (true) {
auto next = this->Peek();
OperatorPrecedence binaryPrecedence = GetBinaryPrecedence(next->GetKind());
if (binaryPrecedence == OperatorPrecedence::No || binaryPrecedence <= parentPrecedence) {
break;
}
auto operatorKind = GetBinaryOperatorKind(next->GetKind());
this->Next();
auto right = this->ParseBinaryExpression(this->Next(), binaryPrecedence);
auto startPos = left->GetStartPosition();
left = new BinaryExpression(operatorKind, left, right, startPos, right->GetEndPosition() - startPos);
}
return left;
}
ParsedExpression *Parser::ParsePrimaryExpression(const IToken *current) {
switch (current->GetKind()) {
case TokenKind::Integer:
return new LiteralIntegerExpression((IntegerToken *) current);
case TokenKind::Float:
return new LiteralFloatExpression((FloatToken *) current);
case TokenKind::String:
return new LiteralStringExpression((StringToken *) current);
case TokenKind::TrueKeyword:
return new LiteralBoolExpression(current);
case TokenKind::FalseKeyword:
return new LiteralBoolExpression(current);
case TokenKind::Identifier:
return new VariableExpression((IdentifierToken *) current);
case TokenKind::OpenParenthesis:
return this->ParseParenthesizedExpression(current);
case TokenKind::OpenCurlyBracket:
return this->ParseTableExpression(current);
// If we find a bad token here, we should have already logged it in the lexer, so don't log another error.
case TokenKind::BadToken:
return new BadExpression(current->GetStartPosition(), current->GetLength());
default:
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, current->GetStartPosition(),
current->GetLength());
return new BadExpression(current->GetStartPosition(), current->GetLength());
}
}
ParsedExpression *Parser::ParseParenthesizedExpression(const IToken *current) {
auto next = this->Next();
auto expression = this->ParseExpression(next);
auto closeToken = this->Next();
if (closeToken->GetKind() != TokenKind::CloseParenthesis) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, closeToken->GetStartPosition(),
closeToken->GetLength());
return new BadExpression(closeToken->GetStartPosition(), closeToken->GetLength());
}
auto start = current->GetStartPosition();
return new ParenthesizedExpression(expression, start, closeToken->GetEndPosition() - start);
}
ParsedExpression *Parser::ParseFunctionCallExpression(ParsedExpression *functionExpression) {
this->Next(); // consume the open parenthesis
vector<const ParsedExpression *> parameters;
auto peeked = this->Peek();
auto peekedKind = peeked->GetKind();
if (peekedKind == TokenKind::CloseParenthesis) {
this->Next();
} else {
while (peekedKind != TokenKind::CloseParenthesis) {
if (peekedKind == TokenKind::EndOfFile) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, peeked->GetStartPosition(),
peeked->GetLength());
return new BadExpression(peeked->GetStartPosition(), peeked->GetLength());
}
parameters.push_back(this->ParseExpression(this->Next()));
peeked = this->Next();
peekedKind = peeked->GetKind();
if (peekedKind != TokenKind::CloseParenthesis && peekedKind != TokenKind::CommaToken) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, peeked->GetStartPosition(),
peeked->GetLength());
return new BadExpression(peeked->GetStartPosition(), peeked->GetLength());
}
}
}
auto start = functionExpression->GetStartPosition();
return new FunctionCallExpression(functionExpression, parameters, start, peeked->GetEndPosition() - start);
}
ParsedExpression *Parser::ParseIndexExpression(ParsedExpression *indexingExpression) {
this->Next(); // consume '[' token
auto indexExpression = this->ParseExpression(this->Next());
auto closeBracket = this->Next();
if (closeBracket->GetKind() != TokenKind::CloseSquareBracket) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, closeBracket->GetStartPosition(),
closeBracket->GetLength());
return new BadExpression(closeBracket->GetStartPosition(), closeBracket->GetLength());
}
auto start = indexingExpression->GetStartPosition();
return new IndexExpression(indexingExpression, indexExpression, start, closeBracket->GetEndPosition() - start);
}
ParsedExpression *Parser::ParsePeriodIndexExpression(ParsedExpression *indexingExpression) {
this->Next(); // consume '.' token
auto identifier = this->Next();
if (identifier->GetKind() != TokenKind::Identifier) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, identifier->GetStartPosition(),
identifier->GetLength());
return new BadExpression(indexingExpression->GetStartPosition(),
identifier->GetEndPosition() - indexingExpression->GetStartPosition());
}
auto start = indexingExpression->GetStartPosition();
return new PeriodIndexExpression(indexingExpression, ((IdentifierToken *) identifier)->GetValue(), start,
identifier->GetEndPosition() - start);
}
ParsedExpression *Parser::ParseTableExpression(const IToken *current) {
if (this->Peek()->GetKind() == TokenKind::CloseCurlyBracket) {
this->Next();
auto start = current->GetStartPosition();
return new ParsedNumericalTableExpression({}, start, this->Peek()->GetEndPosition() - start);
}
auto start = current->GetStartPosition();
auto firstItem = this->ParseStatement(this->Next());
// If the first item is an expression, and is followed by a comma, we're dealing with a simple {1, 2, 3} kind of array
if (firstItem->GetKind() == ParsedStatementKind::Expression &&
(this->Peek()->GetKind() == TokenKind::CommaToken)) {
auto expr = ((ParsedExpressionStatement *) firstItem)->GetExpression();
auto expressions = vector<const ParsedExpression *>{expr};
auto n = this->Next(); // consume the comma
bool hasErrors = false;
while (n->GetKind() != TokenKind::CloseCurlyBracket) {
auto expression = this->ParseExpression(this->Next());
expressions.push_back(expression);
n = this->Next();
if (n->GetKind() != TokenKind::CommaToken && n->GetKind() != TokenKind::CloseCurlyBracket &&
!hasErrors) {
this->ScriptData->Diagnostics->LogError(DiagnosticCode::UnexpectedToken, n->GetStartPosition(),
n->GetLength());
hasErrors = true;
}
}
if (hasErrors) {
return new BadExpression(start, n->GetEndPosition() - start);
}
return new ParsedNumericalTableExpression(expressions, start, n->GetEndPosition() - start);
}
// Otherwise we have a more complex table, which can be defined by a block
else {
auto block = (ParsedBlockStatement *) this->ParseBlock({TokenKind::CloseCurlyBracket}, {firstItem});
auto closeToken = this->PeekAt(-1);
return new ParsedTableExpression(block, start, closeToken->GetEndPosition() - start);
}
}
}

View File

@ -7,51 +7,69 @@
#include "ParsedStatements/ParsedStatement.hpp" #include "ParsedStatements/ParsedStatement.hpp"
#include "../Script.hpp" #include "../Script.hpp"
enum class OperatorPrecedence { namespace Porygon::Parser {
No, enum class OperatorPrecedence {
LogicalOr, No,
LogicalAnd, LogicalOr,
Equality, LogicalAnd,
Additive, Equality,
Multiplication, Additive,
Unary, Multiplication,
}; Unary,
};
class Parser { class Parser {
vector<const IToken*> _tokens; vector<const IToken *> _tokens;
unsigned int _position; unsigned int _position;
Script* ScriptData; Porygon::Script *ScriptData;
const IToken* Peek(); const IToken *Peek();
const IToken *PeekAt(int offset);
const IToken* Next();
ParsedStatement* ParseStatement(const IToken* current); const IToken *PeekAt(int offset);
ParsedStatement* ParseVariableAssignment(const IToken *current);
ParsedStatement* ParseIndexAssignment(ParsedExpression *indexer);
ParsedStatement *ParseBlock(const vector<TokenKind>& endTokens, const vector<const ParsedStatement*>& openStatements = {});
ParsedStatement* ParseFunctionDeclaration(const IToken* current);
ParsedStatement *ParseReturnStatement(const IToken *current);
ParsedStatement *ParseIfStatement(const IToken *current);
ParsedExpression* ParseExpression(const IToken* current); const IToken *Next();
ParsedExpression* ParseBinaryExpression(const IToken* current, OperatorPrecedence parentPrecedence);
ParsedExpression* ParsePrimaryExpression(const IToken* current);
ParsedExpression* ParseParenthesizedExpression(const IToken *current);
ParsedExpression* ParseFunctionCallExpression(ParsedExpression* functionExpression); ParsedStatement *ParseStatement(const IToken *current);
ParsedExpression *ParseIndexExpression(ParsedExpression *indexingExpression);
ParsedExpression *ParsePeriodIndexExpression(ParsedExpression *indexingExpression);
ParsedExpression *ParseTableExpression(const IToken *current);
public:
ParsedScriptStatement* Parse();
explicit Parser(const vector<const IToken*>& tokens, Script* scriptData){
_tokens = tokens;
_position = 0;
ScriptData = scriptData;
}
}; ParsedStatement *ParseVariableAssignment(const IToken *current);
ParsedStatement *ParseIndexAssignment(ParsedExpression *indexer);
ParsedStatement *
ParseBlock(const vector<TokenKind> &endTokens, const vector<const ParsedStatement *> &openStatements = {});
ParsedStatement *ParseFunctionDeclaration(const IToken *current);
ParsedStatement *ParseReturnStatement(const IToken *current);
ParsedStatement *ParseIfStatement(const IToken *current);
ParsedExpression *ParseExpression(const IToken *current);
ParsedExpression *ParseBinaryExpression(const IToken *current, OperatorPrecedence parentPrecedence);
ParsedExpression *ParsePrimaryExpression(const IToken *current);
ParsedExpression *ParseParenthesizedExpression(const IToken *current);
ParsedExpression *ParseFunctionCallExpression(ParsedExpression *functionExpression);
ParsedExpression *ParseIndexExpression(ParsedExpression *indexingExpression);
ParsedExpression *ParsePeriodIndexExpression(ParsedExpression *indexingExpression);
ParsedExpression *ParseTableExpression(const IToken *current);
public:
ParsedScriptStatement *Parse();
explicit Parser(const vector<const IToken *> &tokens, Porygon::Script *scriptData) {
_tokens = tokens;
_position = 0;
ScriptData = scriptData;
}
};
}
#endif //PORYGONLANG_PARSER_HPP #endif //PORYGONLANG_PARSER_HPP

View File

@ -10,122 +10,119 @@
#include "../Utilities/HashedString.hpp" #include "../Utilities/HashedString.hpp"
using namespace std; using namespace std;
using namespace Porygon::Utilities;
class IToken{ namespace Porygon::Parser {
const unsigned int _position; class IToken {
const unsigned int _length; const unsigned int _position;
public: const unsigned int _length;
virtual const TokenKind GetKind() const = 0; public:
virtual const TokenKind GetKind() const = 0;
IToken(unsigned int position, unsigned int length) IToken(unsigned int position, unsigned int length)
: _position(position), _length(length) : _position(position), _length(length) {
{ }
}
const unsigned int GetStartPosition() const{ const unsigned int GetStartPosition() const {
return _position; return _position;
} }
const unsigned int GetEndPosition() const{ const unsigned int GetEndPosition() const {
return _position + _length - 1; return _position + _length - 1;
} }
const unsigned int GetLength() const{ const unsigned int GetLength() const {
return _length; return _length;
} }
virtual ~IToken() = default; virtual ~IToken() = default;
}; };
class SimpleToken : public IToken{ class SimpleToken : public IToken {
const TokenKind _kind; const TokenKind _kind;
public: public:
explicit SimpleToken(TokenKind kind, unsigned int position, unsigned int length) explicit SimpleToken(TokenKind kind, unsigned int position, unsigned int length)
: IToken(position, length), : IToken(position, length),
_kind(kind) _kind(kind) {
{ }
}
const TokenKind GetKind() const final{ const TokenKind GetKind() const final {
return _kind; return _kind;
} }
}; };
class IntegerToken : public IToken{ class IntegerToken : public IToken {
const long _value; const long _value;
public: public:
explicit IntegerToken(long value, unsigned int position, unsigned int length) explicit IntegerToken(long value, unsigned int position, unsigned int length)
: IToken(position, length), : IToken(position, length),
_value(value) _value(value) {
{ }
}
const TokenKind GetKind() const final{ const TokenKind GetKind() const final {
return TokenKind::Integer; return TokenKind::Integer;
} }
const long GetValue() const{ const long GetValue() const {
return _value; return _value;
} }
}; };
class FloatToken : public IToken{ class FloatToken : public IToken {
const double _value; const double _value;
public: public:
explicit FloatToken(double value, unsigned int position, unsigned int length) explicit FloatToken(double value, unsigned int position, unsigned int length)
: IToken(position, length), : IToken(position, length),
_value(value) _value(value) {
{ }
}
const TokenKind GetKind() const final{ const TokenKind GetKind() const final {
return TokenKind::Float; return TokenKind::Float;
} }
const double GetValue() const{ const double GetValue() const {
return _value; return _value;
} }
}; };
class StringToken : public IToken{ class StringToken : public IToken {
const u16string _value; const u16string _value;
public: public:
explicit StringToken(u16string value, unsigned int position, unsigned int length) explicit StringToken(u16string value, unsigned int position, unsigned int length)
: IToken(position, length), : IToken(position, length),
_value(std::move(value)) _value(std::move(value)) {
{ }
}
const TokenKind GetKind() const final{ const TokenKind GetKind() const final {
return TokenKind::String; return TokenKind::String;
} }
const u16string& GetValue() const{ const u16string &GetValue() const {
return _value; return _value;
} }
}; };
class IdentifierToken : public IToken{ class IdentifierToken : public IToken {
const HashedString _value; const Utilities::HashedString _value;
public: public:
explicit IdentifierToken(const HashedString value, unsigned int position, unsigned int length) explicit IdentifierToken(const HashedString value, unsigned int position, unsigned int length)
: IToken(position, length), : IToken(position, length),
_value(value) _value(value) {
{ }
}
const TokenKind GetKind() const final{ const TokenKind GetKind() const final {
return TokenKind::Identifier; return TokenKind::Identifier;
} }
const HashedString GetValue() const{ const HashedString GetValue() const {
return _value; return _value;
} }
}; };
}
#endif //PORYGONLANG_TOKEN_HPP #endif //PORYGONLANG_TOKEN_HPP

View File

@ -1,59 +1,60 @@
#ifndef PORYGONLANG_TOKENKIND_HPP #ifndef PORYGONLANG_TOKENKIND_HPP
#define PORYGONLANG_TOKENKIND_HPP #define PORYGONLANG_TOKENKIND_HPP
enum class TokenKind{ namespace Porygon::Parser {
EndOfFile, enum class TokenKind {
BadToken, EndOfFile,
WhiteSpace, BadToken,
WhiteSpace,
PlusToken, PlusToken,
MinusToken, MinusToken,
SlashToken, SlashToken,
StarToken, StarToken,
AssignmentToken, AssignmentToken,
EqualityToken, EqualityToken,
InequalityToken, InequalityToken,
Less, Less,
LessEquals, LessEquals,
Greater, Greater,
GreaterEquals, GreaterEquals,
OpenParenthesis, OpenParenthesis,
CloseParenthesis, CloseParenthesis,
OpenSquareBracket, OpenSquareBracket,
CloseSquareBracket, CloseSquareBracket,
OpenCurlyBracket, OpenCurlyBracket,
CloseCurlyBracket, CloseCurlyBracket,
PeriodToken, PeriodToken,
CommaToken, CommaToken,
Identifier, Identifier,
Integer, Integer,
Float, Float,
String, String,
AndKeyword,
BreakKeyword,
DoKeyword,
ElseKeyword,
ElseIfKeyword,
EndKeyword,
FalseKeyword,
ForKeyword,
FunctionKeyword,
IfKeyword,
InKeyword,
LocalKeyword,
NilKeyword,
NotKeyword,
OrKeyword,
ReturnKeyword,
ThenKeyword,
TrueKeyword,
WhileKeyword,
};
AndKeyword,
BreakKeyword,
DoKeyword,
ElseKeyword,
ElseIfKeyword,
EndKeyword,
FalseKeyword,
ForKeyword,
FunctionKeyword,
IfKeyword,
InKeyword,
LocalKeyword,
NilKeyword,
NotKeyword,
OrKeyword,
ReturnKeyword,
ThenKeyword,
TrueKeyword,
WhileKeyword,
};
}
#endif //PORYGONLANG_TOKENKIND_HPP #endif //PORYGONLANG_TOKENKIND_HPP

View File

@ -4,22 +4,23 @@
#include "../Utilities/HashedString.hpp" #include "../Utilities/HashedString.hpp"
class TypedVariableIdentifier{ namespace Porygon::Parser {
HashedString _type; class TypedVariableIdentifier {
HashedString _identifier; HashedString _type;
public: HashedString _identifier;
TypedVariableIdentifier(HashedString type, HashedString identifier) public:
: _type(type), _identifier(identifier) TypedVariableIdentifier(HashedString type, HashedString identifier)
{ : _type(type), _identifier(identifier) {
} }
HashedString GetType(){ HashedString GetType() {
return _type; return _type;
} }
HashedString GetIdentifier(){ HashedString GetIdentifier() {
return _identifier; return _identifier;
} }
}; };
}
#endif //PORYGONLANG_TYPEDVARIABLEIDENTIFIER_HPP #endif //PORYGONLANG_TYPEDVARIABLEIDENTIFIER_HPP

View File

@ -2,9 +2,11 @@
#ifndef PORYGONLANG_UNARYOPERATORKIND_HPP #ifndef PORYGONLANG_UNARYOPERATORKIND_HPP
#define PORYGONLANG_UNARYOPERATORKIND_HPP #define PORYGONLANG_UNARYOPERATORKIND_HPP
enum class UnaryOperatorKind{ namespace Porygon::Parser {
Identity, enum class UnaryOperatorKind {
Negation, Identity,
LogicalNegation, Negation,
}; LogicalNegation,
};
}
#endif //PORYGONLANG_UNARYOPERATORKIND_HPP #endif //PORYGONLANG_UNARYOPERATORKIND_HPP

View File

@ -9,7 +9,7 @@
#include "Parser/Parser.hpp" #include "Parser/Parser.hpp"
#include "Binder/Binder.hpp" #include "Binder/Binder.hpp"
Script* Script::Create(const u16string& script) { Porygon::Script* Porygon::Script::Create(const u16string& script) {
auto s = new Script(); auto s = new Script();
s -> Parse(script); s -> Parse(script);
return s; return s;
@ -20,22 +20,22 @@ std::u16string To_UTF16(const string &s)
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> conv; std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> conv;
return conv.from_bytes(s); return conv.from_bytes(s);
} }
Script *Script::Create(const string &script) { Porygon::Script *Porygon::Script::Create(const string &script) {
return Script::Create(To_UTF16(script)); return Script::Create(To_UTF16(script));
} }
Script::Script() { Porygon::Script::Script() {
Diagnostics = new DiagnosticsHolder(); Diagnostics = new DiagnosticsHolder();
_evaluator = new Evaluator(this);
_boundScript = nullptr; _boundScript = nullptr;
_scriptVariables = new unordered_map<uint32_t, shared_ptr<EvalValue>>(0); _scriptVariables = new unordered_map<uint32_t, shared_ptr<EvalValue>>(0);
_evaluator = new Evaluator(this -> _scriptVariables);
} }
EvalValue* Script::Evaluate() { EvalValue* Porygon::Script::Evaluate() {
return _evaluator->Evaluate(_boundScript); return _evaluator->Evaluate(_boundScript);
} }
Script::~Script() { Porygon::Script::~Script() {
delete this -> Diagnostics; delete this -> Diagnostics;
delete this -> _boundScript; delete this -> _boundScript;
delete this -> _evaluator; delete this -> _evaluator;
@ -43,10 +43,10 @@ Script::~Script() {
delete this->_scriptVariables; delete this->_scriptVariables;
} }
void Script::Parse(const u16string& script) { void Porygon::Script::Parse(const u16string& script) {
auto lexer = Lexer(script, this); auto lexer = Lexer(script, this);
auto lexResult = lexer.Lex(); auto lexResult = lexer.Lex();
auto parser = Parser(lexResult, this); auto parser = Parser::Parser(lexResult, this);
auto parseResult = parser.Parse(); auto parseResult = parser.Parse();
for (auto token : lexResult){ for (auto token : lexResult){
delete token; delete token;
@ -55,7 +55,7 @@ void Script::Parse(const u16string& script) {
if (!Diagnostics->HasErrors()){ if (!Diagnostics->HasErrors()){
unordered_map<uint32_t, BoundVariable*> scriptScope; unordered_map<uint32_t, BoundVariable*> scriptScope;
auto bindScope = new BoundScope(&scriptScope); auto bindScope = new BoundScope(&scriptScope);
this->_boundScript = Binder::Bind(this, parseResult, bindScope); this->_boundScript = Binder::Binder::Bind(this, parseResult, bindScope);
for (const auto& v : scriptScope){ for (const auto& v : scriptScope){
this->_scriptVariables -> insert({v.first, nullptr}); this->_scriptVariables -> insert({v.first, nullptr});
delete v.second; delete v.second;
@ -65,59 +65,57 @@ void Script::Parse(const u16string& script) {
delete parseResult; delete parseResult;
} }
EvalValue *Script::GetVariable(const u16string &key) { EvalValue *Porygon::Script::GetVariable(const u16string &key) {
return _scriptVariables -> at(HashedString(key).GetHash()).get(); return _scriptVariables -> at(HashedString(key).GetHash()).get();
} }
bool Script::HasVariable(const u16string &key) { bool Porygon::Script::HasVariable(const u16string &key) {
auto f = _scriptVariables->find(HashedString(key).GetHash()); auto f = _scriptVariables->find(HashedString(key).GetHash());
return f != _scriptVariables->end(); return f != _scriptVariables->end();
} }
EvalValue *Script::GetLastValue() { EvalValue *Porygon::Script::GetLastValue() {
return _evaluator->GetLastValue(); return _evaluator->GetLastValue();
} }
bool Script::HasFunction(const u16string &key) { bool Porygon::Script::HasFunction(const u16string &key) {
auto f = _scriptVariables->find(HashedString(key).GetHash()); auto f = _scriptVariables->find(HashedString(key).GetHash());
return f != _scriptVariables->end() && f.operator->()->second->GetTypeClass() == TypeClass ::Function; return f != _scriptVariables->end() && f.operator->()->second->GetTypeClass() == TypeClass ::Function;
} }
shared_ptr<EvalValue> Script::CallFunction(const u16string &key, const vector<EvalValue *>& variables) { shared_ptr<EvalValue> Porygon::Script::CallFunction(const u16string &key, const vector<EvalValue *>& variables) {
auto var = (ScriptFunctionEvalValue*)GetVariable(key); auto var = (ScriptFunctionEvalValue*)GetVariable(key);
return this->_evaluator->EvaluateFunction(var, variables); return this->_evaluator->EvaluateFunction(var, variables);
} }
extern "C" { extern "C" {
Script* CreateScript(char16_t * s){ Porygon::Script* CreateScript(char16_t * s){
return Script::Create(s); return Porygon::Script::Create(s);
} }
void EvaluateScript(Script* script){ void EvaluateScript(Porygon::Script* script){
script->Evaluate(); script->Evaluate();
} }
EvalValue* GetLastValue(Script* script){ EvalValue* GetLastValue(Porygon::Script* script){
return script->GetLastValue(); return script->GetLastValue();
} }
bool HasVariable(Script* script, const char16_t* key){ bool HasVariable(Porygon::Script* script, const char16_t* key){
return script->HasVariable(key); return script->HasVariable(key);
} }
EvalValue* GetVariable(Script* script, const char16_t* key){ EvalValue* GetVariable(Porygon::Script* script, const char16_t* key){
return script->GetVariable(key); return script->GetVariable(key);
} }
bool HasFunction(Script* script, const char16_t* key){ bool HasFunction(Porygon::Script* script, const char16_t* key){
return script->HasFunction(key); return script->HasFunction(key);
} }
EvalValue* CallFunction(Script* script, const char16_t* key, EvalValue* parameters[], int parameterCount){ 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).get();
} }
} }

View File

@ -1,3 +1,5 @@
#include <utility>
#ifndef PORYGONLANG_SCRIPT_HPP #ifndef PORYGONLANG_SCRIPT_HPP
#define PORYGONLANG_SCRIPT_HPP #define PORYGONLANG_SCRIPT_HPP
@ -6,49 +8,49 @@
#include <unordered_map> #include <unordered_map>
#include "Diagnostics/DiagnosticsHolder.hpp" #include "Diagnostics/DiagnosticsHolder.hpp"
#include "Binder/BoundStatements/BoundStatement.hpp" #include "Binder/BoundStatements/BoundStatement.hpp"
class Script;
class Evaluator;
#include "Evaluator/Evaluator.hpp" #include "Evaluator/Evaluator.hpp"
#include "Evaluator/EvalValues/EvalValue.hpp" #include "Evaluator/EvalValues/EvalValue.hpp"
#include "Utilities/HashedString.hpp" #include "Utilities/HashedString.hpp"
using namespace std; using namespace std;
using namespace Porygon::Evaluation;
class Script { namespace Porygon{
friend class Evaluator; class Script {
Evaluator* _evaluator;
unordered_map<uint32_t, shared_ptr<EvalValue>>* _scriptVariables;
Binder::BoundScriptStatement* _boundScript;
shared_ptr<ScriptType> _returnType;
Evaluator* _evaluator; explicit Script();
unordered_map<uint32_t, shared_ptr<EvalValue>>* _scriptVariables; void Parse(const u16string& script);
BoundScriptStatement* _boundScript; public:
shared_ptr<ScriptType> _returnType; static Script* Create(const u16string& script);
static Script* Create(const string& script);
DiagnosticsHolder* Diagnostics;
explicit Script(); ~Script();
void Parse(const u16string& script);
public:
static Script* Create(const u16string& script);
static Script* Create(const string& script);
DiagnosticsHolder* Diagnostics;
~Script(); shared_ptr<ScriptType> GetReturnType(){
return _returnType;
}
shared_ptr<ScriptType> GetReturnType(){ void SetReturnType(shared_ptr<ScriptType> t){
return _returnType; _returnType = std::move(t);
} }
void SetReturnType(shared_ptr<ScriptType> t){ EvalValue* Evaluate();
_returnType = t;
}
EvalValue* Evaluate(); EvalValue* GetLastValue();
EvalValue* GetLastValue(); EvalValue* GetVariable(const u16string& key);
bool HasVariable(const u16string& key);
EvalValue* GetVariable(const u16string& key); shared_ptr<EvalValue> CallFunction(const u16string& key, const vector<EvalValue*>& variables);
bool HasVariable(const u16string& key); bool HasFunction(const u16string& key);
};
shared_ptr<EvalValue> CallFunction(const u16string& key, const vector<EvalValue*>& variables); }
bool HasFunction(const u16string& key);
};
#endif //PORYGONLANG_SCRIPT_HPP #endif //PORYGONLANG_SCRIPT_HPP

View File

@ -1,27 +1,30 @@
#include "Script.hpp" #include "Script.hpp"
const bool ScriptType::CanBeIndexedWith(ScriptType *indexer) const{ namespace Porygon{
// String type is the only simple script type we want to const bool ScriptType::CanBeIndexedWith(ScriptType *indexer) const{
return _class == TypeClass::String && indexer->_class == TypeClass::Number && !((NumericScriptType*)indexer)->IsFloat(); // String type is the only simple script type we want to
return _class == TypeClass::String && indexer->_class == TypeClass::Number && !((NumericScriptType*)indexer)->IsFloat();
}
const shared_ptr<ScriptType> ScriptType::GetIndexedType(ScriptType *indexer) const{
if (_class == TypeClass::String){
return make_shared<ScriptType>(TypeClass::String);
}
return make_shared<ScriptType>(TypeClass::Error);
}
extern "C"{
ScriptType* CreateScriptType(Porygon::TypeClass t){
return new ScriptType(t);
}
ScriptType* CreateNumericScriptType(bool isAware, bool isFloat){
return new NumericScriptType(isAware, isFloat);
}
ScriptType* CreateStringScriptType(bool knownAtBind, uint32_t hash){
return new StringScriptType(knownAtBind, hash);
}
}
} }
const shared_ptr<ScriptType> ScriptType::GetIndexedType(ScriptType *indexer) const{
if (_class == TypeClass::String){
return make_shared<ScriptType>(TypeClass::String);
}
return make_shared<ScriptType>(TypeClass::Error);
}
extern "C"{
ScriptType* CreateScriptType(TypeClass t){
return new ScriptType(t);
}
ScriptType* CreateNumericScriptType(bool isAware, bool isFloat){
return new NumericScriptType(isAware, isFloat);
}
ScriptType* CreateStringScriptType(bool knownAtBind, uint32_t hash){
return new StringScriptType(knownAtBind, hash);
}
}

View File

@ -12,145 +12,147 @@
using namespace std; using namespace std;
enum class TypeClass{ namespace Porygon{
Error, enum class TypeClass{
Nil, Error,
Number, Nil,
Bool, Number,
String, Bool,
Function, String,
UserData, Function,
Table, UserData,
}; Table,
class ScriptType{
TypeClass _class;
public:
explicit ScriptType(TypeClass c){
_class = c;
}
virtual ~ScriptType() = default;
const TypeClass GetClass() const{
return _class;
}
virtual bool operator ==(const ScriptType& b) const{
return _class == b._class;
}; };
virtual bool operator ==(ScriptType* b) const{ class ScriptType{
return _class == b->_class; TypeClass _class;
public:
explicit ScriptType(TypeClass c){
_class = c;
}
virtual ~ScriptType() = default;
const TypeClass GetClass() const{
return _class;
}
virtual bool operator ==(const ScriptType& b) const{
return _class == b._class;
};
virtual bool operator ==(ScriptType* b) const{
return _class == b->_class;
};
virtual bool operator !=(const ScriptType& b) const{
return ! (operator==(b));
}
virtual bool operator !=(ScriptType* b) const{
return ! (operator==(b));
}
virtual const bool CanBeIndexedWith(ScriptType* indexer) const;
virtual const bool CanBeIndexedWithIdentifier(uint32_t hash) const{
return false;
}
virtual const shared_ptr<ScriptType> GetIndexedType(ScriptType* indexer) const;
virtual const shared_ptr<ScriptType> GetIndexedType(uint32_t hash) const{
throw "Shouldn't be possible";
}
}; };
virtual bool operator !=(const ScriptType& b) const{ class NumericScriptType : public ScriptType{
return ! (operator==(b)); // Are we aware of whether this is a float or not?
} bool _awareOfFloat;
virtual bool operator !=(ScriptType* b) const{ // Is this value a float?
return ! (operator==(b)); bool _isFloat;
} public:
explicit NumericScriptType(bool floatAware, bool isFloat) : ScriptType(TypeClass::Number){
_awareOfFloat = floatAware;
_isFloat = isFloat;
}
virtual const bool CanBeIndexedWith(ScriptType* indexer) const; const bool IsAwareOfFloat() const{
virtual const bool CanBeIndexedWithIdentifier(uint32_t hash) const{ return _awareOfFloat;
return false; }
}
virtual const shared_ptr<ScriptType> GetIndexedType(ScriptType* indexer) const; const bool IsFloat() const{
virtual const shared_ptr<ScriptType> GetIndexedType(uint32_t hash) const{ return _isFloat;
throw "Shouldn't be possible"; }
} };
};
class NumericScriptType : public ScriptType{ class StringScriptType : public ScriptType{
// Are we aware of whether this is a float or not? bool _isKnownAtBind;
bool _awareOfFloat; uint32_t _hashValue;
// Is this value a float? public:
bool _isFloat; explicit StringScriptType(bool knownAtBind, uint32_t hashValue): ScriptType(TypeClass::String){
public: _isKnownAtBind = knownAtBind;
explicit NumericScriptType(bool floatAware, bool isFloat) : ScriptType(TypeClass::Number){ _hashValue = hashValue;
_awareOfFloat = floatAware; }
_isFloat = isFloat;
}
const bool IsAwareOfFloat() const{ const bool IsKnownAtBind() const{
return _awareOfFloat; return _isKnownAtBind;
} }
const bool IsFloat() const{ const uint32_t GetHashValue() const{
return _isFloat; return _hashValue;
} }
}; };
class StringScriptType : public ScriptType{ class FunctionScriptType : public ScriptType{
bool _isKnownAtBind; shared_ptr<ScriptType> _returnType;
uint32_t _hashValue; vector<shared_ptr<ScriptType>> _parameterTypes;
public: vector<shared_ptr<Binder::BoundVariableKey>> _parameterKeys;
explicit StringScriptType(bool knownAtBind, uint32_t hashValue): ScriptType(TypeClass::String){ int _scopeIndex;
_isKnownAtBind = knownAtBind; public:
_hashValue = hashValue; FunctionScriptType(std::shared_ptr<ScriptType> returnType, vector<shared_ptr<ScriptType>> parameterTypes,
} vector<shared_ptr<Binder::BoundVariableKey>> parameterKeys, int scopeIndex)
: ScriptType(TypeClass::Function){
_returnType = std::move(returnType);
_parameterTypes = std::move(parameterTypes);
_parameterKeys = std::move(parameterKeys);
_scopeIndex = scopeIndex;
}
const shared_ptr<ScriptType> GetReturnType() const{
return _returnType;
}
const bool IsKnownAtBind() const{ void SetReturnType(shared_ptr<ScriptType> t){
return _isKnownAtBind; _returnType = std::move(t);
} }
const uint32_t GetHashValue() const{ const vector<shared_ptr<ScriptType>> GetParameterTypes() const{
return _hashValue; return _parameterTypes;
} }
};
class FunctionScriptType : public ScriptType{ const vector<shared_ptr<Binder::BoundVariableKey>> GetParameterKeys() const{
shared_ptr<ScriptType> _returnType; return _parameterKeys;
vector<shared_ptr<ScriptType>> _parameterTypes; }
vector<shared_ptr<BoundVariableKey>> _parameterKeys;
int _scopeIndex;
public:
FunctionScriptType(std::shared_ptr<ScriptType> returnType, vector<shared_ptr<ScriptType>> parameterTypes,
vector<shared_ptr<BoundVariableKey>> parameterKeys, int scopeIndex)
: ScriptType(TypeClass::Function){
_returnType = std::move(returnType);
_parameterTypes = std::move(parameterTypes);
_parameterKeys = std::move(parameterKeys);
_scopeIndex = scopeIndex;
}
const shared_ptr<ScriptType> GetReturnType() const{
return _returnType;
}
void SetReturnType(shared_ptr<ScriptType> t){ const int GetScopeIndex() const{
_returnType = std::move(t); return _scopeIndex;
} }
};
const vector<shared_ptr<ScriptType>> GetParameterTypes() const{ class NumericalTableScriptType : public ScriptType{
return _parameterTypes; shared_ptr<ScriptType> _valueType;
} // Consider adding a check whether the table actually contains a type if every key is static.
public:
explicit NumericalTableScriptType(shared_ptr<ScriptType> valueType) : ScriptType(TypeClass::Table){
_valueType = std::move(valueType);
}
const vector<shared_ptr<BoundVariableKey>> GetParameterKeys() const{ const bool CanBeIndexedWith(ScriptType* indexer) const final{
return _parameterKeys; return indexer->GetClass() == TypeClass ::Number;
} }
const int GetScopeIndex() const{ const shared_ptr<ScriptType> GetIndexedType(ScriptType* indexer) const final{
return _scopeIndex; return _valueType;
} }
}; };
}
class NumericalTableScriptType : public ScriptType{
shared_ptr<ScriptType> _valueType;
// Consider adding a check whether the table actually contains a type if every key is static.
public:
explicit NumericalTableScriptType(shared_ptr<ScriptType> valueType) : ScriptType(TypeClass::Table){
_valueType = std::move(valueType);
}
const bool CanBeIndexedWith(ScriptType* indexer) const final{
return indexer->GetClass() == TypeClass ::Number;
}
const shared_ptr<ScriptType> GetIndexedType(ScriptType* indexer) const final{
return _valueType;
}
};
#endif //PORYGONLANG_SCRIPTTYPE_HPP #endif //PORYGONLANG_SCRIPTTYPE_HPP

View File

@ -4,52 +4,54 @@
#include <unordered_map> #include <unordered_map>
#include "Binder/BoundVariables/BoundVariable.hpp" #include "Binder/BoundVariables/BoundVariable.hpp"
class TableScriptType : public ScriptType{ namespace Porygon{
const unordered_map<uint32_t, BoundVariable*>* _values; class TableScriptType : public ScriptType{
const int _localVariableCount; const unordered_map<uint32_t, BoundVariable*>* _values;
public: const int _localVariableCount;
explicit TableScriptType(unordered_map<uint32_t, BoundVariable*>* values, int localVariableCount) public:
: ScriptType(TypeClass::Table), explicit TableScriptType(unordered_map<uint32_t, BoundVariable*>* values, int localVariableCount)
_values(values), : ScriptType(TypeClass::Table),
_localVariableCount(localVariableCount) _values(values),
_localVariableCount(localVariableCount)
{} {}
~TableScriptType() final{ ~TableScriptType() final{
for (auto i : *_values){ for (auto i : *_values){
delete i.second; delete i.second;
}
delete _values;
} }
delete _values;
}
const bool CanBeIndexedWith(ScriptType* indexer) const final{ const bool CanBeIndexedWith(ScriptType* indexer) const final{
return indexer->GetClass() == TypeClass ::String; return indexer->GetClass() == TypeClass ::String;
}
const bool CanBeIndexedWithIdentifier(uint32_t hash) const final{
return true;
}
const shared_ptr<ScriptType> GetIndexedType(ScriptType* indexer) const final{
auto stringKey = (StringScriptType*)indexer;
if (stringKey->IsKnownAtBind()){
return _values-> at(stringKey->GetHashValue())->GetType();
} }
throw "TODO: indexing with dynamic keys";
}
const shared_ptr<ScriptType> GetIndexedType(uint32_t hash) const final{ const bool CanBeIndexedWithIdentifier(uint32_t hash) const final{
return _values-> at(hash)->GetType(); return true;
} }
const unordered_map<uint32_t, BoundVariable*>* GetValues() const{ const shared_ptr<ScriptType> GetIndexedType(ScriptType* indexer) const final{
return _values; auto stringKey = (StringScriptType*)indexer;
} if (stringKey->IsKnownAtBind()){
return _values-> at(stringKey->GetHashValue())->GetType();
}
throw "TODO: indexing with dynamic keys";
}
const int GetLocalVariableCount() const{ const shared_ptr<ScriptType> GetIndexedType(uint32_t hash) const final{
return _localVariableCount; return _values-> at(hash)->GetType();
} }
}; const unordered_map<uint32_t, BoundVariable*>* GetValues() const{
return _values;
}
const int GetLocalVariableCount() const{
return _localVariableCount;
}
};
}
#include "ScriptType.hpp" #include "ScriptType.hpp"

View File

@ -2,19 +2,21 @@
#include "UserData.hpp" #include "UserData.hpp"
#include "UserDataStorage.hpp" #include "UserDataStorage.hpp"
extern "C"{ namespace Porygon::UserData {
void RegisterUserDataType(uint32_t id){ extern "C" {
void RegisterUserDataType(uint32_t id) {
auto ud = new UserData({}); auto ud = new UserData({});
UserDataStorage::RegisterType(id, ud); UserDataStorage::RegisterType(id, ud);
} }
void RegisterUserDataField(uint32_t typeId, uint32_t fieldId, UserDataField* field){ void RegisterUserDataField(uint32_t typeId, uint32_t fieldId, UserDataField *field) {
auto ud = UserDataStorage::GetUserDataType(typeId); auto ud = UserDataStorage::GetUserDataType(typeId);
ud -> CreateField(fieldId, field); ud->CreateField(fieldId, field);
} }
int32_t GetUserDataFieldCount(uint32_t typeId){ int32_t GetUserDataFieldCount(uint32_t typeId) {
auto ud = UserDataStorage::GetUserDataType(typeId); auto ud = UserDataStorage::GetUserDataType(typeId);
return ud ->GetFieldCount(); return ud->GetFieldCount();
}
} }
} }

View File

@ -5,29 +5,31 @@
#include <unordered_map> #include <unordered_map>
#include "UserDataField.hpp" #include "UserDataField.hpp"
class UserData { namespace Porygon::UserData {
std::unordered_map<uint32_t, UserDataField*> _fields; class UserData {
public: std::unordered_map<uint32_t, UserDataField *> _fields;
explicit UserData(std::unordered_map<uint32_t, UserDataField*> fields){ public:
_fields = std::move(fields); explicit UserData(std::unordered_map<uint32_t, UserDataField *> fields) {
} _fields = std::move(fields);
}
bool ContainsField(uint32_t fieldId){ bool ContainsField(uint32_t fieldId) {
return _fields.find(fieldId) != _fields.end(); return _fields.find(fieldId) != _fields.end();
} }
UserDataField* GetField(uint32_t fieldId){ UserDataField *GetField(uint32_t fieldId) {
return _fields[fieldId]; return _fields[fieldId];
} }
void CreateField(uint32_t fieldId, UserDataField* field){ void CreateField(uint32_t fieldId, UserDataField *field) {
_fields.insert({fieldId, field}); _fields.insert({fieldId, field});
} }
int32_t GetFieldCount(){ int32_t GetFieldCount() {
return _fields.size(); return _fields.size();
} }
}; };
}
#endif //PORYGONLANG_USERDATA_HPP #endif //PORYGONLANG_USERDATA_HPP

View File

@ -1,8 +1,11 @@
#include "UserDataField.hpp" #include "UserDataField.hpp"
extern "C"{ namespace Porygon::UserData {
UserDataField* CreateUserDataField(ScriptType* type, EvalValue* (*getter)(void* obj), void (*setter)(void* obj, EvalValue* val)){ extern "C" {
UserDataField *
CreateUserDataField(ScriptType *type, Evaluation::EvalValue *(*getter)(void *obj), void (*setter)(void *obj, Evaluation::EvalValue *val)) {
return new UserDataField(type, getter, setter); return new UserDataField(type, getter, setter);
} }
}
} }

View File

@ -6,37 +6,39 @@
#include "../Evaluator/EvalValues/EvalValue.hpp" #include "../Evaluator/EvalValues/EvalValue.hpp"
#include "../Evaluator/EvalValues/NumericEvalValue.hpp" #include "../Evaluator/EvalValues/NumericEvalValue.hpp"
class UserDataField { namespace Porygon::UserData{
shared_ptr<ScriptType> _type; class UserDataField {
EvalValue* (*_get)(void* obj); shared_ptr<ScriptType> _type;
void (*_set)(void* obj, EvalValue* val); Evaluation::EvalValue* (*_get)(void* obj);
public: void (*_set)(void* obj, Evaluation::EvalValue* val);
UserDataField(ScriptType* type, EvalValue* (*getter)(void* obj), void (*setter)(void* obj, EvalValue* val)){ public:
_type = shared_ptr<ScriptType>(type); UserDataField(ScriptType* type, Evaluation::EvalValue* (*getter)(void* obj), void (*setter)(void* obj, Evaluation::EvalValue* val)){
_get = getter; _type = shared_ptr<ScriptType>(type);
_set = setter; _get = getter;
} _set = setter;
}
shared_ptr<ScriptType> GetType(){ shared_ptr<ScriptType> GetType(){
return _type; return _type;
} }
bool HasGetter(){ bool HasGetter(){
return _get != nullptr; return _get != nullptr;
} }
EvalValue* Get(void* obj){ Evaluation::EvalValue* Get(void* obj){
return this ->_get(obj); return this ->_get(obj);
} }
bool HasSetter(){ bool HasSetter(){
return _set != nullptr; return _set != nullptr;
} }
void Set(void* obj, EvalValue* val){ void Set(void* obj, Evaluation::EvalValue* val){
this->_set(obj, val); this->_set(obj, val);
} }
}; };
}
#endif //PORYGONLANG_USERDATAFIELD_HPP #endif //PORYGONLANG_USERDATAFIELD_HPP

View File

@ -8,46 +8,49 @@
#include "UserData.hpp" #include "UserData.hpp"
#include "UserDataStorage.hpp" #include "UserDataStorage.hpp"
class UserDataScriptType : public ScriptType{ namespace Porygon::UserData {
shared_ptr<UserData> _userData; class UserDataScriptType : public ScriptType {
public: shared_ptr<UserData> _userData;
explicit UserDataScriptType(uint32_t id) : ScriptType(TypeClass::UserData){ public:
_userData = UserDataStorage::GetUserDataType(id); explicit UserDataScriptType(uint32_t id) : ScriptType(TypeClass::UserData) {
} _userData = UserDataStorage::GetUserDataType(id);
explicit UserDataScriptType(shared_ptr<UserData> ud) : ScriptType(TypeClass::UserData){
_userData = std::move(ud);
}
const bool CanBeIndexedWith(ScriptType* indexer) const final{
if (indexer->GetClass() != TypeClass ::String){
return false;
} }
auto str = (StringScriptType*)indexer;
if (!str->IsKnownAtBind())
return false;
return _userData->ContainsField(str->GetHashValue());
}
const bool CanBeIndexedWithIdentifier(uint32_t hash) const final{ explicit UserDataScriptType(shared_ptr<UserData> ud) : ScriptType(TypeClass::UserData) {
return true; _userData = std::move(ud);
}
UserDataField* GetField(uint32_t id){
return _userData -> GetField(id);
}
const shared_ptr<ScriptType> GetIndexedType(ScriptType* indexer) const final{
auto stringKey = (StringScriptType*)indexer;
if (stringKey->IsKnownAtBind()){
return _userData->GetField(stringKey->GetHashValue())->GetType();
} }
throw "TODO: indexing with dynamic keys";
}
const shared_ptr<ScriptType> GetIndexedType(uint32_t hash) const final{ const bool CanBeIndexedWith(ScriptType *indexer) const final {
return _userData->GetField(hash)->GetType(); if (indexer->GetClass() != TypeClass::String) {
} return false;
}; }
auto str = (StringScriptType *) indexer;
if (!str->IsKnownAtBind())
return false;
return _userData->ContainsField(str->GetHashValue());
}
const bool CanBeIndexedWithIdentifier(uint32_t hash) const final {
return true;
}
UserDataField *GetField(uint32_t id) {
return _userData->GetField(id);
}
const shared_ptr<ScriptType> GetIndexedType(ScriptType *indexer) const final {
auto stringKey = (StringScriptType *) indexer;
if (stringKey->IsKnownAtBind()) {
return _userData->GetField(stringKey->GetHashValue())->GetType();
}
throw "TODO: indexing with dynamic keys";
}
const shared_ptr<ScriptType> GetIndexedType(uint32_t hash) const final {
return _userData->GetField(hash)->GetType();
}
};
}
#endif //PORYGONLANG_USERDATASCRIPTTYPE_HPP #endif //PORYGONLANG_USERDATASCRIPTTYPE_HPP

View File

@ -1,4 +1,6 @@
#include "UserDataStorage.hpp" #include "UserDataStorage.hpp"
UserDataStorage::_internalDataStorage UserDataStorage::_internal = UserDataStorage::_internalDataStorage(); namespace Porygon::UserData {
UserDataStorage::_internalDataStorage UserDataStorage::_internal = UserDataStorage::_internalDataStorage();
}

View File

@ -5,26 +5,28 @@
#include <unordered_map> #include <unordered_map>
#include "UserData.hpp" #include "UserData.hpp"
class UserDataStorage { namespace Porygon::UserData {
class _internalDataStorage{ class UserDataStorage {
class _internalDataStorage {
public:
std::unordered_map<uint32_t, shared_ptr<UserData>> _userData;
};
static _internalDataStorage _internal;
public: public:
std::unordered_map<uint32_t, shared_ptr<UserData>> _userData; static void RegisterType(uint32_t i, UserData *ud) {
UserDataStorage::_internal._userData.insert({i, shared_ptr<UserData>(ud)});
}
static bool HasUserDataType(uint32_t i) {
return UserDataStorage::_internal._userData.find(i) != UserDataStorage::_internal._userData.end();
}
static shared_ptr<UserData> GetUserDataType(uint32_t i) {
return UserDataStorage::_internal._userData[i];
}
}; };
static _internalDataStorage _internal; }
public:
static void RegisterType(uint32_t i, UserData* ud){
UserDataStorage::_internal._userData.insert({i, shared_ptr<UserData>(ud)});
}
static bool HasUserDataType(uint32_t i){
return UserDataStorage::_internal._userData.find(i) != UserDataStorage::_internal._userData.end();
}
static shared_ptr<UserData> GetUserDataType(uint32_t i){
return UserDataStorage::_internal._userData[i];
}
};
#endif //PORYGONLANG_USERDATASTORAGE_HPP #endif //PORYGONLANG_USERDATASTORAGE_HPP

View File

@ -1,8 +1,10 @@
#include "UserDataValue.hpp" #include "UserDataValue.hpp"
extern "C"{ namespace Porygon::UserData {
UserDataValue* CreateUserDataEvalValue(uint32_t typeHash, void* obj){ extern "C" {
UserDataValue *CreateUserDataEvalValue(uint32_t typeHash, void *obj) {
return new UserDataValue(typeHash, obj); return new UserDataValue(typeHash, obj);
} }
}
} }

View File

@ -7,57 +7,56 @@
#include "UserData.hpp" #include "UserData.hpp"
#include "UserDataStorage.hpp" #include "UserDataStorage.hpp"
class UserDataValue : public EvalValue{ namespace Porygon::UserData {
const shared_ptr<UserData> _userData; class UserDataValue : public Evaluation::EvalValue {
void* _obj; const shared_ptr<UserData> _userData;
public: void *_obj;
UserDataValue(shared_ptr<UserData> userData, void* obj) public:
: _userData(std::move(userData)) UserDataValue(shared_ptr<UserData> userData, void *obj)
{ : _userData(std::move(userData)) {
_obj = obj; _obj = obj;
} }
UserDataValue(uint32_t userDataId, void* obj) UserDataValue(uint32_t userDataId, void *obj)
: _userData(UserDataStorage::GetUserDataType(userDataId)) : _userData(UserDataStorage::GetUserDataType(userDataId)) {
{ _obj = obj;
_obj = obj; }
}
const TypeClass GetTypeClass() const final{ const TypeClass GetTypeClass() const final {
return TypeClass ::UserData; return TypeClass::UserData;
} }
const bool operator ==(EvalValue* b) const final { const bool operator==(EvalValue *b) const final {
if (b->GetTypeClass() != TypeClass::UserData) if (b->GetTypeClass() != TypeClass::UserData)
return false; return false;
return _obj == ((UserDataValue*)b)->_obj; return _obj == ((UserDataValue *) b)->_obj;
} }
const shared_ptr<EvalValue> Clone() const final{ const shared_ptr<EvalValue> Clone() const final {
return make_shared<UserDataValue>(_userData, _obj); return make_shared<UserDataValue>(_userData, _obj);
} }
const std::size_t GetHashCode() const final{ const std::size_t GetHashCode() const final {
return reinterpret_cast<intptr_t>(_obj); return reinterpret_cast<intptr_t>(_obj);
} }
const shared_ptr<EvalValue> IndexValue(EvalValue* val) const final { const shared_ptr<EvalValue> IndexValue(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<EvalValue>(field->Get(_obj)); return shared_ptr<EvalValue>(field->Get(_obj));
} }
const shared_ptr<EvalValue> IndexValue(uint32_t hash) const final{ const shared_ptr<EvalValue> IndexValue(uint32_t hash) const final {
auto field = _userData->GetField(hash); auto field = _userData->GetField(hash);
return shared_ptr<EvalValue>(field->Get(_obj)); return shared_ptr<EvalValue>(field->Get(_obj));
} }
void SetIndexValue(EvalValue *key, const shared_ptr<EvalValue>& value) const final{
auto fieldId = key->GetHashCode();
auto field = _userData->GetField(fieldId);
field -> Set(_obj, value.get());
}
};
void SetIndexValue(EvalValue *key, const shared_ptr<EvalValue> &value) const final {
auto fieldId = key->GetHashCode();
auto field = _userData->GetField(fieldId);
field->Set(_obj, value.get());
}
};
}
#endif //PORYGONLANG_USERDATAVALUE_HPP #endif //PORYGONLANG_USERDATAVALUE_HPP

View File

@ -4,41 +4,43 @@
#include <string> #include <string>
class HashedString{ namespace Porygon::Utilities{
const uint32_t _hash; class HashedString{
public: const uint32_t _hash;
explicit HashedString(const std::u16string& s) : _hash(ConstHash(s.c_str())){ public:
} explicit HashedString(const std::u16string& s) : _hash(ConstHash(s.c_str())){
explicit HashedString(char16_t const *input) : _hash(ConstHash(input)){ }
} explicit HashedString(char16_t const *input) : _hash(ConstHash(input)){
}
explicit HashedString(char const *input) : _hash(ConstHash(input)){ explicit HashedString(char const *input) : _hash(ConstHash(input)){
} }
HashedString(const HashedString& b) = default; HashedString(const HashedString& b) = default;
static uint32_t constexpr ConstHash(char16_t const *input) { static uint32_t constexpr ConstHash(char16_t const *input) {
return *input ? return *input ?
static_cast<uint32_t>(*input) + 33 * ConstHash(input + 1) : static_cast<uint32_t>(*input) + 33 * ConstHash(input + 1) :
5381; 5381;
} }
static uint32_t constexpr ConstHash(char const *input) { static uint32_t constexpr ConstHash(char const *input) {
return *input ? return *input ?
static_cast<uint32_t>(*input) + 33 * ConstHash(input + 1) : static_cast<uint32_t>(*input) + 33 * ConstHash(input + 1) :
5381; 5381;
} }
const uint32_t GetHash() const{ const uint32_t GetHash() const{
return _hash; return _hash;
} }
bool operator==(const HashedString& b) const{ bool operator==(const HashedString& b) const{
return _hash == b._hash; return _hash == b._hash;
} }
bool operator!=(const HashedString& b) const{ bool operator!=(const HashedString& b) const{
return _hash != b._hash; return _hash != b._hash;
} }
}; };
}
#endif //PORYGONLANG_HASHEDSTRING_HPP #endif //PORYGONLANG_HASHEDSTRING_HPP

View File

@ -2,6 +2,8 @@
#include <catch.hpp> #include <catch.hpp>
#include "../src/Script.hpp" #include "../src/Script.hpp"
using namespace Porygon;
TEST_CASE( "Basic conditional", "[integration]" ) { TEST_CASE( "Basic conditional", "[integration]" ) {
Script* script = Script::Create("if true then foo = true end"); Script* script = Script::Create("if true then foo = true end");
REQUIRE(!script->Diagnostics -> HasErrors()); REQUIRE(!script->Diagnostics -> HasErrors());

View File

@ -3,6 +3,7 @@
#include <catch.hpp> #include <catch.hpp>
#include "../src/Script.hpp" #include "../src/Script.hpp"
using namespace Porygon;
TEST_CASE( "Diagnostic invalid character", "[integration]" ) { TEST_CASE( "Diagnostic invalid character", "[integration]" ) {
auto script = Script::Create("1 + 1 @"); auto script = Script::Create("1 + 1 @");
REQUIRE(script->Diagnostics -> HasErrors()); REQUIRE(script->Diagnostics -> HasErrors());

View File

@ -3,6 +3,7 @@
#include <catch.hpp> #include <catch.hpp>
#include "../src/Script.hpp" #include "../src/Script.hpp"
using namespace Porygon;
TEST_CASE( "True Equals True", "[integration]" ) { TEST_CASE( "True Equals True", "[integration]" ) {
auto script = Script::Create("true == true"); auto script = Script::Create("true == true");
REQUIRE(!script->Diagnostics -> HasErrors()); REQUIRE(!script->Diagnostics -> HasErrors());

View File

@ -2,6 +2,8 @@
#include <catch.hpp> #include <catch.hpp>
#include "../src/Script.hpp" #include "../src/Script.hpp"
using namespace Porygon;
TEST_CASE( "Define script function", "[integration]" ) { TEST_CASE( "Define script function", "[integration]" ) {
Script* script = Script::Create("function add(number a, number b) a + b end"); Script* script = Script::Create("function add(number a, number b) a + b end");
REQUIRE(!script->Diagnostics -> HasErrors()); REQUIRE(!script->Diagnostics -> HasErrors());

View File

@ -1,6 +1,7 @@
#ifdef TESTS_BUILD #ifdef TESTS_BUILD
#include <catch.hpp> #include <catch.hpp>
#include "../src/Script.hpp" #include "../src/Script.hpp"
using namespace Porygon;
TEST_CASE( "String indexing", "[integration]" ) { TEST_CASE( "String indexing", "[integration]" ) {
auto script = Script::Create("'foobar'[4]"); auto script = Script::Create("'foobar'[4]");

View File

@ -1,6 +1,7 @@
#ifdef TESTS_BUILD #ifdef TESTS_BUILD
#include <catch.hpp> #include <catch.hpp>
#include "../src/Script.hpp" #include "../src/Script.hpp"
using namespace Porygon;
TEST_CASE( "Basic True", "[integration]" ) { TEST_CASE( "Basic True", "[integration]" ) {
auto script = Script::Create("true"); auto script = Script::Create("true");

View File

@ -1,6 +1,7 @@
#ifdef TESTS_BUILD #ifdef TESTS_BUILD
#include <catch.hpp> #include <catch.hpp>
#include "../src/Script.hpp" #include "../src/Script.hpp"
using namespace Porygon;
TEST_CASE( "Integer Negation", "[integration]" ) { TEST_CASE( "Integer Negation", "[integration]" ) {
auto script = Script::Create("-60"); auto script = Script::Create("-60");

View File

@ -3,6 +3,7 @@
#include <catch.hpp> #include <catch.hpp>
#include "../src/Script.hpp" #include "../src/Script.hpp"
using namespace Porygon;
TEST_CASE( "Simple String", "[integration]" ) { TEST_CASE( "Simple String", "[integration]" ) {
auto script = Script::Create("\"foo bar\""); auto script = Script::Create("\"foo bar\"");

View File

@ -2,6 +2,7 @@
#include <catch.hpp> #include <catch.hpp>
#include "../src/Script.hpp" #include "../src/Script.hpp"
#include "../../src/Evaluator/EvalValues/TableEvalValue.hpp" #include "../../src/Evaluator/EvalValues/TableEvalValue.hpp"
using namespace Porygon;
TEST_CASE( "Create empty table", "[integration]" ) { TEST_CASE( "Create empty table", "[integration]" ) {
Script* script = Script::Create("table = {}"); Script* script = Script::Create("table = {}");

View File

@ -5,6 +5,9 @@
#include "../../src/UserData/UserData.hpp" #include "../../src/UserData/UserData.hpp"
#include "../../src/UserData/UserDataStorage.hpp" #include "../../src/UserData/UserDataStorage.hpp"
#include "../../src/UserData/UserDataValue.hpp" #include "../../src/UserData/UserDataValue.hpp"
using namespace Porygon;
using namespace Porygon::UserData;
using namespace Porygon::Utilities;
class UserDataTestObject{ class UserDataTestObject{
public: public:
@ -18,8 +21,8 @@ public:
((UserDataTestObject*)obj)->foo = val->EvaluateInteger(); ((UserDataTestObject*)obj)->foo = val->EvaluateInteger();
} }
static UserData* CreateData(){ static Porygon::UserData::UserData* CreateData(){
return new UserData({ return new Porygon::UserData::UserData({
{ {
HashedString::ConstHash("foo"), HashedString::ConstHash("foo"),
new UserDataField(new NumericScriptType(true, false), GetFoo, SetFoo) new UserDataField(new NumericScriptType(true, false), GetFoo, SetFoo)

View File

@ -1,6 +1,7 @@
#ifdef TESTS_BUILD #ifdef TESTS_BUILD
#include <catch.hpp> #include <catch.hpp>
#include "../src/Script.hpp" #include "../src/Script.hpp"
using namespace Porygon;
TEST_CASE( "Create script variable", "[integration]" ) { TEST_CASE( "Create script variable", "[integration]" ) {
Script* script = Script::Create("foo = true"); Script* script = Script::Create("foo = true");

View File

@ -3,6 +3,7 @@
#include <codecvt> #include <codecvt>
#include <locale> #include <locale>
#include "../../src/Parser/Lexer.hpp" #include "../../src/Parser/Lexer.hpp"
using namespace Porygon::Parser;
TEST_CASE( "When at end of script return terminator", "[lexer]" ) { TEST_CASE( "When at end of script return terminator", "[lexer]" ) {
Lexer lexer = Lexer(u"", nullptr); Lexer lexer = Lexer(u"", nullptr);

View File

@ -3,6 +3,7 @@
#ifdef TESTS_BUILD #ifdef TESTS_BUILD
#include <catch.hpp> #include <catch.hpp>
#include "../../src/Parser/Parser.hpp" #include "../../src/Parser/Parser.hpp"
using namespace Porygon::Parser;
TEST_CASE( "Parse single true keyword", "[parser]" ) { TEST_CASE( "Parse single true keyword", "[parser]" ) {
vector<const IToken*> v {new SimpleToken(TokenKind::TrueKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0)}; vector<const IToken*> v {new SimpleToken(TokenKind::TrueKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0)};