2019-06-13 16:14:59 +00:00
|
|
|
#include <memory>
|
|
|
|
|
2019-05-21 16:09:08 +00:00
|
|
|
#include "Binder.hpp"
|
2019-06-12 13:19:28 +00:00
|
|
|
#include "../TableScriptType.hpp"
|
|
|
|
#include "BoundExpressions/BoundTableExpression.hpp"
|
2019-06-14 12:59:38 +00:00
|
|
|
#include "../UserData/UserDataScriptType.hpp"
|
2019-06-01 11:43:25 +00:00
|
|
|
#include <memory>
|
2019-05-21 16:09:08 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
using namespace Porygon::Parser;
|
|
|
|
|
|
|
|
namespace Porygon::Binder {
|
|
|
|
BoundScriptStatement *Binder::Bind(Script *script, const ParsedScriptStatement *s, BoundScope *scriptScope) {
|
|
|
|
auto binder = Binder();
|
|
|
|
binder._scriptData = script;
|
|
|
|
|
|
|
|
binder._scope = scriptScope;
|
|
|
|
auto statements = s->GetStatements();
|
|
|
|
vector<BoundStatement *> boundStatements(statements->size());
|
|
|
|
for (int i = 0; i < statements->size(); i++) {
|
|
|
|
boundStatements[i] = binder.BindStatement(statements->at(i));
|
|
|
|
}
|
|
|
|
return new BoundScriptStatement(boundStatements, scriptScope->GetLocalVariableCount());
|
2019-05-21 18:59:26 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
Binder::~Binder() {
|
|
|
|
delete _scope;
|
2019-05-21 18:59:26 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundStatement *Binder::BindStatement(const ParsedStatement *statement) {
|
|
|
|
switch (statement->GetKind()) {
|
|
|
|
case ParsedStatementKind::Script:
|
|
|
|
throw; // This shouldn't happen.
|
|
|
|
case ParsedStatementKind::Block:
|
|
|
|
return this->BindBlockStatement(statement);
|
|
|
|
case ParsedStatementKind::Expression:
|
|
|
|
return this->BindExpressionStatement(statement);
|
|
|
|
case ParsedStatementKind::Assignment:
|
|
|
|
return this->BindAssignmentStatement(statement);
|
|
|
|
case ParsedStatementKind::IndexAssignment:
|
|
|
|
return this->BindIndexAssignmentStatement(statement);
|
|
|
|
case ParsedStatementKind::FunctionDeclaration:
|
|
|
|
return this->BindFunctionDeclarationStatement(statement);
|
|
|
|
case ParsedStatementKind::Return:
|
|
|
|
return this->BindReturnStatement(statement);
|
|
|
|
case ParsedStatementKind::Conditional:
|
|
|
|
return this->BindConditionalStatement(statement);
|
|
|
|
|
|
|
|
case ParsedStatementKind::Bad:
|
|
|
|
return new BoundBadStatement();
|
|
|
|
}
|
2019-05-21 18:59:26 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundStatement *Binder::BindBlockStatement(const ParsedStatement *statement) {
|
|
|
|
auto statements = ((ParsedBlockStatement *) statement)->GetStatements();
|
|
|
|
vector<BoundStatement *> boundStatements(statements->size());
|
|
|
|
this->_scope->GoInnerScope();
|
|
|
|
for (int i = 0; i < statements->size(); i++) {
|
|
|
|
boundStatements[i] = this->BindStatement(statements->at(i));
|
|
|
|
}
|
|
|
|
this->_scope->GoOuterScope();
|
|
|
|
return new BoundBlockStatement(boundStatements);
|
2019-05-28 15:49:03 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundStatement *Binder::BindExpressionStatement(const ParsedStatement *statement) {
|
|
|
|
auto exp = ((ParsedExpressionStatement *) statement)->GetExpression();
|
|
|
|
return new BoundExpressionStatement(this->BindExpression(exp));
|
2019-06-17 13:45:33 +00:00
|
|
|
}
|
2019-06-14 15:12:27 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundStatement *Binder::BindAssignmentStatement(const ParsedStatement *statement) {
|
|
|
|
auto s = (ParsedAssignmentStatement *) statement;
|
|
|
|
auto boundExpression = this->BindExpression(s->GetExpression());
|
|
|
|
VariableAssignment assignment =
|
|
|
|
s->IsLocal() ?
|
|
|
|
this->_scope->CreateExplicitLocal(s->GetIdentifier().GetHash(), boundExpression->GetType())
|
|
|
|
: this->_scope->AssignVariable(s->GetIdentifier().GetHash(), boundExpression->GetType());
|
|
|
|
if (assignment.GetResult() == VariableAssignmentResult::Ok) {
|
|
|
|
auto key = assignment.GetKey();
|
|
|
|
return new BoundAssignmentStatement(key, boundExpression);
|
|
|
|
} else {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
statement->GetLength());
|
|
|
|
return new BoundBadStatement();
|
|
|
|
}
|
2019-06-01 10:33:52 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundStatement *Binder::BindIndexAssignmentStatement(const ParsedStatement *statement) {
|
|
|
|
auto s = (ParsedIndexAssignmentStatement *) statement;
|
|
|
|
auto indexExp = s->GetIndexExpression();
|
|
|
|
const BoundExpression *indexable;
|
|
|
|
if (indexExp->GetKind() == ParsedExpressionKind::Indexer) {
|
|
|
|
indexable = this->BindIndexExpression((IndexExpression *) indexExp, true);
|
|
|
|
} else {
|
|
|
|
indexable = this->BindPeriodIndexExpression((PeriodIndexExpression *) indexExp, true);
|
2019-06-14 20:21:33 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
auto valueExpression = this->BindExpression(s->GetValueExpression());
|
|
|
|
auto boundIndexType = indexable->GetType();
|
|
|
|
if (boundIndexType->GetClass() != TypeClass::Error &&
|
|
|
|
boundIndexType->operator!=(valueExpression->GetType().get())) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidTableValueType,
|
2019-06-17 16:35:12 +00:00
|
|
|
statement->GetStartPosition(), statement->GetLength());
|
|
|
|
return new BoundBadStatement();
|
2019-06-01 11:43:25 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
return new BoundIndexAssignmentStatement(indexable, valueExpression);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<ScriptType> ParseTypeIdentifier(HashedString s) {
|
|
|
|
auto hash = s.GetHash();
|
|
|
|
switch (hash) {
|
|
|
|
case HashedString::ConstHash("number"):
|
|
|
|
return std::make_shared<NumericScriptType>(false, false);
|
|
|
|
case HashedString::ConstHash("bool"):
|
|
|
|
return std::make_shared<ScriptType>(TypeClass::Bool);
|
|
|
|
case HashedString::ConstHash("string"):
|
|
|
|
return std::make_shared<StringScriptType>(false, 0);
|
|
|
|
default:
|
|
|
|
if (!UserData::UserDataStorage::HasUserDataType(hash)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return std::make_shared<UserData::UserDataScriptType>(hash);
|
2019-06-01 11:43:25 +00:00
|
|
|
}
|
2019-06-01 10:33:52 +00:00
|
|
|
}
|
2019-06-08 14:02:21 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundStatement *Binder::BindFunctionDeclarationStatement(const ParsedStatement *statement) {
|
|
|
|
auto functionStatement = (ParsedFunctionDeclarationStatement *) statement;
|
|
|
|
auto parameters = functionStatement->GetParameters();
|
|
|
|
auto parameterTypes = vector<shared_ptr<ScriptType>>(parameters->size());
|
|
|
|
auto parameterKeys = vector<shared_ptr<BoundVariableKey>>(parameters->size());
|
|
|
|
|
|
|
|
auto scopeIndex = this->_scope->GetCurrentScope();
|
|
|
|
this->_scope->GoInnerScope();
|
|
|
|
for (int i = 0; i < parameters->size(); i++) {
|
|
|
|
auto var = parameters->at(i);
|
|
|
|
auto parsedType = ParseTypeIdentifier(var->GetType());
|
|
|
|
if (parsedType == nullptr) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidTypeName, statement->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
statement->GetLength());
|
|
|
|
return new BoundBadStatement();
|
|
|
|
}
|
|
|
|
parameterTypes.at(i) = parsedType;
|
|
|
|
auto parameterAssignment = this->_scope->CreateExplicitLocal(var->GetIdentifier().GetHash(), parsedType);
|
|
|
|
if (parameterAssignment.GetResult() == VariableAssignmentResult::Ok) {
|
|
|
|
parameterKeys.at(i) = std::shared_ptr<BoundVariableKey>(parameterAssignment.GetKey());
|
|
|
|
} else {
|
|
|
|
//TODO: log error
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2019-06-12 16:45:47 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
auto identifier = functionStatement->GetIdentifier();
|
|
|
|
auto returnType = make_shared<ScriptType>(TypeClass::Nil);
|
|
|
|
auto type = make_shared<FunctionScriptType>(returnType, parameterTypes, parameterKeys, scopeIndex);
|
|
|
|
this->_currentFunction = type;
|
2019-06-01 10:33:52 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
auto assignment = this->_scope->AssignVariable(identifier.GetHash(), type);
|
|
|
|
if (assignment.GetResult() != VariableAssignmentResult::Ok) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
statement->GetLength());
|
|
|
|
return new BoundBadStatement();
|
|
|
|
}
|
|
|
|
auto boundBlock = this->BindBlockStatement(functionStatement->GetBlock());
|
|
|
|
this->_scope->GoOuterScope();
|
|
|
|
this->_currentFunction = nullptr;
|
|
|
|
return new BoundFunctionDeclarationStatement(type, assignment.GetKey(), (BoundBlockStatement *) boundBlock);
|
2019-06-07 13:23:13 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
BoundStatement *Binder::BindReturnStatement(const ParsedStatement *statement) {
|
|
|
|
auto expression = ((ParsedReturnStatement *) statement)->GetExpression();
|
|
|
|
shared_ptr<ScriptType> currentReturnType;
|
|
|
|
if (this->_currentFunction == nullptr) {
|
|
|
|
currentReturnType = this->_scriptData->GetReturnType();
|
|
|
|
} else {
|
|
|
|
currentReturnType = this->_currentFunction->GetReturnType();
|
|
|
|
}
|
2019-06-19 14:21:21 +00:00
|
|
|
if (expression == nullptr && (currentReturnType != nullptr && currentReturnType -> GetClass() != TypeClass::Nil)) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidReturnType, statement->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
statement->GetLength());
|
|
|
|
return new BoundBadStatement();
|
2019-06-19 14:21:21 +00:00
|
|
|
} else if (expression == nullptr){
|
|
|
|
currentReturnType = make_shared<ScriptType>(TypeClass::Nil);
|
|
|
|
return new BoundReturnStatement(nullptr);
|
2019-06-17 16:35:12 +00:00
|
|
|
}
|
|
|
|
auto boundExpression = this->BindExpression(expression);
|
|
|
|
auto expresionType = boundExpression->GetType();
|
|
|
|
if (currentReturnType == nullptr || currentReturnType->GetClass() == TypeClass::Nil) {
|
|
|
|
if (this->_currentFunction == nullptr) {
|
|
|
|
this->_scriptData->SetReturnType(expresionType);
|
|
|
|
} else {
|
|
|
|
this->_currentFunction->SetReturnType(expresionType);
|
|
|
|
}
|
|
|
|
return new BoundReturnStatement(boundExpression);
|
|
|
|
}
|
|
|
|
if (currentReturnType.get()->operator!=(expresionType.get())) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidReturnType, statement->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
statement->GetLength());
|
|
|
|
return new BoundBadStatement();
|
2019-06-12 16:45:47 +00:00
|
|
|
}
|
2019-06-07 13:23:13 +00:00
|
|
|
return new BoundReturnStatement(boundExpression);
|
|
|
|
}
|
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundStatement *Binder::BindConditionalStatement(const ParsedStatement *statement) {
|
|
|
|
auto conditionalStatement = (ParsedConditionalStatement *) statement;
|
|
|
|
auto boundCondition = this->BindExpression(conditionalStatement->GetCondition());
|
|
|
|
if (boundCondition->GetType()->GetClass() != TypeClass::Bool) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ConditionNotABool, statement->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
statement->GetLength());
|
|
|
|
return new BoundBadStatement();
|
|
|
|
}
|
|
|
|
auto boundBlock = this->BindStatement(conditionalStatement->GetBlock());
|
|
|
|
BoundStatement *elseStatement = nullptr;
|
|
|
|
if (conditionalStatement->GetElseStatement() != nullptr) {
|
|
|
|
elseStatement = this->BindStatement(conditionalStatement->GetElseStatement());
|
|
|
|
}
|
|
|
|
return new BoundConditionalStatement(boundCondition, boundBlock, elseStatement);
|
2019-06-08 12:25:15 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundExpression *Binder::BindExpression(const ParsedExpression *expression) {
|
|
|
|
switch (expression->GetKind()) {
|
|
|
|
case ParsedExpressionKind::LiteralInteger:
|
|
|
|
return new BoundLiteralIntegerExpression(((LiteralIntegerExpression *) expression)->GetValue(),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
case ParsedExpressionKind::LiteralFloat:
|
|
|
|
return new BoundLiteralFloatExpression(((LiteralFloatExpression *) expression)->GetValue(),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
case ParsedExpressionKind::LiteralString:
|
|
|
|
return new BoundLiteralStringExpression(((LiteralStringExpression *) expression)->GetValue(),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
case ParsedExpressionKind::LiteralBool:
|
|
|
|
return new BoundLiteralBoolExpression(((LiteralBoolExpression *) expression)->GetValue(),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
case ParsedExpressionKind::Variable:
|
|
|
|
return this->BindVariableExpression((VariableExpression *) expression);
|
|
|
|
|
|
|
|
case ParsedExpressionKind::Binary:
|
|
|
|
return this->BindBinaryOperator((BinaryExpression *) expression);
|
|
|
|
case ParsedExpressionKind::Unary:
|
|
|
|
return this->BindUnaryOperator((UnaryExpression *) expression);
|
|
|
|
|
|
|
|
case ParsedExpressionKind::Parenthesized:
|
|
|
|
return BindExpression(((ParenthesizedExpression *) expression)->GetInnerExpression());
|
|
|
|
case ParsedExpressionKind::FunctionCall:
|
|
|
|
return this->BindFunctionCall((FunctionCallExpression *) expression);
|
|
|
|
|
|
|
|
case ParsedExpressionKind::Indexer:
|
|
|
|
return this->BindIndexExpression((IndexExpression *) expression, false);
|
|
|
|
case ParsedExpressionKind::PeriodIndexer:
|
|
|
|
return this->BindPeriodIndexExpression((PeriodIndexExpression *) expression, false);
|
|
|
|
case ParsedExpressionKind::NumericalTable:
|
|
|
|
return this->BindNumericalTableExpression((ParsedNumericalTableExpression *) expression);
|
|
|
|
case ParsedExpressionKind::Table:
|
|
|
|
return this->BindTableExpression((ParsedTableExpression *) expression);
|
|
|
|
|
|
|
|
case ParsedExpressionKind::Bad:
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
2019-05-21 18:59:26 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundExpression *Binder::BindVariableExpression(const VariableExpression *expression) {
|
|
|
|
auto key = expression->GetValue();
|
|
|
|
auto scope = this->_scope->Exists(key.GetHash());
|
|
|
|
if (scope == -1) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::VariableNotFound, expression->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
expression->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
auto var = this->_scope->GetVariable(scope, key.GetHash());
|
|
|
|
auto type = var->GetType();
|
|
|
|
return new BoundVariableExpression(new BoundVariableKey(key.GetHash(), scope, false), type,
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-30 13:23:48 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundExpression *Binder::BindBinaryOperator(const BinaryExpression *expression) {
|
|
|
|
auto boundLeft = this->BindExpression(expression->GetLeft());
|
|
|
|
auto boundRight = this->BindExpression(expression->GetRight());
|
|
|
|
|
|
|
|
auto boundLeftType = boundLeft->GetType();
|
|
|
|
auto boundRightType = boundRight->GetType();
|
|
|
|
|
|
|
|
switch (expression->GetOperatorKind()) {
|
|
|
|
case BinaryOperatorKind::Addition:
|
|
|
|
if (boundLeftType->GetClass() == TypeClass::Number && boundRightType->GetClass() == TypeClass::Number) {
|
|
|
|
auto leftNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundLeftType);
|
|
|
|
auto rightNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundRightType);
|
|
|
|
if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()) {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight,
|
|
|
|
BoundBinaryOperation::Addition,
|
|
|
|
std::make_shared<NumericScriptType>(true,
|
|
|
|
leftNumeric->IsFloat() ||
|
|
|
|
rightNumeric->IsFloat()),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
} else {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Addition,
|
|
|
|
std::make_shared<NumericScriptType>(false, false),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
} else if (boundLeftType->GetClass() == TypeClass::String) {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Concatenation,
|
|
|
|
std::make_shared<StringScriptType>(false,
|
|
|
|
0),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
break;
|
|
|
|
case BinaryOperatorKind::Subtraction:
|
|
|
|
if (boundLeftType->GetClass() == TypeClass::Number && boundRightType->GetClass() == TypeClass::Number) {
|
|
|
|
auto leftNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundLeftType);
|
|
|
|
auto rightNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundRightType);
|
|
|
|
if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()) {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight,
|
|
|
|
BoundBinaryOperation::Subtraction,
|
|
|
|
std::make_shared<NumericScriptType>(true,
|
|
|
|
leftNumeric->IsFloat() ||
|
|
|
|
rightNumeric->IsFloat()),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
} else {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Subtraction,
|
|
|
|
std::make_shared<NumericScriptType>(false, false),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BinaryOperatorKind::Multiplication:
|
|
|
|
if (boundLeftType->GetClass() == TypeClass::Number && boundRightType->GetClass() == TypeClass::Number) {
|
|
|
|
auto leftNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundLeftType);
|
|
|
|
auto rightNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundRightType);
|
|
|
|
if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()) {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight,
|
|
|
|
BoundBinaryOperation::Multiplication,
|
|
|
|
std::make_shared<NumericScriptType>(true,
|
|
|
|
leftNumeric->IsFloat() ||
|
|
|
|
rightNumeric->IsFloat()),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
} else {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Multiplication,
|
|
|
|
std::make_shared<NumericScriptType>(false, false),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BinaryOperatorKind::Division:
|
|
|
|
if (boundLeftType->GetClass() == TypeClass::Number && boundRightType->GetClass() == TypeClass::Number) {
|
|
|
|
auto leftNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundLeftType);
|
|
|
|
auto rightNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundRightType);
|
|
|
|
if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()) {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight,
|
|
|
|
BoundBinaryOperation::Division,
|
|
|
|
std::make_shared<NumericScriptType>(true,
|
|
|
|
leftNumeric->IsFloat() ||
|
|
|
|
rightNumeric->IsFloat()),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
} else {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Division,
|
|
|
|
std::make_shared<NumericScriptType>(false, false),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BinaryOperatorKind::Equality:
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Equality,
|
|
|
|
std::make_shared<ScriptType>(TypeClass::Bool),
|
2019-05-25 14:15:20 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-06-17 16:35:12 +00:00
|
|
|
case BinaryOperatorKind::Inequality:
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Inequality,
|
|
|
|
std::make_shared<ScriptType>(TypeClass::Bool),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
case BinaryOperatorKind::Less:
|
|
|
|
if (boundLeft->GetType()->GetClass() == TypeClass::Number &&
|
|
|
|
boundRight->GetType()->GetClass() == TypeClass::Number) {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::LessThan,
|
|
|
|
std::make_shared<ScriptType>(TypeClass::Bool),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
case BinaryOperatorKind::LessOrEquals:
|
|
|
|
if (boundLeft->GetType()->GetClass() == TypeClass::Number &&
|
|
|
|
boundRight->GetType()->GetClass() == TypeClass::Number) {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::LessThanEquals,
|
|
|
|
std::make_shared<ScriptType>(TypeClass::Bool),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
case BinaryOperatorKind::Greater:
|
|
|
|
if (boundLeft->GetType()->GetClass() == TypeClass::Number &&
|
|
|
|
boundRight->GetType()->GetClass() == TypeClass::Number) {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::GreaterThan,
|
|
|
|
std::make_shared<ScriptType>(TypeClass::Bool),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
case BinaryOperatorKind::GreaterOrEquals:
|
|
|
|
if (boundLeft->GetType()->GetClass() == TypeClass::Number &&
|
|
|
|
boundRight->GetType()->GetClass() == TypeClass::Number) {
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::GreaterThanEquals,
|
|
|
|
std::make_shared<ScriptType>(TypeClass::Bool),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
case BinaryOperatorKind::LogicalAnd:
|
|
|
|
if (boundLeftType->GetClass() == TypeClass::Bool && boundRightType->GetClass() == TypeClass::Bool)
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::LogicalAnd,
|
|
|
|
std::make_shared<ScriptType>(TypeClass::Bool),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-06-17 16:35:12 +00:00
|
|
|
break;
|
|
|
|
case BinaryOperatorKind::LogicalOr:
|
|
|
|
if (boundLeftType->GetClass() == TypeClass::Bool && boundRightType->GetClass() == TypeClass::Bool)
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::LogicalOr,
|
|
|
|
std::make_shared<ScriptType>(TypeClass::Bool),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-06-17 16:35:12 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NoBinaryOperationFound, expression->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
expression->GetLength());
|
2019-06-01 17:20:31 +00:00
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
BoundExpression *Binder::BindUnaryOperator(const UnaryExpression *expression) {
|
|
|
|
auto operand = this->BindExpression(expression->GetOperand());
|
|
|
|
auto operandType = operand->GetType();
|
|
|
|
switch (expression->GetOperatorKind()) {
|
|
|
|
case UnaryOperatorKind::Identity:
|
|
|
|
if (operandType->GetClass() == TypeClass::Number) {
|
|
|
|
// Identity won't change anything during evaluation, so just return the inner operand.
|
|
|
|
return operand;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case UnaryOperatorKind::Negation:
|
|
|
|
if (operandType->GetClass() == TypeClass::Number) {
|
|
|
|
auto innerType = std::dynamic_pointer_cast<NumericScriptType>(operandType);
|
|
|
|
return new BoundUnaryExpression(operand, BoundUnaryOperation::Negation,
|
|
|
|
std::make_shared<NumericScriptType>(
|
|
|
|
innerType.get()->IsAwareOfFloat(),
|
|
|
|
innerType.get()->IsFloat()),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case UnaryOperatorKind::LogicalNegation:
|
|
|
|
if (operandType->GetClass() == TypeClass::Bool) {
|
|
|
|
return new BoundUnaryExpression(operand, BoundUnaryOperation::LogicalNegation,
|
|
|
|
std::make_shared<ScriptType>(TypeClass::Bool),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NoUnaryOperationFound, expression->GetStartPosition(),
|
2019-06-01 17:20:31 +00:00
|
|
|
expression->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
2019-06-17 16:35:12 +00:00
|
|
|
|
2019-06-01 17:20:31 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
BoundExpression *Binder::BindFunctionCall(const FunctionCallExpression *expression) {
|
|
|
|
auto functionExpression = BindExpression(expression->GetFunction());
|
|
|
|
auto type = functionExpression->GetType();
|
|
|
|
if (type->GetClass() != TypeClass::Function) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ExpressionIsNotAFunction,
|
2019-06-17 16:35:12 +00:00
|
|
|
expression->GetStartPosition(),
|
|
|
|
expression->GetLength());
|
2019-06-01 17:20:31 +00:00
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
2019-06-21 15:03:13 +00:00
|
|
|
auto functionType = std::dynamic_pointer_cast<GenericFunctionScriptType>(type);
|
2019-06-17 16:35:12 +00:00
|
|
|
auto parameterTypes = functionType->GetParameterTypes();
|
|
|
|
auto givenParameters = expression->GetParameters();
|
|
|
|
if (parameterTypes.size() != givenParameters->size()) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ParameterCountMismatch,
|
2019-06-17 16:35:12 +00:00
|
|
|
expression->GetStartPosition(),
|
|
|
|
expression->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
vector<BoundExpression *> boundParameters = vector<BoundExpression *>(givenParameters->size());
|
|
|
|
for (int i = 0; i < givenParameters->size(); i++) {
|
|
|
|
auto parameter = givenParameters->at(i);
|
|
|
|
auto boundParameter = this->BindExpression(parameter);
|
|
|
|
if (boundParameter->GetType().get()->operator!=(parameterTypes.at(i).get())) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ParameterTypeMismatch,
|
2019-06-17 16:35:12 +00:00
|
|
|
parameter->GetStartPosition(),
|
|
|
|
parameter->GetLength());
|
2019-06-15 13:38:52 +00:00
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
boundParameters[i] = boundParameter;
|
2019-06-15 13:38:52 +00:00
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
return new BoundFunctionCallExpression(functionExpression, boundParameters, functionType.get()->GetReturnType(),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-06-15 13:38:52 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundExpression *Binder::BindIndexExpression(const IndexExpression *expression, bool setter) {
|
|
|
|
auto indexer = this->BindExpression(expression->GetIndexer());
|
|
|
|
auto index = this->BindExpression(expression->GetIndex());
|
2019-06-08 12:25:15 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
auto indexerType = indexer->GetType();
|
|
|
|
if (!indexerType->CanBeIndexedWith(index->GetType().get())) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantIndex, index->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
index->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
if (indexerType->GetClass() == TypeClass::UserData) {
|
|
|
|
auto stringKey = dynamic_pointer_cast<StringScriptType>(index->GetType());
|
|
|
|
auto field = dynamic_pointer_cast<UserData::UserDataScriptType>(indexerType)->GetField(stringKey->GetHashValue());
|
|
|
|
if (!setter) {
|
|
|
|
if (!field->HasGetter()) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UserDataFieldNoGetter,
|
2019-06-17 16:35:12 +00:00
|
|
|
index->GetStartPosition(),
|
|
|
|
index->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!field->HasSetter()) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UserDataFieldNoSetter,
|
2019-06-17 16:35:12 +00:00
|
|
|
index->GetStartPosition(),
|
|
|
|
index->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
2019-06-17 13:45:33 +00:00
|
|
|
}
|
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
|
|
|
|
auto resultType = indexer->GetType()->GetIndexedType(index->GetType().get());
|
|
|
|
return new BoundIndexExpression(indexer, index, resultType, expression->GetStartPosition(),
|
|
|
|
expression->GetLength());
|
2019-06-17 13:45:33 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundExpression *Binder::BindPeriodIndexExpression(const PeriodIndexExpression *expression, bool setter) {
|
|
|
|
auto indexer = this->BindExpression(expression->GetIndexer());
|
|
|
|
const auto &identifier = expression->GetIndex();
|
|
|
|
const auto &indexerType = indexer->GetType();
|
|
|
|
if (!indexerType->CanBeIndexedWithIdentifier(identifier.GetHash())) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantIndex, expression->GetStartPosition(),
|
2019-06-17 16:35:12 +00:00
|
|
|
expression->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
if (indexerType->GetClass() == TypeClass::UserData) {
|
|
|
|
auto field = dynamic_pointer_cast<UserData::UserDataScriptType>(indexerType)->GetField(identifier.GetHash());
|
|
|
|
if (!setter) {
|
|
|
|
if (!field->HasGetter()) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UserDataFieldNoGetter,
|
2019-06-17 16:35:12 +00:00
|
|
|
expression->GetStartPosition(),
|
|
|
|
expression->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!field->HasSetter()) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::UserDataFieldNoSetter,
|
2019-06-17 16:35:12 +00:00
|
|
|
expression->GetStartPosition(),
|
|
|
|
expression->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-06-17 13:45:33 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
auto resultType = indexer->GetType()->GetIndexedType(identifier.GetHash());
|
|
|
|
return new BoundPeriodIndexExpression(indexer, identifier, resultType, expression->GetStartPosition(),
|
|
|
|
expression->GetLength());
|
2019-06-17 13:45:33 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BoundExpression *Binder::BindNumericalTableExpression(const ParsedNumericalTableExpression *expression) {
|
|
|
|
auto expressions = expression->GetExpressions();
|
|
|
|
auto boundExpressions = vector<const BoundExpression *>(expressions->size());
|
|
|
|
shared_ptr<ScriptType> valueType = nullptr;
|
|
|
|
if (!boundExpressions.empty()) {
|
|
|
|
boundExpressions[0] = this->BindExpression(expressions->at(0));
|
|
|
|
valueType = boundExpressions[0]->GetType();
|
|
|
|
for (int i = 1; i < expressions->size(); i++) {
|
|
|
|
boundExpressions[i] = this->BindExpression(expressions->at(i));
|
|
|
|
if (boundExpressions[i]->GetType().get()->operator!=(valueType.get())) {
|
2019-06-18 14:39:36 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidTableValueType,
|
2019-06-17 16:35:12 +00:00
|
|
|
boundExpressions[i]->GetStartPosition(),
|
|
|
|
boundExpressions[i]->GetLength());
|
|
|
|
}
|
2019-06-09 18:15:09 +00:00
|
|
|
}
|
|
|
|
}
|
2019-06-17 16:35:12 +00:00
|
|
|
if (valueType == nullptr) {
|
|
|
|
valueType = std::make_shared<ScriptType>(TypeClass::Nil);
|
|
|
|
}
|
|
|
|
auto tableType = std::make_shared<NumericalTableScriptType>(valueType);
|
|
|
|
return new BoundNumericalTableExpression(boundExpressions, tableType, expression->GetStartPosition(),
|
|
|
|
expression->GetLength());
|
2019-06-09 18:15:09 +00:00
|
|
|
}
|
2019-06-12 13:19:28 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
BoundExpression *Binder::BindTableExpression(const ParsedTableExpression *expression) {
|
|
|
|
auto tableScope = new unordered_map<uint32_t, BoundVariable *>();
|
|
|
|
auto innerScope = new BoundScope(tableScope);
|
|
|
|
auto currentScope = this->_scope;
|
|
|
|
this->_scope = innerScope;
|
|
|
|
auto block = this->BindBlockStatement(expression->GetBlock());
|
|
|
|
this->_scope = currentScope;
|
2019-06-12 13:19:28 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
auto tableType = std::make_shared<TableScriptType>(tableScope, innerScope->GetLocalVariableCount());
|
|
|
|
delete innerScope;
|
2019-06-12 13:19:28 +00:00
|
|
|
|
2019-06-17 16:35:12 +00:00
|
|
|
return new BoundTableExpression((BoundBlockStatement *) block, tableType, expression->GetStartPosition(),
|
|
|
|
expression->GetLength());
|
|
|
|
}
|
2019-06-12 13:19:28 +00:00
|
|
|
}
|