Found a hilarious bug where numbers greater than 255 were truncated due to bitwise and with FF on all the shift ops
This commit is contained in:
parent
5b32dd7036
commit
93c6f9eda1
12
file.twss
12
file.twss
|
@ -1,11 +1,11 @@
|
|||
<!--tws
|
||||
d = list();
|
||||
d.add(5);
|
||||
d.add(6);
|
||||
d.add("Demi Lovato");
|
||||
for(i = 0;i<d.count;i++)
|
||||
l = list();
|
||||
l.add(52);
|
||||
l.add(52);
|
||||
l.add(69);
|
||||
each(l)
|
||||
{
|
||||
print d.at(i);
|
||||
print item;
|
||||
print "\n";
|
||||
}
|
||||
-->
|
|
@ -120,12 +120,24 @@ namespace Tesses::WebServer::ScriptEngine
|
|||
};
|
||||
|
||||
|
||||
|
||||
typedef std::variant<std::string,ObjectType> IttrType;
|
||||
|
||||
|
||||
|
||||
|
||||
class IttrKVP {
|
||||
public:
|
||||
IttrType ittr;
|
||||
int64_t index;
|
||||
};
|
||||
|
||||
|
||||
typedef std::variant<Undefined,Null,ObjectType,std::string,int64_t,double,bool,char> ScriptType;
|
||||
|
||||
typedef std::variant<Undefined,Null,ObjectType,IttrKVP,std::string,int64_t,double,bool,char> 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<bool>(st))
|
||||
{
|
||||
std::cout << (std::get<bool>(st) ? "true" : "false") << std::endl;
|
||||
return std::get<bool>(st);
|
||||
}
|
||||
if(std::holds_alternative<char>(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<IttrKVP>(st))
|
||||
{
|
||||
auto v = IttrGetValue(st);
|
||||
|
||||
return IttrGetKey(st) + ": " + ConvertToString(v);
|
||||
}
|
||||
|
||||
if(std::holds_alternative<Null>(st))
|
||||
{
|
||||
|
@ -460,6 +476,173 @@ namespace Tesses::WebServer::ScriptEngine
|
|||
}
|
||||
};
|
||||
|
||||
inline ScriptType CreateIttrFor(ScriptType& st)
|
||||
{
|
||||
if(std::holds_alternative<std::string>(st))
|
||||
{
|
||||
Ittr* ittr =new Ittr();
|
||||
ittr->index = -1;
|
||||
ittr->ittr = std::get<std::string>(st);
|
||||
ObjectType t(ittr);
|
||||
return t;
|
||||
}
|
||||
if(std::holds_alternative<ObjectType>(st))
|
||||
{
|
||||
auto ot = std::get<ObjectType>(st).data;
|
||||
auto ls = dynamic_cast<List*>(ot);
|
||||
auto dict = dynamic_cast<Dictionary*>(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<ObjectType>(st))
|
||||
{
|
||||
auto objIttr = std::get<ObjectType>(st).data;
|
||||
auto ittr = dynamic_cast<Ittr*>(objIttr);
|
||||
if(ittr == nullptr) return false;
|
||||
if(std::holds_alternative<std::string>(ittr->ittr))
|
||||
{
|
||||
std::string str = std::get<std::string>(ittr->ittr);
|
||||
if(ittr->index >= -1 && ittr->index + 1 < str.size())
|
||||
{
|
||||
(ittr->index)++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(std::holds_alternative<ObjectType>(ittr->ittr))
|
||||
{
|
||||
auto ot = std::get<ObjectType>(ittr->ittr).data;
|
||||
auto ls = dynamic_cast<List*>(ot);
|
||||
auto dict = dynamic_cast<Dictionary*>(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<ObjectType>(st))
|
||||
{
|
||||
auto objIttr = std::get<ObjectType>(st).data;
|
||||
auto ittr = dynamic_cast<Ittr*>(objIttr);
|
||||
if(ittr == nullptr) return Null();
|
||||
if(std::holds_alternative<std::string>(ittr->ittr))
|
||||
{
|
||||
std::string str = std::get<std::string>(ittr->ittr);
|
||||
if(ittr->index >= 0 && ittr->index < str.size())
|
||||
{
|
||||
return str[ittr->index];
|
||||
}
|
||||
}
|
||||
if(std::holds_alternative<ObjectType>(ittr->ittr))
|
||||
{
|
||||
auto ot = std::get<ObjectType>(ittr->ittr).data;
|
||||
auto ls = dynamic_cast<List*>(ot);
|
||||
auto dict = dynamic_cast<Dictionary*>(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<IttrKVP>(st))
|
||||
{
|
||||
auto ittr = std::get<IttrKVP>(st);
|
||||
|
||||
if(std::holds_alternative<ObjectType>(ittr.ittr))
|
||||
{
|
||||
auto ot = std::get<ObjectType>(ittr.ittr).data;
|
||||
auto dict = dynamic_cast<Dictionary*>(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<IttrKVP>(st))
|
||||
{
|
||||
auto ittr = std::get<IttrKVP>(st);
|
||||
|
||||
if(std::holds_alternative<ObjectType>(ittr.ittr))
|
||||
{
|
||||
auto ot = std::get<ObjectType>(ittr.ittr).data;
|
||||
auto dict = dynamic_cast<Dictionary*>(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<ScriptType> 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<ObjectType>(member).data;
|
||||
auto ls = dynamic_cast<List*>(obj);
|
||||
auto dict = dynamic_cast<Dictionary*>(obj);
|
||||
|
||||
auto ittr = dynamic_cast<Ittr*>(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<IttrKVP>(instance))
|
||||
{
|
||||
if(name == "key")
|
||||
{
|
||||
return IttrGetKey(instance);
|
||||
}
|
||||
|
||||
if(name == "value")
|
||||
{
|
||||
return IttrGetValue(instance);
|
||||
}
|
||||
}
|
||||
if(std::holds_alternative<ObjectType>(instance))
|
||||
{
|
||||
auto inst = std::get<ObjectType>(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<IttrKVP>(item))
|
||||
{
|
||||
return "ittrkvp";
|
||||
}
|
||||
if(std::holds_alternative<bool>(item))
|
||||
{
|
||||
return "bool";
|
||||
|
@ -3003,7 +3254,8 @@ namespace Tesses::WebServer::ScriptEngine
|
|||
auto dict = dynamic_cast<Dictionary*>(ot);
|
||||
auto ifunc = dynamic_cast<InternalFunction*>(ot);
|
||||
auto efunc = dynamic_cast<ExternalFunction*>(ot);
|
||||
|
||||
auto ittr = dynamic_cast<Ittr*>(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<std::string> __eachs;
|
||||
|
||||
int jmpId = 0;
|
||||
std::string NewJumpId()
|
||||
{
|
||||
|
@ -3341,6 +3594,7 @@ namespace Tesses::WebServer::ScriptEngine
|
|||
auto whileNode = dynamic_cast<WhileNode*>(n);
|
||||
auto breakNode = dynamic_cast<BreakNode*>(n);
|
||||
auto cont = dynamic_cast<ContinueNode*>(n);
|
||||
auto eachLoop = dynamic_cast<EachNode*>(n);
|
||||
auto forLoop = dynamic_cast<ForNode*>(n);
|
||||
auto lOr = dynamic_cast<LogicalOrExpression*>(n);
|
||||
auto lAnd = dynamic_cast<LogicalAndExpression*>(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)
|
||||
|
|
Loading…
Reference in New Issue