Support for explicit casting
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2019-08-18 14:32:14 +02:00
parent 1d72e2eccd
commit e939920e5c
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
8 changed files with 173 additions and 105 deletions

View File

@ -1,5 +1,5 @@
#include <memory>
#include <memory>
#include "Binder.hpp" #include "Binder.hpp"
#include "../ScriptTypes/TableScriptType.hpp" #include "../ScriptTypes/TableScriptType.hpp"
#include "BoundExpressions/BoundTableExpression.hpp" #include "BoundExpressions/BoundTableExpression.hpp"
@ -48,9 +48,9 @@ namespace Porygon::Binder {
case ParsedStatementKind::NumericalFor: case ParsedStatementKind::NumericalFor:
return this->BindNumericalForStatement(statement); return this->BindNumericalForStatement(statement);
case ParsedStatementKind::GenericFor: case ParsedStatementKind::GenericFor:
return this -> BindGenericForStatement(statement); return this->BindGenericForStatement(statement);
case ParsedStatementKind::While: case ParsedStatementKind::While:
return this -> BindWhileStatement(statement); return this->BindWhileStatement(statement);
case ParsedStatementKind::Break: case ParsedStatementKind::Break:
//TODO: Validate we're in a loop //TODO: Validate we're in a loop
return new BoundBreakStatement(); return new BoundBreakStatement();
@ -87,7 +87,8 @@ namespace Porygon::Binder {
auto key = assignment.GetKey(); auto key = assignment.GetKey();
return new BoundAssignmentStatement(key, boundExpression); return new BoundAssignmentStatement(key, boundExpression);
} else { } else {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable,
statement->GetStartPosition(),
statement->GetLength()); statement->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
@ -114,7 +115,7 @@ namespace Porygon::Binder {
return new BoundIndexAssignmentStatement(indexable, valueExpression); return new BoundIndexAssignmentStatement(indexable, valueExpression);
} }
std::shared_ptr<ScriptType> ParseTypeIdentifier(const HashedString* s) { std::shared_ptr<ScriptType> ParseTypeIdentifier(const HashedString *s) {
auto hash = s->GetHash(); auto hash = s->GetHash();
switch (hash) { switch (hash) {
case HashedString::ConstHash("number"): case HashedString::ConstHash("number"):
@ -142,7 +143,8 @@ namespace Porygon::Binder {
auto var = parameters->at(i); auto var = parameters->at(i);
auto parsedType = ParseTypeIdentifier(var->GetType()); auto parsedType = ParseTypeIdentifier(var->GetType());
if (parsedType == nullptr) { if (parsedType == nullptr) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidTypeName, statement->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidTypeName,
statement->GetStartPosition(),
statement->GetLength()); statement->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
@ -162,31 +164,33 @@ namespace Porygon::Binder {
this->_currentFunction = option; this->_currentFunction = option;
shared_ptr<const GenericFunctionScriptType> type; shared_ptr<const GenericFunctionScriptType> type;
auto scope = this -> _scope -> Exists(identifier); auto scope = this->_scope->Exists(identifier);
const BoundVariableKey* assignmentKey; const BoundVariableKey *assignmentKey;
if (scope >= 0){ if (scope >= 0) {
auto var = this -> _scope -> GetVariable(scope, identifier); auto var = this->_scope->GetVariable(scope, identifier);
auto varType =var->GetType(); auto varType = var->GetType();
if (varType->GetClass() != TypeClass::Function){ if (varType->GetClass() != TypeClass::Function) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable,
statement->GetStartPosition(),
statement->GetLength()); statement->GetLength());
} }
type = dynamic_pointer_cast<const GenericFunctionScriptType>(varType); type = dynamic_pointer_cast<const GenericFunctionScriptType>(varType);
type->RegisterFunctionOption(option); type->RegisterFunctionOption(option);
assignmentKey = new BoundVariableKey(identifier, scope, false); assignmentKey = new BoundVariableKey(identifier, scope, false);
} else{ } else {
type = make_shared<const GenericFunctionScriptType>(); type = make_shared<const GenericFunctionScriptType>();
type->RegisterFunctionOption(option); type->RegisterFunctionOption(option);
auto assignment = this->_scope->AssignVariable(identifier, type); auto assignment = this->_scope->AssignVariable(identifier, type);
if (assignment.GetResult() != VariableAssignmentResult::Ok) { if (assignment.GetResult() != VariableAssignmentResult::Ok) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable,
statement->GetStartPosition(),
statement->GetLength()); statement->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
assignmentKey = assignment.GetKey(); assignmentKey = assignment.GetKey();
} }
auto boundBlock = dynamic_cast<BoundBlockStatement*>(this->BindBlockStatement(functionStatement->GetBlock())); auto boundBlock = dynamic_cast<BoundBlockStatement *>(this->BindBlockStatement(functionStatement->GetBlock()));
this->_scope->GoOuterScope(); this->_scope->GoOuterScope();
this->_currentFunction = nullptr; this->_currentFunction = nullptr;
return new BoundFunctionDeclarationStatement(type, assignmentKey, boundBlock); return new BoundFunctionDeclarationStatement(type, assignmentKey, boundBlock);
@ -200,11 +204,13 @@ namespace Porygon::Binder {
} else { } else {
currentReturnType = this->_currentFunction->GetReturnType(); currentReturnType = this->_currentFunction->GetReturnType();
} }
if (expression == nullptr && (currentReturnType != nullptr && currentReturnType -> GetClass() != TypeClass::Nil)) { if (expression == nullptr &&
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidReturnType, statement->GetStartPosition(), (currentReturnType != nullptr && currentReturnType->GetClass() != TypeClass::Nil)) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidReturnType,
statement->GetStartPosition(),
statement->GetLength()); statement->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} else if (expression == nullptr){ } else if (expression == nullptr) {
currentReturnType = make_shared<ScriptType>(TypeClass::Nil); currentReturnType = make_shared<ScriptType>(TypeClass::Nil);
return new BoundReturnStatement(nullptr); return new BoundReturnStatement(nullptr);
} }
@ -219,7 +225,8 @@ namespace Porygon::Binder {
return new BoundReturnStatement(boundExpression); return new BoundReturnStatement(boundExpression);
} }
if (currentReturnType.get()->operator!=(expresionType.get())) { if (currentReturnType.get()->operator!=(expresionType.get())) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidReturnType, statement->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidReturnType,
statement->GetStartPosition(),
statement->GetLength()); statement->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
@ -230,7 +237,8 @@ namespace Porygon::Binder {
auto conditionalStatement = (ParsedConditionalStatement *) statement; auto conditionalStatement = (ParsedConditionalStatement *) statement;
auto boundCondition = this->BindExpression(conditionalStatement->GetCondition()); auto boundCondition = this->BindExpression(conditionalStatement->GetCondition());
if (boundCondition->GetType()->GetClass() != TypeClass::Bool) { if (boundCondition->GetType()->GetClass() != TypeClass::Bool) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ConditionNotABool, statement->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ConditionNotABool,
statement->GetStartPosition(),
statement->GetLength()); statement->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
@ -243,92 +251,100 @@ namespace Porygon::Binder {
} }
BoundStatement *Binder::BindNumericalForStatement(const ParsedStatement *statement) { BoundStatement *Binder::BindNumericalForStatement(const ParsedStatement *statement) {
auto forStatement = (ParsedNumericalForStatement*) statement; auto forStatement = (ParsedNumericalForStatement *) statement;
auto identifier = forStatement->GetIdentifier(); auto identifier = forStatement->GetIdentifier();
auto start = this -> BindExpression(forStatement->GetStart()); auto start = this->BindExpression(forStatement->GetStart());
auto end = this -> BindExpression(forStatement->GetEnd()); auto end = this->BindExpression(forStatement->GetEnd());
auto parsedStep = forStatement -> GetStep(); auto parsedStep = forStatement->GetStep();
BoundExpression* step = nullptr; BoundExpression *step = nullptr;
if (parsedStep != nullptr){ if (parsedStep != nullptr) {
step = this -> BindExpression(parsedStep); step = this->BindExpression(parsedStep);
} }
if (start -> GetType()->GetClass() != TypeClass::Number){ if (start->GetType()->GetClass() != TypeClass::Number) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NumericalForArgumentNotANumber, start->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NumericalForArgumentNotANumber,
start->GetStartPosition(),
start->GetLength()); start->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
if (end -> GetType()->GetClass() != TypeClass::Number){ if (end->GetType()->GetClass() != TypeClass::Number) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NumericalForArgumentNotANumber, end->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NumericalForArgumentNotANumber,
end->GetStartPosition(),
end->GetLength()); end->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
if (step != nullptr && step -> GetType()->GetClass() != TypeClass::Number){ if (step != nullptr && step->GetType()->GetClass() != TypeClass::Number) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NumericalForArgumentNotANumber, step->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NumericalForArgumentNotANumber,
step->GetStartPosition(),
step->GetLength()); step->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
this -> _scope ->GoInnerScope(); this->_scope->GoInnerScope();
auto variableKey = this -> _scope ->CreateExplicitLocal(identifier, make_shared<NumericScriptType>(true, false)); auto variableKey = this->_scope->CreateExplicitLocal(identifier, make_shared<NumericScriptType>(true, false));
if (variableKey.GetResult() != VariableAssignmentResult::Ok){ if (variableKey.GetResult() != VariableAssignmentResult::Ok) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable,
statement->GetStartPosition(),
statement->GetLength()); statement->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
auto block = this -> BindBlockStatement(forStatement->GetBlock()); auto block = this->BindBlockStatement(forStatement->GetBlock());
this -> _scope ->GoOuterScope(); this->_scope->GoOuterScope();
return new BoundNumericalForStatement(variableKey.GetKey(), start, end, step, block); return new BoundNumericalForStatement(variableKey.GetKey(), start, end, step, block);
} }
BoundStatement *Binder::BindGenericForStatement(const ParsedStatement *statement) { BoundStatement *Binder::BindGenericForStatement(const ParsedStatement *statement) {
auto genericFor = (ParsedGenericForStatement*) statement; auto genericFor = (ParsedGenericForStatement *) statement;
auto boundIterator = BindExpression(genericFor -> GetIteratorExpression()); auto boundIterator = BindExpression(genericFor->GetIteratorExpression());
const auto& itType = boundIterator -> GetType(); const auto &itType = boundIterator->GetType();
if (!itType -> CanBeIterated()){ if (!itType->CanBeIterated()) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantIterateExpression, statement->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantIterateExpression,
statement->GetStartPosition(),
statement->GetLength()); statement->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
auto keyType = itType -> GetIteratorKeyType(); auto keyType = itType->GetIteratorKeyType();
auto keyIdentifier = genericFor -> GetKeyIdentifier(); auto keyIdentifier = genericFor->GetKeyIdentifier();
this -> _scope -> GoInnerScope(); this->_scope->GoInnerScope();
auto keyVariableAssignment = this -> _scope -> CreateExplicitLocal(keyIdentifier, keyType); auto keyVariableAssignment = this->_scope->CreateExplicitLocal(keyIdentifier, keyType);
if (keyVariableAssignment.GetResult() != VariableAssignmentResult::Ok){ if (keyVariableAssignment.GetResult() != VariableAssignmentResult::Ok) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable,
statement->GetStartPosition(),
statement->GetLength()); statement->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
auto keyVariable = keyVariableAssignment.GetKey(); auto keyVariable = keyVariableAssignment.GetKey();
auto valueIdentifier = genericFor -> GetValueIdentifier(); auto valueIdentifier = genericFor->GetValueIdentifier();
auto isValueVariableDefined = valueIdentifier.GetHash() != 0; auto isValueVariableDefined = valueIdentifier.GetHash() != 0;
const BoundVariableKey* valueVariable = nullptr; const BoundVariableKey *valueVariable = nullptr;
if (isValueVariableDefined){ if (isValueVariableDefined) {
auto valueType = itType -> GetIndexedType(keyType.get()); auto valueType = itType->GetIndexedType(keyType.get());
auto valueVariableAssignment = this -> _scope -> CreateExplicitLocal(valueIdentifier, valueType); auto valueVariableAssignment = this->_scope->CreateExplicitLocal(valueIdentifier, valueType);
if (valueVariableAssignment.GetResult() != VariableAssignmentResult::Ok){ if (valueVariableAssignment.GetResult() != VariableAssignmentResult::Ok) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable,
statement->GetStartPosition(),
statement->GetLength()); statement->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
valueVariable = valueVariableAssignment.GetKey(); valueVariable = valueVariableAssignment.GetKey();
} }
auto boundBlock = this -> BindBlockStatement(genericFor -> GetBlock()); auto boundBlock = this->BindBlockStatement(genericFor->GetBlock());
this -> _scope -> GoOuterScope(); this->_scope->GoOuterScope();
return new BoundGenericForStatement(keyVariable, valueVariable, boundIterator, boundBlock); return new BoundGenericForStatement(keyVariable, valueVariable, boundIterator, boundBlock);
} }
BoundStatement *Binder::BindWhileStatement(const ParsedStatement *statement) { BoundStatement *Binder::BindWhileStatement(const ParsedStatement *statement) {
auto whileStatement = (ParsedWhileStatement*)statement; auto whileStatement = (ParsedWhileStatement *) statement;
auto boundCondition = this -> BindExpression(whileStatement->GetCondition()); auto boundCondition = this->BindExpression(whileStatement->GetCondition());
if (boundCondition->GetType()->GetClass() != TypeClass::Bool){ if (boundCondition->GetType()->GetClass() != TypeClass::Bool) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ConditionNotABool, statement->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ConditionNotABool,
statement->GetStartPosition(),
statement->GetLength()); statement->GetLength());
return new BoundBadStatement(); return new BoundBadStatement();
} }
auto boundBlock = this -> BindBlockStatement(whileStatement->GetBlock()); auto boundBlock = this->BindBlockStatement(whileStatement->GetBlock());
return new BoundWhileStatement(boundCondition, boundBlock); return new BoundWhileStatement(boundCondition, boundBlock);
} }
@ -382,7 +398,8 @@ namespace Porygon::Binder {
auto key = expression->GetValue(); auto key = expression->GetValue();
auto scope = this->_scope->Exists(key); auto scope = this->_scope->Exists(key);
if (scope == -1) { if (scope == -1) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::VariableNotFound, expression->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::VariableNotFound,
expression->GetStartPosition(),
expression->GetLength()); expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength()); return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
} }
@ -526,7 +543,8 @@ namespace Porygon::Binder {
expression->GetStartPosition(), expression->GetLength()); expression->GetStartPosition(), expression->GetLength());
break; break;
} }
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NoBinaryOperationFound, expression->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NoBinaryOperationFound,
expression->GetStartPosition(),
expression->GetLength()); expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength()); return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
} }
@ -561,7 +579,8 @@ namespace Porygon::Binder {
default: default:
break; break;
} }
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NoUnaryOperationFound, expression->GetStartPosition(), this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::NoUnaryOperationFound,
expression->GetStartPosition(),
expression->GetLength()); expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength()); return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
@ -569,10 +588,13 @@ namespace Porygon::Binder {
BoundExpression *Binder::BindFunctionCall(const FunctionCallExpression *expression) { BoundExpression *Binder::BindFunctionCall(const FunctionCallExpression *expression) {
auto func = expression->GetFunction(); auto func = expression->GetFunction();
if (func->GetKind() == ParsedExpressionKind::Variable){ if (func->GetKind() == ParsedExpressionKind::Variable) {
auto variable = dynamic_cast<const VariableExpression*>(func); auto variable = dynamic_cast<const VariableExpression *>(func);
if (variable->GetValue().GetHash() == HashedString::ConstHash("require")){ auto hash = variable->GetValue().GetHash();
if (hash == HashedString::ConstHash("require")) {
return this->BindRequire(expression); return this->BindRequire(expression);
} else if (hash == HashedString::ConstHash("cast")) {
return this->BindCast(expression);
} }
} }
auto functionExpression = BindExpression(func); auto functionExpression = BindExpression(func);
@ -586,58 +608,96 @@ namespace Porygon::Binder {
auto functionType = std::dynamic_pointer_cast<const GenericFunctionScriptType>(type); auto functionType = std::dynamic_pointer_cast<const GenericFunctionScriptType>(type);
auto givenParameters = expression->GetParameters(); auto givenParameters = expression->GetParameters();
vector<BoundExpression *> boundParameters = vector<BoundExpression *>(givenParameters->size()); vector<BoundExpression *> boundParameters = vector<BoundExpression *>(givenParameters->size());
for (size_t i = 0; i < givenParameters->size(); i++){ for (size_t i = 0; i < givenParameters->size(); i++) {
boundParameters[i] = this -> BindExpression(givenParameters->at(i)); boundParameters[i] = this->BindExpression(givenParameters->at(i));
} }
auto functionOption = functionType->GetFunctionOption(this->_scriptData->Diagnostics, &boundParameters); auto functionOption = functionType->GetFunctionOption(this->_scriptData->Diagnostics, &boundParameters);
if (functionOption == nullptr){ if (functionOption == nullptr) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters, this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters,
expression->GetStartPosition(), expression->GetStartPosition(),
expression->GetLength()); expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength()); return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
} }
return new BoundFunctionCallExpression(functionExpression, boundParameters, functionOption, functionOption->GetReturnType(), return new BoundFunctionCallExpression(functionExpression, boundParameters, functionOption,
functionOption->GetReturnType(),
expression->GetStartPosition(), expression->GetLength()); expression->GetStartPosition(), expression->GetLength());
} }
BoundExpression *Binder::BindRequire(const FunctionCallExpression* exp){ BoundExpression *Binder::BindRequire(const FunctionCallExpression *exp) {
auto parameters = exp->GetParameters(); auto parameters = exp->GetParameters();
if (parameters->size() != 1){ if (parameters->size() != 1) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters, this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters,
exp->GetStartPosition(), exp->GetStartPosition(),
exp->GetLength()); exp->GetLength());
return new BoundBadExpression(exp->GetStartPosition(), exp ->GetLength()); return new BoundBadExpression(exp->GetStartPosition(), exp->GetLength());
} }
auto parameter = parameters->at(0); auto parameter = parameters->at(0);
auto boundParameter = this -> BindExpression(parameter); auto boundParameter = this->BindExpression(parameter);
if (boundParameter->GetKind() != BoundExpressionKind::LiteralString){ if (boundParameter->GetKind() != BoundExpressionKind::LiteralString) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters, this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters,
exp->GetStartPosition(), exp->GetStartPosition(),
exp->GetLength()); exp->GetLength());
return new BoundBadExpression(exp->GetStartPosition(), exp ->GetLength()); return new BoundBadExpression(exp->GetStartPosition(), exp->GetLength());
} }
auto key = *dynamic_cast<BoundLiteralStringExpression*>(boundParameter)->GetValue(); auto key = *dynamic_cast<BoundLiteralStringExpression *>(boundParameter)->GetValue();
auto opt = this->_scriptData->GetScriptOptions(); auto opt = this->_scriptData->GetScriptOptions();
auto transformedKey = Utilities::StringUtils::FromUTF8(key); auto transformedKey = Utilities::StringUtils::FromUTF8(key);
delete boundParameter; delete boundParameter;
if (!opt->DoesModuleExist(transformedKey)){ if (!opt->DoesModuleExist(transformedKey)) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ModuleDoesntExist, this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ModuleDoesntExist,
exp->GetStartPosition(), exp->GetStartPosition(),
exp->GetLength()); exp->GetLength());
return new BoundBadExpression(exp->GetStartPosition(), exp ->GetLength()); return new BoundBadExpression(exp->GetStartPosition(), exp->GetLength());
} }
auto module = Script::Clone(opt->ResolveModule(transformedKey)); auto module = Script::Clone(opt->ResolveModule(transformedKey));
if (module -> GetReturnType() == nullptr){ if (module->GetReturnType() == nullptr) {
for (const auto& v: *module->GetScriptVariables()){ for (const auto &v: *module->GetScriptVariables()) {
auto type = module->GetVariableType(v.first); auto type = module->GetVariableType(v.first);
auto result = this -> _scope -> AssignVariable(v.first, type); auto result = this->_scope->AssignVariable(v.first, type);
delete result.GetKey(); delete result.GetKey();
} }
} }
return new BoundRequireExpression(module, exp->GetStartPosition(), exp ->GetLength()); return new BoundRequireExpression(module, exp->GetStartPosition(), exp->GetLength());
}
BoundExpression *Binder::BindCast(const FunctionCallExpression* exp){
auto parameters = exp->GetParameters();
if (parameters->size() != 2) {
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters,
exp->GetStartPosition(),
exp->GetLength());
return new BoundBadExpression(exp->GetStartPosition(), exp->GetLength());
}
auto toCastParameter = this ->BindExpression(parameters->at(0));
const auto& toCastParameterType = toCastParameter->GetType();
auto destinationTypeParameter = parameters -> at(1);
if (destinationTypeParameter ->GetKind() != ParsedExpressionKind::Variable){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters,
exp->GetStartPosition(),
exp->GetLength());
return new BoundBadExpression(exp->GetStartPosition(), exp->GetLength());
}
auto destinationTypeContent = dynamic_cast<const VariableExpression*>(destinationTypeParameter)->GetValue();
auto destinationType = ParseTypeIdentifier(&destinationTypeContent);
auto castResult = toCastParameterType->CastableTo(destinationType, true);
if (castResult == CastResult::InvalidCast){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidCast, exp->GetStartPosition(),
exp->GetLength());
return new BoundBadExpression(exp->GetStartPosition(), exp->GetLength());
}
else if (castResult == CastResult::DataLoss){
this->_scriptData->Diagnostics->LogWarning(Diagnostics::DiagnosticCode::DataLossOnCast, exp->GetStartPosition(),
exp->GetLength());
}
else if (castResult == CastResult::UncheckedCast){
this->_scriptData->Diagnostics->LogInfo(Diagnostics::DiagnosticCode::UnvalidatedCast, exp->GetStartPosition(),
exp->GetLength());
}
return new BoundCastExpression(toCastParameter, destinationType);
} }
BoundExpression *Binder::BindIndexExpression(const IndexExpression *expression, bool setter) { BoundExpression *Binder::BindIndexExpression(const IndexExpression *expression, bool setter) {

View File

@ -42,6 +42,7 @@ namespace Porygon::Binder {
BoundExpression *BindUnaryOperator(const UnaryExpression *expression); BoundExpression *BindUnaryOperator(const UnaryExpression *expression);
BoundExpression *BindFunctionCall(const FunctionCallExpression *expression); BoundExpression *BindFunctionCall(const FunctionCallExpression *expression);
BoundExpression *BindRequire(const FunctionCallExpression *exp); BoundExpression *BindRequire(const FunctionCallExpression *exp);
BoundExpression *BindCast(const FunctionCallExpression *exp);
BoundExpression *BindIndexExpression(const IndexExpression *expression, bool setter); BoundExpression *BindIndexExpression(const IndexExpression *expression, bool setter);
BoundExpression *BindNumericalTableExpression(const ParsedNumericalTableExpression *expression); BoundExpression *BindNumericalTableExpression(const ParsedNumericalTableExpression *expression);
BoundExpression *BindTableExpression(const ParsedTableExpression *expression); BoundExpression *BindTableExpression(const ParsedTableExpression *expression);

View File

@ -28,7 +28,7 @@ namespace Porygon::Binder {
NumericalTable, NumericalTable,
Table, Table,
Require, Require,
ImplicitCast, Cast,
}; };
class BoundExpression { class BoundExpression {
@ -333,10 +333,10 @@ namespace Porygon::Binder {
} }
}; };
class BoundImplicitCastExpression : public BoundExpression { class BoundCastExpression : public BoundExpression {
const BoundExpression* _expression; const BoundExpression* _expression;
public: public:
BoundImplicitCastExpression(BoundExpression* expression, shared_ptr<const ScriptType> castType) BoundCastExpression(BoundExpression* expression, shared_ptr<const ScriptType> castType)
: BoundExpression(expression->GetStartPosition(), expression->GetLength(), castType), : BoundExpression(expression->GetStartPosition(), expression->GetLength(), castType),
_expression(expression) _expression(expression)
{} {}
@ -345,13 +345,13 @@ namespace Porygon::Binder {
return _expression; return _expression;
} }
~BoundImplicitCastExpression() final { ~BoundCastExpression() final {
delete _expression; delete _expression;
} }
[[nodiscard]] [[nodiscard]]
inline BoundExpressionKind GetKind() const final { inline BoundExpressionKind GetKind() const final {
return BoundExpressionKind::ImplicitCast; return BoundExpressionKind::Cast;
} }
}; };

View File

@ -28,9 +28,13 @@ namespace Porygon::Diagnostics {
CantIterateExpression, CantIterateExpression,
InvalidFunctionParameters, InvalidFunctionParameters,
ModuleDoesntExist, ModuleDoesntExist,
InvalidCast,
// Bind warnings // Bind warnings
DataLossOnImplicitCast, DataLossOnCast,
// Bind info
UnvalidatedCast,
}; };
} }
#endif //PORYGONLANG_DIAGNOSTICCODE_HPP #endif //PORYGONLANG_DIAGNOSTICCODE_HPP

View File

@ -257,7 +257,7 @@ namespace Porygon::Evaluation {
return this->EvaluateComplexTableExpression(expression); return this->EvaluateComplexTableExpression(expression);
case BoundExpressionKind::Require: case BoundExpressionKind::Require:
return this -> EvaluateRequireExpression(expression); return this -> EvaluateRequireExpression(expression);
case BoundExpressionKind::ImplicitCast: case BoundExpressionKind::Cast:
return this -> EvaluateImplicitCastExpression(expression); return this -> EvaluateImplicitCastExpression(expression);
} }
} }
@ -416,7 +416,7 @@ namespace Porygon::Evaluation {
} }
EvalValuePointer Evaluator::EvaluateImplicitCastExpression(const BoundExpression *pExpression) { EvalValuePointer Evaluator::EvaluateImplicitCastExpression(const BoundExpression *pExpression) {
auto iCExpression = dynamic_cast<const BoundImplicitCastExpression*>(pExpression); auto iCExpression = dynamic_cast<const BoundCastExpression*>(pExpression);
auto val = EvaluateExpression(iCExpression->GetExpression()); auto val = EvaluateExpression(iCExpression->GetExpression());
return val->Cast(iCExpression->GetType()); return val->Cast(iCExpression->GetType());
} }

View File

@ -3,8 +3,9 @@
namespace Porygon{ namespace Porygon{
enum class CastResult{ enum class CastResult{
Success, ValidCast,
Failure, InvalidCast,
UncheckedCast,
DataLoss, DataLoss,
}; };
} }

View File

@ -47,15 +47,15 @@ namespace Porygon {
const auto& parameterType = parameter->GetType(); const auto& parameterType = parameter->GetType();
if (parameterType->operator!=(_parameterTypes[i].get())){ if (parameterType->operator!=(_parameterTypes[i].get())){
auto castResult = parameterType->CastableTo(_parameterTypes[i], false); auto castResult = parameterType->CastableTo(_parameterTypes[i], false);
if (castResult == CastResult::Failure){ if (castResult == CastResult::InvalidCast){
return false; return false;
} }
else{ else{
if (castResult == CastResult::DataLoss){ if (castResult == CastResult::DataLoss){
diagnostics->LogWarning(Diagnostics::DiagnosticCode::DataLossOnImplicitCast, parameter->GetStartPosition(), diagnostics->LogWarning(Diagnostics::DiagnosticCode::DataLossOnCast, parameter->GetStartPosition(),
parameter->GetLength()); parameter->GetLength());
} }
parameters->at(i) = new Binder::BoundImplicitCastExpression(parameter, _parameterTypes[i]); parameters->at(i) = new Binder::BoundCastExpression(parameter, _parameterTypes[i]);
} }
} }
} }

View File

@ -77,7 +77,9 @@ namespace Porygon{
} }
[[nodiscard]] virtual CastResult CastableTo(const shared_ptr<const ScriptType>& castType, bool explicitCast) const{ [[nodiscard]] virtual CastResult CastableTo(const shared_ptr<const ScriptType>& castType, bool explicitCast) const{
return CastResult::Failure; if (explicitCast)
return CastResult::InvalidCast;
return CastResult::InvalidCast;
} }
}; };
@ -120,12 +122,12 @@ namespace Porygon{
[[nodiscard]] CastResult CastableTo(const shared_ptr<const ScriptType>& castType, bool explicitCast) const final{ [[nodiscard]] CastResult CastableTo(const shared_ptr<const ScriptType>& castType, bool explicitCast) const final{
if (!explicitCast){ if (!explicitCast){
if (castType->GetClass() != TypeClass::Number ) if (castType->GetClass() != TypeClass::Number )
return CastResult::Failure; return CastResult::InvalidCast;
auto bNum = dynamic_pointer_cast<const NumericScriptType>(castType); auto bNum = dynamic_pointer_cast<const NumericScriptType>(castType);
if (bNum->IsFloat() && !IsFloat()) return CastResult::Success; if (bNum->IsFloat() && !IsFloat()) return CastResult::ValidCast;
if (!bNum->IsFloat() && IsFloat()) return CastResult::DataLoss; if (!bNum->IsFloat() && IsFloat()) return CastResult::DataLoss;
} }
return CastResult::Success; return ScriptType::CastableTo(castType, explicitCast);
} }
}; };