From 1c9707b5b8e401b6dd110e3caee7a0d7d0898ab7 Mon Sep 17 00:00:00 2001 From: Mike Nolan Date: Sun, 1 Sep 2024 22:19:22 -0500 Subject: [PATCH] removing each --- file.twss | 12 + main.twss | 8 + templater.cpp | 36 + tessesscriptengine.hpp | 4242 +++++++++++++++++++++++++++++++++ tesseswebserver.cpp | 41 + tesseswebserver.hpp | 1142 +++++++++ tesseswebserverfeatures.hpp | 7 + wwwroot/cgi-bin/add-todo.twss | 8 + wwwroot/deinit.twss | 3 + wwwroot/index.twss | 26 + wwwroot/init.twss | 3 + 11 files changed, 5528 insertions(+) create mode 100644 file.twss create mode 100644 main.twss create mode 100644 templater.cpp create mode 100644 tessesscriptengine.hpp create mode 100644 tesseswebserver.cpp create mode 100644 tesseswebserver.hpp create mode 100644 tesseswebserverfeatures.hpp create mode 100644 wwwroot/cgi-bin/add-todo.twss create mode 100644 wwwroot/deinit.twss create mode 100644 wwwroot/index.twss create mode 100644 wwwroot/init.twss diff --git a/file.twss b/file.twss new file mode 100644 index 0000000..494c0e8 --- /dev/null +++ b/file.twss @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/main.twss b/main.twss new file mode 100644 index 0000000..e48704b --- /dev/null +++ b/main.twss @@ -0,0 +1,8 @@ + +John + diff --git a/templater.cpp b/templater.cpp new file mode 100644 index 0000000..12ec18f --- /dev/null +++ b/templater.cpp @@ -0,0 +1,36 @@ +#include "tesseswebserver.hpp" +TESSESWEBSERVER_STATIC_DECLARATION +using namespace Tesses::WebServer; +using namespace Tesses::WebServer::ScriptEngine; + + +int main(int argc,char** argv) +{ + RootEnvironment* rEnv = new RootEnvironment(); + rEnv->print = [](ScriptType arg)-> void { + + std::cout << ConvertToString(arg); + }; + + BytecodeCompiler bcc(ScriptParser::Parse("file.twss")); + bcc.Compile(); + auto rf = bcc.file->rootFunction; + rf->env = rEnv; + rf->isRoot=true; + for(auto f : bcc.file->functions) + { + auto rf2 = f.second; + rf2->env = rEnv; + rf2->isRoot=false; + + + + + rEnv->SetValue(f.first,ObjectType(f.second)); + } + + rf->Execute(rEnv,{}); + + + +} \ No newline at end of file diff --git a/tessesscriptengine.hpp b/tessesscriptengine.hpp new file mode 100644 index 0000000..fdcb14f --- /dev/null +++ b/tessesscriptengine.hpp @@ -0,0 +1,4242 @@ +#pragma once + +#include "tesseswebserver.hpp" + + +#if defined(INCLUDED_FROM_TESSESWEBSERVER_H) +namespace ScriptEngine +#else +namespace Tesses::WebServer::ScriptEngine +#endif +{ + class Instruction + { + public: + virtual int Length()=0; + virtual void Write(uint8_t* buffer)=0; + virtual ~Instruction() + { + + } + const static uint8_t ADD = 0; + const static uint8_t SUB = 1; + const static uint8_t TIMES = 2; + const static uint8_t DIVIDE = 3; + const static uint8_t MOD = 4; + const static uint8_t LEFTSHIFT = 5; + const static uint8_t RIGHTSHIFT = 6; + const static uint8_t LESSTHAN = 7; + const static uint8_t GREATERTHAN = 8; + const static uint8_t LESSTHANEQUALTO = 9; + const static uint8_t GREATERTHANEQUALTO = 10; + const static uint8_t EQUALS = 11; + const static uint8_t NOTEQUALS = 12; + const static uint8_t BITWISEOR = 13; + const static uint8_t BITWISEAND = 14; + const static uint8_t BITWISENOT = 15; + const static uint8_t EXCLUSIVEOR = 16; + const static uint8_t LOGICALNOT = 17; + const static uint8_t NEGATIVE = 18; + const static uint8_t GETVARIABLE = 19; + const static uint8_t SETVARIABLE = 20; + const static uint8_t GETFIELD = 21; + const static uint8_t SETFIELD = 22; + const static uint8_t GETARRAY = 23; + const static uint8_t SETARRAY = 24; + const static uint8_t PUSH_STRING = 25; + const static uint8_t PUSH_CHAR = 26; + const static uint8_t PUSH_LONG = 27; + const static uint8_t PUSH_DOUBLE = 28; + const static uint8_t SET_LOOP = 29; //for scoping reasons + const static uint8_t GET_LOOP = 30; + const static uint8_t DESTROY_LOOP = 31; + const static uint8_t CALL_FUNC = 32; + const static uint8_t CALL_METHOD = 33; + const static uint8_t PRINT = 34; + const static uint8_t JMPC = 35; + const static uint8_t JMP = 36; + const static uint8_t POP = 37; + const static uint8_t RET = 38; + const static uint8_t SCOPE_BEGIN = 39; + const static uint8_t SCOPE_END = 40; + const static uint8_t GET_GLOBAL_VARIABLE = 41; + const static uint8_t SET_GLOBAL_VARIABLE = 42; + const static uint8_t GET_CALLER_VARIABLE = 43; + const static uint8_t SET_CALLER_VARIABLE = 44; + const static uint8_t DECLARE_VARIABLE = 45; + const static uint8_t PUSH_NULL = 46; + const static uint8_t PUSH_UNDEFINED = 47; + const static uint8_t PUSH_FALSE = 48; + const static uint8_t PUSH_TRUE = 49; + const static uint8_t ITTR = 50; + + #if defined(DEBUG) + virtual void Print() + { + + } + #endif + }; + class Object { + + public: + + virtual std::string ToString() + { + return ""; + } + virtual bool ToBool() + { + return false; + } + virtual bool CanDestroy() + { + return true; + } + + virtual ~Object() + { + + } + }; + + class Undefined { + + + }; + class Null + { + + }; + + + class ObjectType { + public: + Object* data; + ObjectType(Object* o) + { + this->data = o; + } + }; + + + typedef std::variant IttrType; + + + + + class IttrKVP { + public: + IttrType ittr; + int64_t index; + }; + + + typedef std::variant ScriptType; + class Ittr : public Object { + public: + IttrType ittr; + int64_t index; + }; + + + inline bool Equals(ScriptType& left, ScriptType& right) + { + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) == std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) == std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) == std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) == std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return (double)std::get(left) == std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) == (double)std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) == std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return true; + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return true; + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + auto objLeft = std::get(left).data; + auto objRight = std::get(right).data; + if(objLeft == objRight) + return true; + } + return false; + } + inline bool ConvertToBool(ScriptType& st) + { + if(std::holds_alternative(st)) + { + return std::get(st).size() > 0; + } + if(std::holds_alternative(st)) + { + return std::get(st) != 0; + } + if(std::holds_alternative(st)) + { + return std::get(st) != 0; + } + if(std::holds_alternative(st)) + { + std::cout << (std::get(st) ? "true" : "false") << std::endl; + return std::get(st); + } + if(std::holds_alternative(st)) + { + return std::get(st) != 0; + } + if(std::holds_alternative(st)) + { + return std::get(st).data->ToBool(); + } + return false; + } + inline ScriptType IttrGetValue(ScriptType& st); + inline std::string IttrGetKey(ScriptType& st); + inline std::string ConvertToString(ScriptType& st); + inline std::string ConvertToString(ScriptType& st) + { + if(std::holds_alternative(st)) + { + auto v = IttrGetValue(st); + + return IttrGetKey(st) + ": " + ConvertToString(v); + } + + if(std::holds_alternative(st)) + { + return "null"; + } + if(std::holds_alternative(st)) + { + return std::get(st); + } + if(std::holds_alternative(st)) + { + return std::to_string(std::get(st)); + } + if(std::holds_alternative(st)) + { + return std::to_string(std::get(st)); + } + if(std::holds_alternative(st)) + { + return std::get(st) ? "true" : "false"; + } + if(std::holds_alternative(st)) + { + return std::string({std::get(st)}); + } + if(std::holds_alternative(st)) + { + return std::get(st).data->ToString(); + } + + return "undefined"; + } + + class RootEnvironment; + + class Environment { + public: + std::function print; + virtual bool HasObject(std::string key) = 0; + virtual bool HasObjectRecurse(std::string key) = 0; + virtual ScriptType GetValue(std::string key) = 0; + virtual void SetValue(std::string key,ScriptType val) = 0; + virtual Environment* GetRoot()=0; + virtual Environment* GetParent()=0; + virtual Environment* GetGlobal() + { + return this->GetRoot()->GetGlobal(); + } + virtual void Declare(std::string key,ScriptType val) + { + SetValue(key,val); + } + Environment* GetSub(); + virtual ~Environment() + { + + } + }; + + class SubEnvironment : public Environment + { + Environment* parent; + public: + std::map items; + SubEnvironment(Environment* env) + { + this->parent = env; + } + Environment* GetParent() + { + return parent; + } + Environment* GetRoot() + { + return parent->GetRoot(); + } + + bool HasObject(std::string key) + { + return items.count(key) > 0; + } + bool HasObjectRecurse(std::string key) + { + if(items.count(key) > 0) return true; + + return this->parent->HasObjectRecurse(key); + } + ScriptType GetValue(std::string key) + { + if(HasObject(key)) + { + return items[key]; + } + return this->parent->GetValue(key); + } + void SetValue(std::string key,ScriptType val) + { + if(HasObject(key)) + { + items[key] = val; + return; + } + if(this->parent->HasObjectRecurse(key)) + { + this->parent->SetValue(key,val); + } + items[key] = val; + } + void Declare(std::string key,ScriptType val) + { + this->items[key] = val; + } + }; + + inline Environment* Environment::GetSub() + { + SubEnvironment* env = new SubEnvironment(this); + env->print = this->print; + return env; + } + class CallableObject : public Object + { + public: + bool useGlobalEnv=false; + + virtual bool FirstArgumentIsThis() + { + return false; + } + + bool CanDestroy() + { + return false; + } + + virtual ScriptType Execute(Environment* callerEnv,std::vector args) + { + return Null(); + } + + ScriptType Execute(Environment* callerEnv,std::initializer_list args) + { + return Execute(callerEnv,std::vector(args)); + } + + std::string ToString() + { + return ""; + } + bool ToBool() + { + return true; + } + + }; + + class ExternalFunction : public CallableObject { + public: + std::function)> callback; + bool firstArgIsThis; + bool FirstArgumentIsThis() + { + return firstArgIsThis; + } + ExternalFunction(std::function)> callback,bool firstArgIsThis=false) + { + this->callback = callback; + this->firstArgIsThis = firstArgIsThis; + } + ScriptType Execute(Environment* callerEnv,std::vector args) + { + return callback(callerEnv,args); + } + + ~ExternalFunction() + { + + } + }; + + class InternalFunction; + + class List : public Object { + public: + std::vector items; + std::string ToString() + { + return ""; + } + bool ToBool() + { + return items.size() > 0; + } + }; + + class Dictionary : public Object { + public: + std::vector> items; + std::string ToString() + { + return ""; + } + bool ToBool() + { + return items.size() > 0; + } + bool HasValue(std::string key) + { + for(auto item : items) + if(item.first == key) return true; + return false; + } + ScriptType GetValue(std::string key) + { + for(auto item : items) + if(item.first == key) return item.second; + return Undefined(); + } + + void SetValue(std::string key, ScriptType& value) + { + if(std::holds_alternative(value)) + { + for(auto item = items.cbegin();item <= items.cend();item++) + { + auto myItem = *item; + if(myItem.first == key) + { + items.erase(item); + return; + } + } + } + else + { + + for(auto item : items) + { + if(item.first == key) + { + item.second = value; + return; + } + } + + items.push_back(std::pair(key,value)); + } + } + }; + + inline ScriptType CreateIttrFor(ScriptType& st) + { + if(std::holds_alternative(st)) + { + Ittr* ittr =new Ittr(); + ittr->index = -1; + ittr->ittr = std::get(st); + ObjectType t(ittr); + return t; + } + if(std::holds_alternative(st)) + { + auto ot = std::get(st).data; + auto ls = dynamic_cast(ot); + auto dict = dynamic_cast(ot); + if(ls != nullptr) + { + Ittr* ittr=new Ittr(); + ittr->index = -1; + ittr->ittr = ObjectType(ls); + ObjectType t(ittr); + return t; + } + if(dict != nullptr) + { + Ittr* ittr=new Ittr(); + ittr->index = -1; + ittr->ittr = ObjectType(dict); + ObjectType t(ittr); + return t; + } + } + return Null(); + } + + inline bool IttrMoveNext(ScriptType& st) + { + if(std::holds_alternative(st)) + { + auto objIttr = std::get(st).data; + auto ittr = dynamic_cast(objIttr); + if(ittr == nullptr) return false; + std::cout << "INDEXB: " << ittr->index << std::endl; + ittr->index++; + std::cout << "INDEXA: " << ittr->index << std::endl; + + if(std::holds_alternative(ittr->ittr)) + { + std::string str = std::get(ittr->ittr); + + + if(ittr->index >= 0 && ittr->index < str.size()) + { + return true; + } + } + if(std::holds_alternative(ittr->ittr)) + { + auto ot = std::get(ittr->ittr).data; + auto ls = dynamic_cast(ot); + auto dict = dynamic_cast(ot); + + if(ls != nullptr) + { + + if(ittr->index >= 0 && ittr->index < ls->items.size()) + { + + return true; + } + } + if(dict != nullptr) + { + + if(ittr->index >= 0 && ittr->index < dict->items.size()) + { + + return true; + } + } + } + } + return false; + } + + inline ScriptType IttrCurrent(ScriptType& st) + { + if(std::holds_alternative(st)) + { + auto objIttr = std::get(st).data; + auto ittr = dynamic_cast(objIttr); + if(ittr == nullptr) return Null(); + if(std::holds_alternative(ittr->ittr)) + { + std::string str = std::get(ittr->ittr); + if(ittr->index >= 0 && ittr->index < str.size()) + { + return str[ittr->index]; + } + } + if(std::holds_alternative(ittr->ittr)) + { + auto ot = std::get(ittr->ittr).data; + auto ls = dynamic_cast(ot); + auto dict = dynamic_cast(ot); + + if(ls != nullptr) + { + if(ittr->index >= 0 && ittr->index < ls->items.size()) + { + return ls->items[ittr->index]; + } + } + if(dict != nullptr) + { + if(ittr->index >= 0 && ittr->index < dict->items.size()) + { + IttrKVP kvp; + kvp.index = ittr->index; + kvp.ittr = ittr->ittr; + return kvp; + } + } + } + } + return Null(); + } + inline std::string IttrGetKey(ScriptType& st) + { + if(std::holds_alternative(st)) + { + auto ittr = std::get(st); + + if(std::holds_alternative(ittr.ittr)) + { + auto ot = std::get(ittr.ittr).data; + auto dict = dynamic_cast(ot); + + + if(dict != nullptr) + { + if(ittr.index >= 0 && ittr.index < dict->items.size()) + { + return dict->items[ittr.index].first; + } + } + } + } + return std::string({}); + } + + inline ScriptType IttrGetValue(ScriptType& st) + { + if(std::holds_alternative(st)) + { + auto ittr = std::get(st); + + if(std::holds_alternative(ittr.ittr)) + { + auto ot = std::get(ittr.ittr).data; + auto dict = dynamic_cast(ot); + + + if(dict != nullptr) + { + if(ittr.index >= 0 && ittr.index < dict->items.size()) + { + return dict->items[ittr.index].second; + } + } + } + } + return Null(); + } + inline ScriptType TypeOf(Environment* env, std::vector args); + class RootEnvironment : public Environment + { + std::vector fns; + public: + RootEnvironment() + { + DeclareFunctions(); + } + Environment* global=nullptr; + std::map items; + Environment* GetRoot() + { + return this; + } + Environment* GetGlobal() + { + if(global != nullptr) return global; + return this; + } + Environment* GetParent() + { + return this; + } + bool HasObject(std::string key) + { + return items.count(key) > 0; + } + bool HasObjectRecurse(std::string key) + { + return items.count(key) > 0; + } + ScriptType GetValue(std::string key) + { + return items[key]; + } + void SetValue(std::string key,ScriptType val) + { + items[key] = val; + } + void Free(ScriptType t,bool tree=false) + { + + if(std::holds_alternative(t)) + { + auto myObj=std::get(t); + + if(tree) + { + auto ls = dynamic_cast(myObj.data); + auto dict = dynamic_cast(myObj.data); + if(ls != nullptr) + { + for(auto item : ls->items) + Free(item,true); + } + if(dict != nullptr) + { + for(auto item : dict->items) + Free(item.second,true); + } + } + if(myObj.data != nullptr && myObj.data->CanDestroy()) + delete myObj.data; + } + } + void DeclareFunctions() + { + DeclareFunction("dictionary",[this](Environment* env, std::vector args)-> ScriptType { + Dictionary* dict=new Dictionary(); + ObjectType ot(dict); + return ot; + }); + DeclareFunction("list",[this](Environment* env, std::vector args)-> ScriptType { + List* list=new List(); + ObjectType ot(list); + return ot; + }); + DeclareFunction("typeof",TypeOf); + DeclareFunction("free",[this](Environment* env, std::vector args)-> ScriptType { + if(args.size() > 0) + { + Free(args[0]); + } + return Null(); + }); + + DeclareFunction("free_tree",[this](Environment* env, std::vector args)-> ScriptType { + if(args.size() > 0) + { + Free(args[0],true); + } + return Null(); + }); + } + void DeclareFunction(std::string name,std::function)> method) + { + ExternalFunction* item = new ExternalFunction(method); + + fns.push_back(item); + + ObjectType ot(item); + SetValue(name,ot); + } + ~RootEnvironment() + { + + for(auto item : fns) + delete item; + + } + }; + + class ChunkExecuter + { + uint8_t* bytecode; + size_t bytecodeLength; + std::vector* args; + size_t ip=0; + std::stack stack; + Environment* env; + public: + ChunkExecuter(Environment* env,uint8_t* bytecode,size_t bytecodeLength,std::vector* args) + { + this->bytecode = bytecode; + this->bytecodeLength = bytecodeLength; + this->args = args; + this->env = env; + } + + ScriptType Pop() + { + if(stack.empty()) throw std::exception(); + ScriptType t = stack.top(); + + + stack.pop(); + return t; + } + template + T PopSpecific() + { + auto p = Pop(); + + if(std::holds_alternative(p)) + { + return std::get(p); + } + else + { + std::vector args; + args.push_back(p); + auto v = TypeOf(env,args); + this->env->print("IP: "); + this->env->print((int64_t)ip); + this->env->print(" Unexpected type: "); + this->env->print(v); + this->env->print(" with value "); + this->env->print(p); + this->env->print("\n"); + + + throw std::exception(); + } + } + int64_t PopLong() + { + auto val = PopSpecific(); + + + return val; + } + std::string PopString() + { + auto val = PopSpecific(); + return val; + } + + + ScriptType Mod(ScriptType& left,ScriptType& right) + { + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) % std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return fmod(std::get(left), (double)std::get(right)); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return fmod((double)std::get(left), std::get(right)); + } + + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return fmod(std::get(left),std::get(right)); + } + + return Null(); + } + + ScriptType Divide(ScriptType& left,ScriptType& right) + { + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) / std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) / (double)std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return (double)std::get(left) / std::get(right); + } + + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) / std::get(right); + } + + return Null(); + } + + + ScriptType Times(ScriptType& left,ScriptType& right) + { + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) * std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) * (double)std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return (double)std::get(left) * std::get(right); + } + + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) * std::get(right); + } + + return Null(); + } + ScriptType GreaterThan(ScriptType& left,ScriptType& right) + { + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) > std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) > (double)std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return (double)std::get(left) > std::get(right); + } + + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) > std::get(right); + } + + return Null(); + } + ScriptType LessThan(ScriptType& left,ScriptType& right) + { + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) < std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) < (double)std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return (double)std::get(left) < std::get(right); + } + + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) < std::get(right); + } + + return Null(); + } + + ScriptType GreaterThanEqualsTo(ScriptType& left,ScriptType& right) + { + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) >= std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) >= (double)std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return (double)std::get(left) >= std::get(right); + } + + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) >= std::get(right); + } + + return Null(); + } + ScriptType LessThanEqualsTo(ScriptType& left,ScriptType& right) + { + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) <= std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) <= (double)std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return (double)std::get(left) <= std::get(right); + } + + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) <= std::get(right); + } + + return Null(); + } + + + + ScriptType Sub(ScriptType& left,ScriptType& right) + { + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) - std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) - (double)std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return (double)std::get(left) - std::get(right); + } + + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) - std::get(right); + } + + return Null(); + } + + ScriptType Add(ScriptType& left,ScriptType& right) + { + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) + std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) + (double)std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return (double)std::get(left) + std::get(right); + } + + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) + std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) + std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::to_string(std::get(left)) + std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) + std::to_string(std::get(right)); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::to_string(std::get(left)) + std::get(right); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) + std::to_string(std::get(right)); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::get(left) + std::string({std::get(right)}); + } + if(std::holds_alternative(left) && std::holds_alternative(right)) + { + return std::string({std::get(left)}) + std::get(right); + } + return Null(); + } + + ScriptType CallMethod(ScriptType& member, std::string key, std::vector& args) + { + + + if(std::holds_alternative(member)) + { + if(key == "toString") + { + return "undefined"; + } + } + if(std::holds_alternative(member)) + { + if(key == "toString") + { + return "null"; + } + } + if(std::holds_alternative(member)) + { + auto obj = std::get(member).data; + auto ls = dynamic_cast(obj); + auto dict = dynamic_cast(obj); + auto ittr = dynamic_cast(obj); + if(ittr != nullptr) + { + if(key == "current") + { + return IttrCurrent(member); + } + if(key == "movenext") + { + return IttrMoveNext(member); + } + + } + if(ls != nullptr) + { + if(key == "add" && args.size() > 0) + { + ls->items.push_back(args[0]); + } + else if(key == "remove" && args.size() > 0) + { + for(auto ittr = ls->items.cbegin();ittritems.cend();ittr++) + { + auto item = *ittr; + if(Equals(item,args[0])) + { + ls->items.erase(ittr); + break; + } + } + } + else if(key == "indexof" && args.size() > 0) + { + int64_t index = -1; + for(auto ittr = ls->items.cbegin();ittritems.cend();ittr++) + { + auto item = *ittr; + if(Equals(item,args[0])) + { + break; + } + index++; + } + + return index; + } + else if(key == "insert" && args.size() > 1) + { + auto index = args[0]; + if(std::holds_alternative(index)) + { + auto myIndex=std::get(index); + if(myIndex >= 0 && myIndex <= ls->items.size()) + { + ls->items.insert(ls->items.cbegin() + myIndex,{args[1]}); + } + } + } + else if(key == "removeat" && args.size() > 0) + { + auto index = args[0]; + if(std::holds_alternative(index)) + { + auto myIndex=std::get(index); + if(myIndex >= 0 && myIndex < ls->items.size()) + { + ls->items.erase(ls->items.cbegin() + myIndex); + } + } + } + else if(key == "count" || key == "length") + { + return (int64_t)ls->items.size(); + } + else if(key == "clear") { + ls->items.clear(); + } + else if(key == "at" && args.size() > 0) + { + auto index = args[0]; + if(std::holds_alternative(index)) + { + auto myIndex=std::get(index); + if(myIndex >= 0 && myIndex < ls->items.size()) + { + return ls->items.at((size_t)myIndex); + } + } + } + else if(key == "set" && args.size() > 1) + { + auto index = args[0]; + if(std::holds_alternative(index)) + { + auto myIndex=std::get(index); + if(myIndex >= 0 && myIndex < ls->items.size()) + { + return ls->items[(size_t)myIndex]=args[1]; + } + } + } + } + + if(dict != nullptr) + { + auto item = dict->GetValue(key); + if(std::holds_alternative(item)) + { + auto fnt = std::get(item).data; + auto fn = dynamic_cast(fnt); + if(fn != nullptr) + { + if(fn->FirstArgumentIsThis()) + args.insert(args.cbegin(),{member}); + + + return fn->Execute(this->env,args); + } + } + if(key == "toString" && args.size() == 0) + { + return std::string({}); + } + } + } + if(std::holds_alternative(member)) + { + if(key == "toString") + { + return std::to_string(std::get(member)); + } + if(key == "toDouble") + { + return (double)std::get(member); + } + if(key == "toDoubleBits") + { + return std::bit_cast(std::get(member)); + } + if(key == "toChar") + { + return (char)std::get(member); + } + } + if(std::holds_alternative(member)) + { + std::string myStr=std::get(member); + if(key == "toString") + { + return myStr; + } + if(key == "length" || key == "count") + { + return (int64_t)myStr.size(); + } + if(key == "toLower") + { + std::transform(myStr.begin(),myStr.end(),myStr.begin(),::tolower); + return myStr; + } + if(key == "toUpper") + { + std::transform(myStr.begin(),myStr.end(),myStr.begin(),::toupper); + return myStr; + } + } + if(std::holds_alternative(member)) + { + if(key == "toString") + { + return std::string({std::get(member)}); + } + if(key == "toLong") + { + return (int64_t)std::get(member); + } + if(key == "toLower") + { + return (char)std::tolower(std::get(member)); + } + if(key == "toUpper") + { + return (char)std::toupper(std::get(member)); + } + } + if(std::holds_alternative(member)) + { + if(key == "toString") + { + return std::to_string(std::get(member)); + } + if(key == "toLong") + { + return (int64_t)std::get(member); + } + if(key == "toLongBits") + { + return std::bit_cast(std::get(member)); + } + } + + return Undefined(); + } + + ScriptType SetField(ScriptType& instance,std::string name,ScriptType& value) + { + + if(std::holds_alternative(instance)) + { + auto inst = std::get(instance).data; + + auto dict = dynamic_cast(inst); + + if(dict != nullptr) + { + auto myFuncObj = dict->GetValue(std::string("set") + name); + + if(std::holds_alternative(myFuncObj)) + { + auto myFuncObj2 = std::get(myFuncObj).data; + auto callbl = dynamic_cast(myFuncObj2); + if(callbl != nullptr) + { + if(callbl->FirstArgumentIsThis()) + { + return callbl->Execute(env,{instance,value}); + } + else + { + return callbl->Execute(env,{value}); + } + } + } + + + dict->SetValue(name,value); + } + } + return value; + } + + ScriptType GetField(ScriptType& instance, std::string name) + { + if(std::holds_alternative(instance)) + { + auto str = std::get(instance); + if(name == "length" || name == "count") + { + return (int64_t)str.size(); + } + } + if(std::holds_alternative(instance)) + { + if(name == "key") + { + return IttrGetKey(instance); + } + + if(name == "value") + { + return IttrGetValue(instance); + } + return Null(); + } + if(std::holds_alternative(instance)) + { + auto inst = std::get(instance).data; + auto ls = dynamic_cast(inst); + auto dict = dynamic_cast(inst); + if(ls != nullptr) + { + if(name == "length" || name == "count") + { + return (int64_t)ls->items.size(); + } + } + if(dict != nullptr) + { + auto myFuncObj = dict->GetValue(std::string("get") + name); + + if(std::holds_alternative(myFuncObj)) + { + auto myFuncObj2 = std::get(myFuncObj).data; + auto callbl = dynamic_cast(myFuncObj2); + if(callbl != nullptr) + { + if(callbl->FirstArgumentIsThis()) + { + return callbl->Execute(env,{instance}); + } + else + { + return callbl->Execute(env,{}); + } + } + } + + + return dict->GetValue(name); + } + } + return Undefined(); + } + + ScriptType Execute(Environment* callerEnv,std::vector __args) + { + // std::cout << __args.size() << " " << this->args->size() << std::endl; + if(__args.size() != this->args->size()) + { + callerEnv->print("Expected " + std::to_string((int64_t)this->args->size()) + " args, got " + std::to_string((int64_t)__args.size()) + " args.\n"); + throw std::exception(); + } + + for(size_t i = 0;i<__args.size();i++) + { + + env->Declare(this->args->at(i),__args[i]); + } + + + int scopes=0; + std::stack loops; + + while(ip < bytecodeLength) + { + uint8_t instruction = bytecode[ip]; + + ip++; + switch(instruction) + { + case Instruction::PUSH_FALSE: + { + stack.push(false); + } + break; + case Instruction::PUSH_TRUE: + { + stack.push(true); + } + break; + case Instruction::PUSH_NULL: + { + stack.push(Null()); + } + break; + case Instruction::PUSH_UNDEFINED: + { + stack.push(Undefined()); + } + break; + case Instruction::PUSH_CHAR: + { + if(ip + 1 <= bytecodeLength) + { + stack.push((char)bytecode[ip++]); + } + else + { + throw std::exception(); + } + } + break; + case Instruction::CALL_FUNC: + { + int64_t lng=PopLong(); + std::vector _args; + for(int i = 0;i(std::get(fCall).data); + if(myF != nullptr) + { + stack.push(myF->Execute(env,_args)); + + } + else + { + stack.push(Null()); + } + } + break; + case Instruction::CALL_METHOD: + { + int64_t lng=PopLong(); + std::vector _args; + for(int i = 0;iGetValue(str); + stack.push(v); + } + break; + case Instruction::SET_CALLER_VARIABLE: + { + auto v = Pop(); + auto str = PopString(); + callerEnv->SetValue(str,v); + stack.push(v); + } + break; + case Instruction::GET_GLOBAL_VARIABLE: + { + auto str = PopString(); + auto v = env->GetGlobal()->GetValue(str); + stack.push(v); + } + break; + case Instruction::SET_GLOBAL_VARIABLE: + { + auto v = Pop(); + auto str = PopString(); + env->GetGlobal()->SetValue(str,v); + stack.push(v); + } + break; + case Instruction::GETVARIABLE: + { + auto str = PopString(); + + auto v = env->GetValue(str); + stack.push(v); + } + break; + case Instruction::SETVARIABLE: + { + auto v = Pop(); + auto str = PopString(); + env->SetValue(str,v); + stack.push(v); + } + break; + case Instruction::DECLARE_VARIABLE: + { + auto v = Pop(); + auto str = PopString(); + env->Declare(str,v); + stack.push(v); + } + break; + case Instruction::PRINT: + { + auto v = Pop(); + + callerEnv->print(v); + } + break; + case Instruction::SCOPE_BEGIN: + { + scopes++; + env = env->GetSub(); + } + break; + case Instruction::SCOPE_END: + { + Environment* env2 = env; + env=env2->GetParent(); + if(env != env2) + { + delete env2; + } + scopes--; + } + break; + case Instruction::SET_LOOP: + { + loops.push(scopes); + } + break; + case Instruction::GET_LOOP: + { + int myLoops = loops.top(); + + while(scopes > myLoops) + { + Environment* env2 = env; + env=env2->GetParent(); + if(env != env2) + { + delete env2; + } + + scopes--; + } + } + break; + case Instruction::DESTROY_LOOP: + { + int myLoops = loops.top(); + loops.pop(); + + while(scopes > myLoops) + { + Environment* env2 = env; + env=env2->GetParent(); + if(env != env2) + { + delete env2; + } + + scopes--; + } + } + break; + case Instruction::RET: + { + auto val = Pop(); + while(scopes > 0) + { + Environment* env2 = env; + env=env2->GetParent(); + if(env != env2) + { + delete env2; + } + + scopes--; + } + + return val; + } + break; + case Instruction::JMP: + { + if(ip + 4 <= bytecodeLength) + { + + + size_t len = (bytecode[ip++] << 24) & 0xFF; + len |= (bytecode[ip++] << 16) & 0xFF; + len |= (bytecode[ip++] << 8) & 0xFF; + len |= bytecode[ip++] & 0xFF; + if(len < bytecodeLength) + ip = len; + else + { + std::cout << "Jump failed" << std::endl; + throw std::exception(); + } + } + } + break; + case Instruction::JMPC: + { + if(ip + 4 <= bytecodeLength) + { + + + size_t len = (bytecode[ip++] << 24) & 0xFF; + len |= (bytecode[ip++] << 16) & 0xFF; + len |= (bytecode[ip++] << 8) & 0xFF; + len |= bytecode[ip++] & 0xFF; + if(len < bytecodeLength) + { + auto v = Pop(); + if(ConvertToBool(v)) + ip = len; + + } + else + { + std::cout << "Jump failed" << std::endl; + throw std::exception(); + } + } + } + break; + case Instruction::ITTR: + { + auto ittr=Pop(); + stack.push(CreateIttrFor(ittr)); + } + break; + case Instruction::GETFIELD: + { + std::string name = PopString(); + auto instance = Pop(); + stack.push(GetField(instance,name)); + } + break; + case Instruction::SETFIELD: + { + auto val = Pop(); + std::string name = PopString(); + auto instance = Pop(); + stack.push(SetField(instance,name,val)); + } + break; + } + } + while(scopes > 0) + { + Environment* env2 = env; + env=env2->GetParent(); + if(env != env2) + { + delete env2; + } + + scopes--; + } + return Null(); + } + }; + + class InternalFunction : public CallableObject + { + public: + bool isRoot=false; + uint8_t* bytecode; + size_t bytecodeLength; + std::vector args; + Environment* env; + bool FirstArgumentIsThis() + { + return args.size() > 0 && args[0] == "this"; + } + ScriptType Execute(Environment* callerEnv,std::vector args) + { + Environment* env2 = isRoot ? env : env->GetSub(); + ChunkExecuter exec(env2,bytecode,bytecodeLength,&this->args); + + + auto ret=exec.Execute(callerEnv,args); + + if(!isRoot) delete env2; + return ret; + } + }; + + + + class LexToken { + public: + std::string text; + bool isString; + bool isChar; + + LexToken(std::string text) + { + this->text = text; + this->isString = false; + this->isChar = false; + } + + LexToken(std::string text,bool isString) + { + this->text = text; + this->isString = isString; + this->isChar = !isChar; + } + + LexToken(const LexToken& tkn) + { + this->text = tkn.text; + this->isString = tkn.isString; + this->isChar = tkn.isChar; + } + }; + + class Node { + public: + virtual bool IsExpression() { + return false; + } + virtual ~Node() + { + + } + }; + + class Expression : public Node { + public: + bool IsExpression() + { + return true; + } + }; + + class OneExpression : public Expression { + public: + Node* node; + OneExpression(Node* node) + { + this->node = node; + } + }; + + class TwoExpression : public Expression { + public: + Node* left; + Node* right; + TwoExpression(Node* left,Node* right) + { + this->left = left; + this->right = right; + } + }; + + #define LIST_OF_CONST_EXPRESSIONS \ + NODE(bool,Bool) \ + NODE(std::string,String) \ + NODE(int64_t,Long) \ + NODE(double,Double) \ + NODE(char,Char) + + + + #define LIST_OF_ONE_EXPRESSIONS \ + NODE(PostfixIncrement) \ + NODE(PostfixDecrement) \ + NODE(PrefixIncrement) \ + NODE(PrefixDecrement) \ + NODE(BitwiseNot) \ + NODE(LogicalNot) \ + NODE(Negative) \ + NODE(CompoundAssign) \ + NODE(Global) \ + NODE(Caller) \ + NODE(Var) + + #define LIST_OF_TWO_EXPRESSIONS \ + NODE(Add) \ + NODE(Sub) \ + NODE(Times) \ + NODE(Divide) \ + NODE(Mod) \ + NODE(LeftShift) \ + NODE(RightShift) \ + NODE(LessThan) \ + NODE(GreaterThan) \ + NODE(LessThanEqualTo) \ + NODE(GreaterThanEqualTo) \ + NODE(Equals) \ + NODE(NotEquals) \ + NODE(BitwiseOr) \ + NODE(BitwiseAnd) \ + NODE(ExclusiveOr) \ + NODE(LogicalOr) \ + NODE(LogicalAnd) \ + NODE(Assign) + + + #define NODE(_node) class _node##Expression : public OneExpression { \ + public: \ + _node##Expression(Node* n) : OneExpression(n) {} ~_node##Expression() {delete node;} \ + }; + LIST_OF_ONE_EXPRESSIONS + #undef NODE + + #define NODE(node) class node##Expression : public TwoExpression { \ + public: \ + node##Expression(Node* n,Node* n2) : TwoExpression(n,n2) {} ~node##Expression() {delete left; delete right;} \ + }; + LIST_OF_TWO_EXPRESSIONS + #undef NODE + + #define NODE(ttype,tname) class Const##tname##Expression : public Expression { \ + public: \ + ttype value; \ + Const##tname##Expression(ttype v) \ + { \ + this->value = v; \ + }\ + }; + LIST_OF_CONST_EXPRESSIONS + #undef NODE + + class ConstNullExpression : public Expression {}; + class ConstUndefinedExpression : public Expression {}; + + class GetVariableExpression : public Expression { + public: + std::string name; + GetVariableExpression(std::string name) + { + this->name = name; + } + }; + + class IfNode : public Node { + public: + Node* cond; + Node* yes; + Node* no; + IfNode(Node* cond,Node* yes,Node* no) + { + this->cond = cond; + this->yes = yes; + this->no = no; + } + ~IfNode() + { + delete cond; + delete yes; + delete no; + } + }; + class TernaryExpression : public Expression { + public: + Node* cond; + Node* yes; + Node* no; + TernaryExpression(Node* cond,Node* yes,Node* no) + { + this->cond = cond; + this->yes = yes; + this->no = no; + } + ~TernaryExpression() + { + delete cond; + delete yes; + delete no; + } + }; + + class WhileNode : public Node { + public: + Node* cond; + Node* body; + bool isDo; + WhileNode(Node* cond,Node* body, bool isDo) + { + this->cond = cond; + this->body = body; + this->isDo = isDo; + } + ~WhileNode() + { + delete cond; + delete body; + } + }; + + class ForNode : public Node { + public: + Node* init; + Node* cond; + Node* inc; + Node* body; + ForNode(Node* init,Node* cond,Node* inc,Node* body) + { + this->init = init; + this->cond = cond; + this->inc = inc; + this->body = body; + } + ~ForNode() + { + delete init; + delete cond; + delete inc; + delete body; + } + }; + + class PrintNode : public Node { + public: + Node* expr; + PrintNode(Node* expr) + { + this->expr = expr; + } + ~PrintNode() + { + delete expr; + } + }; + + class EachNode : public Node { + public: + Node* item; + Node* list; + Node* body; + EachNode(Node* item,Node* list,Node* body) + { + this->item = item; + this->list = list; + this->body = body; + } + ~EachNode() + { + delete item; + delete list; + delete body; + } + }; + + class FunctionDeclarationNode : public Node { + public: + Node* nameAndArgs; + Node* body; + FunctionDeclarationNode(Node* nameAndArgs,Node* body) + { + this->nameAndArgs = nameAndArgs; + this->body = body; + } + ~FunctionDeclarationNode() + { + delete nameAndArgs; + delete body; + } + }; + + class FunctionCallExpression : public Expression + { + public: + std::vector args; + Node* name; + FunctionCallExpression(Node* name) { + this->name = name; + } + ~FunctionCallExpression() + { + for(auto item : args) + { + delete item; + } + delete name; + } + }; + + class GetMemberExpression : public Expression + { + public: + std::string name; + Node* parent; + GetMemberExpression(Node* parent,std::string name) + { + this->parent = parent; + this->name = name; + } + ~GetMemberExpression() + { + delete parent; + } + }; + class GetArrayExpression : public Expression + { + public: + Node* expr; + Node* parent; + GetArrayExpression(Node* parent,Node* expr) + { + this->parent = parent; + this->expr = expr; + } + ~GetArrayExpression() + { + delete expr; + delete parent; + } + }; + + class ReturnNode : public Node { + public: + Node* retVal; + ReturnNode(Node* retVal) + { + this->retVal = retVal; + } + ~ReturnNode() + { + delete retVal; + } + }; + + class BreakNode : public Node {}; + class ContinueNode : public Node {}; + + class ScopeNode : public Node { + public: + std::vector items; + bool rootScope; + ~ScopeNode() + { + for(auto item : items) + delete item; + } + }; + + class ScriptParser + { + size_t i = 0; + std::vector tokens; + std::filesystem::path path; + + + + static std::string Template(std::filesystem::path file) + { + //convert anything out of to print ""; statements + + std::string myRealBuf = {}; + + bool inCode = false; + std::string buffer={}; + + FILE* fs = fopen(file.c_str(),"rb"); + if(fs == NULL) return ""; + + uint8_t sliding_buffer[7]; + + size_t len=0; + + auto advance = [&sliding_buffer,&len,&fs]()-> bool { + if(len > 0) + { + len--; + for(size_t i = 0;i 0; + }; + + auto flush = [&buffer,&myRealBuf,&inCode]() -> void { + if(buffer.size() == 0) return; + if(inCode) + { + myRealBuf.append(buffer); + } + else + { + myRealBuf.append("print \""); + for(auto item : buffer) + { + switch(item) + { + case '\0': + myRealBuf.append("\\0"); + break; + case '\n': + myRealBuf.append("\\n"); + break; + case '\r': + myRealBuf.append("\\r"); + break; + case '\f': + myRealBuf.append("\\f"); + break; + case '\t': + myRealBuf.append("\\t"); + break; + case '\v': + myRealBuf.append("\\v"); + break; + case '\b': + myRealBuf.append("\\b"); + break; + case '\a': + myRealBuf.append("\\a"); + break; + case '\x1B': + myRealBuf.append("\\e"); + break; + case '\"': + case '\'': + case '\\': + myRealBuf.push_back('\\'); + myRealBuf.push_back(item); + break; + default: + myRealBuf.push_back(item); + break; + } + } + + myRealBuf.append("\";"); + } + buffer = {}; + }; + + while(advance()) + { + if(memcmp(sliding_buffer,"",3) == 0) + { + flush(); + inCode=false; + for(int i = 0;i<3;i++) + if(advance() == false) break; + if(len == 0) break; + } + + buffer.push_back((char)sliding_buffer[0]); + } + flush(); + fclose(fs); + return myRealBuf; + } + + static void Lex(std::filesystem::path file,std::vector& tokens) + { + std::string text = Template(file); + + size_t offset = 0; + + int peeked = -1; + + auto peek = [&text,&offset,&peeked]() -> int { + if(peeked > -1) return peeked; + + if(offset < text.size()) + { + peeked = text[offset]; + offset++; + return peeked; + } + return -1; + }; + + auto read = [&text,&offset,&peeked]() -> int { + if(peeked != -1) + { + int myPeek = peeked; + peeked=-1; + return myPeek; + } + + if(offset < text.size()) + { + int c = text[offset]; + offset++; + return c; + } + return -1; + }; + int myRead=-1; + int myPeek=-1; + + std::string buf={}; + + auto flush = [&buf,&tokens]()-> void { + if(buf.size() > 0) + { + tokens.push_back(LexToken(buf)); + buf.clear(); + } + }; + + auto read_chr_ = [&read]()-> std::pair + { + int myC = read(); + if(myC == '\\') + { + myC = read(); + + if(myC == 'n') + { + return std::pair('\n',true); + } + else if(myC == 'r') + { + return std::pair('\r',true); + } + else if(myC == 'v') + { + return std::pair('\v',true); + } + else if(myC == 't') + { + return std::pair('\t',true); + } + else if(myC == 'b') + { + return std::pair('\b',true); + } + else if(myC == 'a') + { + return std::pair('\a',true); + } + else if(myC == 'e') + { + return std::pair('\x1B',true); + } + else if(myC == '0') + { + return std::pair('\0',true); + } + else if(myC == 'x') + { + int x1 = read(); + int x2 = read(); + + return std::pair(((HttpUtils::hex_char_to_nibble(x1) << 4) & 0xF) | (HttpUtils::hex_char_to_nibble(x2) & 0xF),true); + } + else { + return std::pair(myC,true); + } + } + return std::pair(myC,false); + }; + + auto read_string = [&read_chr_,&tokens]()-> void { + std::pair c; + std::string myStr = {}; + while((c = read_chr_()).first != -1) + { + if(c.first == '\"' && !c.second) break; + myStr.push_back((char)c.first); + } + + tokens.push_back(LexToken(myStr,true)); + }; + + auto read_char = [&read_chr_,&tokens,&read]()-> void { + auto v = read_chr_(); + if(v.first != -1) + { + tokens.push_back(LexToken(std::string({(char)v.first}),false)); + } + read(); + }; + + while((myRead = read()) != -1) + { + myPeek = peek(); + + switch(myRead) + { + case '/': + flush(); + if(myPeek == '/') + { + while(true) + { + myRead = read(); + if(myRead == -1) throw std::exception(); + if(myRead == '\n') break; + } + } + else if(myPeek == '*') + { + read(); + while(true) + { + myRead = read(); + if(myRead == -1) throw std::exception(); + if(myRead == '*') + { + myRead = read(); + if(myRead == '/') break; + } + } + } + else if(myPeek == '=') + { + read(); + tokens.push_back(LexToken(std::string({(char)myRead,(char)myPeek}))); + } + else + { + tokens.push_back(LexToken(std::string({(char)myRead}))); + } + break; + case '\"': + flush(); + read_string(); + break; + case '\'': + flush(); + read_char(); + break; + case '<': + case '>': + { + if(myPeek == myRead) + { + read(); + flush(); + int myPeek2 = peek(); + + if(myPeek2 == '=') + { + read(); + tokens.push_back(LexToken(std::string({(char)myRead,(char)myPeek,'='}))); + } + else{ + tokens.push_back(LexToken(std::string({(char)myRead,(char)myPeek}))); + } + } + else if(myPeek == '=') + { + read(); + flush(); + tokens.push_back(LexToken(std::string({(char)myRead,(char)myPeek}))); + } + else + { + flush(); + tokens.push_back(LexToken(std::string({(char)myRead}))); + } + } + + break; + case '+': + case '-': + case '|': + case '&': + { + if(myPeek == myRead) + { + read(); + flush(); + tokens.push_back(LexToken(std::string({(char)myRead,(char)myPeek}))); + } + else if(myPeek == '=') + { + read(); + flush(); + tokens.push_back(LexToken(std::string({(char)myRead,(char)myPeek}))); + } + else + { + flush(); + tokens.push_back(LexToken(std::string({(char)myRead}))); + } + } + + break; + case '^': + case '*': + case '%': + case '=': + case '!': + { + if(myPeek == '=') + { + read(); + flush(); + tokens.push_back(LexToken(std::string({(char)myRead,(char)myPeek}))); + } + else + { + flush(); + tokens.push_back(LexToken(std::string({(char)myRead}))); + } + } + break; + case '?': + case '.': + case ';': + case ':': + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case ',': + flush(); + tokens.push_back(LexToken(std::string({(char)myRead}))); + break; + case '\r': + case '\n': + case '\t': + case ' ': + flush(); + break; + default: + buf.push_back((char)myRead); + break; + + } + } + } + + bool NextTokenIs(std::string val, bool take=true) + { + //std::cout << val << " == " << tokens[i].text << std::endl; + if(i >= tokens.size()) return false; + if(!tokens[i].isChar && !tokens[i].isString && tokens[i].text == val) + { + if(take) i++; + + return true; + } + return false; + } + + ScriptParser(std::filesystem::path path) + { + Lex(path,tokens); + this->path = path; + } + + + + + void Ensure(std::string val) + { + + + if(i >= tokens.size()) throw std::exception(); + + + if(!tokens[i].isChar && !tokens[i].isString && tokens[i].text == val) + { + i++; + return; + } + + throw std::exception(); + } + + bool IsAnyOf(std::initializer_list tkns, std::string& txt) + { + if(this->i >= this->tokens.size()) return false; + for(auto item : tkns) + { + if(this->tokens[i].isString) continue; + if(this->tokens[i].isChar) continue; + if(this->tokens[i].text.compare(item) == 0) + { + this->i++; + txt = item; + return true; + } + } + return false; + } + Node* ParseValue() + { + if(i>=tokens.size()) throw std::exception(); + if(tokens[i].isString) + { + auto val=tokens[i].text; + i++; + return new ConstStringExpression(val); + } + if(tokens[i].isChar) + { + auto val = tokens[i].text; + i++; + return new ConstCharExpression(val[0]); + } + + std::string token = tokens[i].text; + + + i++; + + bool hasNumber=true; + int64_t lngNum = 0; + + if(token.size() == 1 && token[0] == '0') + { + lngNum = 0; + } + else + if(token.size() > 0 && token[0] == '0') + { + if(token.size() > 1 && token[1] == 'x') + { + lngNum = std::stoll(token.substr(2),nullptr,16); + } + else if(token.size() > 1 && token[1] == 'b') + { + lngNum = std::stoll(token.substr(2),nullptr,2); + } + else + { + lngNum = std::stoll(token.substr(1),nullptr,8); + } + + } + else if(token.size() > 0 && token[0] >= '0' && token[0] <= '9') + { + lngNum=std::stoll(token,nullptr,10); + } + else + { + hasNumber = false; + } + + Node* val = nullptr; + + + + if(hasNumber && this->NextTokenIs(".",false) && i+1 < tokens.size() && !tokens[i+1].isChar && !tokens[i+1].isString) + { + std::string myToken = tokens[i+1].text; + if(myToken.size() > 0 && myToken[0] >= '0' && myToken[0] <= '9') + { + i+=2; + std::string myN = std::to_string(lngNum) + "." + myToken; + + double v = std::stod(myN,nullptr); + + val = new ConstDoubleExpression(v); + } + else + { + val = new ConstLongExpression(lngNum); + } + } + else if(hasNumber) + { + val = new ConstLongExpression(lngNum); + } + else { + if(token == "(") + { + val = ParseExpression(); + Ensure(")"); + } + if(token == "true") + { + val = new ConstBoolExpression(true); + } + else if(token == "false") + { + val = new ConstBoolExpression(false); + } + else if(token == "null") + { + val = new ConstNullExpression(); + } + else if(token == "undefined") + { + val = new ConstUndefinedExpression(); + } + else if(token == "var") + { + if(i>=tokens.size()) throw std::exception(); + if(tokens[i].isString) throw std::exception(); + if(tokens[i].isChar) throw std::exception(); + val = new VarExpression(new GetVariableExpression(tokens[i].text)); + i++; + + } + else if(token == "global") + { + if(i>=tokens.size()) throw std::exception(); + if(tokens[i].isString) throw std::exception(); + if(tokens[i].isChar) throw std::exception(); + val = new GlobalExpression(new GetVariableExpression(tokens[i].text)); + i++; + } + else if(token == "caller") + { + if(i>=tokens.size()) throw std::exception(); + if(tokens[i].isString) throw std::exception(); + if(tokens[i].isChar) throw std::exception(); + val = new CallerExpression(new GetVariableExpression(tokens[i].text)); + i++; + } + else { + + val = new GetVariableExpression(token); + } + } + std::string myT; + while(IsAnyOf({".","[","("},myT)) + { + if(myT == ".") + { + if(i>=tokens.size()) throw std::exception(); + if(tokens[i].isChar || tokens[i].isString) throw std::exception(); + std::string name = tokens[i].text; + i++; + val = new GetMemberExpression(val, name); + } + if(myT == "[") + { + Node* expr=ParseExpression(); + Ensure("]"); + val = new GetArrayExpression(val,expr); + } + if(myT == "(") + { + auto fcall = new FunctionCallExpression(val); + while(!NextTokenIs(")",false)) + { + fcall->args.push_back(ParseExpression()); + if(!NextTokenIs(")",false)) + Ensure(","); + } + Ensure(")"); + val = fcall; + } + } + + return val; + } + Node* ParseUnary() + { + if(NextTokenIs("-")) + { + return new NegativeExpression(ParseUnary()); + } + if(NextTokenIs("~")) + { + return new BitwiseNotExpression(ParseUnary()); + } + if(NextTokenIs("!")) + { + return new LogicalNotExpression(ParseUnary()); + } + if(NextTokenIs("--")) + { + return new PrefixDecrementExpression(ParseUnary()); + } + if(NextTokenIs("++")) + { + return new PrefixIncrementExpression(ParseUnary()); + } + + + return ParseValue(); + } + Node* ParseFactor() + { + Node* v = ParseUnary(); + std::string tok; + while(IsAnyOf({"*","/","%"},tok)) + { + if(tok == "*") + v = new TimesExpression(v,ParseUnary()); + if(tok == "/") + v = new DivideExpression(v,ParseUnary()); + if(tok == "%") + v = new ModExpression(v,ParseUnary()); + } + return v; + } + Node* ParseSum() + { + Node* v = ParseFactor(); + std::string tok; + while(IsAnyOf({"+","-"},tok)) + { + if(tok == "+") + v = new AddExpression(v,ParseFactor()); + if(tok == "-") + v = new SubExpression(v,ParseFactor()); + } + return v; + } + Node* ParseShift() + { + Node* v = ParseSum(); + std::string tok; + while(IsAnyOf({"<<",">>"},tok)) + { + if(tok == "<<") + v = new LeftShiftExpression(v,ParseSum()); + if(tok == ">>") + v = new RightShiftExpression(v,ParseSum()); + } + return v; + } + Node* ParseRel() + { + Node* v = ParseShift(); + std::string tok; + while(IsAnyOf({"<",">","<=",">="},tok)) + { + if(tok == "<") + v = new LessThanExpression(v,ParseShift()); + if(tok == ">") + v = new GreaterThanExpression(v,ParseShift()); + if(tok == "<=") + v = new LessThanEqualToExpression(v,ParseShift()); + if(tok == ">=") + v = new GreaterThanEqualToExpression(v,ParseShift()); + } + return v; + } + Node* ParseEq() + { + Node* v = ParseRel(); + std::string tok; + while(IsAnyOf({"!=","=="},tok)) + { + if(tok == "!=") + v = new NotEqualsExpression(v,ParseRel()); + if(tok == "==") + v = new EqualsExpression(v,ParseRel()); + } + return v; + } + Node* ParseBAnd() + { + Node* v = ParseEq(); + while(NextTokenIs("&")) + { + v = new BitwiseAndExpression(v,ParseEq()); + } + return v; + } + Node* ParseXOr() + { + Node* v = ParseBAnd(); + while(NextTokenIs("^")) + { + v = new ExclusiveOrExpression(v,ParseBAnd()); + } + return v; + } + Node* ParseBOr() + { + Node* v = ParseXOr(); + while(NextTokenIs("|")) + { + v = new BitwiseOrExpression(v,ParseXOr()); + } + return v; + } + Node* ParseLAnd() + { + Node* v = ParseBOr(); + while(NextTokenIs("&&")) + { + v = new LogicalAndExpression(v,ParseBOr()); + } + return v; + } + + Node* ParseLOr() + { + Node* v = ParseLAnd(); + while(NextTokenIs("||")) + { + v = new LogicalOrExpression(v,ParseLAnd()); + } + return v; + } + + Node* ParseTernary() + { + Node* cond = ParseLOr(); + if(NextTokenIs("?")) + { + Node* yes = ParseTernary(); + Ensure(":"); + Node* no = ParseTernary(); + return new TernaryExpression(cond,yes,no); + } + return cond; + } + + Node* ParseExpression() + { + Node* v = ParseTernary(); + std::string t; + while(IsAnyOf({"=","+=","-=","*=","/=","%=","<<=",">>=","&=","^=","|="},t)) + { + if(t == "=") + { + v = new AssignExpression(v,ParseTernary()); + } + if (t == "+=") + { + v = new CompoundAssignExpression(new AddExpression(v,ParseTernary())); + } + if (t == "-=") + { + v = new CompoundAssignExpression(new SubExpression(v,ParseTernary())); + } + if (t == "*=") + { + v = new CompoundAssignExpression(new TimesExpression(v,ParseTernary())); + } + if (t == "/=") + { + v = new CompoundAssignExpression(new DivideExpression(v,ParseTernary())); + } + if (t == "%=") + { + v = new CompoundAssignExpression(new ModExpression(v,ParseTernary())); + } + if (t == "<<=") + { + v = new CompoundAssignExpression(new LeftShiftExpression(v,ParseTernary())); + } + if (t == ">>=") + { + v = new CompoundAssignExpression(new RightShiftExpression(v,ParseTernary())); + } + if (t == "&=") + { + v = new CompoundAssignExpression(new BitwiseAndExpression(v,ParseTernary())); + } + if (t == "^=") + { + v = new CompoundAssignExpression(new ExclusiveOrExpression(v,ParseTernary())); + } + if (t == "|=") + { + v = new CompoundAssignExpression(new BitwiseOrExpression(v,ParseTernary())); + } + } + return v; + } + + + Node* ParseNode(bool rootNode=false) + { + if(NextTokenIs("{") || rootNode) + { + + ScopeNode* sn = new ScopeNode(); + sn->rootScope = rootNode; + + while(this->i < this->tokens.size() && !NextTokenIs("}")) + { + sn->items.push_back(ParseNode()); + + NextTokenIs(";"); + } + return sn; + } + + if(NextTokenIs("include")) + { + + if(i < tokens.size()) + { + std::filesystem::path par = this->path.parent_path(); + + std::string file = tokens[i].text; + i++; + Ensure(";"); + + ScriptParser p(par / file); + + return p.ParseNode(true); + } + } + if(NextTokenIs("print")) + { + Node* n=new PrintNode(ParseExpression()); + Ensure(";"); + return n; + } + if(NextTokenIs("return")) + { + Node* n=new ReturnNode(ParseExpression()); + Ensure(";"); + return n; + } + if(NextTokenIs("break")) + { + Ensure(";"); + return new BreakNode(); + } + if(NextTokenIs("continue")) + { + Ensure(";"); + return new ContinueNode(); + } + if(NextTokenIs("if")) + { + Ensure("("); + Node* cond = ParseExpression(); + Ensure(")"); + + Node* yes = nullptr; + + if(!NextTokenIs("else",false)) + { + yes = ParseNode(); + NextTokenIs(";"); + } + + Node* no = nullptr; + + if(NextTokenIs("else")) + { + no = ParseNode(); + NextTokenIs(";"); + } + + return new IfNode(cond,yes,no); + } + if(NextTokenIs("for")) + { + Ensure("("); + + Node* init = nullptr; + Node* cond = nullptr; + Node* inc = nullptr; + + if(!NextTokenIs(";",false)) + { + init = ParseExpression(); + } + Ensure(";"); + if(!NextTokenIs(";",false)) + { + cond = ParseExpression(); + } + Ensure(";"); + if(!NextTokenIs(")",false)) + { + inc = ParseExpression(); + } + Ensure(")"); + + Node* body = ParseNode(); + NextTokenIs(";"); + + return new ForNode(init,cond,inc,body); + } + if(NextTokenIs("while")) + { + Ensure("("); + Node* cond = ParseExpression(); + Ensure(")"); + Node* body = ParseNode(); + NextTokenIs(";"); + return new WhileNode(cond,body,false); + } + if(NextTokenIs("do")) + { + Ensure("("); + Node* cond = ParseExpression(); + Ensure(")"); + Node* body = ParseNode(); + NextTokenIs(";"); + return new WhileNode(cond,body,true); + } + if(NextTokenIs("each")) + { + Ensure("("); + Node* list = ParseExpression(); + Node* item = nullptr; + + if(NextTokenIs(":")) + { + item = list; + list = ParseExpression(); + } + else + { + item = new GetVariableExpression("item"); + } + Ensure(")"); + Node* body = ParseNode(); + NextTokenIs(";"); + return new EachNode(item,list,body); + } + if(NextTokenIs("func")) + { + Node* fn = ParseExpression(); + Node* body = ParseNode(); + NextTokenIs(";"); + + return new FunctionDeclarationNode(fn,body); + } + Node* n= ParseExpression(); + Ensure(";"); + return n; + } + + + public: + static Node* Parse(std::filesystem::path path) + { + ScriptParser p(path); + return p.ParseNode(true); + } + + }; + + inline ScriptType TypeOf(Environment* env, std::vector args) + { + + if(args.size() > 0) + { + auto item = args[0]; + if(std::holds_alternative(item)) + { + return "char"; + } + if(std::holds_alternative(item)) + { + return "string"; + } + if(std::holds_alternative(item)) + { + return "long"; + } + if(std::holds_alternative(item)) + { + return "double"; + } + + if(std::holds_alternative(item)) + { + return "ittrkvp"; + } + if(std::holds_alternative(item)) + { + return "bool"; + } + if(std::holds_alternative(item)) + { + return "undefined"; + } + if(std::holds_alternative(item)) + { + return "null"; + } + if(std::holds_alternative(item)) + { + auto ot = std::get(item).data; + auto ls = dynamic_cast(ot); + auto dict = dynamic_cast(ot); + auto ifunc = dynamic_cast(ot); + auto efunc = dynamic_cast(ot); + auto ittr = dynamic_cast(ot); + if(ittr != nullptr) return "ittr"; + if(ls != nullptr) return "list"; + if(dict != nullptr) return "dictionary"; + if(ifunc != nullptr) return "internal_function"; + if(efunc != nullptr) return "external_function"; + } + } + return Null(); + + } + + class BytecodeFile { + public: + std::map functions; + InternalFunction* rootFunction; + + ~BytecodeFile() + { + delete rootFunction; + for(auto item : functions) + { + delete item.second; + } + } + }; + + #if defined(DEBUG) + #define INSTRUCTION_NAME(INAME) case Instruction:: INAME : printf("%s",#INAME); break; +#endif + + + class SimpleInstruction : public Instruction + { + public: + uint8_t instruction; + SimpleInstruction(uint8_t instruction) + { + this->instruction = instruction; + } + int Length() + { + return 1; + } + void Write(uint8_t* buffer) + { + buffer[0] = instruction; + } + #if defined(DEBUG) + void Print() + { + switch(instruction) + { + INSTRUCTION_NAME(ADD) + INSTRUCTION_NAME(SUB) + INSTRUCTION_NAME(TIMES) + INSTRUCTION_NAME(DIVIDE) + INSTRUCTION_NAME(MOD) + INSTRUCTION_NAME(LEFTSHIFT) + INSTRUCTION_NAME(RIGHTSHIFT) + INSTRUCTION_NAME(LESSTHAN) + INSTRUCTION_NAME(GREATERTHAN) + INSTRUCTION_NAME(GREATERTHANEQUALTO) + INSTRUCTION_NAME(LESSTHANEQUALTO) + INSTRUCTION_NAME(PRINT) + INSTRUCTION_NAME(SCOPE_BEGIN) + INSTRUCTION_NAME(SCOPE_END) + INSTRUCTION_NAME(POP) + INSTRUCTION_NAME(GETVARIABLE) + INSTRUCTION_NAME(SETVARIABLE) + INSTRUCTION_NAME(GETFIELD) + INSTRUCTION_NAME(SETFIELD) + INSTRUCTION_NAME(CALL_METHOD) + INSTRUCTION_NAME(CALL_FUNC) + INSTRUCTION_NAME(DESTROY_LOOP) + INSTRUCTION_NAME(ITTR) + INSTRUCTION_NAME(SET_LOOP) + INSTRUCTION_NAME(GET_LOOP) + default: + printf("UNKNOWN: %i\n",(int)instruction); + break; + } + printf("\n"); + } + #endif + }; + + class LabelInstruction : public Instruction + { + std::string label; + public: + LabelInstruction(std::string label) + { + this->label = label; + } + std::string GetLabel() + { + return label; + } + void SetLabel(std::string lbl) + { + label = lbl; + } + int Length() + { + return 0; + } + void Write(uint8_t* buffer) + { + + } + #if defined(DEBUG) + void Print() + { + printf("%s:\n",label.c_str()); + } + #endif + }; + + class LabelableInstruction : public Instruction + { + public: + virtual std::string GetLabel()=0; + virtual void SetLabel(std::string lbl)=0; + virtual int GetPosition()=0; + virtual void SetPosition(int pos)=0; + }; + + class JumpInstruction : public LabelableInstruction + { + std::string label; + int position; + uint8_t instr; + public: + JumpInstruction(uint8_t instr,std::string label) + { + this->instr = instr; + this->label = label; + this->position = 0; + } + std::string GetLabel() + { + return label; + } + void SetLabel(std::string lbl) + { + label = lbl; + } + int GetPosition() + { + return position; + } + void SetPosition(int pos) + { + this->position = pos; + } + int Length() {return 5;} + void Write(uint8_t* buffer) + { + buffer[0] = instr; + buffer[1] = (uint8_t)((position >> 24) & 0xFF); + buffer[2] = (uint8_t)((position >> 16) & 0xFF); + buffer[3] = (uint8_t)((position >> 8) & 0xFF); + buffer[4] = (uint8_t)(position & 0xFF); + } + + #if defined(DEBUG) + void Print() + { + switch(instr) + { + INSTRUCTION_NAME(JMP) + INSTRUCTION_NAME(JMPC) + } + printf(" %s [%i]\n", label.c_str(),this->position); + } + + #endif + }; + + class LongInstruction : public Instruction { + + public: + int64_t value; + LongInstruction(int64_t value) + { + this->value = value; + } + int Length() + { + return 9; + } + void Write(uint8_t* buffer) + { + buffer[0] = Instruction::PUSH_LONG; + buffer[1] = (uint8_t)((value >> 56) & 0xFF); + buffer[2] = (uint8_t)((value >> 48) & 0xFF); + buffer[3] = (uint8_t)((value >> 40) & 0xFF); + buffer[4] = (uint8_t)((value >> 32) & 0xFF); + buffer[5] = (uint8_t)((value >> 24) & 0xFF); + buffer[6] = (uint8_t)((value >> 16) & 0xFF); + buffer[7] = (uint8_t)((value >> 8) & 0xFF); + buffer[8] = (uint8_t)(value & 0xFF); + } + #if defined(DEBUG) + void Print() + { + std::cout << "PUSH_LONG " << value << std::endl; + } + #endif + }; + class CharInstruction : public Instruction { + public: + char value; + CharInstruction(char c) + { + this->value = c; + } + int Length() + { + return 2; + } + + void Write(uint8_t* buffer) + { + buffer[0] = Instruction::PUSH_CHAR; + buffer[1] = value; + } + #if defined(DEBUG) + void Print() + { + std::cout << "PUSH_CHAR \'" << value << "\'" << std::endl; + } + #endif + }; + class StringInstruction : public Instruction { + + public: + std::string value; + StringInstruction(std::string value) + { + this->value = value; + } + int Length() + { + return 5+value.size(); + } + void Write(uint8_t* buffer) + { + buffer[0] = Instruction::PUSH_STRING; + auto sz = this->value.size(); + buffer[1] = (uint8_t)((sz >> 24) & 0xFF); + buffer[2] = (uint8_t)((sz >> 16) & 0xFF); + buffer[3] = (uint8_t)((sz >> 8) & 0xFF); + buffer[4] = (uint8_t)(sz & 0xFF); + for(size_t i = 0;i __eachs; + + int jmpId = 0; + std::string NewJumpId() + { + std::string s = "__compGen" + std::to_string(jmpId); + jmpId++; + return s; + } + void ExpressionPop(Node* n,std::vector& instructions) + { + if(n == nullptr) return; + if(n->IsExpression()) + instructions.push_back(new SimpleInstruction(Instruction::POP)); + } + Node* n; + void GenerateFree(Node* _n,std::vector& instructions) + { + GetVariableExpression fnName("free"); + FunctionCallExpression fcE(&fnName); + fcE.args.push_back(_n); + Compile(&fcE,instructions); + instructions.push_back(new SimpleInstruction(Instruction::POP)); + fcE.args.clear(); + fcE.name=nullptr; + } + void Compile(Node* n,std::vector& instructions) + { + if(n==nullptr) return; + auto addExpr = dynamic_cast(n); + auto subExpr = dynamic_cast(n); + auto timesExpr = dynamic_cast(n); + auto divExpr = dynamic_cast(n); + auto modExpr = dynamic_cast(n); + auto lsExpr = dynamic_cast(n); + auto rsExpr = dynamic_cast(n); + auto ltExpr = dynamic_cast(n); + auto gtExpr = dynamic_cast(n); + auto lteExpr = dynamic_cast(n); + auto gteExpr = dynamic_cast(n); + auto funcDecl = dynamic_cast(n); + auto varDecl = dynamic_cast(n); + auto lnotExpr = dynamic_cast(n); + + auto scope = dynamic_cast(n); + + auto print = dynamic_cast(n); + auto lng = dynamic_cast(n); + auto str = dynamic_cast(n); + + auto assign = dynamic_cast(n); + auto compound = dynamic_cast(n); + + auto varGet = dynamic_cast(n); + auto memGet = dynamic_cast(n); + auto arrGet = dynamic_cast(n); + auto gblGet = dynamic_cast(n); + auto callerGet = dynamic_cast(n); + + auto fCall = dynamic_cast(n); + + auto ifNode = dynamic_cast(n); + auto ternary = dynamic_cast(n); + auto whileNode = dynamic_cast(n); + auto breakNode = dynamic_cast(n); + auto cont = dynamic_cast(n); + auto eachLoop = dynamic_cast(n); + auto forLoop = dynamic_cast(n); + auto lOr = dynamic_cast(n); + auto lAnd = dynamic_cast(n); + auto retNode = dynamic_cast(n); + auto boolExpr = dynamic_cast(n); + auto nullExpr = dynamic_cast(n); + auto undefinedExpr = dynamic_cast(n); + auto chrExpr = dynamic_cast(n); + auto equalsExpr = dynamic_cast(n); + auto notEqualsExpr = dynamic_cast(n); + if(equalsExpr != nullptr) + { + Compile(equalsExpr->left,instructions); + Compile(equalsExpr->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::EQUALS)); + } + if(notEqualsExpr != nullptr) + { + Compile(notEqualsExpr->left,instructions); + Compile(notEqualsExpr->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::NOTEQUALS)); + } + + if(chrExpr != nullptr) + { + instructions.push_back(new CharInstruction(chrExpr->value)); + } + if(boolExpr != nullptr) + { + instructions.push_back(new SimpleInstruction(boolExpr->value ? Instruction::PUSH_TRUE : Instruction::PUSH_FALSE)); + } + if(nullExpr != nullptr) + { + instructions.push_back(new SimpleInstruction(Instruction::PUSH_NULL)); + } + if(undefinedExpr != nullptr) + { + instructions.push_back(new SimpleInstruction(Instruction::PUSH_UNDEFINED)); + } + if(retNode != nullptr) + { + while(!this->__eachs.empty()) + { + auto item = this->__eachs.top(); + GetVariableExpression gve(item); + GenerateFree(&gve,instructions); + this->__eachs.pop(); + } + Compile(retNode->retVal,instructions); + instructions.push_back(new SimpleInstruction(Instruction::RET)); + } + if(lnotExpr != nullptr) + { + Compile(lnotExpr->node,instructions); + instructions.push_back(new SimpleInstruction(Instruction::LOGICALNOT)); + } + if(lOr != nullptr) + { + std::string end = this->NewJumpId(); + std::string pushTrue = this->NewJumpId(); + Compile(lOr->left,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMPC,pushTrue)); + Compile(lOr->right,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMP,end)); + instructions.push_back(new LabelInstruction(pushTrue)); + instructions.push_back(new SimpleInstruction(Instruction::PUSH_TRUE)); + instructions.push_back(new LabelInstruction(end)); + } + if(lAnd != nullptr) + { + std::string end = this->NewJumpId(); + std::string pushFalse = this->NewJumpId(); + std::string hndl = this->NewJumpId(); + Compile(lAnd->left,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMPC,hndl)); + instructions.push_back(new JumpInstruction(Instruction::JMP,pushFalse)); + instructions.push_back(new LabelInstruction(hndl)); + Compile(lAnd->right,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMP,end)); + instructions.push_back(new LabelInstruction(pushFalse)); + instructions.push_back(new SimpleInstruction(Instruction::PUSH_FALSE)); + instructions.push_back(new LabelInstruction(end)); + } + if(breakNode != nullptr) + { + if( _brk.size() > 0) + { + instructions.push_back(new SimpleInstruction(Instruction::GET_LOOP)); + instructions.push_back(new JumpInstruction(Instruction::JMP,_brk)); + } else { + throw std::exception(); + } + } + if(cont != nullptr) + { + if(_cont.size() > 0) + { + instructions.push_back(new SimpleInstruction(Instruction::GET_LOOP)); + instructions.push_back(new JumpInstruction(Instruction::JMP, _cont)); + } + else { + throw std::exception(); + } + } + if(forLoop != nullptr) + { + instructions.push_back(new SimpleInstruction(Instruction::SET_LOOP)); + Compile(forLoop->init,instructions); + ExpressionPop(forLoop->init,instructions); + std::string oldcont = _cont; + std::string oldbrk = _brk; + + std::string end = NewJumpId(); + std::string begin = NewJumpId(); + std::string yes = NewJumpId(); + + std::string cont = NewJumpId(); + + _cont = cont; + _brk = end; + + + instructions.push_back(new LabelInstruction(begin)); + Compile(forLoop->cond,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMPC,yes)); + instructions.push_back(new JumpInstruction(Instruction::JMP,end)); + instructions.push_back(new LabelInstruction(yes)); + Compile(forLoop->body,instructions); + ExpressionPop(forLoop->body,instructions); + instructions.push_back(new LabelInstruction(cont)); + Compile(forLoop->inc,instructions); + ExpressionPop(forLoop->inc,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMP,begin)); + instructions.push_back(new LabelInstruction(end)); //used for break + instructions.push_back(new SimpleInstruction(Instruction::DESTROY_LOOP)); + + _cont = oldcont; + _brk = oldbrk; + } + if(eachLoop != nullptr) + { + + instructions.push_back(new SimpleInstruction(Instruction::SET_LOOP)); + std::string eachIttr = NewJumpId(); + __eachs.push(eachIttr); + instructions.push_back(new StringInstruction(eachIttr)); + Compile(eachLoop->list,instructions); + instructions.push_back(new SimpleInstruction(Instruction::ITTR)); + instructions.push_back(new SimpleInstruction(Instruction::SETVARIABLE)); + instructions.push_back(new SimpleInstruction(Instruction::POP)); + std::string oldcont = _cont; + std::string oldbrk = _brk; + std::string yes = NewJumpId(); + std::string end = NewJumpId(); + std::string begin = NewJumpId(); + + _cont = begin; + _brk = end; + + instructions.push_back(new LabelInstruction(begin)); + GetVariableExpression var(eachIttr); + GetMemberExpression mem(&var,"movenext"); + FunctionCallExpression ce(&mem); + Compile(&ce,instructions); + ce.name = nullptr; + mem.parent=nullptr; + + instructions.push_back(new JumpInstruction(Instruction::JMPC,yes)); + instructions.push_back(new JumpInstruction(Instruction::JMP,end)); + instructions.push_back(new LabelInstruction(yes)); + GetMemberExpression mem2(&var,"current"); + FunctionCallExpression ce2(&mem2); + AssignExpression assignExpr(eachLoop->item,&ce2); + + + Compile(&assignExpr,instructions); + ExpressionPop(&assignExpr,instructions); + + mem2.parent=nullptr; + ce2.name=nullptr; + + assignExpr.left=nullptr; + assignExpr.right = nullptr; + Compile(eachLoop->body,instructions); + ExpressionPop(eachLoop->body,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMP,begin)); + instructions.push_back(new LabelInstruction(end)); + __eachs.pop(); + + GenerateFree(&var,instructions); + instructions.push_back(new SimpleInstruction(Instruction::DESTROY_LOOP)); + + _cont = oldcont; + _brk = oldbrk; + } + if(whileNode != nullptr) + { + if(whileNode->isDo) + { + instructions.push_back(new SimpleInstruction(Instruction::SET_LOOP)); + std::string oldcont = _cont; + std::string oldbrk = _brk; + + std::string end = NewJumpId(); + std::string begin = NewJumpId(); + + _cont = begin; + _brk = end; + instructions.push_back(new LabelInstruction(begin)); + Compile(whileNode->body,instructions); + ExpressionPop(whileNode->body,instructions); + + + Compile(whileNode->cond,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMPC,begin)); + instructions.push_back(new LabelInstruction(end)); //used for break + + instructions.push_back(new SimpleInstruction(Instruction::DESTROY_LOOP)); + + _cont = oldcont; + _brk = oldbrk; + } + else + { + instructions.push_back(new SimpleInstruction(Instruction::SET_LOOP)); + std::string oldcont = _cont; + std::string oldbrk = _brk; + std::string yes = NewJumpId(); + std::string end = NewJumpId(); + std::string begin = NewJumpId(); + + _cont = begin; + _brk = end; + + instructions.push_back(new LabelInstruction(begin)); + Compile(whileNode->cond,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMPC,yes)); + instructions.push_back(new JumpInstruction(Instruction::JMP,end)); + instructions.push_back(new LabelInstruction(yes)); + Compile(whileNode->body,instructions); + ExpressionPop(whileNode->body,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMP,begin)); + instructions.push_back(new LabelInstruction(end)); + + instructions.push_back(new SimpleInstruction(Instruction::DESTROY_LOOP)); + + _cont = oldcont; + _brk = oldbrk; + } + } + + if(ifNode != nullptr) + { + std::string yes = NewJumpId(); + std::string end = NewJumpId(); + Compile(ifNode->cond,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMPC,yes)); + Compile(ifNode->no,instructions); + ExpressionPop(ifNode->no,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMP,end)); + instructions.push_back(new LabelInstruction(yes)); + Compile(ifNode->yes,instructions); + ExpressionPop(ifNode->yes,instructions); + instructions.push_back(new LabelInstruction(end)); + } + if(ternary != nullptr) + { + std::string yes = NewJumpId(); + std::string end = NewJumpId(); + + Compile(ternary->cond,instructions); + instructions.push_back(new JumpInstruction(Instruction::JMPC,yes)); + Compile(ternary->no,instructions); + + instructions.push_back(new JumpInstruction(Instruction::JMP,end)); + instructions.push_back(new LabelInstruction(yes)); + Compile(ternary->yes,instructions); + + instructions.push_back(new LabelInstruction(end)); + } + + if(compound != nullptr) + { + auto twoNode = dynamic_cast(compound->node); + if(twoNode != nullptr) + { + AssignExpression aE(twoNode->left,twoNode); + Compile(&aE,instructions); + aE.left = nullptr; + aE.right = nullptr; + } + } + + if(addExpr != nullptr) + { + Compile(addExpr->left,instructions); + Compile(addExpr->right,instructions); + + instructions.push_back(new SimpleInstruction(Instruction::ADD)); + } + + if(subExpr != nullptr) + { + Compile(subExpr->left,instructions); + Compile(subExpr->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::SUB)); + } + if(timesExpr != nullptr) + { + Compile(timesExpr->left,instructions); + Compile(timesExpr->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::TIMES)); + } + if(divExpr != nullptr) + { + Compile(divExpr->left,instructions); + Compile(divExpr->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::DIVIDE)); + } + if(modExpr != nullptr) + { + Compile(modExpr->left,instructions); + Compile(modExpr->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::MOD)); + } + if(lsExpr != nullptr) + { + Compile(lsExpr->left,instructions); + Compile(lsExpr->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::LEFTSHIFT)); + } + if(rsExpr != nullptr) + { + Compile(rsExpr->left,instructions); + Compile(rsExpr->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::RIGHTSHIFT)); + } + if(ltExpr != nullptr) + { + Compile(ltExpr->left,instructions); + Compile(ltExpr->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::LESSTHAN)); + } + if(gtExpr != nullptr) + { + Compile(gtExpr->left,instructions); + Compile(gtExpr->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::GREATERTHAN)); + } + if(lteExpr != nullptr) + { + Compile(lteExpr->left,instructions); + Compile(lteExpr->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::LESSTHANEQUALTO)); + } + if(gteExpr != nullptr) + { + Compile(gteExpr->left,instructions); + Compile(gteExpr->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::GREATERTHANEQUALTO)); + } + if(funcDecl != nullptr) + { + auto fcall = dynamic_cast(funcDecl->nameAndArgs); + if(fcall != nullptr) + { + auto fname = dynamic_cast(fcall->name); + + if(fname != nullptr) + { + + + auto fn = new InternalFunction(); + this->file->functions[fname->name] = fn; + + + + for(auto arg : fcall->args) + { + auto argTXT = dynamic_cast(arg); + if(argTXT != nullptr) + { + fn->args.push_back(argTXT->name); + } + + } + + Compile(funcDecl->body,fn); + } + + } + + } + if(scope != nullptr) + { + if(!scope->rootScope) + instructions.push_back(new SimpleInstruction(Instruction::SCOPE_BEGIN)); + + for(auto no : scope->items) + { + Compile(no,instructions); + ExpressionPop(no,instructions); + } + + if(!scope->rootScope) + instructions.push_back(new SimpleInstruction(Instruction::SCOPE_END)); + + } + if(lng != nullptr) + { + + instructions.push_back(new LongInstruction(lng->value)); + } + if(str != nullptr) + { + + instructions.push_back(new StringInstruction(str->value)); + } + if(print != nullptr) + { + Compile(print->expr,instructions); + instructions.push_back(new SimpleInstruction(Instruction::PRINT)); + } + if(varDecl != nullptr) + { + auto gvn = dynamic_cast(varDecl->node); + if(gvn != nullptr) + { + instructions.push_back(new StringInstruction(gvn->name)); + instructions.push_back(new SimpleInstruction(Instruction::PUSH_NULL)); + instructions.push_back(new SimpleInstruction(Instruction::DECLARE_VARIABLE)); + } + + + } + + if(assign != nullptr) + { + GetVariableExpression* gVar = dynamic_cast(assign->left); + GetMemberExpression* gMem = dynamic_cast(assign->left); + GetArrayExpression* gArray = dynamic_cast(assign->left); + VarExpression* vDecl = dynamic_cast(assign->left); + GlobalExpression* gGbl = dynamic_cast(assign->left); + CallerExpression* gCaller = dynamic_cast(assign->left); + if(gVar != nullptr) + { + instructions.push_back(new StringInstruction(gVar->name)); + Compile(assign->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::SETVARIABLE)); + } + if(gMem != nullptr) + { + + Compile(gMem->parent,instructions); + instructions.push_back(new StringInstruction(gMem->name)); + Compile(assign->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::SETFIELD)); + } + + if(gArray != nullptr) + { + + Compile(gArray->parent,instructions); + Compile(gArray->expr,instructions); + Compile(assign->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::SETARRAY)); + } + + if(gGbl != nullptr) + { + gVar = dynamic_cast(gGbl->node); + if(gVar != nullptr) + { + instructions.push_back(new StringInstruction(gVar->name)); + Compile(assign->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::SET_GLOBAL_VARIABLE)); + } + } + + if(gCaller != nullptr) + { + gVar = dynamic_cast(gCaller->node); + if(gVar != nullptr) + { + instructions.push_back(new StringInstruction(gVar->name)); + Compile(assign->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::SET_CALLER_VARIABLE)); + } + } + if(vDecl != nullptr) + { + gVar = dynamic_cast(vDecl->node); + if(gVar != nullptr) + { + instructions.push_back(new StringInstruction(gVar->name)); + Compile(assign->right,instructions); + instructions.push_back(new SimpleInstruction(Instruction::DECLARE_VARIABLE)); + } + } + } + + if(varGet != nullptr) + { + instructions.push_back(new StringInstruction(varGet->name)); + instructions.push_back(new SimpleInstruction(Instruction::GETVARIABLE)); + } + + if(gblGet != nullptr) + { + varGet = dynamic_cast(gblGet->node); + if(varGet != nullptr) + { + instructions.push_back(new StringInstruction(varGet->name)); + instructions.push_back(new SimpleInstruction(Instruction::GET_GLOBAL_VARIABLE)); + } + } + if(callerGet != nullptr) + { + varGet = dynamic_cast(callerGet->node); + if(varGet != nullptr) + { + instructions.push_back(new StringInstruction(varGet->name)); + instructions.push_back(new SimpleInstruction(Instruction::GET_CALLER_VARIABLE)); + } + } + + if(memGet != nullptr) + { + Compile(memGet->parent,instructions); + instructions.push_back(new StringInstruction(memGet->name)); + instructions.push_back(new SimpleInstruction(Instruction::GETFIELD)); + } + + if(arrGet != nullptr) + { + Compile(arrGet->parent,instructions); + Compile(arrGet->expr,instructions); + instructions.push_back(new SimpleInstruction(Instruction::GETARRAY)); + } + if(fCall != nullptr) + { + auto field = dynamic_cast(fCall->name); + if(field != nullptr) + { + Compile(field->parent,instructions); + instructions.push_back(new StringInstruction(field->name)); + for(auto item : fCall->args) + Compile(item,instructions); + instructions.push_back(new LongInstruction(fCall->args.size())); + instructions.push_back(new SimpleInstruction(Instruction::CALL_METHOD)); + } + else + { + Compile(fCall->name,instructions); + for(auto item : fCall->args) + Compile(item,instructions); + + + instructions.push_back(new LongInstruction(fCall->args.size())); + instructions.push_back(new SimpleInstruction(Instruction::CALL_FUNC)); + } + } + } + void Compile(Node* n, InternalFunction* func) + { + std::vector instructions; + Compile(n,instructions); + int length=0; + std::map lbls; + for(auto item : instructions) + { + auto lbl = dynamic_cast(item); + if(lbl != nullptr) + lbls[lbl->GetLabel()] = length; + length += item->Length(); + } + + func->bytecodeLength = length; + func->bytecode = new uint8_t[length]; + + uint8_t* buffer = func->bytecode; + #if defined(DEBUG) + printf("INSTRUCTIONS:\n\n"); + #endif + size_t len2=0; + for(auto item : instructions) + { + auto lblable = dynamic_cast(item); + if(lblable != nullptr) + { + lblable->SetPosition(lbls[lblable->GetLabel()]); + } + item->Write(buffer); + buffer += item->Length(); + + #if defined(DEBUG) + printf("OFFSET %i\n",(int)len2); + item->Print(); + #endif + len2+=item->Length(); + + delete item; + } + + #if defined(DEBUG) + printf("\n\nEND OF INSTRUCTIONS\n\n"); + #endif + instructions.clear(); + } + public: + BytecodeFile* file; + BytecodeCompiler(Node* root) + { + this->n = root; + file=new BytecodeFile(); + file->rootFunction = new InternalFunction(); + file->rootFunction->isRoot=true; + + + } + + + + void Compile() + { + Compile(n,file->rootFunction); + } + + + }; + + + + + +} \ No newline at end of file diff --git a/tesseswebserver.cpp b/tesseswebserver.cpp new file mode 100644 index 0000000..f769125 --- /dev/null +++ b/tesseswebserver.cpp @@ -0,0 +1,41 @@ +#include "tesseswebserver.hpp" +TESSESWEBSERVER_STATIC_DECLARATION +using namespace Tesses::WebServer; +using namespace Tesses::WebServer::ScriptEngine; + +class DummyServer : public IServer +{ + public: + bool Handle(ServerContext* ctx) + { + std::string resp = {}; + + for(auto param : ctx->queryParams.GetAll()) + { + resp.append(param.first); + resp.append(": "); + resp.append(param.second); + resp.append("\r\n"); + } + + ctx->SetContentType("text/plain")->SendText(resp); + return true; + } +}; + +int main(int argc,char** argv) +{ + + + + + + HttpServerListener::Init(); + + IServer* myServer = new DummyServer(); + + HttpServerListener::Listen(myServer,3000); + + + +} \ No newline at end of file diff --git a/tesseswebserver.hpp b/tesseswebserver.hpp new file mode 100644 index 0000000..ced9a86 --- /dev/null +++ b/tesseswebserver.hpp @@ -0,0 +1,1142 @@ +#pragma once +//#define GEKKO +#include "tesseswebserverfeatures.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if defined(USE_JANSSON) +#include +#endif + +#if defined(USE_CURL) +#include +#include +#endif + +#if defined(USE_SQLITE3) +#include +#endif + +#if defined(USE_MBEDTLS) +#include +#endif + +#if defined(DEBUG) + + #define DEBUGOUT(...) printf(__VA_ARGS__) +#else + #define DEBUGOUT(...) +#endif + +#if defined(GEKKO) +#include +#include + +#if defined(HW_RVL) && defined(USE_WIISOCKETS) + #include + #include +#else + #include + #define socket net_socket + #define bind net_bind + #define listen net_listen + #define recv net_recv + #define send net_send + #define close net_close +#endif + +#else +#include +#include +#include +#include +#endif + +namespace Tesses::WebServer { + +#if defined(GEKKO) +typedef void* THREAD_RETURN_TYPE; + +#define THREAD_DEFAULT_RETURN_TYPE (NULL) + +typedef THREAD_RETURN_TYPE (*callback)(void* arg); +#else +typedef int THREAD_RETURN_TYPE; + +#define THREAD_DEFAULT_RETURN_TYPE 0 + +typedef THREAD_RETURN_TYPE (*callback)(void* arg); + + +#endif + +class Statics { + public: + #if defined(GEKKO) + std::vector joined_threads; + mutex_t mtx; + #else + mtx_t mtx; + #endif + std::atomic isRunning; +}; +extern Tesses::WebServer::Statics tesses_webserver_statics; +class Thread { + #if defined(GEKKO) + lwp_t thrd; + std::atomic hasExited; + callback cb; + void* arg; + + #else + thrd_t thrd; + + + #endif + public: + + static void Init() + { + #if defined(GEKKO) + LWP_MutexInit(&tesses_webserver_statics.mtx,true); + #else + mtx_init(&tesses_webserver_statics.mtx,mtx_recursive); + #endif + } + + Thread(callback cb,void* arg,uint32_t stackSize) + { + #if defined(GEKKO) + this->hasExited=false; + this->cb = cb; + this->arg = arg; + LWP_CreateThread(&this->thrd,HANDLER,arg,NULL,stackSize,80); + #else + thrd_create(&thrd,cb,arg); + #endif + } + #if defined(GEKKO) + static THREAD_RETURN_TYPE HANDLER(void* arg) + { + Thread* thrd = (Thread*)arg; + THREAD_RETURN_TYPE t = thrd->cb(arg); + thrd->hasExited=true; + return t; + } + #endif + + int Join(THREAD_RETURN_TYPE* retType) + { + #if defined(GEKKO) + return LWP_JoinThread(this->thrd,retType); + #else + return thrd_join(this->thrd,retType); + #endif + } + + void Detach() + { + #if defined(GEKKO) + Lock(); + tesses_webserver_statics.joined_thrads.push_back(this); + Unlock(); + #else + thrd_detach(this->thrd); + delete this; + #endif + } + + static void Lock() + { + #if defined(GEKKO) + LWP_MutexLock(tesses_webserver_statics.mtx); + #else + mtx_lock(&tesses_webserver_statics.mtx); + #endif + } + static void Unlock() + { + #if defined(GEKKO) + LWP_MutexUnlock(tesses_webserver_statics.mtx); + #else + mtx_unlock(&tesses_webserver_statics.mtx); + #endif + } + + + + static void CleanThreads() + { + #if defined(GEKKO) + Lock(); + for(auto i = tesses_webserver_statics.joined_threads.begin();ihasExited) + { + THREAD_RETURN_TYPE arg; + item->Join(&arg); + delete item; + tesses_webserver_statics.joined_threads.erase(i); + i--; + } + } + Unlock(); + #endif + } +}; + +class Stream { + public: + virtual ssize_t Read(uint8_t* buffer,size_t len)=0; + virtual ssize_t Write(uint8_t* buffer,size_t len)=0; + + virtual void Seek(uint64_t offset,int whence) + { + + } + + virtual int64_t Position() + { + return 0; + } + + virtual bool CanSeek() + { + return false; + } + + void WriteBlock(uint8_t* buffer,size_t len) + { + size_t read; + do{ + read = 1024; + if(len < 1024) + read = len; + if(read > 0) + read=this->Write(buffer,read); + + + + buffer += read; + len -= read; + } while(read > 0); + } + + virtual int64_t Length() + { + return -1; + } + virtual ~Stream() + { + + } + + int ReadByte() + { + uint8_t byte; + if(Read(&byte,1) == 0) return -1; + + return byte; + } + + std::string ReadLine() + { + std::string str = {}; + int c = ReadByte(); + while(c != '\n' && c != -1) + { + if(c != '\r') + { + str.push_back((char)c); + } + c = ReadByte(); + } + + DEBUGOUT("ReadLine: %s\n",str.c_str()); + + return str; + } +}; + + +class FileStream : public Stream +{ + private: + FILE* f; + bool canSeek; + bool owns; + public: + + FileStream(std::string filename, std::string mode) + { + this->f = fopen(filename.c_str(),mode.c_str()); + this->canSeek=true; + this->owns=true; + } + + FileStream(FILE* f,bool canSeek,bool owns) + { + this->f = f; + this->canSeek = canSeek; + this->owns = owns; + } + + ssize_t Read(uint8_t* buffer,size_t len) + { + return (ssize_t)fread(buffer,1,len,this->f); + + } + + ssize_t Write(uint8_t* buffer, size_t len) + { + return (ssize_t)fwrite(buffer,1,len,this->f); + } + int64_t Position() + { + #if(_FILE_OFFSET_BITS == 64) + #if defined(WIN32) + return (int64_t)_ftelli64(this->f); + #else + return (int64_t)ftello(this->f); + #endif + #else + return (int64_t)ftell(this->f); + #endif + } + + void Seek(uint64_t offset,int whence) + { + #if(_FILE_OFFSET_BITS == 64) + #if defined(WIN32) + _ftelli64(this->f,(__int64)offset,whence); + #else + fseeko(this->f,(off_t)offset,whence); + #endif + #else + fseek(this->f,(long)offset,whence); + #endif + } +}; + +class SocketStream : public Stream { + int sock; + public: + SocketStream(int sock) + { + this->sock = sock; + } + ssize_t Read(uint8_t* buffer,size_t len) + { + ssize_t r= recv(this->sock,buffer,len,0); + return r; + } + ssize_t Write(uint8_t* buffer,size_t len) + { + return send(this->sock,buffer,len,0); + } + ~SocketStream() + { + close(sock); + } +}; +typedef enum StatusCode { + Continue=100, + SwitchingProtocols=101, + Processing=102, + EarlyHints=103, + OK=200, + Created=201, + Accepted=202, + NonAuthoritativeInformation=203, + NoContent=204, + ResetContent=205, + PartialContent=206, + MultiStatus=207, + AlreadyReported=208, + IMUsed=226, + MultipleChoices=300, + MovedPermanently=301, + Found=302, + SeeOther=303, + NotModified=304, + UseProxy=305, + TemporaryRedirect=307, + PermanentRedirect=308, + BadRequest=400, + Unauthorized=401, + PaymentRequired=402, + Forbidden=403, + NotFound=404, + MethodNotAllowed=405, + NotAcceptable=406, + ProxyAuthenticationRequired=407, + RequestTimeout=408, + Conflict=409, + Gone=410, + LengthRequired=411, + PreconditionFailed=412, + PayloadTooLarge=413, + URITooLong=414, + UnsupportedMediaType=415, + RangeNotSatisfiable=416, + ExpectationFailed=417, + ImATeapot=418, + MisdirectedRequest=421, + UnprocessableContent=422, + Locked=423, + FailedDependency=424, + TooEarly=425, + UpgradeRequired=426, + PreconditionRequired=428, + TooManyRequests=429, + RequestHeaderFieldsTooLarge=431, + UnavailableForLegalReasons=451, + InternalServerError=500, + NotImplemented=501, + BadGateway=502, + ServiceUnavailable=503, + GatewayTimeout=504, + HTTPVersionNotSupported=505, + VariantAlsoNegotiates=506, + InsufficientStorage=507, + LoopDetected=508, + NotExtended=510, + NetworkAuthenticationRequired=511 +} StatusCode; + + +class HttpUtils { + + + public: + static char nibble_to_hex_char(uint8_t number) + { + if(number >= 0 && number <= 9) + { + return '0'+number; + } + if(number >= 0xA && number <= 0xF) + { + return (char)(55+number); + } + return '0'; + } + static uint8_t hex_char_to_nibble(char c) + { + if(c >= '0' && c <= '9') + return c - '0'; + + if(c >= 'A' && c <= 'F') + return (c-'A')+0xA; + + if(c >= 'a' && c <= 'f') + return (c-'a')+0xA; + return 0; + } + static std::vector> QueryParamsDecode(std::string query) + { + std::vector> strs; + for(auto item : SplitString(query,"&")) + { + std::vector ss=SplitString(item,"=",2); + if(ss.size() >= 1) + { + std::string value = {}; + if(ss.size() == 2) + { + value = UrlDecode(ss[1]); + } + strs.push_back(std::pair(ss[0],value)); + } + } + return strs; + } + + static std::string QueryParamsEncode(std::vector> query) + { + std::string s={}; + bool first = true; + for(auto item : query) + { + if(!first) + { + s.push_back('&'); + } + s.insert(s.size(),item.first); + s.push_back('='); + s.insert(s.size(),UrlEncode(item.second)); + first=false; + } + return s; + } + + static std::string UrlDecode(std::string v) + { + std::string s = {}; + + for(size_t i = 0;i= 'A' && item <= 'Z') + s.push_back(item); + else if(item >= 'a' && item <= 'z') + s.push_back(item); + else if(item >= '0' && item <= '9') + s.push_back(item); + else if(item == '-' || item == '_' || item == '.' || item == '~') + s.push_back(item); + else + { + s.push_back('%'); + s.push_back(nibble_to_hex_char((item >> 4) & 0xF)); + s.push_back(nibble_to_hex_char((item) & 0xF)); + } + } + return s; + } + static std::string UrlPathDecode(std::string v) + { + std::string s = {}; + + for(size_t i = 0;i= 'A' && item <= 'Z') + s.push_back(item); + else if(item >= 'a' && item <= 'z') + s.push_back(item); + else if(item >= '0' && item <= '9') + s.push_back(item); + else if(item == '-' || item == '_' || item == '.' || item == '~') + s.push_back(item); + else + { + s.push_back('%'); + s.push_back(nibble_to_hex_char((item >> 4) & 0xF)); + s.push_back(nibble_to_hex_char((item) & 0xF)); + } + } + return s; + } + + static std::vector SplitString(std::string text, std::string delimiter,std::size_t maxCnt = std::string::npos) + { + std::vector strs; + std::size_t i = 1; + while(text.length() > 0) + { + if(i == maxCnt) + { + strs.push_back(text); + break; + } + std::size_t index= text.find_first_of(delimiter); + + + + if(index == std::string::npos) + { + strs.push_back(text); + break; + } + else + { + std::string left = text.substr(0,index); + + text = text.substr(index+delimiter.size()); + + strs.push_back(left); + } + i++; + } + return strs; + } + static std::string HtmlEncode(std::string html) + { + std::string myHtml = {}; + for(auto item : html) + { + if(item == '\"') + { + myHtml.append("""); + } + else if(item == '\'') + { + myHtml.append("'"); + } + else if(item == '&') + { + myHtml.append("&"); + } + else if(item == '<') + { + myHtml.append("<"); + } + else if(item == '>') + { + myHtml.append(">"); + } + else + { + myHtml.push_back(item); + } + } + return myHtml; + } + static std::string StatusCodeString(StatusCode code) + { + switch(code) + { + case StatusCode::Continue: + return "Continue"; + case StatusCode::SwitchingProtocols: + return "Switching Protocols"; + case StatusCode::Processing: + return "Processing"; + case StatusCode::EarlyHints: + return "Early Hints"; + case StatusCode::OK: + return "OK"; + case StatusCode::Created: + return "Created"; + case StatusCode::Accepted: + return "Accepted"; + case StatusCode::NonAuthoritativeInformation: + return "Non-Authoritative Information"; + case StatusCode::NoContent: + return "No Content"; + case StatusCode::ResetContent: + return "Reset Content"; + case StatusCode::PartialContent: + return "PartialContent"; + case StatusCode::MultiStatus: + return "Multi-Status"; + case StatusCode::AlreadyReported: + return "Already Reported"; + case StatusCode::IMUsed: + return "IM Used"; + case StatusCode::MultipleChoices: + return "Multiple Choices"; + case StatusCode::MovedPermanently: + return "Moved Permanently"; + case StatusCode::Found: + return "Found"; + case StatusCode::SeeOther: + return "See Other"; + case StatusCode::NotModified: + return "Not Modified"; + case StatusCode::UseProxy: + return "Use Proxy"; + case StatusCode::TemporaryRedirect: + return "Temporary Redirect"; + case StatusCode::PermanentRedirect: + return "Permanent Redirect"; + case StatusCode::BadRequest: + return "Bad Request"; + case StatusCode::Unauthorized: + return "Unauthorized"; + case StatusCode::PaymentRequired: + return "Payment Required"; + case StatusCode::Forbidden: + return "Forbidden"; + case StatusCode::NotFound: + return "Not Found"; + case StatusCode::MethodNotAllowed: + return "Method Not Allowed"; + case StatusCode::NotAcceptable: + return "Not Acceptable"; + case StatusCode::ProxyAuthenticationRequired: + return "Proxy Authentication Required"; + case StatusCode::RequestTimeout: + return "Request Timeout"; + case StatusCode::Conflict: + return "Conflict"; + case StatusCode::Gone: + return "Gone"; + case StatusCode::LengthRequired: + return "Length Required"; + case StatusCode::PreconditionFailed: + return "Precondition Failed"; + case StatusCode::PayloadTooLarge: + return "Payload Too Large"; + case StatusCode::URITooLong: + return "URI Too Long"; + case StatusCode::UnsupportedMediaType: + return "Unsupported Media Type"; + case StatusCode::RangeNotSatisfiable: + return "Range Not Satisfiable"; + case StatusCode::ExpectationFailed: + return "Expectation Failed"; + case StatusCode::ImATeapot: + return "I'm a teapot"; + case StatusCode::MisdirectedRequest: + return "Misdirected Request"; + case StatusCode::UnprocessableContent: + return "Unprocessable Content"; + case StatusCode::Locked: + return "Locked"; + case StatusCode::FailedDependency: + return "Failed Dependency"; + case StatusCode::TooEarly: + return "Too Early"; + case StatusCode::UpgradeRequired: + return "Upgrade Required"; + case StatusCode::PreconditionRequired: + return "Precondition Required"; + case StatusCode::TooManyRequests: + return "Too Many Requests"; + case StatusCode::RequestHeaderFieldsTooLarge: + return "Request Header Fields Too Large"; + case StatusCode::UnavailableForLegalReasons: + return "Unavailable For Legal Reasons"; + case StatusCode::InternalServerError: + return "Internal Server Error"; + case StatusCode::NotImplemented: + return "Not Implemented"; + case StatusCode::ServiceUnavailable: + return "Service Unavailable"; + case StatusCode::GatewayTimeout: + return "Gateway Timeout"; + case StatusCode::HTTPVersionNotSupported: + return "HTTP Version Not Supported"; + case StatusCode::VariantAlsoNegotiates: + return "Variant Also Negotiates"; + case StatusCode::InsufficientStorage: + return "Insufficient Storage"; + case StatusCode::LoopDetected: + return "Loop Detected"; + case StatusCode::NotExtended: + return "Not Extended"; + case StatusCode::NetworkAuthenticationRequired: + return "Network Authentication Required"; + default: + return ""; + } + } +}; + +class QueryParams { + private: + std::vector> items; + public: + void Add(std::string key, std::string value) + { + Add(std::pair(key,value)); + } + void Add(std::pair pair) + { + items.push_back(pair); + } + void Add(std::vector>& items) + { + for(auto item : items) + this->items.push_back(item); + } + std::vector>& GetAll() + { + return this->items; + } + void Get(std::vector& v, std::string key) + { + for(auto item : this->items) + if(item.first == key) + v.push_back(item.second); + } + void Set(std::string key,std::string value) + { + Clear(key); + Add(key,value); + } + + + void Set(std::pair item) + { + Set(item.first,item.second); + } + + void Set(std::string key, std::vector& value) + { + Clear(key); + for(auto item : value) + Add(key,item); + } + + bool TryGetFirst(std::string key,std::string& val) + { + for(auto item : this->items) + if(item.first == key) + { + val = item.second; + return true; + } + return false; + } + void Clear(std::string key) + { + + for(auto item = items.begin();itemstrm = strm; + std::string firstLine = strm->ReadLine(); + DEBUGOUT("READ Request line\n"); + std::vector firstLineA=HttpUtils::SplitString(firstLine," ",4); + DEBUGOUT("Split Request line\n"); + + if(firstLineA.size() == 4 || firstLineA.size() < 3) + { + DEBUGOUT("Request line does not have 3 entries\n"); + this->ok=false; + } + else + { + this->ok=false; + method = firstLineA[0]; + std::vector p = HttpUtils::SplitString(firstLineA[1],"?",2); + if(p.size() >= 1) + { + this->ok = true; + this->originalPath = p[0]; + DEBUGOUT("Path %s\n",this->originalPath.c_str()); + this->path = originalPath; + if(p.size() == 2) + { + auto qp=HttpUtils::QueryParamsDecode(p[1]); + this->queryParams.Add(qp); + } + } + version = firstLineA[2]; + responseVersion=version; + std::string line; + while((line=strm->ReadLine()).size() > 0) + { + std::vector header=HttpUtils::SplitString(line,": ",2); + if(header.size() == 2) + { + this->requestHeaders.Add(std::pair(header[0],header[1])); + } + } + + } + + + + } + bool CanHandleRequest() + { + return this->ok; + } + + std::string method; + std::string originalPath; + std::string path; + std::string version; + + std::string responseVersion; + + bool ConnectionOpen() + { + std::string keep_alive; + if(requestHeaders.TryGetFirst("Connection",keep_alive)) + { + return keep_alive.compare("keep-alive") == 0; + } + return false; + } + + QueryParams queryParams; + QueryParams requestHeaders; + QueryParams responseHeaders; + + StatusCode statusCode=StatusCode::OK; + + void SendHeaders() + { + std::string headers = responseVersion + " " + std::to_string((int)statusCode) + " " + HttpUtils::StatusCodeString(statusCode) + "\r\n"; + + for(auto header : responseHeaders.GetAll()) + { + headers += header.first + ": " + header.second + "\r\n"; + } + headers += "\r\n"; + this->strm->WriteBlock((uint8_t*)headers.c_str(),headers.size()); + + } + + void SendErrorPage(bool showPath) + { + std::string errorHtml = showPath ? ("File " + HttpUtils::HtmlEncode(this->originalPath) + " " + HttpUtils::StatusCodeString(this->statusCode) + "

" + std::to_string((int)this->statusCode) + " " + HttpUtils::StatusCodeString(this->statusCode) + "

" + HttpUtils::HtmlEncode(this->originalPath) + "

") : ""; + + SetContentType("text/html")->SendText(errorHtml); + } + + ServerContext* SetContentType(std::string contentType) + { + return this->SetHeader("Content-Type",contentType); + } + + ServerContext* SetHeader(std::string key,std::string value) + { + this->responseHeaders.Set(key,value); + return this; + } + + void SendBytes(uint8_t* buffer,size_t len) + { + this->SetHeader("Content-Length",std::to_string(len))->SendHeaders(); + this->strm->WriteBlock(buffer,len); + } + + void SendText(std::string text) + { + SendBytes((uint8_t*)text.c_str(),text.size()); + } + + void SendNotFound() + { + statusCode = StatusCode::NotFound; + SendErrorPage(true); + } + void SendBadRequest() + { + statusCode = StatusCode::BadRequest; + SendErrorPage(false); + } + + ~ServerContext() + { + if(!ConnectionOpen()) + delete strm; + } +}; + +class IServer { + public: + virtual bool Handle(ServerContext* ctx)=0; +}; + + +#if defined(USE_SCRIPT_ENGINE) + #define INCLUDED_FROM_TESSESWEBSERVER_H + #include "tessesscriptengine.hpp" + #undef INCLUDED_FROM_TESSESWEBSERVER_H +#endif + +class HttpServerListener { + + + static THREAD_RETURN_TYPE HandleRequestOnThread(void* arg) + { + DEBUGOUT("Started thread\n"); + void** args = (void**)arg; + IServer* svr= static_cast(args[0]); + Stream* strm = static_cast(args[1]); + + delete args; + + HandleRequest(svr,strm); + + return THREAD_DEFAULT_RETURN_TYPE; + } + + public: + + static void Init() + { + tesses_webserver_statics.isRunning=true; + Thread::Init(); + } + + + + static void HandleRequest(IServer* server,Stream* strm) + { + start: + ServerContext* ctx = new ServerContext(strm); + + if(!ctx->CanHandleRequest()) + { + ctx->SendBadRequest(); + delete ctx; + return; + } + + if(!server->Handle(ctx)) + ctx->SendNotFound(); + + + if(ctx->ConnectionOpen()) + { + delete ctx; + goto start; + } + + delete ctx; + + + } + + + + static void ListenWithBoundSocket(IServer* server,int boundAndListeningSocket) + { + printf("\033[31mAlmost ready to listen\033[0m\n"); + while(tesses_webserver_statics.isRunning) + { + struct sockaddr addr; + socklen_t addrlen; + int a = accept(boundAndListeningSocket, &addr, &addrlen); + + void** myArg = new void*[2]; + + myArg[0] = static_cast(server); + myArg[1] = static_cast(new SocketStream(a)); + + + Thread* thread = new Thread(HandleRequestOnThread,myArg,512000); + thread->Detach(); + + /*ServerContext* ctx = ReadHeaders(a); + + if(!server->Handle(ctx)) + ctx->SendNotFound(); + + delete ctx; + + + close(a); + */ + } + } + static void Listen(IServer* server, unsigned int domain,const struct sockaddr* addr, socklen_t addrlen) + { + int s=socket(domain,SOCK_STREAM,0); + if(s == -1) + { + printf("Socket error\n"); + + throw std::exception(); + } + if(bind(s,addr,addrlen) == -1) + { + printf("Bind error\n"); + throw std::exception(); + } + + if(listen(s,10) == -1) + { + printf("Listen error\n"); + throw std::exception(); + } + ListenWithBoundSocket(server,s); + } + + static void Listen(IServer* server, int port) + { + struct sockaddr_in addr; + memset(&addr,0,sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons((uint16_t)port); + addr.sin_addr.s_addr = 0; + + Listen(server,AF_INET,(struct sockaddr*)&addr,(socklen_t)sizeof(addr)); + } + + static void DoJobs() + { + #if defined(GEKKO) + Thread::CleanThreads(); + #endif + } + + static void Stop() + { + + } +}; + +#define TESSESWEBSERVER_STATIC_DECLARATION Tesses::WebServer::Statics Tesses::WebServer::tesses_webserver_statics; + + + +} \ No newline at end of file diff --git a/tesseswebserverfeatures.hpp b/tesseswebserverfeatures.hpp new file mode 100644 index 0000000..58ea23f --- /dev/null +++ b/tesseswebserverfeatures.hpp @@ -0,0 +1,7 @@ +#pragma once + +#define USE_SCRIPT_ENGINE +#define USE_MBEDTLS +#define USE_CURL +#define USE_SQLITE3 +#define USE_JANSSON \ No newline at end of file diff --git a/wwwroot/cgi-bin/add-todo.twss b/wwwroot/cgi-bin/add-todo.twss new file mode 100644 index 0000000..05a9e99 --- /dev/null +++ b/wwwroot/cgi-bin/add-todo.twss @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/wwwroot/deinit.twss b/wwwroot/deinit.twss new file mode 100644 index 0000000..a60b3e1 --- /dev/null +++ b/wwwroot/deinit.twss @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/wwwroot/index.twss b/wwwroot/index.twss new file mode 100644 index 0000000..b320bcc --- /dev/null +++ b/wwwroot/index.twss @@ -0,0 +1,26 @@ + + + + + + ToDo List + + +

ToDo List

+ +
+ + +
+ +
    + +
  • + +
+ + \ No newline at end of file diff --git a/wwwroot/init.twss b/wwwroot/init.twss new file mode 100644 index 0000000..3e43948 --- /dev/null +++ b/wwwroot/init.twss @@ -0,0 +1,3 @@ + \ No newline at end of file