Files
crosslang/src/assembler/asm.cpp
2026-01-30 19:34:45 -06:00

1324 lines
48 KiB
C++

#include "CrossLang.hpp"
using namespace Tesses::Framework::Serialization::Json;
namespace Tesses::CrossLang {
class ChunkInstruction {
public:
virtual ~ChunkInstruction() {}
virtual size_t Size()=0;
};
class SimpleChunkInstruction : public ChunkInstruction
{
public:
SimpleChunkInstruction(Instruction instr) : instruction(instr)
{
}
Instruction instruction;
size_t Size()
{
return 1;
}
};
class PushLongChunkInstruction : public ChunkInstruction {
public:
PushLongChunkInstruction(int64_t v) : value(v)
{}
int64_t value;
size_t Size()
{
return 9;
}
};
class PushDoubleChunkInstruction : public ChunkInstruction {
public:
PushDoubleChunkInstruction(double v) : value(v)
{}
double value;
size_t Size()
{
return 9;
}
};
class PushStringChunkInstruction : public ChunkInstruction {
public:
PushStringChunkInstruction(std::string v) : value(v)
{}
std::string value;
size_t Size()
{
return 5;
}
};
class PushCharChunkInstruction : public ChunkInstruction {
public:
PushCharChunkInstruction(char v) : value(v)
{}
char value;
size_t Size()
{
return 2;
}
};
class PushResourceChunkInstruction : public ChunkInstruction {
public:
PushResourceChunkInstruction(std::string v) : value(v)
{}
std::string value;
size_t Size()
{
return 5;
}
};
class PushResourceStreamChunkInstruction : public ChunkInstruction {
public:
PushResourceStreamChunkInstruction(std::string v) : value(v)
{}
std::string value;
size_t Size()
{
return 5;
}
};
class LabelChunkInstruction : public ChunkInstruction {
public:
LabelChunkInstruction(std::string lbl) : lbl(lbl)
{}
std::string lbl;
size_t Size()
{
return 0;
}
};
class JumpStyleChunkInstruction : public ChunkInstruction {
public:
JumpStyleChunkInstruction(Instruction instr,std::string lbl) : instr(instr), lbl(lbl)
{
}
Instruction instr;
std::string lbl;
size_t Size()
{
return 5;
}
};
class ScopeEndTimesChunkInstruction : public ChunkInstruction {
public:
ScopeEndTimesChunkInstruction(uint32_t times) : times(times)
{}
uint32_t times;
size_t Size()
{
return 5;
}
};
class ChunkData {
public:
std::vector<std::string> args;
std::vector<std::shared_ptr<ChunkInstruction>> instructions;
};
class ClosureChunkInstruction : public ChunkInstruction {
public:
ClosureChunkInstruction(bool scoped) : scoped(scoped)
{
}
ChunkData data;
bool scoped;
size_t Size()
{
return 5;
}
};
class FunctionData {
public:
std::vector<std::string> name;
ChunkData chunk;
};
class ClassDataEntry {
public:
ChunkData data;
std::string documentation;
std::string name;
TClassModifier modifier;
bool isFunction;
bool isAbstract;
};
class ClassData {
public:
std::string documentation;
std::vector<std::string> name;
std::vector<std::string> inherits;
std::vector<ClassDataEntry> entries;
};
class AssemblerParser {
std::vector<LexToken>& tokens;
size_t i=0;
std::string ReadIdent()
{
if(i >= tokens.size()) throw std::out_of_range("End of file");
if(tokens[i].type != LexTokenType::Identifier) throw std::runtime_error("Expected an identifier");
return tokens[i++].text;
}
bool IsIdent(std::string val,bool pop=true)
{
if(i >= tokens.size()) return false;
if(tokens[i].type != LexTokenType::Identifier) return false;
if(tokens[i].text != val) return false;
if(pop) i++;
return true;
}
bool IsSym(std::string val,bool pop=true)
{
if(i >= tokens.size()) return false;
if(tokens[i].type != LexTokenType::Symbol) return false;
if(tokens[i].text != val) return false;
if(pop) i++;
return true;
}
void ParseClosureInstructions(std::vector<std::shared_ptr<ChunkInstruction>>& instrs, std::string lbl_prefix)
{
while(!IsSym("}",false))
{
auto name = ReadIdent();
if(name == "add")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(ADD));
}
else if(name == "sub")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(SUB));
}
else if(name == "mul")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(TIMES));
}
else if(name == "div")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(DIVIDE));
}
else if(name == "mod")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(MODULO));
}
else if(name == "lsh")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(LEFTSHIFT));
}
else if(name == "rsh")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(RIGHTSHIFT));
}
else if(name == "bor")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(BITWISEOR));
}
else if(name == "band")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(BITWISEAND));
}
else if(name == "bnot")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(BITWISENOT));
}
else if(name == "lt")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(LESSTHAN));
}
else if(name == "gt")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(GREATERTHAN));
}
else if(name == "lte")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(LESSTHANEQ));
}
else if(name == "gte")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(GREATERTHANEQ));
}
else if(name == "eq")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(EQ));
}
else if(name == "neq")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(NEQ));
}
else if(name == "not")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(NOT));
}
else if(name == "neg")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(NEGATIVE));
}
else if(name == "xor")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(XOR));
}
else if(name == "pop")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(POP));
}
else if(name == "dup")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(DUP));
}
else if(name == "nop")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(NOP));
}
else if(name == "lineinfo")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(LINEINFO));
}
else if(name == "embeddir")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(PUSHRESOUURCEDIR));
}
else if(name == "pushclosure")
{
auto closure = std::make_shared<ClosureChunkInstruction>(true);
EnsureSymbol("(");
while(!IsSym(")",false) && i < tokens.size())
{
closure->data.args.push_back(ReadIdent());
IsSym(",");
}
EnsureSymbol(")");
EnsureSymbol("{");
ParseClosureInstructions(closure->data.instructions,"closure");
EnsureSymbol("}");
instrs.push_back(closure);
//instrs.push_back(std::make_shared<JumpStyleInstruction>(JMPC,lblName));
}
else if(name == "createdict")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(CREATEDICTIONARY));
}
else if(name == "createarray")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(CREATEARRAY));
}
else if(name == "appendlist")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(APPENDLIST));
}
else if(name == "appenddict")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(APPENDDICT));
}
else if(name == "embed")
{
if(i < tokens.size() && tokens[i].type == LexTokenType::String)
{
std::string str = tokens[i++].text;
instrs.push_back(std::make_shared<PushResourceChunkInstruction>(str));
}
}
else if(name == "embedstrm")
{
if(i < tokens.size() && tokens[i].type == LexTokenType::String)
{
std::string str = tokens[i++].text;
instrs.push_back(std::make_shared<PushResourceStreamChunkInstruction>(str));
}
}
else if(name == "push")
{
if(IsSym("."))
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(PUSHRELATIVEPATH));
}
else if(IsSym("/"))
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(PUSHROOTPATH));
}
else if(IsSym("}",false))
{
throw std::runtime_error("Push needs an argument");
}
else if(i < tokens.size() && tokens[i].type == LexTokenType::Identifier)
{
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;
}
if(hasNumber && this->IsSym(".",false) && i+1 < tokens.size() && tokens[i+1].type == LexTokenType::Identifier)
{
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);
instrs.push_back(std::make_shared<PushDoubleChunkInstruction>(v));
}
else
{
instrs.push_back(std::make_shared<PushLongChunkInstruction>(lngNum));
}
}
else if(hasNumber)
{
instrs.push_back(std::make_shared<PushLongChunkInstruction>(lngNum));
}
if(!hasNumber)
{
if(token == "true")
instrs.push_back(std::make_shared<SimpleChunkInstruction>(PUSHTRUE));
if(token == "false")
instrs.push_back(std::make_shared<SimpleChunkInstruction>(PUSHFALSE));
if(token == "null")
instrs.push_back(std::make_shared<SimpleChunkInstruction>(PUSHNULL));
if(token == "undefined")
instrs.push_back(std::make_shared<SimpleChunkInstruction>(PUSHUNDEFINED));
if(token == "break")
instrs.push_back(std::make_shared<SimpleChunkInstruction>(PUSHBREAK));
if(token == "continue")
instrs.push_back(std::make_shared<SimpleChunkInstruction>(PUSHCONTINUE));
}
}
else if(i < tokens.size() && tokens[i].type == LexTokenType::String)
{
instrs.push_back(std::make_shared<PushStringChunkInstruction>(tokens[i++].text));
}
else if(i < tokens.size() && tokens[i].type == LexTokenType::Char)
{
instrs.push_back(std::make_shared<PushCharChunkInstruction>(tokens[i++].text[0]));
}
}
else if(name == "scopebegin")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(SCOPEBEGIN));
}
else if(name == "scopeend")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(SCOPEEND));
}
else if(name == "scopeendtimes")
{
if(tokens[i].type == LexTokenType::Identifier)
instrs.push_back(std::make_shared<ScopeEndTimesChunkInstruction>((uint32_t)std::stoul(tokens[i++].text)));
}
else if(name == "setvariable")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(SETVARIABLE));
}
else if(name == "getvariable")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(GETVARIABLE));
}
else if(name == "declarevariable")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(DECLAREVARIABLE));
}
else if(name == "declareconstvariable")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(DECLARECONSTVARIABLE));
}
else if(name == "setfield")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(SETFIELD));
}
else if(name == "getfield")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(GETFIELD));
}
else if(name == "callfunction")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(CALLFUNCTION));
}
else if(name == "callmethod")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(CALLMETHOD));
}
else if(name == "ret")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(RET));
}
else if(name == "jmpc")
{
auto lblName = lbl_prefix + "_" + ReadIdent();
instrs.push_back(std::make_shared<JumpStyleChunkInstruction>(JMPC,lblName));
}
else if(name == "jmp")
{
auto lblName = lbl_prefix + "_" + ReadIdent();
instrs.push_back(std::make_shared<JumpStyleChunkInstruction>(JMP,lblName));
}
else if(name == "jmpundefined")
{
auto lblName = lbl_prefix + "_" + ReadIdent();
instrs.push_back(std::make_shared<JumpStyleChunkInstruction>(JMPUNDEFINED,lblName));
}
else if(name == "defer")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(DEFER));
}
else if(name == "trycatch")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(TRYCATCH));
}
else if(name == "throw")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(THROW));
}
else if(name == "pushscopelessclosure")
{
auto closure = std::make_shared<ClosureChunkInstruction>(false);
EnsureSymbol("(");
while(!IsSym(")",false) && i < tokens.size())
{
closure->data.args.push_back(ReadIdent());
IsSym(",");
}
EnsureSymbol(")");
EnsureSymbol("{");
ParseClosureInstructions(closure->data.instructions,"closure");
EnsureSymbol("}");
instrs.push_back(closure);
//instrs.push_back(std::make_shared<JumpStyleInstruction>(JMPC,lblName));
}
else if(name == "yield")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(YIELD));
}
else if(name == "breakpoint")
{
instrs.push_back(std::make_shared<SimpleChunkInstruction>(BREAKPOINT));
}
else if(name == "jmpifbreak")
{
auto lblName = lbl_prefix + "_" + ReadIdent();
instrs.push_back(std::make_shared<JumpStyleChunkInstruction>(JMPIFBREAK,lblName));
}
else if(name == "jmpifcontinue")
{
auto lblName = lbl_prefix + "_" + ReadIdent();
instrs.push_back(std::make_shared<JumpStyleChunkInstruction>(JMPIFCONTINUE,lblName));
}
else if(name == "jmpifdefined")
{
auto lblName = lbl_prefix + "_" + ReadIdent();
instrs.push_back(std::make_shared<JumpStyleChunkInstruction>(JMPIFDEFINED,lblName));
}
else if(name == "lbl")
{
auto lblName = lbl_prefix + "_" + ReadIdent();
instrs.push_back(std::make_shared<LabelChunkInstruction>(lblName));
}
else {
throw std::runtime_error("NOT IMPLEMENTED: " + name);
}
}
}
void EnsureSymbol(std::string txt)
{
if(i < tokens.size())
{
if(tokens[i].type != LexTokenType::Symbol)
{
throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but did not get a symbol at all.");
}
if(tokens[i].text != txt)
{
throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + "\"");
}
i++;
return;
}
throw std::out_of_range("End of file");
}
std::string ParseDocumentation()
{
if(i >= tokens.size()) return {};
if(tokens[i].type != LexTokenType::Documentation) return {};
return tokens[i++].text;
}
public:
AssemblerParser(std::vector<LexToken>& tokens) : tokens(tokens)
{
size_t root=0;
while(i < tokens.size())
{
auto doc = ParseDocumentation();
if(IsIdent("root")) {
EnsureSymbol("{");
ParseClosureInstructions(this->root.instructions, "root_" + std::to_string(root));
EnsureSymbol("}");
root++;
}
else if(IsIdent("func")) {
FunctionData fdata;
fdata.name.push_back(doc);
fdata.name.push_back(ReadIdent());
while(IsSym("."))
{
fdata.name.push_back(ReadIdent());
}
EnsureSymbol("(");
while(!IsSym(")",false) && i < tokens.size())
{
fdata.chunk.args.push_back(ReadIdent());
IsSym(",");
}
EnsureSymbol(")");
EnsureSymbol("{");
ParseClosureInstructions(fdata.chunk.instructions, "func_" + std::to_string(root));
EnsureSymbol("}");
this->functions.push_back(fdata);
}
else if(IsIdent("class"))
{
ClassData cdata;
cdata.documentation = doc;
cdata.name.push_back(ReadIdent());
while(IsSym("."))
{
cdata.name.push_back(ReadIdent());
}
if(IsSym(":"))
{
cdata.inherits.push_back(ReadIdent());
while(IsSym("."))
{
cdata.inherits.push_back(ReadIdent());
}
}
else {
cdata.inherits.push_back("ClassObject");
}
EnsureSymbol("{");
while(i < tokens.size() && !IsSym("}",false))
{
ClassDataEntry ent;
ent.documentation = ParseDocumentation();
if(IsIdent("public"))
{
ent.modifier = TClassModifier::Public;
}
else if(IsIdent("protected"))
{
ent.modifier = TClassModifier::Protected;
}
else if(IsIdent("private"))
{
ent.modifier = TClassModifier::Private;
}
else if(IsIdent("static"))
{
ent.modifier = TClassModifier::Static;
}
else throw std::runtime_error("Invalid modifier on class entry");
if(IsIdent("abstract"))
{
ent.name = ReadIdent();
ent.isAbstract = true;
ent.isFunction=true;
EnsureSymbol("(");
while(!IsSym(")",false) && i < tokens.size())
{
ent.data.args.push_back(ReadIdent());
IsSym(",");
}
EnsureSymbol(")");
EnsureSymbol(";");
}
else {
ent.name = ReadIdent();
if(IsSym("("))
{
ent.isFunction=true;
ent.isAbstract=false;
while(!IsSym(")",false) && i < tokens.size())
{
ent.data.args.push_back(ReadIdent());
IsSym(",");
}
EnsureSymbol(")");
EnsureSymbol("{");
ParseClosureInstructions(ent.data.instructions,"cls_fn");
EnsureSymbol("}");
}
else if(IsSym(";"))
{
ent.isFunction=false;
ent.isAbstract=true;
}
else if(IsSym("{"))
{
ent.isFunction=false;
ent.isAbstract=false;
EnsureSymbol("{");
ParseClosureInstructions(ent.data.instructions,"cls_field");
EnsureSymbol("}");
}
}
cdata.entries.push_back(ent);
}
EnsureSymbol("}");
this->classes.push_back(cdata);
}
}
}
ChunkData root;
std::vector<FunctionData> functions;
std::vector<ClassData> classes;
};
class CodeGen2 {
public:
void Write(std::shared_ptr<Tesses::Framework::Streams::Stream> strm, uint8_t* buffer, size_t len)
{
strm->WriteBlock(buffer,len);
}
void WriteInt(std::shared_ptr<Tesses::Framework::Streams::Stream> strm,uint32_t v)
{
uint8_t buffer[4];
BitConverter::FromUint32BE(buffer[0],v);
Write(strm,buffer,4);
}
void WriteString(std::shared_ptr<Tesses::Framework::Streams::Stream> strm,std::string v)
{
WriteInt(strm,(uint32_t)v.size());
Write(strm,(uint8_t*)v.data(),v.size());
}
void Save(std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs, std::shared_ptr<Tesses::Framework::Streams::Stream> stream)
{
TVMVersion runtime_version(CROSSLANG_BYTECODE_MAJOR,CROSSLANG_BYTECODE_MINOR,CROSSLANG_BYTECODE_PATCH,CROSSLANG_BYTECODE_BUILD,CROSSLANG_BYTECODE_VERSIONSTAGE);
uint8_t buffer[18];
memcpy(buffer,"TCROSSVM",8);
runtime_version.ToArray(buffer+8);
version.ToArray(buffer+13);
Write(stream,buffer,18);
uint32_t sections=5;
uint32_t name = GetString(this->name);
uint32_t info = GetString(this->info);
for(auto& dep : this->dependencies)
{
GetString(dep.first);
sections++;
}
for(auto& tool : this->tools)
{
GetString(tool.first);
sections++;
}
if(!this->icon.empty())
{
this->GetResource(this->icon);
}
for(auto& sec : this->sections)
sections++;
for(auto& vm : this->vms)
{
this->GetString(vm.first);
this->GetString(vm.second);
sections++;
}
for(auto& res : this->res)
sections++;
if(!this->icon.empty())
sections++;
if(!this->classes.empty())
sections++;
WriteInt(stream,sections);
uint32_t strSz=4;
for(auto& s : this->strs)
{
strSz += (uint32_t)s.size() + 4;
}
memcpy(buffer,"STRS",4);
Write(stream,buffer,4);
WriteInt(stream,strSz); //even though its ignored
WriteInt(stream,this->strs.size());
for(auto& str : this->strs)
WriteString(stream,str);
memcpy(buffer,"NAME",4);
Write(stream,buffer,4);
WriteInt(stream,4);
WriteInt(stream,name);
memcpy(buffer,"INFO",4);
Write(stream,buffer,4);
WriteInt(stream,4);
WriteInt(stream,info);
for(auto& dep : this->dependencies)
{
memcpy(buffer,"DEPS",4);
Write(stream,buffer,4);
WriteInt(stream,9); //even though its ignored
WriteInt(stream,GetString(dep.first));
dep.second.ToArray(buffer);
Write(stream,buffer,5);
}
for(auto& tool : this->tools)
{
memcpy(buffer,"TOOL",4);
Write(stream,buffer,4);
WriteInt(stream,9); //even though its ignored
WriteInt(stream,GetString(tool.first));
tool.second.ToArray(buffer);
Write(stream,buffer,5);
}
for(auto& vm : this->vms)
{
memcpy(buffer,"MACH",4);
Write(stream,buffer,4);
WriteInt(stream,8); //even though its ignored
WriteInt(stream,GetString(vm.first));
WriteInt(stream,GetString(vm.second));
}
uint32_t fnLen=4;
for(auto& fn : this->funcs)
{
fnLen += (fn.first.size() + 2) * 4;
}
memcpy(buffer,"FUNS",4);
Write(stream,buffer,4);
WriteInt(stream,fnLen);
WriteInt(stream,(uint32_t)this->funcs.size());
for(auto& fn : this->funcs)
{
WriteInt(stream,(uint32_t)fn.first.size());
for(auto namePart : fn.first)
{
WriteInt(stream,namePart);
}
WriteInt(stream,fn.second);
}
uint32_t clength = 4;
memcpy(buffer,"CHKS",4);
Write(stream,buffer,4);
WriteInt(stream,clength);
WriteInt(stream,(uint32_t)this->chunks.size());
for(auto& chunk : this->chunks)
{
std::vector<uint8_t> buffer;
WriteInt(stream,(uint32_t)chunk.first.size());
for(auto arg : chunk.first)
{
WriteInt(stream,arg);
}
for(auto instr : chunk.second)
{
instr->Write(buffer);
}
WriteInt(stream,(uint32_t)buffer.size());
Write(stream,buffer.data(),buffer.size());
}
if(!classes.empty())
{
uint32_t len = 4;
for(auto& cls : classes)
{
len += 8;
len += cls.name.size() * 4;
len += 4;
len += cls.inherits.size() * 4;
len += 4;
for(auto& clsEnt : cls.entries)
{
len += 17;
for(auto& arg : clsEnt.arguments) len+=4;
}
}
memcpy(buffer,"CLSS",4);
Write(stream,buffer,4);
WriteInt(stream,len);
WriteInt(stream,(uint32_t)classes.size());
for(auto& cls : classes)
{
WriteInt(stream,cls.documentation);
WriteInt(stream,(uint32_t)cls.name.size());
for(auto namePart : cls.name) WriteInt(stream,namePart);
WriteInt(stream,(uint32_t)cls.inherits.size());
for(auto inhPart : cls.inherits) WriteInt(stream,inhPart);
WriteInt(stream,(uint32_t)cls.entries.size());
for(auto& ent : cls.entries)
{
buffer[0] = ent.type;
Write(stream,buffer,1);
WriteInt(stream,ent.documentation);
WriteInt(stream,ent.name);
WriteInt(stream,(uint32_t)ent.arguments.size());
for(auto ar : ent.arguments)
{
WriteInt(stream,ar);
}
WriteInt(stream,ent.closure);
}
}
}
for(auto& reso : res)
{
memcpy(buffer,"RESO",4);
Write(stream,buffer,4);
auto strm = vfs->OpenFile(reso,"rb");
if(strm->EndOfStream())
{
WriteInt(stream,0);
}
else {
WriteInt(stream, (uint32_t)strm->GetLength());
strm->CopyTo(stream);
}
}
if(!this->icon.empty())
{
memcpy(buffer,"ICON",4);
Write(stream,buffer,4);
WriteInt(stream,4);
WriteInt(stream,this->GetResource(this->icon));
}
for(auto& sect : this->sections)
{
memcpy(buffer,sect.first.data(),4);
Write(stream,buffer,4);
WriteInt(stream,(uint32_t)sect.second.size());
Write(stream,sect.second.data(),sect.second.size());
}
}
uint32_t GetResource(std::string resource)
{
for(uint32_t i = 0; i < (uint32_t)this->res.size();i++)
{
if(this->res[i] == resource) return i;
}
uint32_t resI = (uint32_t)this->res.size();
this->res.push_back(resource);
return resI;
}
uint32_t GetString(std::string str)
{
for(uint32_t i = 0; i < (uint32_t)this->strs.size();i++)
{
if(this->strs[i] == str) return i;
}
uint32_t strI = (uint32_t)this->strs.size();
this->strs.push_back(str);
return strI;
}
std::vector<std::string> strs;
std::vector<std::string> res;
std::vector<std::pair<std::vector<uint32_t>,uint32_t>> funcs;
std::vector<CodeGenClass> classes;
std::vector<std::pair<std::vector<uint32_t>, std::vector<std::shared_ptr<ByteCodeInstruction>>>> chunks;
std::vector<std::pair<std::string, TVMVersion>> dependencies;
std::vector<std::pair<std::string, TVMVersion>> tools;
std::vector<std::pair<std::string,std::vector<uint8_t>>> sections;
std::vector<std::pair<std::string,std::string>> vms;
TVMVersion version;
std::string name;
std::string info;
std::string icon;
uint32_t PushChunk(ChunkData& data)
{
uint32_t chunkId = chunks.size();
chunks.push_back(std::pair<std::vector<uint32_t>,std::vector<std::shared_ptr<ByteCodeInstruction>>>());
chunks[chunkId].first.resize(data.args.size());
for(size_t i = 0; i < data.args.size(); i++)
{
chunks[chunkId].first[i] = GetString(data.args[i]);
}
std::map<std::string,uint32_t> labels;
uint32_t offset=0;
for(auto item : data.instructions)
{
offset += item->Size();
auto lbl = std::dynamic_pointer_cast<LabelChunkInstruction>(item);
auto simp = std::dynamic_pointer_cast<SimpleChunkInstruction>(item);
auto lng = std::dynamic_pointer_cast<PushLongChunkInstruction>(item);
auto dbl = std::dynamic_pointer_cast<PushDoubleChunkInstruction>(item);
auto str = std::dynamic_pointer_cast<PushStringChunkInstruction>(item);
auto chr = std::dynamic_pointer_cast<PushCharChunkInstruction>(item);
auto chk = std::dynamic_pointer_cast<ClosureChunkInstruction>(item);
auto reso = std::dynamic_pointer_cast<PushResourceChunkInstruction>(item);
auto resos = std::dynamic_pointer_cast<PushResourceStreamChunkInstruction>(item);
auto jmp = std::dynamic_pointer_cast<JumpStyleChunkInstruction>(item);
auto scopeend = std::dynamic_pointer_cast<ScopeEndTimesChunkInstruction>(item);
if(lbl)
{
labels[lbl->lbl] = offset;
}
if(simp)
{
chunks[chunkId].second.push_back(std::make_shared<SimpleInstruction>(simp->instruction));
}
if(lng)
{
chunks[chunkId].second.push_back(std::make_shared<LongInstruction>(lng->value));
}
if(dbl)
{
chunks[chunkId].second.push_back(std::make_shared<DoubleInstruction>(dbl->value));
}
if(str)
{
chunks[chunkId].second.push_back(std::make_shared<StringInstruction>(GetString(str->value)));
}
if(chr)
{
chunks[chunkId].second.push_back(std::make_shared<CharInstruction>(chr->value));
}
if(chk)
{
auto item = std::make_shared<ClosureInstruction>(PushChunk(chk->data),chk->scoped);
chunks[chunkId].second.push_back(item);
}
if(reso)
{
chunks[chunkId].second.push_back(std::make_shared<EmbedInstruction>(GetResource(reso->value)));
}
if(resos)
{
chunks[chunkId].second.push_back(std::make_shared<EmbedStreamInstruction>(GetResource(reso->value)));
}
if(jmp)
{
chunks[chunkId].second.push_back(std::make_shared<JumpStyleInstruction>(jmp->instr,jmp->lbl));
}
if(scopeend)
{
chunks[chunkId].second.push_back(std::make_shared<ScopeEndTimesInstruction>(scopeend->times));
}
}
for(auto& item : chunks[chunkId].second)
{
auto jmp = std::dynamic_pointer_cast<JumpStyleInstruction>(item);
if(jmp)
{
jmp->n = labels[jmp->label];
}
}
return chunkId;
}
};
Tesses::Framework::Filesystem::VFSPath Assemble(std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs)
{
using namespace Tesses::Framework::Filesystem;
using namespace Tesses::Framework::TextStreams;
std::function<void(VFSPath)> getSrc;
std::vector<LexToken> tokens;
getSrc = [&](VFSPath path)->void {
if(vfs->DirectoryExists(path))
for(auto item : vfs->EnumeratePaths(path))
{
if(vfs->DirectoryExists(item))
{
getSrc(item);
}
else {
if(item.GetExtension() == ".tcasm")
{
StreamReader reader(vfs->OpenFile(item,"rb"));
std::stringstream strm(reader.ReadToEnd(),std::ios_base::binary | std::ios_base::in);
Lex(item.ToString(), strm, tokens);
}
}
}
};
getSrc(VFSPath() / "src");
AssemblerParser parser(tokens);
CodeGen2 cg2;
cg2.name = "out";
cg2.version = TVMVersion(1,0,0,0,TVMVersionStage::ProductionVersion);
auto confFile = VFSPath() / "crossapp.json";
if(vfs->FileExists(confFile))
{
Tesses::Framework::TextStreams::StreamReader reader(vfs->OpenFile(confFile,"rb"));
auto jobj = Json::Decode(reader.ReadToEnd());
JObject main;
if(TryGetJToken(jobj,main))
{
TVMVersion version;
std::string str0;
std::string str1;
JObject dict0;
JArray array0;
main.TryGetValueAsType("name",cg2.name);
if(main.TryGetValueAsType("version",str0))
TVMVersion::TryParse(str0, cg2.version);
if(main.TryGetValueAsType("info",dict0))
cg2.info = Json::Encode(dict0,false);
main.TryGetValueAsType("icon", cg2.icon);
if(main.TryGetValueAsType("dependencies",array0))
{
for(auto item : array0)
{
if(TryGetJToken(item,dict0))
{
if(dict0.TryGetValueAsType("version", str1) && TVMVersion::TryParse(str1,version) && dict0.TryGetValueAsType("name",str0))
{
cg2.dependencies.emplace_back(str0, version);
}
}
}
}
if(main.TryGetValueAsType("tools",array0))
{
for(auto item : array0)
{
if(TryGetJToken(item,dict0))
{
if(dict0.TryGetValueAsType("version", str1) && TVMVersion::TryParse(str1,version) && dict0.TryGetValueAsType("name",str0))
{
cg2.tools.emplace_back(str0, version);
}
}
}
}
if(main.TryGetValueAsType("vms",array0))
{
for(auto item : array0)
{
if(TryGetJToken(item,dict0))
{
if(dict0.TryGetValueAsType("name", str0) && dict0.TryGetValueAsType("how_to_get",str1))
{
cg2.vms.emplace_back(str0, str1);
}
}
}
}
}
}
cg2.PushChunk(parser.root);
for(auto& fn : parser.functions)
{
std::vector<uint32_t> nameParts;
nameParts.resize(fn.name.size());
for(size_t i = 0; i < fn.name.size(); i++)
{
nameParts[i] = cg2.GetString(fn.name[i]);
}
auto chunk = cg2.PushChunk(fn.chunk);
cg2.funcs.push_back(std::pair<std::vector<uint32_t>,uint32_t>(nameParts,chunk));
}
for(auto& cls : parser.classes)
{
CodeGenClass cls2;
cls2.name.resize(cls.name.size());
for(size_t i = 0; i < cls.name.size(); i++)
{
cls2.name[i] = cg2.GetString(cls.name[i]);
}
cls2.inherits.resize(cls.inherits.size());
for(size_t i = 0; i < cls.inherits.size(); i++)
{
cls2.inherits[i] = cg2.GetString(cls.inherits[i]);
}
cls2.documentation = cg2.GetString(cls.documentation);
for(auto clsItem : cls.entries)
{
CodeGenClassEntry ent;
ent.type = 0;
ent.type = (uint8_t)clsItem.modifier & 3;
if(clsItem.isAbstract) ent.type |= 0b00001000;
if(!clsItem.isFunction) ent.type |= 0b00000100;
ent.documentation = cg2.GetString(clsItem.documentation);
ent.name = cg2.GetString(clsItem.name);
ent.closure = 0;
ent.arguments.resize(clsItem.data.args.size());
for(size_t i = 0; i < clsItem.data.args.size(); i++)
{
ent.arguments[i] = cg2.GetString(clsItem.data.args[i]);
}
if(!clsItem.isAbstract)
{
ent.closure = cg2.PushChunk(clsItem.data);
}
cls2.entries.push_back(ent);
}
cg2.classes.push_back(cls2);
}
vfs->CreateDirectory(VFSPath() / "res");
vfs->CreateDirectory(VFSPath() / "bin");
vfs->CreateDirectory(VFSPath() / "sections");
auto sectionsdir = std::make_shared<SubdirFilesystem>(vfs,VFSPath() / "sections");
auto resdir = std::make_shared<SubdirFilesystem>(vfs,VFSPath() / "res");
for(auto file : sectionsdir->EnumeratePaths(VFSPath()))
{
if(file.GetExtension() == ".tsec" && sectionsdir->FileExists(file))
{
auto strm0 = sectionsdir->OpenFile(file,"rb");
int64_t len = strm0->GetLength();
if(len > 4)
{
std::string name(4,' ');
strm0->ReadBlock((uint8_t*)name.data(),4);
size_t off = cg2.sections.size();
cg2.sections.push_back(std::pair<std::string,std::vector<uint8_t>>(name,{}));
cg2.sections[off].second.resize((size_t)len-4);
strm0->ReadBlock(cg2.sections[off].second.data(), cg2.sections[off].second.size());
}
}
}
auto strm = vfs->OpenFile(VFSPath() / "bin" / cg2.name + "-" + cg2.version.ToString() + ".crvm","wb");
cg2.Save(resdir, strm);
return VFSPath() / "bin" / cg2.name + "-" + cg2.version.ToString() + ".crvm";
}
}