From 93c6f9eda1d4958db307276f303f7f620dc6c7a3 Mon Sep 17 00:00:00 2001 From: Mike Nolan Date: Sun, 1 Sep 2024 22:43:10 -0500 Subject: [PATCH] Found a hilarious bug where numbers greater than 255 were truncated due to bitwise and with FF on all the shift ops --- file.twss | 12 +- tessesscriptengine.hpp | 400 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 364 insertions(+), 48 deletions(-) diff --git a/file.twss b/file.twss index 139946b..248a524 100644 --- a/file.twss +++ b/file.twss @@ -1,11 +1,11 @@ \ No newline at end of file diff --git a/tessesscriptengine.hpp b/tessesscriptengine.hpp index b0dae90..f800069 100644 --- a/tessesscriptengine.hpp +++ b/tessesscriptengine.hpp @@ -120,12 +120,24 @@ namespace Tesses::WebServer::ScriptEngine }; - + typedef std::variant IttrType; + + + class IttrKVP { + public: + IttrType ittr; + int64_t index; + }; + - typedef std::variant ScriptType; - + typedef std::variant ScriptType; + class Ittr : public Object { + public: + IttrType ittr; + int64_t index; + }; inline bool Equals(ScriptType& left, ScriptType& right) @@ -191,7 +203,6 @@ namespace Tesses::WebServer::ScriptEngine } if(std::holds_alternative(st)) { - std::cout << (std::get(st) ? "true" : "false") << std::endl; return std::get(st); } if(std::holds_alternative(st)) @@ -209,7 +220,12 @@ namespace Tesses::WebServer::ScriptEngine 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)) { @@ -460,6 +476,173 @@ namespace Tesses::WebServer::ScriptEngine } }; + 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; + if(std::holds_alternative(ittr->ittr)) + { + std::string str = std::get(ittr->ittr); + if(ittr->index >= -1 && ittr->index + 1 < str.size()) + { + (ittr->index)++; + 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 >= -1 && ittr->index + 1 < ls->items.size()) + { + (ittr->index)++; + return true; + } + } + if(dict != nullptr) + { + if(ittr->index >= -1 && ittr->index + 1 < dict->items.size()) + { + (ittr->index)++; + 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 { @@ -615,7 +798,7 @@ namespace Tesses::WebServer::ScriptEngine auto v = TypeOf(env,args); this->env->print("IP: "); this->env->print((int64_t)ip); - this->env->print(" Unexpected type: "); + this->env->print("Unexpected type: "); this->env->print(v); this->env->print(" with value "); this->env->print(p); @@ -896,7 +1079,19 @@ namespace Tesses::WebServer::ScriptEngine 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) @@ -1135,7 +1330,18 @@ namespace Tesses::WebServer::ScriptEngine return (int64_t)str.size(); } } - + if(std::holds_alternative(instance)) + { + if(name == "key") + { + return IttrGetKey(instance); + } + + if(name == "value") + { + return IttrGetValue(instance); + } + } if(std::holds_alternative(instance)) { auto inst = std::get(instance).data; @@ -1352,14 +1558,14 @@ namespace Tesses::WebServer::ScriptEngine if(ip + 8 <= bytecodeLength) { - uint64_t value = ((uint64_t)bytecode[ip++] << 56) & 0xFF; - value |= ((uint64_t)bytecode[ip++] << 48) & 0xFF; - value |= ((uint64_t)bytecode[ip++] << 40) & 0xFF; - value |= ((uint64_t)bytecode[ip++] << 32) & 0xFF; - value |= ((uint64_t)bytecode[ip++] << 24) & 0xFF; - value |= ((uint64_t)bytecode[ip++] << 16) & 0xFF; - value |= ((uint64_t)bytecode[ip++] << 8) & 0xFF; - value |= (uint64_t)bytecode[ip++] & 0xFF; + uint64_t value = ((uint64_t)bytecode[ip++] << 56); + value |= ((uint64_t)bytecode[ip++] << 48); + value |= ((uint64_t)bytecode[ip++] << 40); + value |= ((uint64_t)bytecode[ip++] << 32); + value |= ((uint64_t)bytecode[ip++] << 24); + value |= ((uint64_t)bytecode[ip++] << 16); + value |= ((uint64_t)bytecode[ip++] << 8); + value |= (uint64_t)bytecode[ip++]; stack.push((int64_t)value); } @@ -1369,14 +1575,14 @@ namespace Tesses::WebServer::ScriptEngine { if(ip + 8 <= bytecodeLength) { - uint64_t value = ((uint64_t)bytecode[ip++] << 56) & 0xFF; - value |= ((uint64_t)bytecode[ip++] << 48) & 0xFF; - value |= ((uint64_t)bytecode[ip++] << 40) & 0xFF; - value |= ((uint64_t)bytecode[ip++] << 32) & 0xFF; - value |= ((uint64_t)bytecode[ip++] << 24) & 0xFF; - value |= ((uint64_t)bytecode[ip++] << 16) & 0xFF; - value |= ((uint64_t)bytecode[ip++] << 8) & 0xFF; - value |= (uint64_t)bytecode[ip++] & 0xFF; + uint64_t value = ((uint64_t)bytecode[ip++] << 56); + value |= ((uint64_t)bytecode[ip++] << 48); + value |= ((uint64_t)bytecode[ip++] << 40); + value |= ((uint64_t)bytecode[ip++] << 32); + value |= ((uint64_t)bytecode[ip++] << 24); + value |= ((uint64_t)bytecode[ip++] << 16); + value |= ((uint64_t)bytecode[ip++] << 8); + value |= (uint64_t)bytecode[ip++]; stack.push(*(double*)&value); @@ -1390,10 +1596,10 @@ namespace Tesses::WebServer::ScriptEngine { - size_t len = (bytecode[ip++] << 24) & 0xFF; - len |= (bytecode[ip++] << 16) & 0xFF; - len |= (bytecode[ip++] << 8) & 0xFF; - len |= bytecode[ip++] & 0xFF; + size_t len = ((size_t)bytecode[ip++] << 24); + len |= ((size_t)bytecode[ip++] << 16); + len |= ((size_t)bytecode[ip++] << 8); + len |= (size_t)bytecode[ip++];; if(ip + len <= bytecodeLength) { @@ -1549,10 +1755,10 @@ namespace Tesses::WebServer::ScriptEngine { - size_t len = (bytecode[ip++] << 24) & 0xFF; - len |= (bytecode[ip++] << 16) & 0xFF; - len |= (bytecode[ip++] << 8) & 0xFF; - len |= bytecode[ip++] & 0xFF; + size_t len = ((size_t)bytecode[ip++] << 24); + len |= ((size_t)bytecode[ip++] << 16); + len |= ((size_t)bytecode[ip++] << 8); + len |= (size_t)bytecode[ip++]; if(len < bytecodeLength) ip = len; else @@ -1569,10 +1775,10 @@ namespace Tesses::WebServer::ScriptEngine { - size_t len = (bytecode[ip++] << 24) & 0xFF; - len |= (bytecode[ip++] << 16) & 0xFF; - len |= (bytecode[ip++] << 8) & 0xFF; - len |= bytecode[ip++] & 0xFF; + size_t len = ((size_t)bytecode[ip++] << 24); + len |= ((size_t)bytecode[ip++] << 16); + len |= ((size_t)bytecode[ip++] << 8); + len |= (size_t)bytecode[ip++]; if(len < bytecodeLength) { auto v = Pop(); @@ -1588,7 +1794,12 @@ namespace Tesses::WebServer::ScriptEngine } } break; - + case Instruction::ITTR: + { + auto ittr=Pop(); + stack.push(CreateIttrFor(ittr)); + } + break; case Instruction::GETFIELD: { std::string name = PopString(); @@ -1886,7 +2097,24 @@ namespace Tesses::WebServer::ScriptEngine } }; - + 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: @@ -2937,7 +3165,26 @@ namespace Tesses::WebServer::ScriptEngine 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(); @@ -2984,6 +3231,10 @@ namespace Tesses::WebServer::ScriptEngine return "double"; } + if(std::holds_alternative(item)) + { + return "ittrkvp"; + } if(std::holds_alternative(item)) { return "bool"; @@ -3003,7 +3254,8 @@ namespace Tesses::WebServer::ScriptEngine 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"; @@ -3276,7 +3528,8 @@ namespace Tesses::WebServer::ScriptEngine std::string _cont = {}; - + std::stack __eachs; + int jmpId = 0; std::string NewJumpId() { @@ -3341,6 +3594,7 @@ namespace Tesses::WebServer::ScriptEngine 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); @@ -3382,6 +3636,13 @@ namespace Tesses::WebServer::ScriptEngine } 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)); } @@ -3473,7 +3734,62 @@ namespace Tesses::WebServer::ScriptEngine _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)