Support for loading variables from module with require
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Deukhoofd 2019-08-11 12:32:18 +02:00
parent c39f3a0884
commit 641b6784c7
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
8 changed files with 89 additions and 28 deletions

View File

@ -630,12 +630,12 @@ namespace Porygon::Binder {
exp->GetLength()); exp->GetLength());
return new BoundBadExpression(exp->GetStartPosition(), exp ->GetLength()); return new BoundBadExpression(exp->GetStartPosition(), exp ->GetLength());
} }
auto module = 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()){
//TODO: Currently a hack, will always make all variables nil auto type = module->GetVariableType(v.first);
auto type = make_shared<const ScriptType>(TypeClass::Nil); auto result = this -> _scope -> AssignVariable(v.first, type);
this -> _scope -> AssignVariable(v.first, type); delete result.GetKey();
} }
} }
@ -737,7 +737,7 @@ namespace Porygon::Binder {
BoundExpression *Binder::BindTableExpression(const ParsedTableExpression *expression) { BoundExpression *Binder::BindTableExpression(const ParsedTableExpression *expression) {
auto tableScope = new map<Utilities::HashedString, BoundVariable *>(); auto tableScope = new map<Utilities::HashedString, BoundVariable *>();
auto innerScope = new BoundScope(tableScope); auto innerScope = new BoundScope(tableScope, nullptr);
auto currentScope = this->_scope; auto currentScope = this->_scope;
this->_scope = innerScope; this->_scope = innerScope;
auto block = dynamic_cast<BoundBlockStatement*>(this->BindBlockStatement(expression->GetBlock())); auto block = dynamic_cast<BoundBlockStatement*>(this->BindBlockStatement(expression->GetBlock()));

View File

@ -3,8 +3,10 @@
#include "../../StandardLibraries/StaticScope.hpp" #include "../../StandardLibraries/StaticScope.hpp"
namespace Porygon::Binder { namespace Porygon::Binder {
BoundScope::BoundScope(map<Utilities::HashedString, BoundVariable *> *tableScope) { BoundScope::BoundScope(map<Utilities::HashedString, BoundVariable *> *tableScope,
unordered_map<Utilities::HashedString, shared_ptr<const ScriptType>>* tableVariableTypes) {
_tableScope = tableScope; _tableScope = tableScope;
_tableVariableTypes = tableVariableTypes;
_currentScope = 1; _currentScope = 1;
_lastCreatedScope = 1; _lastCreatedScope = 1;
auto localUpmostScope = new map<Utilities::HashedString, BoundVariable *>(); auto localUpmostScope = new map<Utilities::HashedString, BoundVariable *>();
@ -92,6 +94,9 @@ namespace Porygon::Binder {
if (exists < 0) { if (exists < 0) {
// Creation // Creation
_tableScope->insert({identifier, new BoundVariable(type)}); _tableScope->insert({identifier, new BoundVariable(type)});
if (_tableVariableTypes != nullptr){
_tableVariableTypes->insert({identifier, 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

@ -4,6 +4,7 @@
#include <string> #include <string>
#include <map> #include <map>
#include <unordered_map>
#include <vector> #include <vector>
#include <memory> #include <memory>
#include "BoundVariable.hpp" #include "BoundVariable.hpp"
@ -16,11 +17,13 @@ using namespace std;
namespace Porygon::Binder { namespace Porygon::Binder {
class BoundScope { class BoundScope {
map<Utilities::HashedString, BoundVariable *> *_tableScope; map<Utilities::HashedString, BoundVariable *> *_tableScope;
unordered_map<Utilities::HashedString, shared_ptr<const ScriptType>> * _tableVariableTypes;
vector<map<Utilities::HashedString, BoundVariable *> *> _localScope; vector<map<Utilities::HashedString, BoundVariable *> *> _localScope;
int _currentScope; int _currentScope;
int _lastCreatedScope; int _lastCreatedScope;
public: public:
explicit BoundScope(map<Utilities::HashedString, BoundVariable *> *tableScope); explicit BoundScope(map<Utilities::HashedString, BoundVariable *> *tableScope,
unordered_map<Utilities::HashedString, shared_ptr<const ScriptType>>* tableVariableTypes);
~BoundScope(); ~BoundScope();

View File

@ -402,13 +402,14 @@ namespace Porygon::Evaluation {
EvalValuePointer Evaluator::EvaluateRequireExpression(const BoundExpression* expression) { EvalValuePointer Evaluator::EvaluateRequireExpression(const BoundExpression* expression) {
auto module = dynamic_cast<const BoundRequireExpression*>(expression)->GetModule(); auto module = dynamic_cast<const BoundRequireExpression*>(expression)->GetModule();
auto result = module->Evaluate();
if (module ->GetReturnType() == nullptr){ if (module ->GetReturnType() == nullptr){
for (const auto& v: *module->GetScriptVariables()){ for (const auto& v: *module->GetScriptVariables()){
this->_scriptVariables->insert({v.first, v.second.Clone()}); this->_scriptVariables->at(v.first) = v.second.Clone();
} }
return nullptr; return nullptr;
} else{ } else{
return module -> Evaluate().Take(); return result.Take();
} }
} }
} }

View File

@ -1,6 +1,5 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <iterator>
#include <locale> #include <locale>
#include <codecvt> #include <codecvt>
#include "Script.hpp" #include "Script.hpp"
@ -26,6 +25,7 @@ Porygon::Script::Script(const u16string& s)
: Diagnostics(make_shared<Diagnostics::DiagnosticsHolder>(s)), : Diagnostics(make_shared<Diagnostics::DiagnosticsHolder>(s)),
_boundScript(nullptr), _boundScript(nullptr),
_scriptVariables(new map<Utilities::HashedString, EvalValuePointer>()), _scriptVariables(new map<Utilities::HashedString, EvalValuePointer>()),
_scriptTypes(new unordered_map<Utilities::HashedString, shared_ptr<ScriptType>>{}),
_scriptOptions(nullptr) _scriptOptions(nullptr)
{ {
_evaluator = new Evaluator(this -> _scriptVariables, this -> GetScriptOptions()); _evaluator = new Evaluator(this -> _scriptVariables, this -> GetScriptOptions());
@ -40,6 +40,8 @@ Porygon::Script::~Script() {
delete this -> _evaluator; delete this -> _evaluator;
this->_scriptVariables->clear(); this->_scriptVariables->clear();
delete this->_scriptVariables; delete this->_scriptVariables;
this->_scriptTypes->clear();
delete this->_scriptTypes;
} }
void Porygon::Script::Parse(const u16string& script) { void Porygon::Script::Parse(const u16string& script) {
@ -53,13 +55,18 @@ void Porygon::Script::Parse(const u16string& script) {
lexResult.clear(); lexResult.clear();
if (!Diagnostics->HasErrors()){ if (!Diagnostics->HasErrors()){
map<Utilities::HashedString, BoundVariable*> scriptScope; map<Utilities::HashedString, BoundVariable*> scriptScope;
auto bindScope = new BoundScope(&scriptScope); unordered_map<Utilities::HashedString, shared_ptr<const ScriptType>> variableTypes;
auto bindScope = new BoundScope(&scriptScope, &variableTypes);
this->_boundScript = shared_ptr<BoundScriptStatement>(Binder::Binder::Bind(this, parseResult, bindScope)); this->_boundScript = shared_ptr<BoundScriptStatement>(Binder::Binder::Bind(this, parseResult, bindScope));
for (const auto& v : scriptScope){ for (const auto& v : scriptScope){
this->_scriptVariables -> insert({v.first, nullptr}); this->_scriptVariables -> insert({v.first, nullptr});
delete v.second; delete v.second;
} }
for (const auto& v : variableTypes){
this->_scriptTypes -> insert({v.first, nullptr});
}
scriptScope.clear(); scriptScope.clear();
variableTypes.clear();
} }
delete parseResult; delete parseResult;
} }
@ -73,10 +80,6 @@ bool Porygon::Script::HasVariable(const u16string &key) {
return f != _scriptVariables->end(); return f != _scriptVariables->end();
} }
/*const EvalValue *Porygon::Script::GetLastValue() {
return _evaluator->GetLastValue();
}*/
bool Porygon::Script::HasFunction(const u16string &key) { bool Porygon::Script::HasFunction(const u16string &key) {
auto f = _scriptVariables->find(HashedString::CreateLookup(key)); auto f = _scriptVariables->find(HashedString::CreateLookup(key));
return f != _scriptVariables->end() && f.operator->()->second->GetTypeClass() == TypeClass ::Function; return f != _scriptVariables->end() && f.operator->()->second->GetTypeClass() == TypeClass ::Function;
@ -89,9 +92,13 @@ const EvalValue* Porygon::Script::CallFunction(const u16string &key, const vecto
Porygon::Script *Porygon::Script::Clone(const Porygon::Script *script) { Porygon::Script *Porygon::Script::Clone(const Porygon::Script *script) {
auto s = new Script(script->_boundScript, script->Diagnostics); auto s = new Script(script->_boundScript, script->Diagnostics);
for (auto v: *script->_scriptVariables){ for (const auto& v: *script->_scriptVariables){
s->_scriptVariables->insert({v.first, nullptr}); s->_scriptVariables->insert({v.first, nullptr});
} }
for (const auto& v: *script->_scriptTypes){
s->_scriptTypes->insert({v.first, v.second});
}
s->_returnType = script->_returnType; s->_returnType = script->_returnType;
return s; return s;
} }
@ -101,6 +108,7 @@ Porygon::Script::Script(shared_ptr<BoundScriptStatement> boundScript,
: _boundScript(std::move(boundScript)), : _boundScript(std::move(boundScript)),
Diagnostics(std::move(diagnostics)), Diagnostics(std::move(diagnostics)),
_scriptVariables(new map<Utilities::HashedString, EvalValuePointer>()), _scriptVariables(new map<Utilities::HashedString, EvalValuePointer>()),
_scriptTypes(new unordered_map<Utilities::HashedString, shared_ptr<ScriptType>>{}),
_scriptOptions(nullptr) _scriptOptions(nullptr)
{ {
_evaluator = new Evaluator(_scriptVariables, this -> GetScriptOptions()); _evaluator = new Evaluator(_scriptVariables, this -> GetScriptOptions());

View File

@ -19,6 +19,7 @@ namespace Porygon{
class Script { class Script {
Evaluator* _evaluator; Evaluator* _evaluator;
map<Utilities::HashedString, EvalValuePointer>* _scriptVariables; map<Utilities::HashedString, EvalValuePointer>* _scriptVariables;
unordered_map<Utilities::HashedString, shared_ptr<ScriptType>>* _scriptTypes;
shared_ptr<Binder::BoundScriptStatement> _boundScript; shared_ptr<Binder::BoundScriptStatement> _boundScript;
shared_ptr<const ScriptType> _returnType = nullptr; shared_ptr<const ScriptType> _returnType = nullptr;
ScriptOptions* _scriptOptions; ScriptOptions* _scriptOptions;
@ -54,6 +55,9 @@ namespace Porygon{
const EvalValue* GetVariable(const u16string& key); const EvalValue* GetVariable(const u16string& key);
bool HasVariable(const u16string& key); bool HasVariable(const u16string& key);
shared_ptr<const ScriptType> GetVariableType(const Utilities::HashedString& key){
return _scriptTypes->at(key);
}
const EvalValue* CallFunction(const u16string& key, const vector<EvalValue*>& variables); const EvalValue* CallFunction(const u16string& key, const vector<EvalValue*>& variables);
bool HasFunction(const u16string& key); bool HasFunction(const u16string& key);

View File

@ -63,9 +63,20 @@ namespace Porygon::Utilities{
inline bool operator>(const HashedString& b) const{ inline bool operator>(const HashedString& b) const{
return _hash > b._hash; return _hash > b._hash;
} }
std::size_t operator()(const HashedString& k) const {
return _hash;
}
}; };
} }
namespace std {
template <>
struct hash<Porygon::Utilities::HashedString> {
std::size_t operator()(const Porygon::Utilities::HashedString& k) const{
return k.GetHash();
}
};
};
#endif //PORYGONLANG_HASHEDSTRING_HPP #endif //PORYGONLANG_HASHEDSTRING_HPP

View File

@ -4,20 +4,32 @@
using namespace Porygon; using namespace Porygon;
class ModuleHandler{ class ModuleHandler{
static unordered_map<string, Script*> MODULES; class Internal{
public:
unordered_map<string, Script*> MODULES;
~ModuleHandler(){ Internal(){
for (auto v: MODULES){ MODULES = {
{"simple_return", Script::Create(u"return 500")},
{"simple_variables", Script::Create(u"foo = 50\nbar = \'test\'")}
};
}
~Internal(){
for (const auto& v: MODULES){
delete v.second; delete v.second;
} }
MODULES.clear();
} }
};
static Internal _internal;
inline static bool DoesModuleExist(const string& moduleName){ inline static bool DoesModuleExist(const string& moduleName){
return MODULES.find(moduleName) != MODULES.end(); return _internal.MODULES.find(moduleName) != _internal.MODULES.end();
} }
inline static Script* ResolveModule(const string& moduleName){ inline static Script* ResolveModule(const string& moduleName){
return MODULES[moduleName]; return _internal.MODULES[moduleName];
} }
public: public:
@ -27,9 +39,7 @@ public:
} }
}; };
unordered_map<string, Script*> ModuleHandler::MODULES = unordered_map<string, Script*>{ ModuleHandler::Internal ModuleHandler::_internal;
{"simple_return", Script::Create(u"return 500")}
};
TEST_CASE( "Require simple return script", "[integration]" ) { TEST_CASE( "Require simple return script", "[integration]" ) {
ModuleHandler::Initialize(); ModuleHandler::Initialize();
@ -42,4 +52,23 @@ return require("simple_return")
delete script; delete script;
} }
TEST_CASE( "Require simple variables script", "[integration]" ) {
ModuleHandler::Initialize();
auto script = Script::Create(uR"(
require("simple_variables")
)");
REQUIRE(!script->Diagnostics -> HasErrors());
script->Evaluate();
REQUIRE(script->HasVariable(u"foo"));
REQUIRE(script->HasVariable(u"bar"));
auto foo = script->GetVariable(u"foo");
auto bar = script->GetVariable(u"bar");
CHECK(foo->EvaluateInteger() == 50);
CHECK(bar->EvaluateString() == u"test");
delete foo;
delete bar;
delete script;
}
#endif #endif