#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 args; std::vector> 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 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 name; std::vector inherits; std::vector entries; }; class AssemblerParser { std::vector& 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>& instrs, std::string lbl_prefix) { while(!IsSym("}",false)) { auto name = ReadIdent(); if(name == "add") { instrs.push_back(std::make_shared(ADD)); } else if(name == "sub") { instrs.push_back(std::make_shared(SUB)); } else if(name == "mul") { instrs.push_back(std::make_shared(TIMES)); } else if(name == "div") { instrs.push_back(std::make_shared(DIVIDE)); } else if(name == "mod") { instrs.push_back(std::make_shared(MODULO)); } else if(name == "lsh") { instrs.push_back(std::make_shared(LEFTSHIFT)); } else if(name == "rsh") { instrs.push_back(std::make_shared(RIGHTSHIFT)); } else if(name == "bor") { instrs.push_back(std::make_shared(BITWISEOR)); } else if(name == "band") { instrs.push_back(std::make_shared(BITWISEAND)); } else if(name == "bnot") { instrs.push_back(std::make_shared(BITWISENOT)); } else if(name == "lt") { instrs.push_back(std::make_shared(LESSTHAN)); } else if(name == "gt") { instrs.push_back(std::make_shared(GREATERTHAN)); } else if(name == "lte") { instrs.push_back(std::make_shared(LESSTHANEQ)); } else if(name == "gte") { instrs.push_back(std::make_shared(GREATERTHANEQ)); } else if(name == "eq") { instrs.push_back(std::make_shared(EQ)); } else if(name == "neq") { instrs.push_back(std::make_shared(NEQ)); } else if(name == "not") { instrs.push_back(std::make_shared(NOT)); } else if(name == "neg") { instrs.push_back(std::make_shared(NEGATIVE)); } else if(name == "xor") { instrs.push_back(std::make_shared(XOR)); } else if(name == "pop") { instrs.push_back(std::make_shared(POP)); } else if(name == "dup") { instrs.push_back(std::make_shared(DUP)); } else if(name == "nop") { instrs.push_back(std::make_shared(NOP)); } else if(name == "lineinfo") { instrs.push_back(std::make_shared(LINEINFO)); } else if(name == "embeddir") { instrs.push_back(std::make_shared(PUSHRESOUURCEDIR)); } else if(name == "pushclosure") { auto closure = std::make_shared(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(JMPC,lblName)); } else if(name == "createdict") { instrs.push_back(std::make_shared(CREATEDICTIONARY)); } else if(name == "createarray") { instrs.push_back(std::make_shared(CREATEARRAY)); } else if(name == "appendlist") { instrs.push_back(std::make_shared(APPENDLIST)); } else if(name == "appenddict") { instrs.push_back(std::make_shared(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(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(str)); } } else if(name == "push") { if(IsSym(".")) { instrs.push_back(std::make_shared(PUSHRELATIVEPATH)); } else if(IsSym("/")) { instrs.push_back(std::make_shared(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(v)); } else { instrs.push_back(std::make_shared(lngNum)); } } else if(hasNumber) { instrs.push_back(std::make_shared(lngNum)); } if(!hasNumber) { if(token == "true") instrs.push_back(std::make_shared(PUSHTRUE)); if(token == "false") instrs.push_back(std::make_shared(PUSHFALSE)); if(token == "null") instrs.push_back(std::make_shared(PUSHNULL)); if(token == "undefined") instrs.push_back(std::make_shared(PUSHUNDEFINED)); if(token == "break") instrs.push_back(std::make_shared(PUSHBREAK)); if(token == "continue") instrs.push_back(std::make_shared(PUSHCONTINUE)); } } else if(i < tokens.size() && tokens[i].type == LexTokenType::String) { instrs.push_back(std::make_shared(tokens[i++].text)); } else if(i < tokens.size() && tokens[i].type == LexTokenType::Char) { instrs.push_back(std::make_shared(tokens[i++].text[0])); } } else if(name == "scopebegin") { instrs.push_back(std::make_shared(SCOPEBEGIN)); } else if(name == "scopeend") { instrs.push_back(std::make_shared(SCOPEEND)); } else if(name == "scopeendtimes") { if(tokens[i].type == LexTokenType::Identifier) instrs.push_back(std::make_shared((uint32_t)std::stoul(tokens[i++].text))); } else if(name == "setvariable") { instrs.push_back(std::make_shared(SETVARIABLE)); } else if(name == "getvariable") { instrs.push_back(std::make_shared(GETVARIABLE)); } else if(name == "declarevariable") { instrs.push_back(std::make_shared(DECLAREVARIABLE)); } else if(name == "declareconstvariable") { instrs.push_back(std::make_shared(DECLARECONSTVARIABLE)); } else if(name == "setfield") { instrs.push_back(std::make_shared(SETFIELD)); } else if(name == "getfield") { instrs.push_back(std::make_shared(GETFIELD)); } else if(name == "callfunction") { instrs.push_back(std::make_shared(CALLFUNCTION)); } else if(name == "callmethod") { instrs.push_back(std::make_shared(CALLMETHOD)); } else if(name == "ret") { instrs.push_back(std::make_shared(RET)); } else if(name == "jmpc") { auto lblName = lbl_prefix + "_" + ReadIdent(); instrs.push_back(std::make_shared(JMPC,lblName)); } else if(name == "jmp") { auto lblName = lbl_prefix + "_" + ReadIdent(); instrs.push_back(std::make_shared(JMP,lblName)); } else if(name == "jmpundefined") { auto lblName = lbl_prefix + "_" + ReadIdent(); instrs.push_back(std::make_shared(JMPUNDEFINED,lblName)); } else if(name == "defer") { instrs.push_back(std::make_shared(DEFER)); } else if(name == "trycatch") { instrs.push_back(std::make_shared(TRYCATCH)); } else if(name == "throw") { instrs.push_back(std::make_shared(THROW)); } else if(name == "pushscopelessclosure") { auto closure = std::make_shared(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(JMPC,lblName)); } else if(name == "yield") { instrs.push_back(std::make_shared(YIELD)); } else if(name == "breakpoint") { instrs.push_back(std::make_shared(BREAKPOINT)); } else if(name == "jmpifbreak") { auto lblName = lbl_prefix + "_" + ReadIdent(); instrs.push_back(std::make_shared(JMPIFBREAK,lblName)); } else if(name == "jmpifcontinue") { auto lblName = lbl_prefix + "_" + ReadIdent(); instrs.push_back(std::make_shared(JMPIFCONTINUE,lblName)); } else if(name == "jmpifdefined") { auto lblName = lbl_prefix + "_" + ReadIdent(); instrs.push_back(std::make_shared(JMPIFDEFINED,lblName)); } else if(name == "lbl") { auto lblName = lbl_prefix + "_" + ReadIdent(); instrs.push_back(std::make_shared(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& 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 functions; std::vector classes; }; class CodeGen2 { public: void Write(std::shared_ptr strm, uint8_t* buffer, size_t len) { strm->WriteBlock(buffer,len); } void WriteInt(std::shared_ptr strm,uint32_t v) { uint8_t buffer[4]; BitConverter::FromUint32BE(buffer[0],v); Write(strm,buffer,4); } void WriteString(std::shared_ptr strm,std::string v) { WriteInt(strm,(uint32_t)v.size()); Write(strm,(uint8_t*)v.data(),v.size()); } void Save(std::shared_ptr vfs, std::shared_ptr 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 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 strs; std::vector res; std::vector,uint32_t>> funcs; std::vector classes; std::vector, std::vector>>> chunks; std::vector> dependencies; std::vector> tools; std::vector>> sections; std::vector> 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>>()); 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 labels; uint32_t offset=0; for(auto item : data.instructions) { offset += item->Size(); auto lbl = std::dynamic_pointer_cast(item); auto simp = std::dynamic_pointer_cast(item); auto lng = std::dynamic_pointer_cast(item); auto dbl = std::dynamic_pointer_cast(item); auto str = std::dynamic_pointer_cast(item); auto chr = std::dynamic_pointer_cast(item); auto chk = std::dynamic_pointer_cast(item); auto reso = std::dynamic_pointer_cast(item); auto resos = std::dynamic_pointer_cast(item); auto jmp = std::dynamic_pointer_cast(item); auto scopeend = std::dynamic_pointer_cast(item); if(lbl) { labels[lbl->lbl] = offset; } if(simp) { chunks[chunkId].second.push_back(std::make_shared(simp->instruction)); } if(lng) { chunks[chunkId].second.push_back(std::make_shared(lng->value)); } if(dbl) { chunks[chunkId].second.push_back(std::make_shared(dbl->value)); } if(str) { chunks[chunkId].second.push_back(std::make_shared(GetString(str->value))); } if(chr) { chunks[chunkId].second.push_back(std::make_shared(chr->value)); } if(chk) { auto item = std::make_shared(PushChunk(chk->data),chk->scoped); chunks[chunkId].second.push_back(item); } if(reso) { chunks[chunkId].second.push_back(std::make_shared(GetResource(reso->value))); } if(resos) { chunks[chunkId].second.push_back(std::make_shared(GetResource(reso->value))); } if(jmp) { chunks[chunkId].second.push_back(std::make_shared(jmp->instr,jmp->lbl)); } if(scopeend) { chunks[chunkId].second.push_back(std::make_shared(scopeend->times)); } } for(auto& item : chunks[chunkId].second) { auto jmp = std::dynamic_pointer_cast(item); if(jmp) { jmp->n = labels[jmp->label]; } } return chunkId; } }; Tesses::Framework::Filesystem::VFSPath Assemble(std::shared_ptr vfs) { using namespace Tesses::Framework::Filesystem; using namespace Tesses::Framework::TextStreams; std::function getSrc; std::vector 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 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,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(vfs,VFSPath() / "sections"); auto resdir = std::make_shared(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>(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"; } }