Added namespaces to most classes, general cleanup
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
21d3329c55
commit
fde102d954
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
switch (expression->GetOperation()) {
|
||||||
|
case BoundBinaryOperation::Equality: {
|
||||||
|
auto leftValue = this->EvaluateExpression(expression->GetLeft());
|
||||||
|
auto rightValue = this->EvaluateExpression(expression->GetRight());
|
||||||
|
bool equals = leftValue.get()->operator==(rightValue.get());
|
||||||
|
return make_shared<BooleanEvalValue>(equals);
|
||||||
|
}
|
||||||
|
case BoundBinaryOperation::Inequality: {
|
||||||
|
auto leftValue = this->EvaluateExpression(expression->GetLeft());
|
||||||
|
auto rightValue = this->EvaluateExpression(expression->GetRight());
|
||||||
|
bool equals = leftValue.get()->operator!=(rightValue.get());
|
||||||
|
return make_shared<BooleanEvalValue>(equals);
|
||||||
|
}
|
||||||
|
case BoundBinaryOperation::LessThan: {
|
||||||
|
auto leftValue = this->EvaluateIntegerExpression(expression->GetLeft());
|
||||||
|
auto rightValue = this->EvaluateIntegerExpression(expression->GetRight());
|
||||||
|
return leftValue->operator<(rightValue);
|
||||||
|
}
|
||||||
|
case BoundBinaryOperation::LessThanEquals: {
|
||||||
|
auto leftValue = this->EvaluateIntegerExpression(expression->GetLeft());
|
||||||
|
auto rightValue = this->EvaluateIntegerExpression(expression->GetRight());
|
||||||
|
return leftValue->operator<=(rightValue);
|
||||||
|
}
|
||||||
|
case BoundBinaryOperation::GreaterThan: {
|
||||||
|
auto leftValue = this->EvaluateIntegerExpression(expression->GetLeft());
|
||||||
|
auto rightValue = this->EvaluateIntegerExpression(expression->GetRight());
|
||||||
|
return leftValue->operator>(rightValue);
|
||||||
|
}
|
||||||
|
case BoundBinaryOperation::GreaterThanEquals: {
|
||||||
|
auto leftValue = this->EvaluateIntegerExpression(expression->GetLeft());
|
||||||
|
auto rightValue = this->EvaluateIntegerExpression(expression->GetRight());
|
||||||
|
return leftValue->operator>=(rightValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
case BoundBinaryOperation::LogicalAnd: {
|
||||||
|
auto leftValue = this->EvaluateBoolExpression(expression->GetLeft());
|
||||||
|
if (!leftValue->EvaluateBool()) return leftValue;
|
||||||
|
auto rightValue = this->EvaluateBoolExpression(expression->GetRight());
|
||||||
|
return rightValue;
|
||||||
|
}
|
||||||
|
case BoundBinaryOperation::LogicalOr: {
|
||||||
|
auto leftValue = this->EvaluateBoolExpression(expression->GetLeft());
|
||||||
|
if (leftValue->EvaluateBool()) return leftValue;
|
||||||
|
auto rightValue = this->EvaluateBoolExpression(expression->GetRight());
|
||||||
|
return rightValue;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw EvaluationException("Can't evaluate operation to boolean");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const shared_ptr<StringEvalValue> Evaluator::EvaluateStringBinary(const BoundBinaryExpression *expression) {
|
||||||
|
if (expression->GetOperation() != BoundBinaryOperation::Concatenation)
|
||||||
|
throw;
|
||||||
|
std::basic_ostringstream<char16_t> stringStream;
|
||||||
|
auto left = this->EvaluateStringExpression(expression->GetLeft());
|
||||||
|
stringStream << *left->EvaluateString();
|
||||||
|
auto right = this->EvaluateExpression(expression->GetRight());
|
||||||
|
stringStream << *right->EvaluateString();
|
||||||
|
return make_shared<StringEvalValue>(stringStream.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const shared_ptr<BooleanEvalValue> Evaluator::EvaluateBooleanBinary(const BoundBinaryExpression *expression){
|
|
||||||
switch (expression->GetOperation()){
|
|
||||||
case BoundBinaryOperation::Equality:
|
|
||||||
{
|
|
||||||
auto leftValue = this -> EvaluateExpression(expression->GetLeft());
|
|
||||||
auto rightValue = this -> EvaluateExpression(expression->GetRight());
|
|
||||||
bool equals = leftValue.get()->operator==(rightValue.get());
|
|
||||||
return make_shared<BooleanEvalValue>(equals);
|
|
||||||
}
|
|
||||||
case BoundBinaryOperation::Inequality:
|
|
||||||
{
|
|
||||||
auto leftValue = this -> EvaluateExpression(expression->GetLeft());
|
|
||||||
auto rightValue = this -> EvaluateExpression(expression->GetRight());
|
|
||||||
bool equals = leftValue.get()->operator!=(rightValue.get());
|
|
||||||
return make_shared<BooleanEvalValue>(equals);
|
|
||||||
}
|
|
||||||
case BoundBinaryOperation ::LessThan:
|
|
||||||
{
|
|
||||||
auto leftValue = this -> EvaluateIntegerExpression(expression->GetLeft());
|
|
||||||
auto rightValue = this -> EvaluateIntegerExpression(expression->GetRight());
|
|
||||||
return leftValue->operator<(rightValue);
|
|
||||||
}
|
|
||||||
case BoundBinaryOperation ::LessThanEquals:
|
|
||||||
{
|
|
||||||
auto leftValue = this -> EvaluateIntegerExpression(expression->GetLeft());
|
|
||||||
auto rightValue = this -> EvaluateIntegerExpression(expression->GetRight());
|
|
||||||
return leftValue->operator<=(rightValue);
|
|
||||||
}
|
|
||||||
case BoundBinaryOperation ::GreaterThan:
|
|
||||||
{
|
|
||||||
auto leftValue = this -> EvaluateIntegerExpression(expression->GetLeft());
|
|
||||||
auto rightValue = this -> EvaluateIntegerExpression(expression->GetRight());
|
|
||||||
return leftValue->operator>(rightValue);
|
|
||||||
}
|
|
||||||
case BoundBinaryOperation ::GreaterThanEquals:
|
|
||||||
{
|
|
||||||
auto leftValue = this -> EvaluateIntegerExpression(expression->GetLeft());
|
|
||||||
auto rightValue = this -> EvaluateIntegerExpression(expression->GetRight());
|
|
||||||
return leftValue->operator>=(rightValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
case BoundBinaryOperation::LogicalAnd:
|
|
||||||
{
|
|
||||||
auto leftValue = this -> EvaluateBoolExpression(expression->GetLeft());
|
|
||||||
if (!leftValue->EvaluateBool()) return leftValue;
|
|
||||||
auto rightValue = this -> EvaluateBoolExpression(expression->GetRight());
|
|
||||||
return rightValue;
|
|
||||||
}
|
|
||||||
case BoundBinaryOperation::LogicalOr:
|
|
||||||
{
|
|
||||||
auto leftValue = this -> EvaluateBoolExpression(expression->GetLeft());
|
|
||||||
if (leftValue->EvaluateBool()) return leftValue;
|
|
||||||
auto rightValue = this -> EvaluateBoolExpression(expression->GetRight());
|
|
||||||
return rightValue;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw EvaluationException("Can't evaluate operation to boolean");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const shared_ptr<StringEvalValue> Evaluator::EvaluateStringBinary(const BoundBinaryExpression *expression){
|
|
||||||
if (expression->GetOperation() != BoundBinaryOperation::Concatenation)
|
|
||||||
throw;
|
|
||||||
std::basic_ostringstream<char16_t > stringStream;
|
|
||||||
auto left = this -> EvaluateStringExpression(expression->GetLeft());
|
|
||||||
stringStream << *left->EvaluateString();
|
|
||||||
auto right = this -> EvaluateExpression(expression->GetRight());
|
|
||||||
stringStream << *right->EvaluateString();
|
|
||||||
return make_shared<StringEvalValue>(stringStream.str());
|
|
||||||
}
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()) {
|
||||||
|
return make_shared<FloatEvalValue>(this->GetIntegerValue() + b->GetFloatValue());
|
||||||
|
} else {
|
||||||
|
return make_shared<IntegerEvalValue>(this->GetIntegerValue() + b->GetIntegerValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (b->IsFloat()){
|
|
||||||
return make_shared<FloatEvalValue>(this->GetIntegerValue() + b->GetFloatValue());
|
const shared_ptr<NumericEvalValue> NumericEvalValue::operator-(const shared_ptr<NumericEvalValue> &b) const {
|
||||||
} else{
|
if (this->IsFloat()) {
|
||||||
return make_shared<IntegerEvalValue>(this->GetIntegerValue() + b->GetIntegerValue());
|
if (b->IsFloat()) {
|
||||||
}
|
return make_shared<FloatEvalValue>(this->GetFloatValue() - b->GetFloatValue());
|
||||||
}
|
} else {
|
||||||
}
|
return make_shared<FloatEvalValue>(this->GetFloatValue() - b->GetIntegerValue());
|
||||||
|
}
|
||||||
const shared_ptr<NumericEvalValue> NumericEvalValue::operator-(const shared_ptr<NumericEvalValue>& b) const {
|
} else {
|
||||||
if (this->IsFloat()){
|
if (b->IsFloat()) {
|
||||||
if (b->IsFloat()){
|
return make_shared<FloatEvalValue>(this->GetIntegerValue() - b->GetFloatValue());
|
||||||
return make_shared<FloatEvalValue>(this->GetFloatValue() - b->GetFloatValue());
|
} else {
|
||||||
} else{
|
return make_shared<IntegerEvalValue>(this->GetIntegerValue() - b->GetIntegerValue());
|
||||||
return make_shared<FloatEvalValue>(this->GetFloatValue() - b->GetIntegerValue());
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (b->IsFloat()){
|
|
||||||
return make_shared<FloatEvalValue>(this->GetIntegerValue() - b->GetFloatValue());
|
const shared_ptr<NumericEvalValue> NumericEvalValue::operator*(const shared_ptr<NumericEvalValue> &b) const {
|
||||||
} else{
|
if (this->IsFloat()) {
|
||||||
return make_shared<IntegerEvalValue>(this->GetIntegerValue() - b->GetIntegerValue());
|
if (b->IsFloat()) {
|
||||||
}
|
return make_shared<FloatEvalValue>(this->GetFloatValue() * b->GetFloatValue());
|
||||||
}
|
} else {
|
||||||
}
|
return make_shared<FloatEvalValue>(this->GetFloatValue() * b->GetIntegerValue());
|
||||||
|
}
|
||||||
const shared_ptr<NumericEvalValue> NumericEvalValue::operator*(const shared_ptr<NumericEvalValue>& b) const {
|
} else {
|
||||||
if (this->IsFloat()){
|
if (b->IsFloat()) {
|
||||||
if (b->IsFloat()){
|
return make_shared<FloatEvalValue>(this->GetIntegerValue() * b->GetFloatValue());
|
||||||
return make_shared<FloatEvalValue>(this->GetFloatValue() * b->GetFloatValue());
|
} else {
|
||||||
} else{
|
return make_shared<IntegerEvalValue>(this->GetIntegerValue() * b->GetIntegerValue());
|
||||||
return make_shared<FloatEvalValue>(this->GetFloatValue() * b->GetIntegerValue());
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (b->IsFloat()){
|
|
||||||
return make_shared<FloatEvalValue>(this->GetIntegerValue() * b->GetFloatValue());
|
const shared_ptr<NumericEvalValue> NumericEvalValue::operator/(const shared_ptr<NumericEvalValue> &b) const {
|
||||||
} else{
|
if (this->IsFloat()) {
|
||||||
return make_shared<IntegerEvalValue>(this->GetIntegerValue() * b->GetIntegerValue());
|
if (b->IsFloat()) {
|
||||||
}
|
return make_shared<FloatEvalValue>(this->GetFloatValue() / b->GetFloatValue());
|
||||||
}
|
} else {
|
||||||
}
|
return make_shared<FloatEvalValue>(this->GetFloatValue() / b->GetIntegerValue());
|
||||||
|
}
|
||||||
const shared_ptr<NumericEvalValue> NumericEvalValue::operator/(const shared_ptr<NumericEvalValue>& b) const {
|
} else {
|
||||||
if (this->IsFloat()){
|
if (b->IsFloat()) {
|
||||||
if (b->IsFloat()){
|
return make_shared<FloatEvalValue>(this->GetIntegerValue() / b->GetFloatValue());
|
||||||
return make_shared<FloatEvalValue>(this->GetFloatValue() / b->GetFloatValue());
|
} else {
|
||||||
} else{
|
return make_shared<IntegerEvalValue>(this->GetIntegerValue() / b->GetIntegerValue());
|
||||||
return make_shared<FloatEvalValue>(this->GetFloatValue() / b->GetIntegerValue());
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (b->IsFloat()){
|
|
||||||
return make_shared<FloatEvalValue>(this->GetIntegerValue() / b->GetFloatValue());
|
const bool NumericEvalValue::operator==(EvalValue *b) const {
|
||||||
} else{
|
if (b->GetTypeClass() != TypeClass::Number)
|
||||||
return make_shared<IntegerEvalValue>(this->GetIntegerValue() / b->GetIntegerValue());
|
return false;
|
||||||
}
|
auto numVal = (NumericEvalValue *) b;
|
||||||
}
|
if (this->IsFloat() != numVal->IsFloat())
|
||||||
}
|
return false;
|
||||||
|
|
||||||
const bool NumericEvalValue::operator==(EvalValue *b) const {
|
if (this->IsFloat()) {
|
||||||
if (b->GetTypeClass() != TypeClass::Number)
|
return this->EvaluateFloat() == numVal->EvaluateFloat();
|
||||||
return false;
|
} else {
|
||||||
auto numVal = (NumericEvalValue*)b;
|
return this->EvaluateInteger() == numVal->EvaluateInteger();
|
||||||
if (this->IsFloat() != numVal->IsFloat())
|
}
|
||||||
return false;
|
}
|
||||||
|
|
||||||
if (this->IsFloat()){
|
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator<(const shared_ptr<NumericEvalValue> &b) const {
|
||||||
return this->EvaluateFloat() == numVal->EvaluateFloat();
|
if (this->IsFloat()) {
|
||||||
} else{
|
if (b->IsFloat()) {
|
||||||
return this->EvaluateInteger() == numVal->EvaluateInteger();
|
return make_shared<BooleanEvalValue>(this->GetFloatValue() < b->GetFloatValue());
|
||||||
}
|
} else {
|
||||||
}
|
return make_shared<BooleanEvalValue>(this->GetFloatValue() < b->GetIntegerValue());
|
||||||
|
}
|
||||||
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator<(const shared_ptr<NumericEvalValue>& b) const {
|
} else {
|
||||||
if (this->IsFloat()){
|
if (b->IsFloat()) {
|
||||||
if (b->IsFloat()){
|
return make_shared<BooleanEvalValue>(this->GetIntegerValue() < b->GetFloatValue());
|
||||||
return make_shared<BooleanEvalValue>(this->GetFloatValue() < b->GetFloatValue());
|
} else {
|
||||||
} else{
|
return make_shared<BooleanEvalValue>(this->GetIntegerValue() < b->GetIntegerValue());
|
||||||
return make_shared<BooleanEvalValue>(this->GetFloatValue() < b->GetIntegerValue());
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (b->IsFloat()){
|
|
||||||
return make_shared<BooleanEvalValue>(this->GetIntegerValue() < b->GetFloatValue());
|
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator<=(const shared_ptr<NumericEvalValue> &b) const {
|
||||||
} else{
|
if (this->IsFloat()) {
|
||||||
return make_shared<BooleanEvalValue>(this->GetIntegerValue() < b->GetIntegerValue());
|
if (b->IsFloat()) {
|
||||||
}
|
return make_shared<BooleanEvalValue>(this->GetFloatValue() <= b->GetFloatValue());
|
||||||
}
|
} else {
|
||||||
}
|
return make_shared<BooleanEvalValue>(this->GetFloatValue() <= b->GetIntegerValue());
|
||||||
|
}
|
||||||
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator<=(const shared_ptr<NumericEvalValue>& b) const {
|
} else {
|
||||||
if (this->IsFloat()){
|
if (b->IsFloat()) {
|
||||||
if (b->IsFloat()){
|
return make_shared<BooleanEvalValue>(this->GetIntegerValue() <= b->GetFloatValue());
|
||||||
return make_shared<BooleanEvalValue>(this->GetFloatValue() <= b->GetFloatValue());
|
} else {
|
||||||
} else{
|
return make_shared<BooleanEvalValue>(this->GetIntegerValue() <= b->GetIntegerValue());
|
||||||
return make_shared<BooleanEvalValue>(this->GetFloatValue() <= b->GetIntegerValue());
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (b->IsFloat()){
|
|
||||||
return make_shared<BooleanEvalValue>(this->GetIntegerValue() <= b->GetFloatValue());
|
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator>(const shared_ptr<NumericEvalValue> &b) const {
|
||||||
} else{
|
if (this->IsFloat()) {
|
||||||
return make_shared<BooleanEvalValue>(this->GetIntegerValue() <= b->GetIntegerValue());
|
if (b->IsFloat()) {
|
||||||
}
|
return make_shared<BooleanEvalValue>(this->GetFloatValue() > b->GetFloatValue());
|
||||||
}
|
} else {
|
||||||
}
|
return make_shared<BooleanEvalValue>(this->GetFloatValue() > b->GetIntegerValue());
|
||||||
|
}
|
||||||
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator>(const shared_ptr<NumericEvalValue>& b) const {
|
} else {
|
||||||
if (this->IsFloat()){
|
if (b->IsFloat()) {
|
||||||
if (b->IsFloat()){
|
return make_shared<BooleanEvalValue>(this->GetIntegerValue() > b->GetFloatValue());
|
||||||
return make_shared<BooleanEvalValue>(this->GetFloatValue() > b->GetFloatValue());
|
} else {
|
||||||
} else{
|
return make_shared<BooleanEvalValue>(this->GetIntegerValue() > b->GetIntegerValue());
|
||||||
return make_shared<BooleanEvalValue>(this->GetFloatValue() > b->GetIntegerValue());
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (b->IsFloat()){
|
|
||||||
return make_shared<BooleanEvalValue>(this->GetIntegerValue() > b->GetFloatValue());
|
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator>=(const shared_ptr<NumericEvalValue> &b) const {
|
||||||
} else{
|
if (this->IsFloat()) {
|
||||||
return make_shared<BooleanEvalValue>(this->GetIntegerValue() > b->GetIntegerValue());
|
if (b->IsFloat()) {
|
||||||
}
|
return make_shared<BooleanEvalValue>(this->GetFloatValue() >= b->GetFloatValue());
|
||||||
}
|
} else {
|
||||||
}
|
return make_shared<BooleanEvalValue>(this->GetFloatValue() >= b->GetIntegerValue());
|
||||||
|
}
|
||||||
const shared_ptr<BooleanEvalValue> NumericEvalValue::operator>=(const shared_ptr<NumericEvalValue>& b) const {
|
} else {
|
||||||
if (this->IsFloat()){
|
if (b->IsFloat()) {
|
||||||
if (b->IsFloat()){
|
return make_shared<BooleanEvalValue>(this->GetIntegerValue() >= b->GetFloatValue());
|
||||||
return make_shared<BooleanEvalValue>(this->GetFloatValue() >= b->GetFloatValue());
|
} else {
|
||||||
} else{
|
return make_shared<BooleanEvalValue>(this->GetIntegerValue() >= b->GetIntegerValue());
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
case BoundStatementKind::Bad:
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Evaluator::EvaluateExpressionStatement(const BoundExpressionStatement *statement) {
|
void Evaluator::EvaluateBlockStatement(const BoundBlockStatement *statement) {
|
||||||
// Save new value
|
for (auto s: *statement->GetStatements()) {
|
||||||
this->_lastValue = this -> EvaluateExpression(statement->GetExpression());
|
this->EvaluateStatement(s);
|
||||||
}
|
if (this->_hasReturned)
|
||||||
|
break;
|
||||||
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) {
|
void Evaluator::EvaluateExpressionStatement(const BoundExpressionStatement *statement) {
|
||||||
auto indexExpression = statement -> GetIndexExpression();
|
// Save new value
|
||||||
auto value = this -> EvaluateExpression(statement -> GetValueExpression());
|
this->_lastValue = this->EvaluateExpression(statement->GetExpression());
|
||||||
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){
|
void Evaluator::EvaluateAssignmentStatement(const BoundAssignmentStatement *statement) {
|
||||||
auto expression = statement->GetExpression();
|
auto value = this->EvaluateExpression(statement->GetExpression());
|
||||||
if (expression == nullptr){
|
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->_hasReturned = true;
|
||||||
return;
|
this->_returnValue = value;
|
||||||
}
|
}
|
||||||
auto value = this -> EvaluateExpression(expression);
|
|
||||||
this->_hasReturned = true;
|
|
||||||
this -> _returnValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Evaluator::EvaluateConditionalStatement(const BoundConditionalStatement *statement) {
|
void Evaluator::EvaluateConditionalStatement(const BoundConditionalStatement *statement) {
|
||||||
auto condition = statement->GetCondition();
|
auto condition = statement->GetCondition();
|
||||||
if (EvaluateBoolExpression(condition) -> EvaluateBool()){
|
if (EvaluateBoolExpression(condition)->EvaluateBool()) {
|
||||||
this -> EvaluateStatement(statement->GetBlock());
|
this->EvaluateStatement(statement->GetBlock());
|
||||||
} else{
|
} else {
|
||||||
auto elseStatement = statement -> GetElseStatement();
|
auto elseStatement = statement->GetElseStatement();
|
||||||
if (elseStatement != nullptr){
|
if (elseStatement != nullptr) {
|
||||||
this->EvaluateStatement(elseStatement);
|
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 *> ¶meters) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 *> ¶meters) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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 *> ¶meters);
|
const vector<EvalValue *> ¶meters);
|
||||||
|
|
||||||
EvalValue* GetLastValue(){
|
EvalValue* GetLastValue(){
|
||||||
return _lastValue.get();
|
return _lastValue.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(TypeClass t){
|
|
||||||
return new ScriptType(t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptType* CreateNumericScriptType(bool isAware, bool isFloat){
|
const shared_ptr<ScriptType> ScriptType::GetIndexedType(ScriptType *indexer) const{
|
||||||
return new NumericScriptType(isAware, isFloat);
|
if (_class == TypeClass::String){
|
||||||
|
return make_shared<ScriptType>(TypeClass::String);
|
||||||
|
}
|
||||||
|
return make_shared<ScriptType>(TypeClass::Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptType* CreateStringScriptType(bool knownAtBind, uint32_t hash){
|
extern "C"{
|
||||||
return new StringScriptType(knownAtBind, hash);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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]");
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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\"");
|
||||||
|
|
|
@ -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 = {}");
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)};
|
||||||
|
|
Loading…
Reference in New Issue