PorygonLang/src/Script.cpp

184 lines
6.3 KiB
C++

#include <utility>
#include <vector>
#include <locale>
#include <codecvt>
#include "Script.hpp"
#include "Parser/Lexer.hpp"
#include "Parser/Parser.hpp"
#include "Binder/Binder.hpp"
#include "EvaluateResult.hpp"
Porygon::Script* Porygon::Script::Create(const u16string& script, ScriptOptions* options) {
return new Script(script, options);
}
std::u16string To_UTF16(const string &s)
{
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> conv;
return conv.from_bytes(s);
}
Porygon::Script *Porygon::Script::Create(const string &script, ScriptOptions* options) {
return Script::Create(To_UTF16(script), options);
}
Porygon::Script::Script(const u16string& s, ScriptOptions* options)
: Diagnostics(make_shared<Diagnostics::DiagnosticsHolder>(s)),
_boundScript(nullptr),
_scriptVariables(new map<Utilities::HashedString, EvalValuePointer>()),
_scriptTypes(new unordered_map<Utilities::HashedString, shared_ptr<const ScriptType>>{}),
_scriptOptions(options)
{
_evaluator = new Evaluator(this -> _scriptVariables, this -> GetScriptOptions());
this -> Parse(s);
}
EvalValuePointer Porygon::Script::Evaluate() {
return _evaluator->Evaluate(_boundScript.get());
}
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) {
auto lexer = Lexer(script, this);
auto lexResult = lexer.Lex();
auto parser = Parser::Parser(lexResult, this);
auto parseResult = parser.Parse();
for (auto token : lexResult){
delete token;
}
lexResult.clear();
if (!Diagnostics->HasErrors()){
map<Utilities::HashedString, BoundVariable*> 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, v.second});
}
scriptScope.clear();
variableTypes.clear();
}
delete parseResult;
}
const EvalValue* Porygon::Script::GetVariable(const u16string &key) {
return _scriptVariables -> at(HashedString::CreateLookup(key)).Clone();
}
bool Porygon::Script::HasVariable(const u16string &key) {
auto f = _scriptVariables->find(HashedString::CreateLookup(key));
return f != _scriptVariables->end();
}
bool Porygon::Script::HasFunction(const u16string &key) {
auto f = _scriptVariables->find(HashedString::CreateLookup(key));
return f != _scriptVariables->end() && f.operator->()->second->GetTypeClass() == TypeClass ::Function;
}
const EvalValue* Porygon::Script::CallFunction(const u16string &key, const vector<EvalValue *>& variables) {
auto var = (GenericFunctionEvalValue*)GetVariable(key);
return this->_evaluator->EvaluateFunction(var, variables);
}
Porygon::Script *Porygon::Script::Clone(const Porygon::Script *script) {
auto s = new Script(script->_boundScript, script->Diagnostics);
s->_scriptOptions = script ->_scriptOptions;
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;
}
Porygon::Script::Script(shared_ptr<BoundScriptStatement> boundScript,
shared_ptr<Porygon::Diagnostics::DiagnosticsHolder> diagnostics)
: _boundScript(std::move(boundScript)),
Diagnostics(std::move(diagnostics)),
_scriptVariables(new map<Utilities::HashedString, EvalValuePointer>()),
_scriptTypes(new unordered_map<Utilities::HashedString, shared_ptr<const ScriptType>>{}),
_scriptOptions(nullptr)
{
_evaluator = new Evaluator(_scriptVariables, this -> GetScriptOptions());
}
std::string Porygon::Script::GetTreeString() {
if (_treeString.empty()){
std::stringstream stream;
_boundScript->GetTreeString(stream, 0);
_treeString = stream.str();
}
return _treeString;
}
extern "C" {
Porygon::Script* CreateScript(char16_t * s, Porygon::ScriptOptions* options){
return Porygon::Script::Create(s, options);
}
Porygon::Script* CloneScript(Porygon::Script* p){
return Porygon::Script::Clone(p);
}
Porygon::EvaluateResult* EvaluateScript(Porygon::Script* script){
try{
auto result = script -> Evaluate();
return new Porygon::EvaluateResult(result.Take());
}
catch (const EvaluationException& e){
return new Porygon::EvaluateResult(e.what());
}
}
bool HasVariable(Porygon::Script* script, const char16_t* key){
return script->HasVariable(key);
}
const EvalValue* GetVariable(Porygon::Script* script, const char16_t* key){
return script->GetVariable(key);
}
bool HasFunction(Porygon::Script* script, const char16_t* key){
return script->HasFunction(key);
}
Porygon::EvaluateResult* CallFunction(Porygon::Script* script, const char16_t* key, EvalValue* parameters[], int parameterCount){
try{
std::vector<EvalValue*> v(parameters, parameters + parameterCount);
auto result = script->CallFunction(key, v);
return new Porygon::EvaluateResult(result);
}
catch (const EvaluationException& e){
return new Porygon::EvaluateResult(e.what());
}
}
const char * GetResultError(Porygon::EvaluateResult * result){
return result->GetError();
}
const size_t GetTreeStringLength(Porygon::Script* script){
return script->GetTreeString().size();
}
void GetTreeString(Porygon::Script* script, char* buffer){
auto s = script->GetTreeString();
for (size_t i = 0; i < s.size(); i++){
buffer[i] = s[i];
}
}
}