Implements complex tables
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2019-06-12 15:19:28 +02:00
parent ba4fe888fa
commit c022c91777
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
21 changed files with 272 additions and 50 deletions

View File

@ -1,6 +1,6 @@
#include <memory>
#include "Binder.hpp" #include "Binder.hpp"
#include "../TableScriptType.hpp"
#include "BoundExpressions/BoundTableExpression.hpp"
#include <memory> #include <memory>
BoundScriptStatement *Binder::Bind(Script* script, ParsedScriptStatement *s, BoundScope* scriptScope) { BoundScriptStatement *Binder::Bind(Script* script, ParsedScriptStatement *s, BoundScope* scriptScope) {
@ -71,7 +71,7 @@ std::shared_ptr<ScriptType> ParseTypeIdentifier(HashedString s){
switch (s.GetHash()){ switch (s.GetHash()){
case HashedString::ConstHash("number"): return std::make_shared<NumericScriptType>(false, false); 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("bool"): return std::make_shared<ScriptType>(TypeClass::Bool);
case HashedString::ConstHash("string"): return std::make_shared<ScriptType>(TypeClass::String); case HashedString::ConstHash("string"): return std::make_shared<StringScriptType>(false, 0);
default: return std::make_shared<ScriptType>(TypeClass::Error); // todo: change to userdata default: return std::make_shared<ScriptType>(TypeClass::Error); // todo: change to userdata
} }
} }
@ -178,6 +178,8 @@ BoundExpression* Binder::BindExpression(ParsedExpression* expression){
return this->BindIndexExpression((IndexExpression*)expression); return this->BindIndexExpression((IndexExpression*)expression);
case ParsedExpressionKind::NumericalTable: case ParsedExpressionKind::NumericalTable:
return this -> BindNumericalTableExpression((ParsedNumericalTableExpression*)expression); return this -> BindNumericalTableExpression((ParsedNumericalTableExpression*)expression);
case ParsedExpressionKind ::Table:
return this -> BindTableExpression((ParsedTableExpression*)expression);
case ParsedExpressionKind ::Bad: case ParsedExpressionKind ::Bad:
return new BoundBadExpression(expression->GetStartPosition(), expression-> GetLength()); return new BoundBadExpression(expression->GetStartPosition(), expression-> GetLength());
@ -220,7 +222,8 @@ BoundExpression* Binder::BindBinaryOperator(BinaryExpression* expression){
expression->GetStartPosition(), expression->GetLength()); expression->GetStartPosition(), expression->GetLength());
} }
} else if (boundLeftType->GetClass() == TypeClass::String){ } else if (boundLeftType->GetClass() == TypeClass::String){
return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Concatenation, std::make_shared<ScriptType>(TypeClass::String), return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Concatenation, std::make_shared<StringScriptType>(false,
0),
expression->GetStartPosition(), expression->GetLength()); expression->GetStartPosition(), expression->GetLength());
} }
break; break;
@ -412,7 +415,19 @@ BoundExpression* Binder::BindNumericalTableExpression(ParsedNumericalTableExpres
if (valueType == nullptr){ if (valueType == nullptr){
valueType = std::make_shared<ScriptType>(TypeClass::Nil); valueType = std::make_shared<ScriptType>(TypeClass::Nil);
} }
auto keyType = std::make_shared<ScriptType>(TypeClass::Number); auto tableType = std::make_shared<NumericalTableScriptType>(valueType);
auto tableType = std::make_shared<TableScriptType>(keyType, valueType);
return new BoundNumericalTableExpression(boundExpressions, tableType, expression->GetStartPosition(), expression->GetLength()); return new BoundNumericalTableExpression(boundExpressions, tableType, expression->GetStartPosition(), expression->GetLength());
} }
BoundExpression *Binder::BindTableExpression(ParsedTableExpression *expression) {
auto tableScope = new unordered_map<int, BoundVariable*>();
auto innerScope = new BoundScope(tableScope);
auto currentScope = this -> _scope;
this -> _scope = innerScope;
auto block = this -> BindBlockStatement(expression -> GetBlock());
this -> _scope = currentScope;
auto tableType = shared_ptr<TableScriptType>(new TableScriptType(tableScope, innerScope->GetDeepestScope()));
return new BoundTableExpression((BoundBlockStatement*)block, tableType, expression->GetStartPosition(), expression->GetLength());
}

View File

@ -5,6 +5,8 @@
#include "BoundStatements/BoundStatement.hpp" #include "BoundStatements/BoundStatement.hpp"
#include "../Script.hpp" #include "../Script.hpp"
#include "BoundVariables/BoundScope.hpp" #include "BoundVariables/BoundScope.hpp"
#include "../Parser/ParsedExpressions/ParsedTableExpression.hpp"
using namespace std; using namespace std;
class Binder { class Binder {
@ -29,6 +31,7 @@ class Binder {
BoundExpression *BindFunctionCall(FunctionCallExpression *expression); BoundExpression *BindFunctionCall(FunctionCallExpression *expression);
BoundExpression *BindIndexExpression(IndexExpression *expression); BoundExpression *BindIndexExpression(IndexExpression *expression);
BoundExpression *BindNumericalTableExpression(ParsedNumericalTableExpression *expression); BoundExpression *BindNumericalTableExpression(ParsedNumericalTableExpression *expression);
BoundExpression *BindTableExpression(ParsedTableExpression * expression);
public: public:
static BoundScriptStatement* Bind(Script* script, ParsedScriptStatement* s, BoundScope* scriptScope); static BoundScriptStatement* Bind(Script* script, ParsedScriptStatement* s, BoundScope* scriptScope);

View File

@ -25,6 +25,7 @@ enum class BoundExpressionKind{
FunctionCall, FunctionCall,
Index, Index,
NumericalTable, NumericalTable,
Table,
}; };
class BoundExpression{ class BoundExpression{
@ -102,7 +103,7 @@ class BoundLiteralStringExpression : public BoundExpression{
string _value; string _value;
public: public:
BoundLiteralStringExpression(string value, unsigned int start, unsigned int length) BoundLiteralStringExpression(string value, unsigned int start, unsigned int length)
: BoundExpression(start, length, make_shared<ScriptType>(TypeClass::String)){ : BoundExpression(start, length, make_shared<StringScriptType>(true, HashedString::ConstHash(value.c_str()))){
_value = std::move(value); _value = std::move(value);
} }
@ -276,11 +277,11 @@ class BoundNumericalTableExpression : public BoundExpression{
vector<BoundExpression*> _expressions; vector<BoundExpression*> _expressions;
public: public:
BoundNumericalTableExpression(vector<BoundExpression*> expressions, shared_ptr<ScriptType> type, unsigned int start, unsigned int length) BoundNumericalTableExpression(vector<BoundExpression*> expressions, shared_ptr<ScriptType> type, unsigned int start, unsigned int length)
: BoundExpression(start, length, type){ : BoundExpression(start, length, std::move(type)){
_expressions = std::move(expressions); _expressions = std::move(expressions);
} }
~BoundNumericalTableExpression(){ ~BoundNumericalTableExpression() final{
for (auto e: _expressions){ for (auto e: _expressions){
delete e; delete e;
} }

View File

@ -0,0 +1,32 @@
#include <utility>
#ifndef PORYGONLANG_BOUNDTABLEEXPRESSION_HPP
#define PORYGONLANG_BOUNDTABLEEXPRESSION_HPP
#include "../BoundStatements/BoundStatement.hpp"
class BoundTableExpression : public BoundExpression{
BoundBlockStatement* _block;
public:
BoundTableExpression(BoundBlockStatement* block, shared_ptr<ScriptType> type, unsigned int start, unsigned int length)
: BoundExpression(start, length, std::move(type)){
_block = block;
}
~BoundTableExpression() final{
delete _block;
}
BoundExpressionKind GetKind() final{
return BoundExpressionKind ::Table;
}
BoundBlockStatement* GetBlock(){
return _block;
}
};
#include "BoundExpression.hpp"
#endif //PORYGONLANG_BOUNDTABLEEXPRESSION_HPP

View File

@ -3,8 +3,8 @@
#include "BoundScope.hpp" #include "BoundScope.hpp"
BoundScope::BoundScope(unordered_map<int, BoundVariable *> *scriptScope) { BoundScope::BoundScope(unordered_map<int, BoundVariable *> *tableScope) {
_scriptScope = scriptScope; _tableScope = tableScope;
_currentScope = 1; _currentScope = 1;
_deepestScope = 1; _deepestScope = 1;
auto localUpmostScope = new unordered_map<int, BoundVariable*>(); auto localUpmostScope = new unordered_map<int, BoundVariable*>();
@ -41,8 +41,8 @@ void BoundScope::GoOuterScope() {
} }
int BoundScope::Exists(int key) { int BoundScope::Exists(int key) {
auto found = this -> _scriptScope -> find(key); auto found = this -> _tableScope -> find(key);
if (found != _scriptScope -> end()){ if (found != _tableScope -> end()){
return 0; return 0;
} }
for (int i = _currentScope - 1; i >= 0; i--){ for (int i = _currentScope - 1; i >= 0; i--){
@ -57,8 +57,8 @@ int BoundScope::Exists(int key) {
BoundVariable *BoundScope::GetVariable(int scope, int identifier) { BoundVariable *BoundScope::GetVariable(int scope, int identifier) {
if (scope == 0){ if (scope == 0){
auto find = this -> _scriptScope->find(identifier); auto find = this -> _tableScope->find(identifier);
if (find != _scriptScope->end()){ if (find != _tableScope->end()){
return find -> second; return find -> second;
} }
return nullptr; return nullptr;
@ -85,7 +85,7 @@ VariableAssignment BoundScope::AssignVariable(int identifier, const std::shared_
int exists = this->Exists(identifier); int exists = this->Exists(identifier);
if (exists == -1){ if (exists == -1){
// Creation // Creation
_scriptScope->insert({identifier, new BoundVariable(type)}); _tableScope->insert({identifier, new BoundVariable(type)});
return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, 0, true)); return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, 0, true));
} else{ } else{
// Assigning // Assigning

View File

@ -14,12 +14,12 @@
using namespace std; using namespace std;
class BoundScope { class BoundScope {
unordered_map<int, BoundVariable*>* _scriptScope; unordered_map<int, BoundVariable*>* _tableScope;
vector<unordered_map<int, BoundVariable*>*> _localScope; vector<unordered_map<int, BoundVariable*>*> _localScope;
int _currentScope; int _currentScope;
int _deepestScope; int _deepestScope;
public: public:
explicit BoundScope(unordered_map<int, BoundVariable*> *scriptScope); explicit BoundScope(unordered_map<int, BoundVariable*> *tableScope);
~BoundScope(); ~BoundScope();
void GoInnerScope(); void GoInnerScope();

View File

@ -4,6 +4,7 @@
#include <string> #include <string>
#include "EvalValue.hpp" #include "EvalValue.hpp"
#include "../../Utilities/HashedString.hpp"
using namespace std; using namespace std;
@ -14,8 +15,8 @@ class StringEvalValue : public EvalValue{
public: public:
explicit StringEvalValue(string s){ explicit StringEvalValue(string s){
_value = move(s); _value = move(s);
_type = std::make_shared<ScriptType>(TypeClass::String); _hash = HashedString::ConstHash (_value.c_str());
_hash = std::hash<string>{}(_value); _type = std::make_shared<StringScriptType>(true, _hash);
} }
std::shared_ptr<ScriptType> GetType() final{ std::shared_ptr<ScriptType> GetType() final{

View File

@ -1,5 +1,3 @@
#include <utility>
#ifndef PORYGONLANG_TABLEEVALVALUE_HPP #ifndef PORYGONLANG_TABLEEVALVALUE_HPP
#define PORYGONLANG_TABLEEVALVALUE_HPP #define PORYGONLANG_TABLEEVALVALUE_HPP
#include <utility> #include <utility>
@ -45,6 +43,11 @@ public:
auto hash = val->GetHashCode(); auto hash = val->GetHashCode();
return this -> _table->at(hash); return this -> _table->at(hash);
} }
shared_ptr<EvalValue> IndexValue(const char* val){
auto hash = HashedString::ConstHash(val);
return this -> _table -> at(hash);
}
}; };

View File

@ -2,7 +2,7 @@
#include "EvaluationScope.hpp" #include "EvaluationScope.hpp"
#include <memory> #include <memory>
EvaluationScope::EvaluationScope(unordered_map<int, shared_ptr<EvalValue>> *scriptVariables, int deepestScope) { EvaluationScope::EvaluationScope(unordered_map<size_t, shared_ptr<EvalValue>> *scriptVariables, int deepestScope) {
_scriptScope = scriptVariables; _scriptScope = scriptVariables;
_localScope = vector<shared_ptr<unordered_map<int, shared_ptr<EvalValue>>>>(deepestScope); _localScope = vector<shared_ptr<unordered_map<int, shared_ptr<EvalValue>>>>(deepestScope);
for (int i = 0; i < deepestScope; i++){ for (int i = 0; i < deepestScope; i++){
@ -42,6 +42,7 @@ EvaluationScope* EvaluationScope::CreateBranchingScope(int index){
for (int i = 0; i < index; i++){ for (int i = 0; i < index; i++){
scope->_localScope[i] = this->_localScope[i]; scope->_localScope[i] = this->_localScope[i];
} }
scope->_currentScope = index;
return scope; return scope;
} }
@ -49,9 +50,11 @@ void EvaluationScope::OuterScope() {
_currentScope++; _currentScope++;
} }
void EvaluationScope::InnerScope() { void EvaluationScope::InnerScope(bool clearScope) {
if (clearScope){
auto scope = this->_localScope[_currentScope]; auto scope = this->_localScope[_currentScope];
scope->clear(); scope->clear();
}
_currentScope--; _currentScope--;
} }

View File

@ -7,17 +7,17 @@
#include "../EvalValues/EvalValue.hpp" #include "../EvalValues/EvalValue.hpp"
class EvaluationScope { class EvaluationScope {
unordered_map<int, shared_ptr<EvalValue>>* _scriptScope; unordered_map<size_t, shared_ptr<EvalValue>>* _scriptScope;
vector<shared_ptr<unordered_map<int, shared_ptr<EvalValue>>>> _localScope; vector<shared_ptr<unordered_map<int, shared_ptr<EvalValue>>>> _localScope;
int _currentScope; int _currentScope;
public: public:
explicit EvaluationScope(unordered_map<int, shared_ptr<EvalValue>>* scriptVariables, int deepestScope); explicit EvaluationScope(unordered_map<size_t, shared_ptr<EvalValue>>* scriptVariables, int deepestScope);
~EvaluationScope() = default; ~EvaluationScope() = default;
void CreateVariable(int scope, int id, const shared_ptr<EvalValue>& value); void CreateVariable(int scope, int id, const shared_ptr<EvalValue>& value);
void SetVariable(int scope, int id, const shared_ptr<EvalValue>& value); void SetVariable(int scope, int id, const shared_ptr<EvalValue>& value);
void OuterScope(); void OuterScope();
void InnerScope(); void InnerScope(bool clearScope = true);
shared_ptr<EvalValue> GetVariable(int scope, int id); shared_ptr<EvalValue> GetVariable(int scope, int id);
EvaluationScope* CreateBranchingScope(int index); EvaluationScope* CreateBranchingScope(int index);

View File

@ -6,12 +6,14 @@
#include "EvaluationScope/EvaluationScope.hpp" #include "EvaluationScope/EvaluationScope.hpp"
#include "EvalValues/ScriptFunctionEvalValue.hpp" #include "EvalValues/ScriptFunctionEvalValue.hpp"
#include "EvalValues/TableEvalValue.hpp" #include "EvalValues/TableEvalValue.hpp"
#include "../Binder/BoundExpressions/BoundTableExpression.hpp"
#include "../TableScriptType.hpp"
using namespace std; using namespace std;
void Evaluator::Evaluate(BoundScriptStatement *statement) { void Evaluator::Evaluate(BoundScriptStatement *statement) {
this->_evaluationScope = new EvaluationScope(this->_scriptData->_scriptVariables, statement->GetDeepestScope()); this->_evaluationScope = new EvaluationScope(this->_scriptData->_scriptVariables, statement->GetDeepestScope());
EvaluateBlockStatement(statement); EvaluateBlockStatement(statement, false);
} }
void Evaluator::EvaluateStatement(BoundStatement *statement) { void Evaluator::EvaluateStatement(BoundStatement *statement) {
@ -19,7 +21,7 @@ void Evaluator::EvaluateStatement(BoundStatement *statement) {
return; return;
switch (statement->GetKind()){ switch (statement->GetKind()){
case BoundStatementKind ::Script: throw; // Should never happen case BoundStatementKind ::Script: throw; // Should never happen
case BoundStatementKind ::Block: return this -> EvaluateBlockStatement((BoundBlockStatement*)statement); case BoundStatementKind ::Block: return this -> EvaluateBlockStatement((BoundBlockStatement*)statement, true);
case BoundStatementKind ::Expression: return this -> EvaluateExpressionStatement((BoundExpressionStatement*)statement); case BoundStatementKind ::Expression: return this -> EvaluateExpressionStatement((BoundExpressionStatement*)statement);
case BoundStatementKind ::Assignment: return this -> EvaluateAssignmentStatement((BoundAssignmentStatement*)statement); case BoundStatementKind ::Assignment: return this -> EvaluateAssignmentStatement((BoundAssignmentStatement*)statement);
case BoundStatementKind ::FunctionDeclaration: return this->EvaluateFunctionDeclarationStatement((BoundFunctionDeclarationStatement*)statement); case BoundStatementKind ::FunctionDeclaration: return this->EvaluateFunctionDeclarationStatement((BoundFunctionDeclarationStatement*)statement);
@ -31,14 +33,14 @@ void Evaluator::EvaluateStatement(BoundStatement *statement) {
} }
} }
void Evaluator::EvaluateBlockStatement(BoundBlockStatement* statement) { void Evaluator::EvaluateBlockStatement(BoundBlockStatement* statement, bool clearScope) {
this->_evaluationScope->OuterScope(); this->_evaluationScope->OuterScope();
for (auto s: statement->GetStatements()){ for (auto s: statement->GetStatements()){
this -> EvaluateStatement(s); this -> EvaluateStatement(s);
if (this->_hasReturned) if (this->_hasReturned)
break; break;
} }
this->_evaluationScope->InnerScope(); this->_evaluationScope->InnerScope(clearScope);
} }
void Evaluator::EvaluateExpressionStatement(BoundExpressionStatement *statement) { void Evaluator::EvaluateExpressionStatement(BoundExpressionStatement *statement) {
@ -122,6 +124,7 @@ shared_ptr<NumericEvalValue> Evaluator::EvaluateIntegerExpression(BoundExpressio
case BoundExpressionKind ::LiteralBool: case BoundExpressionKind ::LiteralBool:
case BoundExpressionKind ::Bad: case BoundExpressionKind ::Bad:
case BoundExpressionKind::NumericalTable: case BoundExpressionKind::NumericalTable:
case BoundExpressionKind::Table:
throw; throw;
} }
} }
@ -140,6 +143,7 @@ shared_ptr<BooleanEvalValue> Evaluator::EvaluateBoolExpression(BoundExpression *
case BoundExpressionKind::LiteralFloat: case BoundExpressionKind::LiteralFloat:
case BoundExpressionKind::LiteralString: case BoundExpressionKind::LiteralString:
case BoundExpressionKind::NumericalTable: case BoundExpressionKind::NumericalTable:
case BoundExpressionKind::Table:
throw; throw;
} }
@ -161,6 +165,7 @@ shared_ptr<StringEvalValue> Evaluator::EvaluateStringExpression(BoundExpression
case BoundExpressionKind::LiteralBool: case BoundExpressionKind::LiteralBool:
case BoundExpressionKind::Unary: case BoundExpressionKind::Unary:
case BoundExpressionKind::NumericalTable: case BoundExpressionKind::NumericalTable:
case BoundExpressionKind::Table:
throw; throw;
} }
@ -187,8 +192,9 @@ shared_ptr<EvalValue> Evaluator::EvaluateTableExpression(BoundExpression * expre
case BoundExpressionKind ::Variable: return this->GetVariable((BoundVariableExpression*)expression); case BoundExpressionKind ::Variable: return this->GetVariable((BoundVariableExpression*)expression);
case BoundExpressionKind ::Index: return this->EvaluateIndexExpression(expression); case BoundExpressionKind ::Index: return this->EvaluateIndexExpression(expression);
case BoundExpressionKind ::NumericalTable: return this-> EvaluateNumericTableExpression(expression); case BoundExpressionKind ::NumericalTable: return this-> EvaluateNumericTableExpression(expression);
case BoundExpressionKind ::Table: return this -> EvaluateComplexTableExpression(expression);
default: default:
return nullptr; throw;
} }
} }
@ -222,8 +228,7 @@ shared_ptr<EvalValue> Evaluator::EvaluateFunctionCallExpression(BoundExpression*
auto key = parameterKeys.at(i); auto key = parameterKeys.at(i);
this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), parameter->Clone()); this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), parameter->Clone());
} }
this->_evaluationScope->OuterScope(); this->EvaluateBlockStatement(function->GetInnerBlock().get(), true);
this->EvaluateBlockStatement(function->GetInnerBlock().get());
delete this->_evaluationScope; delete this->_evaluationScope;
this->_evaluationScope = originalScope; this->_evaluationScope = originalScope;
@ -237,6 +242,12 @@ shared_ptr<EvalValue> Evaluator::EvaluateFunction(ScriptFunctionEvalValue *funct
auto type = std::dynamic_pointer_cast<FunctionScriptType>(function->GetType()); auto type = std::dynamic_pointer_cast<FunctionScriptType>(function->GetType());
auto parameterTypes = type->GetParameterTypes(); auto parameterTypes = type->GetParameterTypes();
auto parameterKeys = type->GetParameterKeys(); auto parameterKeys = type->GetParameterKeys();
auto scope = type -> GetScopeIndex();
auto originalScope = this->_evaluationScope;
auto functionScope = this->_evaluationScope->CreateBranchingScope(scope);
this->_evaluationScope = functionScope;
for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++){ for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++){
auto parameter = parameters[i]; auto parameter = parameters[i];
auto requiredType = parameterTypes.at(i); auto requiredType = parameterTypes.at(i);
@ -246,7 +257,9 @@ shared_ptr<EvalValue> Evaluator::EvaluateFunction(ScriptFunctionEvalValue *funct
auto key = parameterKeys.at(i); auto key = parameterKeys.at(i);
this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), parameter->Clone()); this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), parameter->Clone());
} }
this->EvaluateBlockStatement(function->GetInnerBlock().get()); this->EvaluateBlockStatement(function->GetInnerBlock().get(), true);
delete this->_evaluationScope;
this->_evaluationScope = originalScope;
this->_hasReturned = false; this->_hasReturned = false;
auto r = this -> _returnValue; auto r = this -> _returnValue;
this -> _returnValue = nullptr; this -> _returnValue = nullptr;
@ -272,3 +285,18 @@ shared_ptr<EvalValue> Evaluator::EvaluateNumericTableExpression(BoundExpression
return make_shared<TableEvalValue>(valuesPointer, tableExpression->GetType()); return make_shared<TableEvalValue>(valuesPointer, tableExpression->GetType());
} }
shared_ptr<EvalValue> Evaluator::EvaluateComplexTableExpression(BoundExpression *expression) {
auto tableExpression = (BoundTableExpression*)expression;
auto type = dynamic_pointer_cast<TableScriptType>(tableExpression->GetType());
auto declaredVars = type -> GetValues();
auto variables = make_shared<unordered_map<size_t, shared_ptr<EvalValue>>>(declaredVars->size());
for (auto i : *declaredVars){
variables->insert({i.first, nullptr});
}
auto evaluator = new EvaluationScope(variables.get(), type -> GetDeepestScope());
auto currentEvaluator = this -> _evaluationScope;
this -> _evaluationScope = evaluator;
this -> EvaluateBlockStatement(tableExpression->GetBlock(), false);
this -> _evaluationScope = currentEvaluator;
return shared_ptr<TableEvalValue>(new TableEvalValue(variables, tableExpression->GetType()));
}

View File

@ -23,7 +23,7 @@ class Evaluator {
EvaluationScope* _evaluationScope; EvaluationScope* _evaluationScope;
void EvaluateStatement(BoundStatement* statement); void EvaluateStatement(BoundStatement* statement);
void EvaluateBlockStatement(BoundBlockStatement* statement); void EvaluateBlockStatement(BoundBlockStatement* statement, bool clearScope);
void EvaluateExpressionStatement(BoundExpressionStatement* statement); void EvaluateExpressionStatement(BoundExpressionStatement* statement);
void EvaluateAssignmentStatement(BoundAssignmentStatement* statement); void EvaluateAssignmentStatement(BoundAssignmentStatement* statement);
void EvaluateFunctionDeclarationStatement(BoundFunctionDeclarationStatement *statement); void EvaluateFunctionDeclarationStatement(BoundFunctionDeclarationStatement *statement);
@ -67,6 +67,8 @@ public:
EvalValue* GetLastValue(){ EvalValue* GetLastValue(){
return _lastValue.get(); return _lastValue.get();
} }
shared_ptr<EvalValue> EvaluateComplexTableExpression(BoundExpression *expression);
}; };

View File

@ -24,6 +24,7 @@ enum class ParsedExpressionKind{
FunctionCall, FunctionCall,
Indexer, Indexer,
NumericalTable, NumericalTable,
Table,
}; };
class ParsedExpression { class ParsedExpression {

View File

@ -0,0 +1,31 @@
#ifndef PORYGONLANG_PARSEDTABLEEXPRESSION_HPP
#define PORYGONLANG_PARSEDTABLEEXPRESSION_HPP
#include "ParsedExpression.hpp"
#include "../ParsedStatements/ParsedStatement.hpp"
class ParsedTableExpression : public ParsedExpression{
ParsedBlockStatement* _block;
public:
ParsedTableExpression(ParsedBlockStatement* block, unsigned int start, unsigned int length)
: ParsedExpression(start, length){
_block = block;
}
~ParsedTableExpression() final{
delete _block;
}
ParsedBlockStatement* GetBlock(){
return _block;
}
ParsedExpressionKind GetKind() final{
return ParsedExpressionKind::Table;
}
};
#include "ParsedExpression.hpp"
#endif //PORYGONLANG_PARSEDTABLEEXPRESSION_HPP

View File

@ -5,6 +5,7 @@
#include "UnaryOperatorKind.hpp" #include "UnaryOperatorKind.hpp"
#include "BinaryOperatorKind.hpp" #include "BinaryOperatorKind.hpp"
#include "TypedVariableIdentifier.hpp" #include "TypedVariableIdentifier.hpp"
#include "ParsedExpressions/ParsedTableExpression.hpp"
ParsedScriptStatement* Parser::Parse() { ParsedScriptStatement* Parser::Parse() {
@ -372,6 +373,7 @@ ParsedExpression* Parser::ParseTableExpression(IToken* current){
auto start = current->GetStartPosition(); auto start = current->GetStartPosition();
return new ParsedNumericalTableExpression({}, start, this -> Peek()->GetEndPosition() - start); return new ParsedNumericalTableExpression({}, start, this -> Peek()->GetEndPosition() - start);
} }
auto start = current->GetStartPosition();
auto firstItem = this->ParseStatement(this -> Next()); auto firstItem = this->ParseStatement(this -> Next());
// If the first item is an expression, and is followed by a comma, we're dealing with a simple {1, 2, 3} kind of array // If the first item is an expression, and is followed by a comma, we're dealing with a simple {1, 2, 3} kind of array
if (firstItem->GetKind() == ParsedStatementKind::Expression && if (firstItem->GetKind() == ParsedStatementKind::Expression &&
@ -389,7 +391,6 @@ ParsedExpression* Parser::ParseTableExpression(IToken* current){
hasErrors = true; hasErrors = true;
} }
} }
auto start = current->GetStartPosition();
if (hasErrors){ if (hasErrors){
return new BadExpression(start, n->GetEndPosition() - start); return new BadExpression(start, n->GetEndPosition() - start);
} }
@ -400,7 +401,8 @@ ParsedExpression* Parser::ParseTableExpression(IToken* current){
auto block = (ParsedBlockStatement*)this -> ParseBlock({TokenKind ::CloseCurlyBracket}); auto block = (ParsedBlockStatement*)this -> ParseBlock({TokenKind ::CloseCurlyBracket});
auto statements = block->GetStatements(); auto statements = block->GetStatements();
statements->insert(statements->begin(), firstItem); statements->insert(statements->begin(), firstItem);
throw "not implemented TODO"; auto closeToken = this -> PeekAt(-1);
return new ParsedTableExpression(block, start, closeToken->GetEndPosition() - start);
} }
} }

View File

@ -17,7 +17,7 @@ Script::Script() {
Diagnostics = new DiagnosticsHolder(); Diagnostics = new DiagnosticsHolder();
_evaluator = new Evaluator(this); _evaluator = new Evaluator(this);
_boundScript = nullptr; _boundScript = nullptr;
_scriptVariables = new unordered_map<int, shared_ptr<EvalValue>>(0); _scriptVariables = new unordered_map<size_t, shared_ptr<EvalValue>>(0);
} }
void Script::Evaluate() { void Script::Evaluate() {

View File

@ -18,7 +18,7 @@ class Script {
friend class Evaluator; friend class Evaluator;
Evaluator* _evaluator; Evaluator* _evaluator;
unordered_map<int, shared_ptr<EvalValue>>* _scriptVariables; unordered_map<size_t, shared_ptr<EvalValue>>* _scriptVariables;
BoundScriptStatement* _boundScript; BoundScriptStatement* _boundScript;
shared_ptr<ScriptType> _returnType; shared_ptr<ScriptType> _returnType;

View File

@ -6,6 +6,7 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include "Binder/BoundVariables/BoundVariableKey.hpp" #include "Binder/BoundVariables/BoundVariableKey.hpp"
#include "Utilities/HashedString.hpp"
using namespace std; using namespace std;
@ -73,6 +74,24 @@ public:
} }
}; };
class StringScriptType : public ScriptType{
bool _isKnownAtBind;
int _hashValue;
public:
explicit StringScriptType(bool knownAtBind, int hashValue): ScriptType(TypeClass::String){
_isKnownAtBind = knownAtBind;
_hashValue = hashValue;
}
bool IsKnownAtBind(){
return _isKnownAtBind;
}
int GetHashValue(){
return _hashValue;
}
};
class FunctionScriptType : public ScriptType{ class FunctionScriptType : public ScriptType{
shared_ptr<ScriptType> _returnType; shared_ptr<ScriptType> _returnType;
vector<shared_ptr<ScriptType>> _parameterTypes; vector<shared_ptr<ScriptType>> _parameterTypes;
@ -104,24 +123,22 @@ public:
} }
}; };
class TableScriptType : public ScriptType{ class NumericalTableScriptType : public ScriptType{
shared_ptr<ScriptType> _keyType;
shared_ptr<ScriptType> _valueType; shared_ptr<ScriptType> _valueType;
// Consider adding a check whether the table actually contains a type if every key is static. // Consider adding a check whether the table actually contains a type if every key is static.
public: public:
TableScriptType(shared_ptr<ScriptType> keyType, shared_ptr<ScriptType> valueType) : ScriptType(TypeClass::Table){ explicit NumericalTableScriptType(shared_ptr<ScriptType> valueType) : ScriptType(TypeClass::Table){
_keyType = std::move(keyType);
_valueType = std::move(valueType); _valueType = std::move(valueType);
} }
bool CanBeIndexedWith(ScriptType* indexer) final{ bool CanBeIndexedWith(ScriptType* indexer) final{
return _keyType.get()->operator==(indexer); return indexer->GetClass() == TypeClass ::Number;
} }
shared_ptr<ScriptType> GetIndexedType(ScriptType* indexer) final{ shared_ptr<ScriptType> GetIndexedType(ScriptType* indexer) final{
return _valueType; return _valueType;
} }
}; };
#endif //PORYGONLANG_SCRIPTTYPE_HPP #endif //PORYGONLANG_SCRIPTTYPE_HPP

47
src/TableScriptType.hpp Normal file
View File

@ -0,0 +1,47 @@
#ifndef PORYGONLANG_TABLESCRIPTTYPE_HPP
#define PORYGONLANG_TABLESCRIPTTYPE_HPP
#include <unordered_map>
#include "Binder/BoundVariables/BoundVariable.hpp"
class TableScriptType : public ScriptType{
unordered_map<int, BoundVariable*>* _values;
int _deepestScope;
public:
explicit TableScriptType(unordered_map<int, BoundVariable*>* values, int deepestScope) : ScriptType(TypeClass::Table){
_values = values;
_deepestScope = deepestScope;
}
~TableScriptType() final{
for (auto i : *_values){
delete i.second;
}
delete _values;
}
bool CanBeIndexedWith(ScriptType* indexer) final{
return indexer->GetClass() == TypeClass ::String;
}
shared_ptr<ScriptType> GetIndexedType(ScriptType* indexer) final{
auto stringKey = (StringScriptType*)indexer;
if (stringKey->IsKnownAtBind()){
return _values-> at(stringKey->GetHashValue())->GetType();
}
throw "TODO: indexing with dynamic keys";
}
unordered_map<int, BoundVariable*>* GetValues(){
return _values;
}
int GetDeepestScope(){
return _deepestScope;
}
};
#include "ScriptType.hpp"
#endif //PORYGONLANG_TABLESCRIPTTYPE_HPP

View File

@ -1,6 +1,7 @@
#ifdef TESTS_BUILD #ifdef TESTS_BUILD
#include <catch.hpp> #include <catch.hpp>
#include "../src/Script.hpp" #include "../src/Script.hpp"
#include "../../src/Evaluator/EvalValues/TableEvalValue.hpp"
TEST_CASE( "Create empty table", "[integration]" ) { TEST_CASE( "Create empty table", "[integration]" ) {
Script* script = Script::Create("table = {}"); Script* script = Script::Create("table = {}");
@ -43,6 +44,24 @@ result = table[3]
delete script; delete script;
} }
TEST_CASE( "Create complex table", "[integration]" ) {
Script* script = Script::Create(
R"(
table = {
foo = 'test'
bar = 100
}
)");
REQUIRE(!script->Diagnostics -> HasErrors());
script->Evaluate();
auto variable = script->GetVariable("table");
REQUIRE(variable != nullptr);
auto table = (TableEvalValue*)variable;
CHECK(*table->IndexValue("foo")->EvaluateString() == "test");
CHECK(table->IndexValue("bar")->EvaluateInteger() == 100);
delete script;
}
#endif #endif

View File

@ -44,5 +44,22 @@ TEST_CASE( "Create local variable and use", "[integration]" ) {
delete script; delete script;
} }
TEST_CASE( "Local variables in upmost scope persist", "[integration]" ) {
Script* script = Script::Create(R"(
result = 0
local foo = 0
function bar()
foo = foo + 1
result = foo
end
)");
REQUIRE(!script->Diagnostics -> HasErrors());
script->Evaluate();
script -> CallFunction("bar", {});
script -> CallFunction("bar", {});
auto variable = script->GetVariable("result");
REQUIRE(variable != nullptr);
CHECK(variable->EvaluateInteger() == 2);
delete script;
}
#endif #endif