PorygonLang/src/Binder/Binder.cpp

710 lines
42 KiB
C++
Raw Normal View History

#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"
#include "BoundExpressions/BoundFunctionCallExpression.hpp"
2019-06-14 12:59:38 +00:00
#include "../UserData/UserDataScriptType.hpp"
#include "../FunctionScriptType.hpp"
2019-05-21 16:09:08 +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());
}
Binder::~Binder() {
delete _scope;
}
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);
2019-06-22 15:35:33 +00:00
case ParsedStatementKind::NumericalFor:
return this->BindNumericalForStatement(statement);
2019-06-26 14:19:34 +00:00
case ParsedStatementKind::GenericFor:
return this -> BindGenericForStatement(statement);
2019-06-28 11:28:39 +00:00
case ParsedStatementKind::While:
return this -> BindWhileStatement(statement);
2019-06-27 13:55:46 +00:00
case ParsedStatementKind::Break:
//TODO: Validate we're in a loop
return new BoundBreakStatement();
case ParsedStatementKind::Bad:
return new BoundBadStatement();
}
2019-06-28 11:32:28 +00:00
throw "unreachable";
}
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
}
BoundStatement *Binder::BindExpressionStatement(const ParsedStatement *statement) {
auto exp = ((ParsedExpressionStatement *) statement)->GetExpression();
return new BoundExpressionStatement(this->BindExpression(exp));
}
2019-06-14 15:12:27 +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(), boundExpression->GetType())
: this->_scope->AssignVariable(s->GetIdentifier(), 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(),
statement->GetLength());
return new BoundBadStatement();
}
}
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);
}
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,
statement->GetStartPosition(), statement->GetLength());
return new BoundBadStatement();
}
return new BoundIndexAssignmentStatement(indexable, valueExpression);
}
2019-06-26 14:19:34 +00:00
std::shared_ptr<ScriptType> ParseTypeIdentifier(const 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);
}
}
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(),
statement->GetLength());
return new BoundBadStatement();
}
parameterTypes.at(i) = parsedType;
auto parameterAssignment = this->_scope->CreateExplicitLocal(var->GetIdentifier(), parsedType);
if (parameterAssignment.GetResult() == VariableAssignmentResult::Ok) {
parameterKeys.at(i) = std::shared_ptr<BoundVariableKey>(parameterAssignment.GetKey());
} else {
//TODO: log error
continue;
}
}
auto identifier = functionStatement->GetIdentifier();
auto returnType = make_shared<ScriptType>(TypeClass::Nil);
auto option = new ScriptFunctionOption(returnType, parameterTypes, parameterKeys);
this->_currentFunction = option;
shared_ptr<GenericFunctionScriptType> type;
auto scope = this -> _scope -> Exists(identifier);
BoundVariableKey* assignmentKey;
if (scope >= 0){
auto var = this -> _scope -> GetVariable(scope, identifier);
auto varType =var->GetType();
if (varType->GetClass() != TypeClass::Function){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(),
statement->GetLength());
}
type = dynamic_pointer_cast<GenericFunctionScriptType>(varType);
type->RegisterFunctionOption(option);
assignmentKey = new BoundVariableKey(identifier, scope, false);
} else{
type = make_shared<GenericFunctionScriptType>();
type->RegisterFunctionOption(option);
auto assignment = this->_scope->AssignVariable(identifier, type);
if (assignment.GetResult() != VariableAssignmentResult::Ok) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(),
statement->GetLength());
return new BoundBadStatement();
}
assignmentKey = assignment.GetKey();
}
auto boundBlock = this->BindBlockStatement(functionStatement->GetBlock());
this->_scope->GoOuterScope();
this->_currentFunction = nullptr;
return new BoundFunctionDeclarationStatement(type, assignmentKey, (BoundBlockStatement *) boundBlock);
2019-06-07 13:23:13 +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();
}
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(),
statement->GetLength());
return new BoundBadStatement();
} else if (expression == nullptr){
currentReturnType = make_shared<ScriptType>(TypeClass::Nil);
return new BoundReturnStatement(nullptr);
}
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(),
statement->GetLength());
return new BoundBadStatement();
}
2019-06-07 13:23:13 +00:00
return new BoundReturnStatement(boundExpression);
}
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(),
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-22 15:35:33 +00:00
BoundStatement *Binder::BindNumericalForStatement(const ParsedStatement *statement) {
auto forStatement = (ParsedNumericalForStatement*) statement;
auto identifier = forStatement->GetIdentifier();
auto start = this -> BindExpression(forStatement->GetStart());
auto end = this -> BindExpression(forStatement->GetEnd());
auto parsedStep = forStatement -> GetStep();
BoundExpression* step = nullptr;
if (parsedStep != nullptr){
step = this -> BindExpression(parsedStep);
}
if (start -> GetType()->GetClass() != TypeClass::Number){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NumericalForArgumentNotANumber, start->GetStartPosition(),
start->GetLength());
return new BoundBadStatement();
}
if (end -> GetType()->GetClass() != TypeClass::Number){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NumericalForArgumentNotANumber, end->GetStartPosition(),
end->GetLength());
return new BoundBadStatement();
}
if (step != nullptr && step -> GetType()->GetClass() != TypeClass::Number){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NumericalForArgumentNotANumber, step->GetStartPosition(),
step->GetLength());
return new BoundBadStatement();
}
this -> _scope ->GoInnerScope();
auto variableKey = this -> _scope ->CreateExplicitLocal(identifier, make_shared<NumericScriptType>(true, false));
2019-06-22 15:35:33 +00:00
if (variableKey.GetResult() != VariableAssignmentResult::Ok){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(),
statement->GetLength());
return new BoundBadStatement();
}
auto block = this -> BindBlockStatement(forStatement->GetBlock());
this -> _scope ->GoOuterScope();
return new BoundNumericalForStatement(variableKey.GetKey(), start, end, step, block);
}
2019-06-26 14:19:34 +00:00
BoundStatement *Binder::BindGenericForStatement(const ParsedStatement *statement) {
auto genericFor = (ParsedGenericForStatement*) statement;
auto boundIterator = BindExpression(genericFor -> GetIteratorExpression());
const auto& itType = boundIterator -> GetType();
if (!itType -> CanBeIterated()){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantIterateExpression, statement->GetStartPosition(),
statement->GetLength());
return new BoundBadStatement();
}
auto keyType = itType -> GetIteratorKeyType();
auto keyIdentifier = genericFor -> GetKeyIdentifier();
this -> _scope -> GoInnerScope();
auto keyVariableAssignment = this -> _scope -> CreateExplicitLocal(keyIdentifier, keyType);
if (keyVariableAssignment.GetResult() != VariableAssignmentResult::Ok){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(),
statement->GetLength());
return new BoundBadStatement();
}
auto keyVariable = keyVariableAssignment.GetKey();
auto valueIdentifier = genericFor -> GetValueIdentifier();
auto isValueVariableDefined = valueIdentifier.GetHash() != 0;
BoundVariableKey* valueVariable = nullptr;
if (isValueVariableDefined){
auto valueType = itType -> GetIndexedType(keyType.get());
auto valueVariableAssignment = this -> _scope -> CreateExplicitLocal(valueIdentifier, valueType);
if (valueVariableAssignment.GetResult() != VariableAssignmentResult::Ok){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(),
statement->GetLength());
return new BoundBadStatement();
}
valueVariable = valueVariableAssignment.GetKey();
}
auto boundBlock = this -> BindBlockStatement(genericFor -> GetBlock());
this -> _scope -> GoOuterScope();
return new BoundGenericForStatement(keyVariable, valueVariable, boundIterator, boundBlock);
}
2019-06-28 11:28:39 +00:00
BoundStatement *Binder::BindWhileStatement(const ParsedStatement *statement) {
auto whileStatement = (ParsedWhileStatement*)statement;
auto boundCondition = this -> BindExpression(whileStatement->GetCondition());
if (boundCondition->GetType()->GetClass() != TypeClass::Bool){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ConditionNotABool, statement->GetStartPosition(),
statement->GetLength());
return new BoundBadStatement();
}
auto boundBlock = this -> BindBlockStatement(whileStatement->GetBlock());
return new BoundWhileStatement(boundCondition, boundBlock);
}
2019-06-22 15:35:33 +00:00
/////////////////
// Expressions //
/////////////////
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-06-28 11:32:28 +00:00
throw;
}
BoundExpression *Binder::BindVariableExpression(const VariableExpression *expression) {
auto key = expression->GetValue();
auto scope = this->_scope->Exists(key);
if (scope == -1) {
2019-06-18 14:39:36 +00:00
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::VariableNotFound, expression->GetStartPosition(),
expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
}
auto var = this->_scope->GetVariable(scope, key);
auto type = var->GetType();
return new BoundVariableExpression(new BoundVariableKey(key, scope, false), type,
expression->GetStartPosition(), expression->GetLength());
}
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
}
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),
expression->GetStartPosition(), expression->GetLength());
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
}
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
}
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
}
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
}
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());
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());
break;
}
2019-06-18 14:39:36 +00:00
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NoBinaryOperationFound, expression->GetStartPosition(),
expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
}
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(),
expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
}
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,
expression->GetStartPosition(),
expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
}
2019-06-21 15:03:13 +00:00
auto functionType = std::dynamic_pointer_cast<GenericFunctionScriptType>(type);
auto givenParameters = expression->GetParameters();
auto givenParameterTypes = vector<shared_ptr<ScriptType>>(givenParameters->size());
vector<BoundExpression *> boundParameters = vector<BoundExpression *>(givenParameters->size());
for (int i = 0; i < givenParameters->size(); i++){
boundParameters[i] = this -> BindExpression(givenParameters->at(i));
givenParameterTypes[i] = boundParameters[i]->GetType();
}
auto functionOption = functionType->GetFunctionOption(givenParameterTypes);
if (functionOption == nullptr){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters,
expression->GetStartPosition(),
expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
}
return new BoundFunctionCallExpression(functionExpression, boundParameters, functionOption, functionOption->GetReturnType(),
expression->GetStartPosition(), expression->GetLength());
}
BoundExpression *Binder::BindIndexExpression(const IndexExpression *expression, bool setter) {
auto indexer = this->BindExpression(expression->GetIndexer());
auto index = this->BindExpression(expression->GetIndex());
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(),
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,
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,
index->GetStartPosition(),
index->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
}
}
}
auto resultType = indexer->GetType()->GetIndexedType(index->GetType().get());
return new BoundIndexExpression(indexer, index, resultType, expression->GetStartPosition(),
expression->GetLength());
}
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(),
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,
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,
expression->GetStartPosition(),
expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
}
}
}
auto resultType = indexer->GetType()->GetIndexedType(identifier.GetHash());
return new BoundPeriodIndexExpression(indexer, identifier, resultType, expression->GetStartPosition(),
expression->GetLength());
}
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,
boundExpressions[i]->GetStartPosition(),
boundExpressions[i]->GetLength());
}
2019-06-09 18:15:09 +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
BoundExpression *Binder::BindTableExpression(const ParsedTableExpression *expression) {
auto tableScope = new map<Utilities::HashedString, 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
auto tableType = std::make_shared<TableScriptType>(tableScope, innerScope->GetLocalVariableCount());
delete innerScope;
2019-06-12 13:19:28 +00:00
return new BoundTableExpression((BoundBlockStatement *) block, tableType, expression->GetStartPosition(),
expression->GetLength());
}
2019-06-28 11:28:39 +00:00
2019-06-12 13:19:28 +00:00
}