2019-06-09 18:15:09 +00:00
|
|
|
#include <memory>
|
|
|
|
|
2019-05-21 16:09:08 +00:00
|
|
|
#include "Binder.hpp"
|
2019-06-01 11:43:25 +00:00
|
|
|
#include <memory>
|
2019-05-21 16:09:08 +00:00
|
|
|
|
2019-05-28 15:49:03 +00:00
|
|
|
BoundScriptStatement *Binder::Bind(Script* script, ParsedScriptStatement *s, BoundScope* scriptScope) {
|
2019-05-21 18:59:26 +00:00
|
|
|
auto binder = Binder();
|
2019-05-28 15:49:03 +00:00
|
|
|
binder._scriptData = script;
|
|
|
|
|
|
|
|
binder._scope = scriptScope;
|
2019-05-21 18:59:26 +00:00
|
|
|
auto statements = s->GetStatements();
|
2019-06-11 12:58:43 +00:00
|
|
|
vector<BoundStatement*> boundStatements (statements->size());
|
|
|
|
for (int i = 0; i < statements->size(); i++){
|
|
|
|
boundStatements[i] = binder.BindStatement(statements->at(i));
|
2019-05-21 18:59:26 +00:00
|
|
|
}
|
2019-05-29 12:55:03 +00:00
|
|
|
return new BoundScriptStatement(boundStatements, scriptScope->GetDeepestScope());
|
2019-05-21 16:09:08 +00:00
|
|
|
}
|
2019-05-21 18:59:26 +00:00
|
|
|
|
2019-05-28 15:49:03 +00:00
|
|
|
Binder::~Binder() {
|
|
|
|
delete _scope;
|
|
|
|
}
|
|
|
|
|
2019-05-21 18:59:26 +00:00
|
|
|
BoundStatement* Binder::BindStatement(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);
|
2019-05-28 15:49:03 +00:00
|
|
|
case ParsedStatementKind::Assignment: return this -> BindAssignmentStatement(statement);
|
2019-06-01 10:33:52 +00:00
|
|
|
case ParsedStatementKind ::FunctionDeclaration: return this->BindFunctionDeclarationStatement(statement);
|
2019-06-07 13:23:13 +00:00
|
|
|
case ParsedStatementKind::Return: return this -> BindReturnStatement(statement);
|
2019-06-08 12:25:15 +00:00
|
|
|
case ParsedStatementKind::Conditional: return this -> BindConditionalStatement(statement);
|
2019-05-28 15:49:03 +00:00
|
|
|
|
|
|
|
case ParsedStatementKind::Bad: return new BoundBadStatement();
|
2019-05-21 18:59:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BoundStatement *Binder::BindBlockStatement(ParsedStatement *statement) {
|
|
|
|
auto statements = ((ParsedBlockStatement*)statement)->GetStatements();
|
2019-06-11 12:58:43 +00:00
|
|
|
vector<BoundStatement*> boundStatements (statements->size());
|
2019-05-28 16:50:23 +00:00
|
|
|
this->_scope->GoInnerScope();
|
2019-06-11 12:58:43 +00:00
|
|
|
for (int i = 0; i < statements->size(); i++){
|
|
|
|
boundStatements[i] = this -> BindStatement(statements->at(i));
|
2019-05-21 18:59:26 +00:00
|
|
|
}
|
2019-05-28 16:50:23 +00:00
|
|
|
this->_scope->GoOuterScope();
|
2019-05-21 18:59:26 +00:00
|
|
|
return new BoundBlockStatement(boundStatements);
|
|
|
|
}
|
|
|
|
|
|
|
|
BoundStatement *Binder::BindExpressionStatement(ParsedStatement *statement) {
|
|
|
|
auto exp = ((ParsedExpressionStatement*)statement)->GetExpression();
|
|
|
|
return new BoundExpressionStatement(this -> BindExpression(exp));
|
|
|
|
}
|
|
|
|
|
2019-05-28 15:49:03 +00:00
|
|
|
BoundStatement* Binder::BindAssignmentStatement(ParsedStatement *statement){
|
|
|
|
auto s = (ParsedAssignmentStatement*) statement;
|
|
|
|
auto boundExpression = this->BindExpression(s->GetExpression());
|
2019-05-28 16:22:07 +00:00
|
|
|
VariableAssignment assignment =
|
|
|
|
s->IsLocal() ?
|
2019-06-01 17:20:31 +00:00
|
|
|
this->_scope->CreateExplicitLocal(s->GetIdentifier().GetHash(), boundExpression->GetType())
|
|
|
|
: this->_scope->AssignVariable(s->GetIdentifier().GetHash(), boundExpression->GetType());
|
2019-05-28 15:49:03 +00:00
|
|
|
if (assignment.GetResult() == VariableAssignmentResult::Ok){
|
|
|
|
auto key = assignment.GetKey();
|
|
|
|
return new BoundAssignmentStatement(key, boundExpression);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
this -> _scriptData -> Diagnostics -> LogError(DiagnosticCode::CantAssignVariable, statement->GetStartPosition(), statement->GetLength());
|
|
|
|
return new BoundBadStatement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-01 17:20:31 +00:00
|
|
|
std::shared_ptr<ScriptType> ParseTypeIdentifier(HashedString s){
|
2019-06-01 10:33:52 +00:00
|
|
|
switch (s.GetHash()){
|
2019-06-01 17:20:31 +00:00
|
|
|
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<ScriptType>(TypeClass::String);
|
|
|
|
default: return std::make_shared<ScriptType>(TypeClass::Error); // todo: change to userdata
|
2019-06-01 10:33:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BoundStatement *Binder::BindFunctionDeclarationStatement(ParsedStatement *statement) {
|
|
|
|
auto functionStatement = (ParsedFunctionDeclarationStatement*) statement;
|
|
|
|
auto parameters = functionStatement->GetParameters();
|
2019-06-08 14:02:21 +00:00
|
|
|
auto parameterTypes = vector<shared_ptr<ScriptType>>(parameters.size());
|
|
|
|
auto parameterKeys = vector<shared_ptr<BoundVariableKey>>(parameters.size());
|
|
|
|
|
2019-06-08 14:44:47 +00:00
|
|
|
auto scopeIndex = this->_scope->GetCurrentScope();
|
2019-06-01 10:33:52 +00:00
|
|
|
this->_scope->GoInnerScope();
|
|
|
|
for (int i = 0; i < parameters.size(); i++){
|
|
|
|
auto var = parameters[i];
|
|
|
|
auto parsedType = ParseTypeIdentifier(var->GetType());
|
2019-06-08 14:02:21 +00:00
|
|
|
parameterTypes.at(i) = parsedType;
|
2019-06-01 17:20:31 +00:00
|
|
|
auto parameterAssignment = this->_scope->CreateExplicitLocal(var->GetIdentifier().GetHash(), parsedType);
|
2019-06-01 11:43:25 +00:00
|
|
|
if (parameterAssignment.GetResult() == VariableAssignmentResult::Ok){
|
2019-06-08 14:02:21 +00:00
|
|
|
parameterKeys.at(i) = std::shared_ptr<BoundVariableKey>(parameterAssignment.GetKey());
|
2019-06-01 11:43:25 +00:00
|
|
|
}
|
|
|
|
else{
|
|
|
|
//TODO: log error
|
|
|
|
continue;
|
|
|
|
}
|
2019-06-01 10:33:52 +00:00
|
|
|
}
|
2019-06-08 14:02:21 +00:00
|
|
|
|
2019-06-01 10:33:52 +00:00
|
|
|
auto identifier = functionStatement->GetIdentifier();
|
2019-06-08 14:02:21 +00:00
|
|
|
auto returnType = make_shared<ScriptType>(TypeClass::Nil);
|
2019-06-08 14:44:47 +00:00
|
|
|
auto type = make_shared<FunctionScriptType>(returnType, parameterTypes, parameterKeys, scopeIndex);
|
2019-06-01 17:20:31 +00:00
|
|
|
auto assignment = this->_scope->AssignVariable(identifier.GetHash(), type);
|
2019-06-08 14:02:21 +00:00
|
|
|
if (assignment.GetResult() != VariableAssignmentResult::Ok){
|
2019-06-08 14:30:23 +00:00
|
|
|
this -> _scriptData -> Diagnostics -> LogError(DiagnosticCode::CantAssignVariable, statement->GetStartPosition(), statement->GetLength());
|
2019-06-08 14:02:21 +00:00
|
|
|
return new BoundBadStatement();
|
2019-06-01 10:33:52 +00:00
|
|
|
}
|
2019-06-08 14:02:21 +00:00
|
|
|
auto boundBlock = this -> BindBlockStatement(functionStatement->GetBlock());
|
|
|
|
this->_scope->GoOuterScope();
|
|
|
|
return new BoundFunctionDeclarationStatement(type, assignment.GetKey(), (BoundBlockStatement*)boundBlock);
|
2019-06-01 10:33:52 +00:00
|
|
|
}
|
|
|
|
|
2019-06-07 13:23:13 +00:00
|
|
|
BoundStatement *Binder::BindReturnStatement(ParsedStatement* statement){
|
|
|
|
auto expression = ((ParsedReturnStatement*)statement)->GetExpression();
|
|
|
|
shared_ptr<ScriptType> currentReturnType;
|
|
|
|
if (this->_currentFunction == nullptr){
|
|
|
|
currentReturnType = this->_scriptData->GetReturnType();
|
|
|
|
} else{
|
|
|
|
currentReturnType = this->_currentFunction;
|
|
|
|
}
|
|
|
|
if (expression == nullptr && currentReturnType != nullptr){
|
|
|
|
this -> _scriptData -> Diagnostics -> LogError(DiagnosticCode::InvalidReturnType, statement->GetStartPosition(), statement->GetLength());
|
|
|
|
return new BoundBadStatement();
|
|
|
|
}
|
|
|
|
auto boundExpression = this->BindExpression(expression);
|
|
|
|
auto expresionType = boundExpression->GetType();
|
|
|
|
if (currentReturnType == nullptr){
|
|
|
|
currentReturnType.swap(expresionType);
|
|
|
|
return new BoundReturnStatement(boundExpression);
|
|
|
|
}
|
|
|
|
if (currentReturnType.get()->operator!=(expresionType.get())){
|
|
|
|
this -> _scriptData -> Diagnostics -> LogError(DiagnosticCode::InvalidReturnType, statement->GetStartPosition(), statement->GetLength());
|
|
|
|
return new BoundBadStatement();
|
|
|
|
}
|
|
|
|
return new BoundReturnStatement(boundExpression);
|
|
|
|
}
|
|
|
|
|
2019-06-08 12:25:15 +00:00
|
|
|
BoundStatement *Binder::BindConditionalStatement(ParsedStatement* statement) {
|
|
|
|
auto conditionalStatement = (ParsedConditionalStatement*)statement;
|
|
|
|
auto boundCondition = this -> BindExpression(conditionalStatement -> GetCondition());
|
|
|
|
if (boundCondition->GetType() -> GetClass() != TypeClass::Bool){
|
|
|
|
this -> _scriptData -> Diagnostics -> LogError(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-05-21 18:59:26 +00:00
|
|
|
BoundExpression* Binder::BindExpression(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());
|
2019-05-22 11:29:35 +00:00
|
|
|
case ParsedExpressionKind ::LiteralString:
|
|
|
|
return new BoundLiteralStringExpression(((LiteralStringExpression*)expression)->GetValue(), expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 18:59:26 +00:00
|
|
|
case ParsedExpressionKind ::LiteralBool:
|
|
|
|
return new BoundLiteralBoolExpression(((LiteralBoolExpression*)expression)->GetValue(), expression->GetStartPosition(), expression->GetLength());
|
2019-05-30 13:23:48 +00:00
|
|
|
case ParsedExpressionKind ::Variable:
|
|
|
|
return this -> BindVariableExpression((VariableExpression*)expression);
|
2019-05-21 18:59:26 +00:00
|
|
|
|
2019-05-21 20:15:51 +00:00
|
|
|
case ParsedExpressionKind ::Binary:
|
|
|
|
return this -> BindBinaryOperator((BinaryExpression*)expression);
|
2019-05-22 10:22:52 +00:00
|
|
|
case ParsedExpressionKind ::Unary:
|
|
|
|
return this -> BindUnaryOperator((UnaryExpression*)expression);
|
2019-05-21 20:15:51 +00:00
|
|
|
|
2019-05-21 19:00:56 +00:00
|
|
|
case ParsedExpressionKind ::Parenthesized:
|
|
|
|
return BindExpression(((ParenthesizedExpression*)expression)->GetInnerExpression());
|
2019-06-01 17:20:31 +00:00
|
|
|
case ParsedExpressionKind ::FunctionCall:
|
|
|
|
return this->BindFunctionCall((FunctionCallExpression*)expression);
|
2019-05-21 19:00:56 +00:00
|
|
|
|
2019-06-06 15:35:51 +00:00
|
|
|
case ParsedExpressionKind ::Indexer:
|
|
|
|
return this->BindIndexExpression((IndexExpression*)expression);
|
2019-06-09 18:15:09 +00:00
|
|
|
case ParsedExpressionKind::NumericalTable:
|
|
|
|
return this -> BindNumericalTableExpression((ParsedNumericalTableExpression*)expression);
|
2019-06-06 15:35:51 +00:00
|
|
|
|
2019-05-21 18:59:26 +00:00
|
|
|
case ParsedExpressionKind ::Bad:
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression-> GetLength());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-30 13:23:48 +00:00
|
|
|
BoundExpression* Binder::BindVariableExpression(VariableExpression* expression){
|
|
|
|
auto key = expression->GetValue();
|
|
|
|
auto scope = this->_scope->Exists(key.GetHash());
|
|
|
|
if (scope == -1){
|
|
|
|
this -> _scriptData -> Diagnostics->LogError(DiagnosticCode::VariableNotFound, expression->GetStartPosition(), expression->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
auto var = this->_scope->GetVariable(scope, key.GetHash());
|
|
|
|
auto type = var->GetType();
|
|
|
|
return new BoundVariableExpression(scope, key.GetHash(), type, expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
|
2019-05-21 20:15:51 +00:00
|
|
|
BoundExpression* Binder::BindBinaryOperator(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){
|
2019-06-01 17:20:31 +00:00
|
|
|
auto leftNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundLeftType);
|
|
|
|
auto rightNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundRightType);
|
2019-05-21 20:15:51 +00:00
|
|
|
if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()){
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight,
|
2019-06-01 17:20:31 +00:00
|
|
|
BoundBinaryOperation::Addition,
|
|
|
|
std::make_shared<NumericScriptType>(true, leftNumeric->IsFloat() || rightNumeric->IsFloat()),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
|
|
|
else{
|
2019-06-01 17:20:31 +00:00
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Addition,
|
|
|
|
std::make_shared<NumericScriptType>(false, false),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
2019-05-25 14:15:20 +00:00
|
|
|
} else if (boundLeftType->GetClass() == TypeClass::String){
|
2019-06-01 17:20:31 +00:00
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Concatenation, std::make_shared<ScriptType>(TypeClass::String),
|
2019-05-25 14:15:20 +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){
|
2019-06-01 17:20:31 +00:00
|
|
|
auto leftNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundLeftType);
|
|
|
|
auto rightNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundRightType);
|
2019-05-21 20:15:51 +00:00
|
|
|
if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()){
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight,
|
2019-05-22 10:29:29 +00:00
|
|
|
BoundBinaryOperation::Subtraction,
|
2019-06-01 17:20:31 +00:00
|
|
|
std::make_shared<NumericScriptType>(true, leftNumeric->IsFloat() || rightNumeric->IsFloat()),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
|
|
|
else{
|
2019-06-01 17:20:31 +00:00
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Subtraction,
|
|
|
|
std::make_shared<NumericScriptType>(false, false),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BinaryOperatorKind ::Multiplication:
|
|
|
|
if (boundLeftType->GetClass() == TypeClass::Number && boundRightType->GetClass() == TypeClass::Number){
|
2019-06-01 17:20:31 +00:00
|
|
|
auto leftNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundLeftType);
|
|
|
|
auto rightNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundRightType);
|
2019-05-21 20:15:51 +00:00
|
|
|
if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()){
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight,
|
2019-05-22 10:29:29 +00:00
|
|
|
BoundBinaryOperation::Multiplication,
|
2019-06-01 17:20:31 +00:00
|
|
|
std::make_shared<NumericScriptType>(true, leftNumeric->IsFloat() || rightNumeric->IsFloat()),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
|
|
|
else{
|
2019-06-01 17:20:31 +00:00
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Multiplication,
|
|
|
|
std::make_shared<NumericScriptType>(false, false),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BinaryOperatorKind ::Division:
|
|
|
|
if (boundLeftType->GetClass() == TypeClass::Number && boundRightType->GetClass() == TypeClass::Number){
|
2019-06-01 17:20:31 +00:00
|
|
|
auto leftNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundLeftType);
|
|
|
|
auto rightNumeric = std::dynamic_pointer_cast<NumericScriptType>(boundRightType);
|
2019-05-21 20:15:51 +00:00
|
|
|
if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()){
|
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight,
|
2019-05-22 10:29:29 +00:00
|
|
|
BoundBinaryOperation::Division,
|
2019-06-01 17:20:31 +00:00
|
|
|
std::make_shared<NumericScriptType>(true, leftNumeric->IsFloat() || rightNumeric->IsFloat()),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
|
|
|
else{
|
2019-06-01 17:20:31 +00:00
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Division,
|
|
|
|
std::make_shared<NumericScriptType>(false, false),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-21 20:15:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BinaryOperatorKind ::Equality:
|
2019-06-01 17:20:31 +00:00
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Equality, std::make_shared<ScriptType>(TypeClass::Bool),
|
2019-05-22 10:29:29 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-05-25 12:17:52 +00:00
|
|
|
case BinaryOperatorKind ::Inequality:
|
2019-06-01 17:20:31 +00:00
|
|
|
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Inequality, std::make_shared<ScriptType>(TypeClass::Bool),
|
2019-05-25 12:17:52 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-06-08 13:38:08 +00:00
|
|
|
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),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
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),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
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),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
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),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
2019-05-21 20:15:51 +00:00
|
|
|
case BinaryOperatorKind ::LogicalAnd:
|
|
|
|
if (boundLeftType->GetClass() == TypeClass::Bool && boundRightType->GetClass() == TypeClass::Bool)
|
2019-06-01 17:20:31 +00:00
|
|
|
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-05-21 20:15:51 +00:00
|
|
|
break;
|
|
|
|
case BinaryOperatorKind ::LogicalOr:
|
|
|
|
if (boundLeftType->GetClass() == TypeClass::Bool && boundRightType->GetClass() == TypeClass::Bool)
|
2019-06-01 17:20:31 +00:00
|
|
|
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-05-21 20:15:51 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-05-28 15:49:03 +00:00
|
|
|
this -> _scriptData -> Diagnostics->LogError(DiagnosticCode::NoBinaryOperationFound, expression->GetStartPosition(), expression->GetLength());
|
2019-05-22 10:22:52 +00:00
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
|
|
|
|
BoundExpression* Binder::BindUnaryOperator(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){
|
2019-06-01 17:20:31 +00:00
|
|
|
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());
|
2019-05-22 10:22:52 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case UnaryOperatorKind ::LogicalNegation:
|
|
|
|
if (operandType->GetClass() == TypeClass::Bool){
|
2019-06-01 17:20:31 +00:00
|
|
|
return new BoundUnaryExpression(operand, BoundUnaryOperation::LogicalNegation,
|
|
|
|
std::make_shared<ScriptType>(TypeClass::Bool),
|
2019-05-22 10:22:52 +00:00
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2019-05-28 15:49:03 +00:00
|
|
|
this -> _scriptData -> Diagnostics->LogError(DiagnosticCode::NoUnaryOperationFound, expression->GetStartPosition(), expression->GetLength());
|
2019-05-22 10:22:52 +00:00
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
|
2019-05-28 15:49:03 +00:00
|
|
|
}
|
|
|
|
|
2019-06-01 17:20:31 +00:00
|
|
|
BoundExpression* Binder::BindFunctionCall(FunctionCallExpression* expression){
|
|
|
|
auto functionExpression = BindExpression(expression->GetFunction());
|
|
|
|
auto type = functionExpression->GetType();
|
|
|
|
if (type->GetClass() != TypeClass::Function){
|
|
|
|
this->_scriptData->Diagnostics->LogError(DiagnosticCode::ExpressionIsNotAFunction, expression->GetStartPosition(),
|
|
|
|
expression->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
auto functionType = std::dynamic_pointer_cast<FunctionScriptType>(type);
|
|
|
|
auto parameterTypes = functionType->GetParameterTypes();
|
|
|
|
auto givenParameters = expression->GetParameters();
|
2019-06-08 14:02:21 +00:00
|
|
|
if (parameterTypes.size() != givenParameters.size()){
|
2019-06-01 17:20:31 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(DiagnosticCode::ParameterCountMismatch, 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[i];
|
|
|
|
auto boundParameter = this -> BindExpression(parameter);
|
2019-06-08 14:02:21 +00:00
|
|
|
if (boundParameter->GetType().get()->operator!=(parameterTypes.at(i).get())){
|
2019-06-01 17:20:31 +00:00
|
|
|
this->_scriptData->Diagnostics->LogError(DiagnosticCode::ParameterTypeMismatch, parameter->GetStartPosition(),
|
|
|
|
parameter->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
|
|
|
boundParameters[i] = boundParameter;
|
|
|
|
}
|
2019-06-01 10:33:52 +00:00
|
|
|
|
2019-06-01 17:20:31 +00:00
|
|
|
return new BoundFunctionCallExpression(functionExpression, boundParameters, functionType.get()->GetReturnType(),
|
|
|
|
expression->GetStartPosition(), expression->GetLength());
|
2019-06-06 15:35:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BoundExpression *Binder::BindIndexExpression(IndexExpression *expression) {
|
|
|
|
auto indexer = this->BindExpression(expression->GetIndexer());
|
|
|
|
auto index = this->BindExpression(expression->GetIndex());
|
|
|
|
|
|
|
|
if (!indexer->GetType()->CanBeIndexedWith(index->GetType().get())){
|
|
|
|
this->_scriptData->Diagnostics->LogError(DiagnosticCode::CantIndex, index->GetStartPosition(),
|
|
|
|
index->GetLength());
|
|
|
|
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
2019-06-09 18:15:09 +00:00
|
|
|
auto resultType = indexer->GetType()->GetIndexedType(index->GetType().get());
|
2019-06-06 15:35:51 +00:00
|
|
|
return new BoundIndexExpression(indexer, index, resultType, expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|
2019-06-08 12:25:15 +00:00
|
|
|
|
2019-06-09 18:15:09 +00:00
|
|
|
BoundExpression* Binder::BindNumericalTableExpression(ParsedNumericalTableExpression* expression){
|
|
|
|
auto expressions = expression->GetExpressions();
|
|
|
|
auto boundExpressions = vector<BoundExpression*>(expressions.size());
|
|
|
|
shared_ptr<ScriptType> valueType = nullptr;
|
|
|
|
if (!boundExpressions.empty()){
|
|
|
|
boundExpressions[0] = this -> BindExpression(expressions[0]);
|
|
|
|
valueType = boundExpressions[0] -> GetType();
|
|
|
|
for (int i = 1; i < expressions.size(); i++){
|
|
|
|
boundExpressions[i] = this -> BindExpression(expressions[i]);
|
|
|
|
if (boundExpressions[i] -> GetType().get()->operator!=(valueType.get())){
|
|
|
|
this->_scriptData->Diagnostics->LogError(DiagnosticCode::InvalidTableValueType, boundExpressions[i]->GetStartPosition(),
|
|
|
|
boundExpressions[i]->GetLength());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (valueType == nullptr){
|
|
|
|
valueType = std::make_shared<ScriptType>(TypeClass::Nil);
|
|
|
|
}
|
|
|
|
auto keyType = std::make_shared<ScriptType>(TypeClass::Number);
|
|
|
|
auto tableType = std::make_shared<TableScriptType>(keyType, valueType);
|
|
|
|
return new BoundNumericalTableExpression(boundExpressions, tableType, expression->GetStartPosition(), expression->GetLength());
|
|
|
|
}
|