commit 1c9707b5b8e401b6dd110e3caee7a0d7d0898ab7 Author: Mike Nolan Date: Sun Sep 1 22:19:22 2024 -0500 removing each 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