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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -63,9 +63,20 @@ namespace Porygon::Utilities{
inline bool operator>(const HashedString& b) const{
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

View File

@ -4,20 +4,32 @@
using namespace Porygon;
class ModuleHandler{
static unordered_map<string, Script*> MODULES;
class Internal{
public:
unordered_map<string, Script*> MODULES;
~ModuleHandler(){
for (auto v: MODULES){
delete v.second;
Internal(){
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;
}
MODULES.clear();
}
};
static Internal _internal;
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){
return MODULES[moduleName];
return _internal.MODULES[moduleName];
}
public:
@ -27,9 +39,7 @@ public:
}
};
unordered_map<string, Script*> ModuleHandler::MODULES = unordered_map<string, Script*>{
{"simple_return", Script::Create(u"return 500")}
};
ModuleHandler::Internal ModuleHandler::_internal;
TEST_CASE( "Require simple return script", "[integration]" ) {
ModuleHandler::Initialize();
@ -42,4 +52,23 @@ return require("simple_return")
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