Implements assignment binding

This commit is contained in:
2019-05-28 17:49:03 +02:00
parent dbd7dfdd73
commit 5d1c3ac9ba
20 changed files with 443 additions and 152 deletions

View File

@@ -1,9 +1,11 @@
#include "Binder.hpp"
BoundScriptStatement *Binder::Bind(Script* script, ParsedScriptStatement *s) {
BoundScriptStatement *Binder::Bind(Script* script, ParsedScriptStatement *s, BoundScope* scriptScope) {
auto binder = Binder();
binder.ScriptData = script;
binder._scriptData = script;
binder._scope = scriptScope;
auto statements = s->GetStatements();
vector<BoundStatement*> boundStatements (statements.size());
for (int i = 0; i < statements.size(); i++){
@@ -12,11 +14,18 @@ BoundScriptStatement *Binder::Bind(Script* script, ParsedScriptStatement *s) {
return new BoundScriptStatement(boundStatements);
}
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);
case ParsedStatementKind::Assignment: return this -> BindAssignmentStatement(statement);
case ParsedStatementKind::Bad: return new BoundBadStatement();
}
}
@@ -34,6 +43,20 @@ BoundStatement *Binder::BindExpressionStatement(ParsedStatement *statement) {
return new BoundExpressionStatement(this -> BindExpression(exp));
}
BoundStatement* Binder::BindAssignmentStatement(ParsedStatement *statement){
auto s = (ParsedAssignmentStatement*) statement;
auto boundExpression = this->BindExpression(s->GetExpression());
auto assignment = this->_scope->AssignVariable(s->GetIdentifier().GetHash(), boundExpression->GetType());
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();
}
}
BoundExpression* Binder::BindExpression(ParsedExpression* expression){
switch (expression -> GetKind()){
case ParsedExpressionKind ::LiteralInteger:
@@ -149,7 +172,7 @@ BoundExpression* Binder::BindBinaryOperator(BinaryExpression* expression){
expression->GetStartPosition(), expression->GetLength());
break;
}
this -> ScriptData -> Diagnostics->LogError(DiagnosticCode::NoBinaryOperationFound, expression->GetStartPosition(), expression->GetLength());
this -> _scriptData -> Diagnostics->LogError(DiagnosticCode::NoBinaryOperationFound, expression->GetStartPosition(), expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
}
@@ -179,7 +202,8 @@ BoundExpression* Binder::BindUnaryOperator(UnaryExpression* expression){
default:
break;
}
this -> ScriptData -> Diagnostics->LogError(DiagnosticCode::NoUnaryOperationFound, expression->GetStartPosition(), expression->GetLength());
this -> _scriptData -> Diagnostics->LogError(DiagnosticCode::NoUnaryOperationFound, expression->GetStartPosition(), expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
}
}

View File

@@ -4,20 +4,25 @@
#include "../Parser/ParsedStatements/ParsedStatement.hpp"
#include "BoundStatements/BoundStatement.hpp"
#include "../Script.hpp"
#include "BoundVariables/BoundScope.hpp"
class Binder {
Script* ScriptData;
Script* _scriptData;
BoundScope* _scope;
~Binder();
BoundStatement *BindStatement(ParsedStatement *statement);
BoundStatement *BindBlockStatement(ParsedStatement *statement);
BoundStatement *BindExpressionStatement(ParsedStatement *statement);
BoundStatement *BindAssignmentStatement(ParsedStatement *statement);
BoundExpression *BindExpression(ParsedExpression *expression);
BoundExpression *BindBinaryOperator(BinaryExpression *expression);
BoundExpression *BindUnaryOperator(UnaryExpression *expression);
public:
static BoundScriptStatement* Bind(Script* script, ParsedScriptStatement* s);
static BoundScriptStatement* Bind(Script* script, ParsedScriptStatement* s, BoundScope* scriptScope);
};

View File

@@ -6,13 +6,16 @@
#include <vector>
#include "../BoundExpressions/BoundExpression.hpp"
#include "../BoundVariables/BoundVariableKey.hpp"
using namespace std;
enum class BoundStatementKind{
Bad,
Script,
Block,
Expression,
Assignment,
};
class BoundStatement{
@@ -21,6 +24,13 @@ public:
virtual ~BoundStatement() = default;
};
class BoundBadStatement : public BoundStatement{
public:
BoundStatementKind GetKind() final{
return BoundStatementKind ::Bad;
}
};
class BoundBlockStatement : public BoundStatement{
vector<BoundStatement*> _statements;
public:
@@ -72,4 +82,22 @@ public:
}
};
class BoundAssignmentStatement : public BoundStatement{
BoundVariableKey* _key;
BoundExpression* _expression;
public:
BoundAssignmentStatement(BoundVariableKey* key, BoundExpression* expression){
_key = key;
_expression = expression;
}
~BoundAssignmentStatement() final{
delete _key;
delete _expression;
}
BoundStatementKind GetKind() final{
return BoundStatementKind ::Assignment;
}
};
#endif //PORYGONLANG_BOUNDSTATEMENT_HPP

View File

@@ -0,0 +1,2 @@
#include "BoundScope.hpp"

View File

@@ -0,0 +1,88 @@
#ifndef PORYGONLANG_BOUNDSCOPE_HPP
#define PORYGONLANG_BOUNDSCOPE_HPP
#include <string>
#include <unordered_map>
#include <vector>
#include "BoundVariable.hpp"
#include "BoundVariableKey.hpp"
#include "VariableAssigmentResult.hpp"
#include "../../Utilities/HashedString.hpp"
using namespace std;
class BoundScope {
unordered_map<int, BoundVariable*>* _scriptScope;
vector<unordered_map<int, BoundVariable*>> _localScope;
int _currentScope;
public:
explicit BoundScope(unordered_map<int, BoundVariable*> *scriptScope){
_scriptScope = scriptScope;
_currentScope = 1;
_localScope = vector<unordered_map<int, BoundVariable*>>(1);
}
~BoundScope(){
_localScope.clear();
}
int Exists(int key){
auto found = this -> _scriptScope -> find(key);
if (found != _scriptScope -> end()){
return 0;
}
for (int i = _currentScope - 1; i >= 0; i--){
auto scope = _localScope.at(i);
found = scope.find(key);
if (found != scope.end()){
return i + 1;
}
}
return -1;
}
BoundVariable* GetVariable(int scope, int identifier){
if (scope == 0){
auto find = this -> _scriptScope->find(identifier);
if (find != _scriptScope->end()){
return find -> second;
}
return nullptr;
} else{
auto s = this->_localScope.at(scope);
auto find = s.find(identifier);
if (find != s.end()){
return find -> second;
}
return nullptr;
}
}
VariableAssignment CreateExplicitLocal(HashedString& identifier, ScriptType* type){
auto scope = this->_localScope.at(this->_currentScope);
if (scope.find(identifier.GetHash()) != scope.end()){
return VariableAssignment(VariableAssignmentResult::ExplicitLocalVariableExists, nullptr);
}
scope.insert({identifier.GetHash(), new BoundVariable(type)});
return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier.GetHash(), this->_currentScope, true));
}
VariableAssignment AssignVariable(int identifier, ScriptType* type){
int exists = this->Exists(identifier);
if (exists == -1){
// Creation
_scriptScope->insert({identifier, new BoundVariable(type)});
return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, 0, true));
} else{
// Assigning
auto var = this->GetVariable(exists, identifier);
if (var->GetType() != type){
return VariableAssignment(VariableAssignmentResult::VariableDefinedWithDifferentType, nullptr);
}
return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, exists, false));
}
}
};
#endif //PORYGONLANG_BOUNDSCOPE_HPP

View File

@@ -0,0 +1,22 @@
#ifndef PORYGONLANG_BOUNDVARIABLE_HPP
#define PORYGONLANG_BOUNDVARIABLE_HPP
#include "../../ScriptType.hpp"
class BoundVariable{
ScriptType* _type;
public:
explicit BoundVariable(ScriptType* type){
_type = type;
}
~BoundVariable(){
delete _type;
}
ScriptType* GetType(){
return _type;
}
};
#endif //PORYGONLANG_BOUNDVARIABLE_HPP

View File

@@ -0,0 +1,33 @@
#include <utility>
#ifndef PORYGONLANG_BOUNDVARIABLEKEY_HPP
#define PORYGONLANG_BOUNDVARIABLEKEY_HPP
#include <string>
class BoundVariableKey{
int _identifier;
unsigned int _scopeId;
bool _isCreation;
public:
BoundVariableKey(int id, unsigned int scope, bool creation){
_identifier = std::move(id);
_scopeId = scope;
_isCreation = creation;
}
int GetIdentifier(){
return _identifier;
}
unsigned int GetScopeId(){
return _scopeId;
}
bool IsCreation(){
return _isCreation;
}
};
#endif //PORYGONLANG_BOUNDVARIABLEKEY_HPP

View File

@@ -0,0 +1,31 @@
#ifndef PORYGONLANG_VARIABLEASSIGMENTRESULT_HPP
#define PORYGONLANG_VARIABLEASSIGMENTRESULT_HPP
#include "BoundVariableKey.hpp"
enum class VariableAssignmentResult{
Ok,
ExplicitLocalVariableExists,
VariableDefinedWithDifferentType
};
class VariableAssignment{
VariableAssignmentResult _result;
BoundVariableKey* _key;
public:
VariableAssignment(VariableAssignmentResult result, BoundVariableKey *key) {
_result = result;
_key = key;
}
VariableAssignmentResult GetResult(){
return _result;
}
BoundVariableKey* GetKey(){
return _key;
}
};
#endif //PORYGONLANG_VARIABLEASSIGMENTRESULT_HPP