PorygonLang/src/Binder/Binder.cpp

271 lines
15 KiB
C++
Raw Normal View History

2019-05-21 16:09:08 +00:00
#include "Binder.hpp"
#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) {
auto binder = Binder();
2019-05-28 15:49:03 +00:00
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[i]);
}
return new BoundScriptStatement(boundStatements, scriptScope->GetDeepestScope());
2019-05-21 16:09:08 +00:00
}
2019-05-28 15:49:03 +00:00
Binder::~Binder() {
delete _scope;
}
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);
case ParsedStatementKind ::FunctionDeclaration: return this->BindFunctionDeclarationStatement(statement);
2019-05-28 15:49:03 +00:00
case ParsedStatementKind::Bad: return new BoundBadStatement();
}
}
BoundStatement *Binder::BindBlockStatement(ParsedStatement *statement) {
auto statements = ((ParsedBlockStatement*)statement)->GetStatements();
vector<BoundStatement*> boundStatements (statements.size());
2019-05-28 16:50:23 +00:00
this->_scope->GoInnerScope();
for (int i = 0; i < statements.size(); i++){
boundStatements[i] = this -> BindStatement(statements[i]);
}
2019-05-28 16:50:23 +00:00
this->_scope->GoOuterScope();
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-05-28 16:50:23 +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();
}
}
ScriptType* ParseTypeIdentifier(HashedString s){
switch (s.GetHash()){
case HashedString::ConstHash("number"): return new NumericScriptType(false, false);
case HashedString::ConstHash("bool"): return new ScriptType(TypeClass::Bool);
case HashedString::ConstHash("string"): return new ScriptType(TypeClass::String);
default: return new ScriptType(TypeClass::Error); // todo: change to userdata
}
}
BoundStatement *Binder::BindFunctionDeclarationStatement(ParsedStatement *statement) {
auto functionStatement = (ParsedFunctionDeclarationStatement*) statement;
auto parameters = functionStatement->GetParameters();
vector<std::shared_ptr<ScriptType>> parameterTypes = vector<std::shared_ptr<ScriptType>>(parameters.size());
vector<std::shared_ptr<BoundVariableKey>> parameterKeys = vector<std::shared_ptr<BoundVariableKey>>(parameters.size());
this->_scope->GoInnerScope();
for (int i = 0; i < parameters.size(); i++){
auto var = parameters[i];
auto parsedType = ParseTypeIdentifier(var->GetType());
parameterTypes[i] = std::shared_ptr<ScriptType>(parsedType);
auto parameterAssignment = this->_scope->CreateExplicitLocal(var->GetIdentifier().GetHash(), *parsedType);
if (parameterAssignment.GetResult() == VariableAssignmentResult::Ok){
parameterKeys[i] = std::shared_ptr<BoundVariableKey>(parameterAssignment.GetKey());
}
else{
//TODO: log error
continue;
}
}
auto boundBlock = this -> BindBlockStatement(functionStatement->GetBlock());
this->_scope->GoOuterScope();
auto identifier = functionStatement->GetIdentifier();
auto returnType = std::make_shared<ScriptType>(TypeClass::Nil);
auto type = new FunctionScriptType(returnType, parameterTypes, parameterKeys);
auto assignment = this->_scope->AssignVariable(identifier.GetHash(), *type);
if (assignment.GetResult() == VariableAssignmentResult::Ok){
return new BoundFunctionDeclarationStatement(type, assignment.GetKey(), (BoundBlockStatement*)boundBlock);
}
return new BoundBadStatement();
}
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());
case ParsedExpressionKind ::LiteralBool:
return new BoundLiteralBoolExpression(((LiteralBoolExpression*)expression)->GetValue(), expression->GetStartPosition(), expression->GetLength());
case ParsedExpressionKind ::Variable:
return this -> BindVariableExpression((VariableExpression*)expression);
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
case ParsedExpressionKind ::Parenthesized:
return BindExpression(((ParenthesizedExpression*)expression)->GetInnerExpression());
case ParsedExpressionKind ::Bad:
return new BoundBadExpression(expression->GetStartPosition(), expression-> GetLength());
}
}
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){
auto leftNumeric = (NumericScriptType*)boundLeftType;
auto rightNumeric = (NumericScriptType*)boundRightType;
if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()){
return new BoundBinaryExpression(boundLeft, boundRight,
2019-05-22 10:29:29 +00:00
BoundBinaryOperation::Addition, new NumericScriptType(true, leftNumeric->IsFloat() || rightNumeric->IsFloat()),
expression->GetStartPosition(), expression->GetLength());
2019-05-21 20:15:51 +00:00
}
else{
2019-05-22 10:29:29 +00:00
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Addition, new NumericScriptType(false, false),
expression->GetStartPosition(), expression->GetLength());
2019-05-21 20:15:51 +00:00
}
} else if (boundLeftType->GetClass() == TypeClass::String){
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Concatenation, new ScriptType(TypeClass::String),
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 = (NumericScriptType*)boundLeftType;
auto rightNumeric = (NumericScriptType*)boundRightType;
if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()){
return new BoundBinaryExpression(boundLeft, boundRight,
2019-05-22 10:29:29 +00:00
BoundBinaryOperation::Subtraction,
new NumericScriptType(true, leftNumeric->IsFloat() || rightNumeric->IsFloat()),
expression->GetStartPosition(), expression->GetLength());
2019-05-21 20:15:51 +00:00
}
else{
2019-05-22 10:29:29 +00:00
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Subtraction, new NumericScriptType(false, false),
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){
auto leftNumeric = (NumericScriptType*)boundLeftType;
auto rightNumeric = (NumericScriptType*)boundRightType;
if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()){
return new BoundBinaryExpression(boundLeft, boundRight,
2019-05-22 10:29:29 +00:00
BoundBinaryOperation::Multiplication,
new NumericScriptType(true, leftNumeric->IsFloat() || rightNumeric->IsFloat()),
expression->GetStartPosition(), expression->GetLength());
2019-05-21 20:15:51 +00:00
}
else{
2019-05-22 10:29:29 +00:00
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Multiplication, new NumericScriptType(false, false),
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){
auto leftNumeric = (NumericScriptType*)boundLeftType;
auto rightNumeric = (NumericScriptType*)boundRightType;
if (leftNumeric->IsAwareOfFloat() && rightNumeric->IsAwareOfFloat()){
return new BoundBinaryExpression(boundLeft, boundRight,
2019-05-22 10:29:29 +00:00
BoundBinaryOperation::Division,
new NumericScriptType(true, leftNumeric->IsFloat() || rightNumeric->IsFloat()),
expression->GetStartPosition(), expression->GetLength());
2019-05-21 20:15:51 +00:00
}
else{
2019-05-22 10:29:29 +00:00
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Division, new NumericScriptType(false, false),
expression->GetStartPosition(), expression->GetLength());
2019-05-21 20:15:51 +00:00
}
}
break;
case BinaryOperatorKind ::Equality:
2019-05-22 10:29:29 +00:00
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Equality, new ScriptType(TypeClass::Bool),
expression->GetStartPosition(), expression->GetLength());
2019-05-25 12:17:52 +00:00
case BinaryOperatorKind ::Inequality:
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Inequality, new 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-05-22 10:29:29 +00:00
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::LogicalAnd, new ScriptType(TypeClass::Bool),
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-05-22 10:29:29 +00:00
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::LogicalOr, new ScriptType(TypeClass::Bool),
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){
auto innerType = (NumericScriptType*)operandType;
return new BoundUnaryExpression(operand, BoundUnaryOperation::Negation, new NumericScriptType(innerType->IsAwareOfFloat(),
innerType->IsFloat()), expression->GetStartPosition(), expression->GetLength());
}
break;
case UnaryOperatorKind ::LogicalNegation:
if (operandType->GetClass() == TypeClass::Bool){
return new BoundUnaryExpression(operand, BoundUnaryOperation::LogicalNegation, new ScriptType(TypeClass::Bool),
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
}