diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..2ed3fde --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +CompileFlags: # Tweak the parse settings, example directory given to show format + Add: ["-Iinclude"] \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 923535a..598ce72 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -75,5 +75,8 @@ "thread": "cpp", "bitset": "cpp", "regex": "cpp" - } + }, + "clangd.fallbackFlags": [ + "-Iinclude" + ] } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 744ad0d..61f3cbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -203,6 +203,8 @@ add_executable(crossdump src/crosslangdump.cpp ${CROSSLANG_WIN32_EXE_SRC}) add_executable(crosslang src/crosslang.cpp ${CROSSLANG_WIN32_EXE_SRC}) add_executable(crossarchiveextract src/crossarchiveextract.cpp ${CROSSLANG_WIN32_EXE_SRC}) add_executable(crossarchivecreate src/crossarchivecreate.cpp ${CROSSLANG_WIN32_EXE_SRC}) +add_executable(crossthumbnailer src/crossthumbnailer.cpp ${CROSSLANG_WIN32_EXE_SRC}) + target_link_libraries(crossc PUBLIC crosslang_shared) target_link_libraries(crossvm PUBLIC crosslang_shared) target_link_libraries(crossint PUBLIC crosslang_shared) @@ -210,6 +212,7 @@ target_link_libraries(crossdump PUBLIC crosslang_shared) target_link_libraries(crosslang PUBLIC crosslang_shared) target_link_libraries(crossarchiveextract PUBLIC crosslang_shared) target_link_libraries(crossarchivecreate PUBLIC crosslang_shared) +target_link_libraries(crossthumbnailer PUBLIC crosslang_shared) elseif(CROSSLANG_ENABLE_STATIC) add_executable(crossc src/crosslangcompiler.cpp ${CROSSLANG_WIN32_EXE_SRC}) @@ -219,6 +222,7 @@ add_executable(crossdump src/crosslangdump.cpp ${CROSSLANG_WIN32_EXE_SRC}) add_executable(crosslang src/crosslang.cpp ${CROSSLANG_WIN32_EXE_SRC}) add_executable(crossarchiveextract src/crossarchiveextract.cpp ${CROSSLANG_WIN32_EXE_SRC}) add_executable(crossarchivecreate src/crossarchivecreate.cpp ${CROSSLANG_WIN32_EXE_SRC}) +add_executable(crossthumbnailer src/crossthumbnailer.cpp ${CROSSLANG_WIN32_EXE_SRC}) target_link_libraries(crossc PUBLIC crosslang_static) target_link_libraries(crossvm PUBLIC crosslang_static) target_link_libraries(crossint PUBLIC crosslang_static) @@ -226,6 +230,7 @@ target_link_libraries(crossdump PUBLIC crosslang_static) target_link_libraries(crosslang PUBLIC crosslang_static) target_link_libraries(crossarchiveextract PUBLIC crosslang_static) target_link_libraries(crossarchivecreate PUBLIC crosslang_static) +target_link_libraries(crossthumbnailer PUBLIC crosslang_static) else() add_executable(crossc src/crosslangcompiler.cpp ${CROSSLANG_SOURCE} ${CROSSLANG_WIN32_EXE_SRC}) add_executable(crossvm src/crosslangvm.cpp ${CROSSLANG_SOURCE} ${CROSSLANG_WIN32_EXE_SRC}) @@ -234,6 +239,7 @@ add_executable(crossdump src/crosslangdump.cpp ${CROSSLANG_SOURCE} ${CROSSLANG_W add_executable(crosslang src/crosslang.cpp ${CROSSLANG_SOURCE} ${CROSSLANG_WIN32_EXE_SRC}) add_executable(crossarchiveextract src/crossarchiveextract.cpp ${CROSSLANG_SOURCE} ${CROSSLANG_WIN32_EXE_SRC}) add_executable(crossarchivecreate src/crossarchivecreate.cpp ${CROSSLANG_SOURCE} ${CROSSLANG_WIN32_EXE_SRC}) +add_executable(crossthumbnailer src/crossthumbnailer.cpp ${CROSSLANG_SOURCE} ${CROSSLANG_WIN32_EXE_SRC}) CROSSLANG_LINK_DEPS(crossc) CROSSLANG_LINK_DEPS(crossvm) CROSSLANG_LINK_DEPS(crossint) @@ -241,6 +247,7 @@ CROSSLANG_LINK_DEPS(crosslang) CROSSLANG_LINK_DEPS(crossdump) CROSSLANG_LINK_DEPS(crossarchiveextract) CROSSLANG_LINK_DEPS(crossarchivecreate) +CROSSLANG_LINK_DEPS(crossthumbnailer) endif() install(TARGETS crossc DESTINATION bin) install(TARGETS crossvm DESTINATION bin) @@ -249,10 +256,18 @@ install(TARGETS crossdump DESTINATION bin) install(TARGETS crosslang DESTINATION bin) install(TARGETS crossarchiveextract DESTINATION bin) install(TARGETS crossarchivecreate DESTINATION bin) +install(TARGETS crossthumbnailer DESTINATION bin) + configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/crossvm-binfmt.conf.in "${CMAKE_CURRENT_BINARY_DIR}/crossvm-binfmt.conf" INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/binfmt.d) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/crossvm-binfmt.conf" DESTINATION ${CMAKE_INSTALL_LIBDIR}/binfmt.d) +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/crosslang.xml" +DESTINATION ${CMAKE_INSTALL_PREFIX}/share/mime/packages) +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/crosslang.png" +DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons) +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/crosslang.thumbnailer" +DESTINATION ${CMAKE_INSTALL_PREFIX}/share/thumbnailers) endif() include(InstallRequiredSystemLibraries) set(CPACK_PACKAGE_CONTACT "Mike Nolan ") diff --git a/README.md b/README.md index a0e6dd0..b1476d3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Tesses Cross Language ===================== -![CrossImage](logo.png) +![CrossImage](crosslang.png) ## What is required to build this project - [TessesFramework](https://onedev.site.tesses.net/tesses-framework) diff --git a/logo.png b/crosslang.png similarity index 100% rename from logo.png rename to crosslang.png diff --git a/crosslang.thumbnailer b/crosslang.thumbnailer new file mode 100644 index 0000000..24d27e3 --- /dev/null +++ b/crosslang.thumbnailer @@ -0,0 +1,4 @@ +[Thumbnailer Entry] +TryExec=crossthumbnailer +Exec=crossthumbnailer %i %o +MimeType=application/crvm; \ No newline at end of file diff --git a/crosslang.xml b/crosslang.xml new file mode 100644 index 0000000..832ef5f --- /dev/null +++ b/crosslang.xml @@ -0,0 +1,17 @@ + + + + + CrossLang Executable + CrossLang Executable + + + + + + CrossLang Source + CrossLang Source + + + + \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..de7bb09 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,563 @@ +## CrossLang Handbook + +This is a book for my language found [here](https://crosslang.tesseslanguage.com/) + + + +## Statements and loops + + + +#### Declare a variable (it is an expression) + +You can (the var is optional but should be used if the root environment has the same variable and you don't want to set it) + +```js +var myVariable = 42; +``` + +#### Set a variable (it is an expression) + +```js +myVariable = "I have set the variable to a string"; +``` + +#### If statements + +The {} are optional if you only need one statement + +```js +var myExpression = 0; +var myOtherExpression = { + mol = 42 +}; + +if(myExpression) +{ + Console.WriteLine("myExpression is truthy"); +} +else if(myOtherExpression) +{ + //this will run based on the condition + Console.WriteLine("myExpression is falsey but myOtherExpression is truthy"); +} +else { + Console.WriteLine("both myExpression and myOtherExpression are falsey"); +} +``` + +#### For loop + +Note: i will leak, also you can use curly brackets like if + +```js +for(var i = 0; i < 42; i++) + Console.WriteLine(i); +``` + +#### Each loop + +```js +enumerable MyItterator() +{ + yield 42; + yield 100; + yield 88; +} +each(var item : MyItterator()) +{ + Console.WriteLine(item); +} + + +each(var item : [3,7,12]) +{ + Console.WriteLine(item); +} + + +/* + This should output + 42 + 100 + 88 + 3 + 7 + 12 +*/ +``` + +#### While loop + +```js +while(conditionLikeIf) +{ + Console.WriteLine("Hi"); +} + +//If conditionLikeIf is falsey we never print Hi +//If conditionLikeIf is truthy we print Hi until it is falsey +``` + +#### Do loop + +```js +do(conditionLikeIf) +{ + Console.WriteLine("Hi"); +} + +//If conditionLikeIf is falsey we print Hi once +//If conditionLikeIf is truthy we print Hi until it is falsey +``` + + + +#### Try statement + +Note: you can't yield, return, break or continue from inside a try statement (also applys to catch and finally due to these being internally closures) + +```js +try { + Console.WriteLine("God is good."); + throw "my error"; + Console.WriteLine("I am lonely, I am never called."); +} +catch(ex) +{ + Console.WriteLine($"I got an error {ex}."); +} +finally { + Console.WriteLine("For God so loved the world that he gave his only begotten Son, that whoever believes in him should not perish but have eternal life."); +} + + +/* + This should print + God is good. + I got an error my error. + For God so loved the world that he gave his only begotten Son, that whoever believes in him should not perish but have eternal life. +*/ +``` + +#### Switch statement + +NOTE: you can use dictionaries with overloaded equals operator (we will pass the switch's expression as the argument) + +```js +o = { + operator== = (this,v) => { + //this is implicitly passed by runtime, but you must declare it if you want it + return (v * 7) == 42; + } +}; + +var val = 6; + +switch(val) +{ + case 4: + Console.WriteLine("I am four"); + break; + case 5: + Console.WriteLine("I am five"); + break; + case o: + Console.WriteLine("Hitchhiker's guide to the galaxy meaning of life"); + break; + default: + Console.WriteLine("We don't support it we are sorry"); +} +``` + + + +#### Function declaration + +```go +func My.Func.Is.A.Few.Deep(a, b) +{ + return a * b; +} +func main(args) +{ + Console.WriteLine(My.Func.Is.A.Few.Deep(6,7)); +} +``` + +#### Function inside a function + +Oh yeah functions can have exclusively a expression as a body which does not need a return keyword + +```go +func main(args) +{ + func MyOther(a,b) a * b; + Console.WriteLine(MyOther(a,b)); +} +``` + +#### Document a function + +```go +/^ + This function returns 42 +^/ +func MyFunction() 42; +``` + +#### Return statement + +You can also return nothing + +```js +return 42; +return; +``` + +#### Yield statement + +This will halt the function's execution and return the running function object (were you can pop the item and resume it) + +To automaticly make a function enumerable (with each statement) you must use ``enumerable`` instead of func when declaring your function + +```js +yield 42; +``` + +#### Throw statement + +You can catch this with ``try statement`` with ``catch`` clause + +```js +throw "You can replace me with another string or any other object"; +``` + +#### Defer statement + +Your code will be called when your scope is destroyed + +```go +{ + defer { + Console.WriteLine("In defer"); + } + Console.WriteLine("About to leave scope"); +} +Console.WriteLine("Left scope"); + + +/* +The output should be + +About to leave scope +In defer +Left scope +*/ +``` + +## Expressions + +We will place it as a parameter to a function ``doThing`` but these will work anywhere like setting a variable or another expression + +#### Undefined + +```js +doThing(undefined); +``` + +#### Null + +```js +doThing(null); +``` + +#### Boolean + +```js +doThing(false); +doThing(true); +``` + +#### Long + +A signed 64 bit number + +```js +doThing(94); +doThing(599929022); +``` + +#### Double + +A 64 bit floating pointer number + +```js +doThing(5.25); +doThing(942.90204); +``` + +#### Char + +Yes we support single character strings (this escapes a double quote) + +```csharp +doThing('\"'); +``` + +#### String + +Second is an interopolated string + +```csharp +doThing("Hi"); +doThing($"My name is {name}"); +``` + +#### List + +```js +doThing( + [4,5,9,42,true,"Hi",'\n'] +); +``` + +#### Dictionary + +```js +doThing( + { + a = "This is an option", + b = 42, + c = 9 + } +); +``` + +###### Enumerating a dictionary + +```js +var dict = { a = 5, b = 42}; +each(var item : Dictionary.Items(dict)) +{ + Console.WriteLine($"Key: {item.Key}"); + Console.WriteLine($"Value: {item.Value}"); + Console.WriteLine(); +} +/* +This prints +Key: a +Value: 5 + +Key: b +Value: 42 + +*/ +``` + + + +###### Getting a value from dictionary + +```go +func doThing(data) +{ + Console.WriteLine(data.b); //will print 42 +} +``` + +###### Setting a value to dictionary + +```go +func doThing(data) +{ + data.a = true; //replace a with a different value + data.someFieldThatDoesNotExist = 9; //define a new field entirely + +} +``` + +###### Methods + +Note that this is optional but if you do have it it must be the first argument, the this argument points to the dictionary + +```go +var item = { + myMethod = (this, a, b) => { + return a * b; + } +}; + +Console.WriteLine(item.myMethod(6,7)); //prints 42 +``` + +Or + +```go +var item = {}; +func item.myMethod(this, a, b) +{ + return a * b; +} +Console.WriteLine(item.myMethod(6,7)); //prints 42 +``` + +###### Properties + +They are declared like every other method except they are prefixed with ``get`` or ``set`` + +```go +var item = { + getProp = (this)=>{ + return 42; + }, + setProp = (this,v)=>{ + //do something with v + } +}; + +Console.WriteLine(item.Prop); //equivalent to Console.WriteLine(item.getProp()); + +item.Prop = 100; //equivalent to item.setProp(100); will do nothing in this example + +``` + +###### Operator overloading + +```js +var item = { + operator+ = (this,right) => { + return 4 + a; + } + operator- = (this,right) => { + return 4 - right; //be careful right may be undefined if the negate operator is used + } +}; + +Console.WriteLine(item + 5); //prints 9 +``` + +###### Array operator overloading + +```js +var item = { + GetAt = (index)=>{ + return index * 2; //we multiply index by two and return + }, + SetAt => (index,value)=>{ + Console.WriteLine($"The index was {index} and value was {value}"); + } +}; + +Console.WriteLine(item[21]); //prints 42 +item["Hi"] = "John"; //prints The index was Hi and value was John +``` + +#### ByteArray + +```js +var bA = ByteArray(1); +ba[0] = 42; +Console.WriteLine(ba.ToString()); //prints * +``` + +###### ByteArray from string + +```js +var bA = ByteArray("Hi"); +//we can get bytes like this bA[0] which will be 72 +//we can get length by bA.Count or bA.Length +``` + +#### Embedding files (you can't do this easily in C/C++ and C# not as easy as this) + +```js +var bA = embed("myFile.png"); //will embed the file res/myFile.png +//it is stored as a RESO in the crvm file and bA is a ByteArray +//note the argument MUST be a constant string +//note you can access a subdirectory of res as well just use dir/file.bin +``` + +#### Streams + + + +###### From an existing file + +```js +var strm = FS.Local.OpenFile("file.bin","rb"); + +var data = ByteArray(1024); +var read = strm.Read(data,0,data.Count); +//use ReadBlock to ensure you have 1024 bytes if not near end of stream + +//use WriteBlock to ensure you write the amount you say you need + +strm.Close(); +``` + +#### VFS + +```js +var myVFS = FS.Local; //FS.Local is the local filesystem + + +myVFS.CreateDirectory("myDir"); //creates directory in current dir (only local) + +myVFS.DeleteDirectory("myDir"); //now we delete it + + +myVFS.CreateDirectory(Path.FromString(Env.Downloads) / "Folder in Downloads"); //Create a folder in downloads +``` + + + +#### Path + +```js +var path = / "Path" / "To" / "Directory"; +var relativePath = ./"another"/"path"; +var combined = path / relativePath; +var someString = "joel"; +var combinedAndStr = combined / someString; +var combinedWithExtension = combined + ".mp4"; +Console.WriteLine(combined); // outputs /Path/To/Directory/another/path +Console.WriteLine(combined); // outputs /Path/To/Directory/another/path/joel +Console.WriteLine(combinedWithExtension); //outputs /Path/To/Directory/another/path.mp4 +//these paths are used with vfs + + +//to get parent directory use combined.GetParent(); +//to get filename use combined.GetFileName(); +//to get extension use combinedWithExtension.GetExtension();, it will be the extension including . +//to change the extension use combinedWithExtension.ChangeExtension(".mkv"); +//to remove the extension use combinedWithExtension.ChangeExtension(null); or combinedWithExtension.ChangeExtension(); +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/include/CrossLang.hpp b/include/CrossLang.hpp index 80d12c2..ba74c49 100644 --- a/include/CrossLang.hpp +++ b/include/CrossLang.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include #include @@ -144,6 +145,15 @@ namespace Tesses::CrossLang { if(this->build < version.build) return -1; return 0; } + + uint64_t AsLong() + { + uint64_t v = (uint64_t)major << 32; + v |= (uint64_t)minor << 24; + v |= (uint64_t)patch << 16; + v |= (uint64_t)build; + return v; + } int CompareToRuntime() { TVMVersion version(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE); @@ -268,7 +278,7 @@ namespace Tesses::CrossLang { }; - void CrossArchiveCreate(Tesses::Framework::Filesystem::VFS* vfs,Tesses::Framework::Streams::Stream* strm,std::string name,TVMVersion version,std::string info); + void CrossArchiveCreate(Tesses::Framework::Filesystem::VFS* vfs,Tesses::Framework::Streams::Stream* strm,std::string name,TVMVersion version,std::string info, std::string icon=""); std::pair,std::string> CrossArchiveExtract(Tesses::Framework::Streams::Stream* strm,Tesses::Framework::Filesystem::VFS* vfs); @@ -365,7 +375,9 @@ typedef enum { TRYCATCH, THROW, PUSHSCOPELESSCLOSURE, - YIELD + YIELD, + PUSHROOTPATH, + PUSHRELATIVEPATH } Instruction; class ByteCodeInstruction { @@ -502,6 +514,7 @@ class CodeGen { uint32_t GetResource(std::string res); std::vector strs; std::vector res; + std::vector, std::vector>> chunks; std::vector,uint32_t>> funcs; std::vector objectEntries; @@ -509,9 +522,11 @@ class CodeGen { void GenPop(std::vector& instrs,SyntaxNode n); public: std::vector> dependencies; + std::vector> tools; TVMVersion version; std::string name; std::string info; + std::string icon; void GenRoot(SyntaxNode n); void Save(Tesses::Framework::Filesystem::VFS* embedFS,Tesses::Framework::Streams::Stream* output); ~CodeGen(); @@ -589,7 +604,8 @@ constexpr std::string_view DefaultStatement = "defaultStatement"; constexpr std::string_view ObjectStatement = "objectStatement"; constexpr std::string_view StaticStatement = "staticStatement"; constexpr std::string_view MethodDeclaration = "methodDeclaration"; - +constexpr std::string_view RootPathExpression = "rootPathExpression"; +constexpr std::string_view RelativePathExpression = "relativePathExpression"; class AdvancedSyntaxNode { public: @@ -675,7 +691,7 @@ class Parser { class MethodInvoker { }; -using TObject = std::variant; +using TObject = std::variant; class TRootEnvironment; class GC; class GC { @@ -739,7 +755,6 @@ class GC { TFile* file; std::vector code; std::vector args; - std::string name; void Mark(); }; @@ -764,10 +779,12 @@ class GC { std::vector strings; std::vector, uint32_t>> functions; std::vector> dependencies; + std::vector> tools; std::vector> resources; std::string name; TVMVersion version; std::string info; + int32_t icon; void Load(GC* gc, Tesses::Framework::Streams::Stream* strm); void Skip(Tesses::Framework::Streams::Stream* strm,size_t len); @@ -785,6 +802,32 @@ class GC { std::vector items; static TList* Create(GCList* gc); static TList* Create(GCList& gc); + template + static TList* Create(GCList* gc, Itterator begin, Itterator end) + { + auto list = Create(gc); + gc->GetGC()->BarrierBegin(); + for(Itterator i = begin; i != end; ++i) + { + TObject item = *i; + list->Add(item); + } + gc->GetGC()->BarrierEnd(); + return list; + } + template + static TList* Create(GCList& gc, Itterator begin, Itterator end) + { + return Create(&gc,begin,end); + } + static TList* Create(GCList* gc, std::initializer_list il) + { + return Create(gc,il.begin(),il.end()); + } + static TList* Create(GCList& gc, std::initializer_list il) + { + return Create(gc,il.begin(),il.end()); + } virtual int64_t Count(); virtual TObject Get(int64_t index); virtual void Set(int64_t index, TObject value); @@ -795,7 +838,7 @@ class GC { virtual void Mark(); }; - + using TDItem = std::pair; class TDictionary : public THeapObject { @@ -803,8 +846,38 @@ class GC { std::unordered_map items; static TDictionary* Create(GCList* gc); static TDictionary* Create(GCList& gc); + template + static TDictionary* Create(GCList* gc, Itterator begin, Itterator end) + { + auto dict = Create(gc); + gc->GetGC()->BarrierBegin(); + for(Itterator i = begin; i != end; ++i) + { + TDItem item = *i; + dict->SetValue(item.first, item.second); + } + gc->GetGC()->BarrierEnd(); + return dict; + } + template + static TDictionary* Create(GCList& gc, Itterator begin, Itterator end) + { + return Create(&gc,begin,end); + } + + static TDictionary* Create(GCList* gc, std::initializer_list il) + { + return Create(gc,il.begin(),il.end()); + } + static TDictionary* Create(GCList& gc, std::initializer_list il) + { + return Create(gc, il.begin(),il.end()); + } + + virtual bool HasValue(std::string key); + virtual bool MethodExists(GCList& ls,std::string key); virtual TObject GetValue(std::string key); virtual void SetValue(std::string key, TObject value); virtual void Mark(); @@ -823,8 +896,10 @@ class GC { class TCallable : public THeapObject { public: + TObject tag; std::string documentation; virtual TObject Call(GCList& ls,std::vector args)=0; + virtual void Mark(); }; @@ -978,6 +1053,7 @@ class GC { this->marked=true; for(auto item : watch) GC::Mark(item); + GC::Mark(this->tag); } }; @@ -1309,6 +1385,8 @@ class GC { bool CreateArray(GC* gc); bool AppendList(GC* gc); bool AppendDictionary(GC* gc); + bool PushRootPath(GC* gc); + bool PushRelativePath(GC* gc); bool Pop(GC* gc); bool Dup(GC* gc); bool Nop(GC* gc); @@ -1490,4 +1568,6 @@ class GC { #define CROSSLANG_PLUGIN(plugin) DLLEXPORT extern "C" void CrossLangPluginInit(GC* gc, TRootEnvironment* env) { plugin(gc,env); } void LoadPlugin(GC* gc, TRootEnvironment* env, Tesses::Framework::Filesystem::VFSPath sharedObjectPath); + std::string Json_Encode(TObject o,bool indent=false); + TObject Json_Decode(GCList ls,std::string str); }; \ No newline at end of file diff --git a/src/archive.cpp b/src/archive.cpp index 28f4270..ac16128 100644 --- a/src/archive.cpp +++ b/src/archive.cpp @@ -3,7 +3,7 @@ namespace Tesses::CrossLang { - void CrossArchiveCreate(Tesses::Framework::Filesystem::VFS* vfs,Tesses::Framework::Streams::Stream* strm,std::string name, TVMVersion version, std::string info) + void CrossArchiveCreate(Tesses::Framework::Filesystem::VFS* vfs,Tesses::Framework::Streams::Stream* strm,std::string name, TVMVersion version, std::string info, std::string icon) { std::vector ignored_files; std::string file = "/.crossarchiveignore"; @@ -125,6 +125,8 @@ namespace Tesses::CrossLang }; walkFS(std::string("/")); + if(!icon.empty()) + ensureResource(icon); uint8_t main_header[18]; memcpy(main_header,"TCROSSVM",8); @@ -132,7 +134,7 @@ namespace Tesses::CrossLang rtVersion.ToArray(main_header+8); version.ToArray(main_header+13); strm->WriteBlock(main_header,sizeof(main_header)); - writeInt(strm,(uint32_t)(5+resources.size())); + writeInt(strm,(uint32_t)((icon.empty() ? 5 : 6)+resources.size())); strm->WriteBlock((const uint8_t*)"STRS",4); uint32_t sz=4; for(auto str : strs) diff --git a/src/compiler/ast.cpp b/src/compiler/ast.cpp index 659cc0a..1209236 100644 --- a/src/compiler/ast.cpp +++ b/src/compiler/ast.cpp @@ -103,14 +103,14 @@ static json_t* Serialize2(SyntaxNode node) { char c = std::get(node); json_t* json = json_object(); - json_object_set_new(json,"type",json_string(CharExpression.begin())); + json_object_set_new(json,"type",json_string((const char*)CharExpression.data())); json_object_set_new(json, "value", json_integer((uint8_t)c)); return json; } if(std::holds_alternative(node)) { json_t* json = json_object(); - json_object_set_new(json,"type",json_string(UndefinedExpression.begin())); + json_object_set_new(json,"type",json_string((const char*)UndefinedExpression.data())); return json; } @@ -148,4 +148,4 @@ return str; return ""; } -} \ No newline at end of file +} diff --git a/src/compiler/codegen.cpp b/src/compiler/codegen.cpp index 8769d3d..28e0b4d 100644 --- a/src/compiler/codegen.cpp +++ b/src/compiler/codegen.cpp @@ -42,14 +42,28 @@ namespace Tesses::CrossLang 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& res : this->res) sections++; + if(!this->icon.empty()) + sections++; + WriteInt(stream,sections); uint32_t strSz=4; @@ -81,6 +95,15 @@ namespace Tesses::CrossLang 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); + } uint32_t fnLen=4; @@ -155,7 +178,7 @@ namespace Tesses::CrossLang WriteInt(stream,(uint32_t)buffer.size()); Write(stream,buffer.data(),buffer.size()); } - + for(auto& reso : res) { memcpy(buffer,"RESO",4); @@ -186,6 +209,14 @@ namespace Tesses::CrossLang WriteInt(stream,0); } } + if(!this->icon.empty()) + { + memcpy(buffer,"ICON",4); + Write(stream,buffer,4); + WriteInt(stream,4); + WriteInt(stream,this->GetResource(this->icon)); + + } } @@ -430,7 +461,15 @@ namespace Tesses::CrossLang TWO_EXPR(NotEqualsExpression, NEQ) TWO_EXPR(EqualsExpression, EQ) TWO_EXPR(XOrExpression, XOR) - if(adv.nodeName == SwitchStatement && adv.nodes.size() == 2) + if(adv.nodeName == RelativePathExpression) + { + instructions.push_back(new SimpleInstruction(Instruction::PUSHRELATIVEPATH)); + } + else if(adv.nodeName == RootPathExpression) + { + instructions.push_back(new SimpleInstruction(Instruction::PUSHROOTPATH)); + } + else if(adv.nodeName == SwitchStatement && adv.nodes.size() == 2) { //THIS CODE WORKED FIRST TRY, I DON'T SEE THAT EVERY DAY, PRAISE GOD!!!!!!! auto expr = adv.nodes[0]; diff --git a/src/compiler/parser.cpp b/src/compiler/parser.cpp index fa98d5e..16b7395 100644 --- a/src/compiler/parser.cpp +++ b/src/compiler/parser.cpp @@ -1,5 +1,6 @@ #include "CrossLang.hpp" #include +#include namespace Tesses::CrossLang { std::string LexTokenType_ToString(LexTokenType t) @@ -135,24 +136,25 @@ namespace Tesses::CrossLang else if(IsSymbol("{")) { if(IsSymbol("}",false)) - node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{}); + node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{}); else - node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{ParseExpression()}); + node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{ParseExpression()}); + EnsureSymbol("}"); } else if(IsSymbol("(")) { if(IsSymbol(")",false)) - node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{}); + node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{}); else - node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{ParseExpression()}); + node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{ParseExpression()}); EnsureSymbol(")"); } else if(IsIdentifier("var")) { if(i >= tokens.size()) throw std::out_of_range("End of file"); - auto variable = tokens[i]; - i++; + auto variable = tokens[i]; + i++; if(variable.type != LexTokenType::Identifier) throw SyntaxException(variable.lineInfo, "Expected an identifier got a " + LexTokenType_ToString(variable.type) + " \"" + variable.text + "\""); node = AdvancedSyntaxNode::Create(DeclareExpression,true,{variable.text}); } @@ -347,6 +349,23 @@ namespace Tesses::CrossLang { return AdvancedSyntaxNode::Create(PrefixDecrementExpression,true,{ParseUnary()}); } + else if(IsSymbol("/")) + { + if(this->i < this->tokens.size() && (this->tokens[this->i].type == LexTokenType::String || this->tokens[this->i].type == LexTokenType::Identifier)) + { + return AdvancedSyntaxNode::Create(DivideExpression,true,{ + AdvancedSyntaxNode::Create(RootPathExpression,true,{}), + ParseValue() + }); + } + else { + return AdvancedSyntaxNode::Create(RootPathExpression,true,{}); + } + } + else if(IsSymbol(".")) + { + return AdvancedSyntaxNode::Create(RelativePathExpression, true, {}); + } return ParseValue(); } @@ -569,6 +588,98 @@ namespace Tesses::CrossLang if(IsIdentifier("object")) { //TODO: complete this + if(i < tokens.size()) + { + std::string name = tokens[i++].text; + EnsureSymbol("{"); + std::vector name_and_methods; + name_and_methods.push_back(name); + + while(!IsSymbol("}",false) && i < tokens.size()) + { + std::string documentation = ""; + bool hasDocumentation=false; + + + + if(tokens[i].type == LexTokenType::Documentation) + { + hasDocumentation=true; + documentation = tokens[i++].text; + } + + if(i < tokens.size()) + { + if(IsIdentifier("method")) + { + auto nameAndArgs = ParseExpression(); + + if(IsSymbol("{",false)) + { + auto r = AdvancedSyntaxNode::Create(MethodDeclaration,false,{nameAndArgs,ParseNode()}); + if(hasDocumentation) + { + name_and_methods.push_back(AdvancedSyntaxNode::Create(DocumentationStatement,false,{documentation,r})); + } + else + { + name_and_methods.push_back(r); + } + } + else + { + auto v = ParseExpression(); + + EnsureSymbol(";"); + auto r= AdvancedSyntaxNode::Create(MethodDeclaration,false,{nameAndArgs,AdvancedSyntaxNode::Create(ReturnStatement,false,{v})}); + if(hasDocumentation) + { + name_and_methods.push_back(AdvancedSyntaxNode::Create(DocumentationStatement,false,{documentation,r})); + } + else + { + name_and_methods.push_back(r); + } + } + } + else if(IsIdentifier("static")) + { + auto nameAndArgs = ParseExpression(); + + if(IsSymbol("{",false)) + { + auto r = AdvancedSyntaxNode::Create(StaticStatement,false,{nameAndArgs,ParseNode()}); + if(hasDocumentation) + { + name_and_methods.push_back(AdvancedSyntaxNode::Create(DocumentationStatement,false,{documentation,r})); + } + else + { + name_and_methods.push_back(r); + } + } + else + { + auto v = ParseExpression(); + + EnsureSymbol(";"); + auto r= AdvancedSyntaxNode::Create(StaticStatement,false,{nameAndArgs,AdvancedSyntaxNode::Create(ReturnStatement,false,{v})}); + if(hasDocumentation) + { + name_and_methods.push_back(AdvancedSyntaxNode::Create(DocumentationStatement,false,{documentation,r})); + } + else + { + name_and_methods.push_back(r); + } + } + } + } + } + EnsureSymbol("}"); + return AdvancedSyntaxNode::Create(ObjectStatement, false, name_and_methods); + } + else throw std::out_of_range("End of file"); } if(IsIdentifier("enumerable")) { diff --git a/src/crossarchivecreate.cpp b/src/crossarchivecreate.cpp index d01f684..325851f 100644 --- a/src/crossarchivecreate.cpp +++ b/src/crossarchivecreate.cpp @@ -8,6 +8,7 @@ void Help(const char* filename) printf("USAGE: %s [OPTIONS] \n", filename); printf("OPTIONS:\n"); printf(" -i: Set info (ex {\"maintainer\": \"Mike Nolan\", \"repo\": \"https://example.com/\", \"homepage\": \"https://example.com/\",\"license\":\"MIT\"})\n"); + printf(" -I: Set icon name (relative to dirasroot), should be a 128x128 png\n"); printf(" -v: Set version (1.0.0.0-prod defaults to 1.0.0.0-dev)\n"); printf(" -n: Set name (MyAppOrLibName defaults to out)\n"); printf(" -h, --help: Prints help\n"); @@ -19,6 +20,7 @@ int main(int argc, char** argv) std::string name="out"; std::string info="{}"; TVMVersion version; + std::string icon=""; std::vector args; for(int i = 1; i < argc; i++) { @@ -34,6 +36,14 @@ int main(int argc, char** argv) info = argv[i]; } } + else if(strcmp(argv[i], "-I") == 0) + { + i++; + if(i < argc) + { + icon = argv[i]; + } + } else if(strcmp(argv[i], "-n") == 0) { i++; @@ -77,7 +87,7 @@ int main(int argc, char** argv) } FileStream strm(f,true,"wb",true); - CrossArchiveCreate(&sdfs,&strm,name,version,info); + CrossArchiveCreate(&sdfs,&strm,name,version,info,icon); return 0; } \ No newline at end of file diff --git a/src/crosslangcompiler.cpp b/src/crosslangcompiler.cpp index 2c19c91..25b0a4f 100644 --- a/src/crosslangcompiler.cpp +++ b/src/crosslangcompiler.cpp @@ -10,8 +10,10 @@ void Help(const char* filename) printf("OPTIONS:\n"); printf(" -o: Output directory (OUTDIR, defaults to ./bin)\n"); printf(" -i: Set info (ex {\"maintainer\": \"Mike Nolan\", \"repo\": \"https://example.com/\", \"homepage\": \"https://example.com/\",\"license\":\"MIT\"})\n"); + printf(" -I: Set icon resource name (in the resource folder), should be a 128x128 png\n"); printf(" -v: Set version (1.0.0.0-prod defaults to 1.0.0.0-dev)\n"); printf(" -d: Add dependency (DependencyName-1.0.0.0-prod)\n"); + printf(" -t: Declare a tool (ToolName-1.0.0.0-prod)\n"); printf(" -n: Set name (MyAppOrLibName defaults to out)\n"); printf(" -r: Set resource directory (RESDIR defaults to res)\n"); printf(" -h, --help: Prints help\n"); @@ -37,8 +39,10 @@ int main(int argc, char** argv) std::vector source; std::filesystem::path resourceDir = std::filesystem::current_path() / "res"; std::vector> dependencies; + std::vector> tools; std::string name="out"; std::string info="{}"; + std::string icon=""; TVMVersion version; @@ -72,6 +76,14 @@ int main(int argc, char** argv) info = argv[i]; } } + else if(strcmp(argv[i],"-I") == 0) + { + i++; + if(i < argc) + { + icon = argv[i]; + } + } else if(strcmp(argv[i], "-d") == 0) { i++; @@ -106,6 +118,40 @@ int main(int argc, char** argv) } } } + else if(strcmp(argv[i], "-t") == 0) + { + i++; + if(i < argc) + { + std::string str = argv[i]; + auto lastDash = str.find_last_of('-'); + if(lastDash < str.size()) + { + std::string str2 = str.substr(lastDash+1); + if(str2 == "dev" || str2 == "alpha" || str2 == "beta" || str2 == "prod") + { + lastDash = str.find_last_of('-',lastDash-1); + } + std::string str1 = str.substr(0,lastDash); + str2 = str.substr(lastDash+1); + + TVMVersion v2; + if(!TVMVersion::TryParse(str2,v2)) + { + printf("ERROR: Invalid syntax for version\n"); + printf("Expected MAJOR[.MINOR[.PATCH[.BUILD[-dev,-alpha,-beta,-prod]]]]\n"); + exit(1); + } + tools.push_back(std::pair(str1,v2)); + + } + else + { + printf("ERROR: Tool must have version\n"); + exit(1); + } + } + } else if(strcmp(argv[i], "-n") == 0) { i++; @@ -154,10 +200,16 @@ int main(int argc, char** argv) gen.name = name; gen.version = version; gen.info = info; + gen.icon = icon; for(auto deps : dependencies) { gen.dependencies.push_back(deps); } + for(auto tool : tools) + { + gen.tools.push_back(tool); + } + std::filesystem::create_directory(outputDir); { diff --git a/src/crosslangdump.cpp b/src/crosslangdump.cpp index 188e9d2..86feec3 100644 --- a/src/crosslangdump.cpp +++ b/src/crosslangdump.cpp @@ -53,13 +53,18 @@ void DumpFile(std::filesystem::path p) char table_name[4]; + bool hasIcon=false; for(size_t i = 0; i < _len; i++) { Ensure(strm,(uint8_t*)table_name,sizeof(table_name)); size_t tableLen = (size_t)EnsureInt(strm); std::string tableName(table_name,4); - if(tableName == "STRS") + if(tableName == "ICON") + { + hasIcon=true; + } + else if(tableName == "STRS") { size_t strsLen = (size_t)EnsureInt(strm); for(size_t j = 0;j < strsLen;j++) @@ -129,6 +134,10 @@ void DumpFile(std::filesystem::path p) strm.Seek((int64_t)tableLen,Tesses::Framework::Streams::SeekOrigin::Current); } } + if(hasIcon) + std::cout << "Has Icon: yes" << std::endl; + else + std::cout << "Has Icon: no" << std::endl; for(size_t i = 1; i < closures.size(); i++) { diff --git a/src/crossthumbnailer.cpp b/src/crossthumbnailer.cpp new file mode 100644 index 0000000..f2848dd --- /dev/null +++ b/src/crossthumbnailer.cpp @@ -0,0 +1,61 @@ +#include "CrossLang.hpp" +#include +#include +#include +#include +#include +#include +#include +int main(int argc,char** argv) +{ + std::string p = argv[0]; + auto emptyThumb =Tesses::CrossLang::GetRealExecutablePath(p).GetParent().GetParent() / "share" / "icons" / "crosslang.png"; + + if(argc < 3) + { + std::cout << "USAGE: " << argv[0] << " CRVMFILE NEWPNG" << std::endl; + return 1; + } + std::string crvm = argv[1]; + std::string png = argv[2]; + + Tesses::Framework::Filesystem::LocalFilesystem lfs; + + if(lfs.FileExists(crvm)) + { + + Tesses::CrossLang::TFile file; + auto f = lfs.OpenFile(crvm, "rb"); + + file.Load(nullptr,f); + + delete f; + + if(file.icon >= 0 && file.icon < file.resources.size()) + { + auto f2 = lfs.OpenFile(png, "wb"); + if(f2 != nullptr) + { + auto& icon = file.resources[file.icon]; + f2->WriteBlock(icon.data(),icon.size()); + delete f2; + } + return 0; + + } + + + } + if(lfs.FileExists(emptyThumb)) + { + auto src = lfs.OpenFile(emptyThumb,"rb"); + auto dest = lfs.OpenFile(png,"wb"); + if(src != nullptr && dest != nullptr) + { + src->CopyTo(dest); + } + delete src; + delete dest; + } + return 0; +} \ No newline at end of file diff --git a/src/runtime_methods/io.cpp b/src/runtime_methods/io.cpp index 51d40a7..5ae6233 100644 --- a/src/runtime_methods/io.cpp +++ b/src/runtime_methods/io.cpp @@ -82,11 +82,13 @@ namespace Tesses::CrossLang std::string name; std::string version; std::string info; + std::string icon=""; TVMVersion version2; - if(GetArgumentHeap(args,0,vfs) && GetArgumentHeap(args,1,strm) && GetArgument(args,2,name) && GetArgument(args,3,version) && GetArgument(args,4,info) && TVMVersion::TryParse(version,version2)) + if(GetArgumentHeap(args,0,vfs) && GetArgumentHeap(args,1,strm) && GetArgument(args,2,name) && GetArgument(args,4,info) && ((GetArgument(args,3,version) && TVMVersion::TryParse(version,version2)) || GetArgument(args,3,version2))) { - CrossArchiveCreate(vfs->vfs,strm->stream,name,version2,info); + GetArgument(args,5,icon); + CrossArchiveCreate(vfs->vfs,strm->stream,name,version2,info,icon); } return nullptr; } diff --git a/src/runtime_methods/json.cpp b/src/runtime_methods/json.cpp index 0f810e1..40e983e 100644 --- a/src/runtime_methods/json.cpp +++ b/src/runtime_methods/json.cpp @@ -80,7 +80,7 @@ namespace Tesses::CrossLang return json_null(); } - static TObject Json_Encode(GCList& ls2, std::vector args) + static TObject JsonEncode(GCList& ls2, std::vector args) { if(args.size() >= 1) { @@ -141,7 +141,7 @@ namespace Tesses::CrossLang } return Undefined(); } - static TObject Json_Decode(GCList& ls2,std::vector args) + static TObject JsonDecode(GCList& ls2,std::vector args) { if(args.size() > 0 && std::holds_alternative(args[0])) { @@ -155,6 +155,31 @@ namespace Tesses::CrossLang return Undefined(); } #endif + std::string Json_Encode(TObject o,bool indent) + { + #if defined(CROSSLANG_ENABLE_JSON) + auto json = JsonSerialize(o); + char* txt = json_dumps(json, indent ? JSON_INDENT(4) : 0); + std::string str = txt; + free(txt); + json_decref(json); + return str; + #else + return ""; + #endif + + } + TObject Json_Decode(GCList ls,std::string str) + { + #if defined(CROSSLANG_ENABLE_JSON) + json_t* json = json_loadb(str.c_str(), str.size(),0,NULL); + auto res = JsonDeserialize(ls,json); + json_decref(json); + return res; + #else + return nullptr; + #endif + } void TStd::RegisterJson(GC* gc,TRootEnvironment* env) { @@ -162,8 +187,8 @@ namespace Tesses::CrossLang #if defined(CROSSLANG_ENABLE_JSON) GCList ls(gc); TDictionary* dict = TDictionary::Create(ls); - dict->DeclareFunction(gc, "Decode","Deserialize Json",{"Json string"},Json_Decode); - dict->DeclareFunction(gc, "Encode","Serialize Json",{"any","$indent"},Json_Encode); + dict->DeclareFunction(gc, "Decode","Deserialize Json",{"Json string"},JsonDecode); + dict->DeclareFunction(gc, "Encode","Serialize Json",{"any","$indent"},JsonEncode); gc->BarrierBegin(); diff --git a/src/runtime_methods/net.cpp b/src/runtime_methods/net.cpp index 92495b9..8b38812 100644 --- a/src/runtime_methods/net.cpp +++ b/src/runtime_methods/net.cpp @@ -1,4 +1,10 @@ #include "CrossLang.hpp" +#include +#include +#include +#include +#include +#include #include #include #include @@ -6,8 +12,33 @@ #include using namespace Tesses::Framework::Streams; using namespace Tesses::Framework::Http; +using namespace Tesses::Framework::Mail; namespace Tesses::CrossLang { + static SMTPBody* TObjectToSMTPBody(GCList& ls,std::string mimeType, TObject obj) + { + SMTPBody* body = nullptr; + std::string text; + TByteArray* ba; + TStreamHeapObject* sho; + if(GetObject(obj,text)) + { + body = new SMTPStringBody(text,mimeType); + } + else if(GetObjectHeap(obj,ba)) { + MemoryStream* ms = new MemoryStream(true); + ms->WriteBlock(ba->data.data(), ba->data.size()); + ms->Seek(0L, SeekOrigin::Begin); + + body = new SMTPStreamBody(mimeType,ms,true); + } + else if(GetObjectHeap(obj,sho)) + { + ls.Add(sho); + body = new SMTPStreamBody(mimeType,sho->stream,false); + } + return body; + } TServerHeapObject* TServerHeapObject::Create(GCList& ls, Tesses::Framework::Http::IHttpServer* svr) { TServerHeapObject* ho = new TServerHeapObject(); @@ -157,7 +188,17 @@ namespace Tesses::CrossLang dict->DeclareFunction(gc,"OpenResponseStream","Open Response Stream",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector args2)->TObject { return TStreamHeapObject::Create(ls2, ctx->OpenResponseStream()); }); - + dict->DeclareFunction(gc, "ParseFormData","Parse the form data",{},[ctx](GCList& ls, std::vector args)->TObject { + TCallable* callable; + if(GetArgumentHeap(args, 0, callable)) + { + ctx->ParseFormData([callable,&ls](std::string a,std::string b, std::string c)->Tesses::Framework::Streams::Stream*{ + auto res = callable->Call(ls,{a,b,c}); + return new Tesses::CrossLang::TObjectStream(ls.GetGC(),res); + }); + } + return nullptr; + }); dict->DeclareFunction(gc,"getNeedToParseFormData","Check if Need to parse form data",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector args2)->TObject{ return ctx->NeedToParseFormData(); }); @@ -169,13 +210,13 @@ namespace Tesses::CrossLang dict->DeclareFunction(gc,"SendText","Send response text",{"text"},[ctx](Tesses::CrossLang::GCList &ls2, std::vector args2)->TObject{ std::string text; if(GetArgument(args2,0,text)) - ctx->SendText(text); + ctx->SendText(text); return nullptr; }); dict->DeclareFunction(gc,"WithMimeType","Set mime type",{"mimeType"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector args2)->TObject{ std::string text; if(GetArgument(args2,0,text)) - ctx->WithMimeType(text); + ctx->WithMimeType(text); return dict; }); dict->DeclareFunction(gc,"WithContentDisposition","Set content disposition",{"filename","inline"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector args2)->TObject{ @@ -205,6 +246,11 @@ namespace Tesses::CrossLang ctx->SendBytes(ba->data); return nullptr; }); + dict->DeclareFunction(gc,"WriteHeaders","Send the headers",{},[ctx](GCList& ls, std::vector args)->TObject{ + ctx->WriteHeaders(); + return nullptr; + }); + // dict->DeclareFunction(gc,"getUrlWithQuery","Get original path with query parameters",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector args2)->TObject {return ctx->GetUrlWithQuery();}); dict->DeclareFunction(gc,"StartWebSocketSession","Start websocket session",{"dict"}, [ctx](GCList& ls,std::vector args)->TObject { TDictionary* dict; @@ -582,6 +628,143 @@ namespace Tesses::CrossLang return nullptr; } + + static TObject Net_Smtp_Send(GCList& ls, std::vector args) + { + TDictionary* dict; + if(GetArgumentHeap(args,0,dict)) + { + //the body should be either type text/plain or text/html + //the body and attachment data can also point to bytearray of stream + //server can also be a stream + //as of right now the email is fire and forget (ie no error checking) + //check function return type just in case (this function returns a empty string if no error) + //we rolled our own smtp client + + /* + dict looks like this from crosslang's point of view + { + server = { + host = "smtp.example.com", + tls = true + }, + auth = { + username = "from", + password = "THEPASSWORD" + }, + domain = "example.com", + from = { + name = "The name shown in the mail where it is from", + email = "from@example.com" + }, + to = "to@example.com", + subject = "My little message", + body = { + type = "text/html", + data = "

Hello, world

" + }, + attachments = [ + { + name = "myimg.png", + type = "image/png", + data = embed("myimg.png") + } + ] + } + */ + ls.GetGC()->BarrierBegin(); + auto server = dict->GetValue("server"); + TDictionary* dict2; + Tesses::Framework::Streams::Stream* strm=nullptr; + bool ownsStream=true; + TStreamHeapObject* objStrm; + if(GetObjectHeap(server,dict2)) + { + auto tlsO = dict2->GetValue("tls"); + auto hostO = dict2->GetValue("host"); + auto portO = dict2->GetValue("port"); + std::string host; + bool tls=false; + int64_t port; + GetObject(tlsO,tls); + + if(!GetObject(portO, port)) port = tls ? 465 : 25; + + GetObject(hostO,host); + strm = new NetworkStream(host,(uint16_t)port,false,false,false); + if(tls) + { + strm = new Framework::Crypto::ClientTLSStream(strm,true,true,host); + } + + } + else if (GetObjectHeap(server, objStrm)) { + ownsStream=false; + strm = objStrm->stream; + } + + Tesses::Framework::Mail::SMTPClient client(strm,ownsStream); + auto o = dict->GetValue("domain"); + + GetObject(o,client.domain); + o = dict->GetValue("to"); + GetObject(o,client.to); + o = dict->GetValue("subject"); + GetObject(o,client.subject); + o = dict->GetValue("auth"); + if(GetObjectHeap(o, dict2)) + { + o = dict2->GetValue("username"); + GetObject(o,client.username); + o = dict2->GetValue("password"); + GetObject(o, client.password); + } + o = dict->GetValue("from"); + if(GetObjectHeap(o, dict2)) + { + o = dict2->GetValue("email"); + GetObject(o,client.from); + o = dict2->GetValue("name"); + GetObject(o, client.from_name); + } + o = dict->GetValue("body"); + if(GetObjectHeap(o, dict2)) + { + //type, data + std::string type = "text/plain"; + o = dict2->GetValue("type"); + GetObject(o,type); + o = dict2->GetValue("data"); + client.body = TObjectToSMTPBody(ls,type,o); + } + o = dict->GetValue("attachments"); + TList* als; + if(GetObjectHeap(o,als)) + { + for(int64_t i = 0; i < als->Count(); i++) + { + auto item = als->Get(i); + if(GetObjectHeap(item, dict2)) + { + o = dict2->GetValue("name"); + std::string name; + GetObject(o,name); + std::string type = "text/plain"; + o = dict2->GetValue("type"); + GetObject(o,type); + o = dict2->GetValue("data"); + + client.attachments.push_back(std::pair(name,TObjectToSMTPBody(ls, type, o))); + } + } + } + + ls.GetGC()->BarrierEnd(); + client.Send(); + return ""; + } + return nullptr; + } void TStd::RegisterNet(GC* gc, TRootEnvironment* env) { @@ -591,6 +774,7 @@ namespace Tesses::CrossLang TDictionary* dict = TDictionary::Create(ls); TDictionary* http = TDictionary::Create(ls); + TDictionary* smtp = TDictionary::Create(ls); http->DeclareFunction(gc, "HtmlEncode","Html encode",{"param"}, Net_HtmlEncode); http->DeclareFunction(gc, "UrlEncode","Url encode query param",{"param"}, Net_UrlEncode); @@ -601,6 +785,29 @@ namespace Tesses::CrossLang //http->DeclareFunction(gc, "ProcessServer","Process HTTP server connection",{"networkstream","server","ip","port","encrypted"},, Net_ProcessServer); + http->DeclareFunction(gc, "StreamHttpRequestBody","Create a stream request body",{"stream","mimeType"},[](GCList& ls, std::vector args)->TObject { + std::string mimeType; + if(GetArgument(args, 1, mimeType)) + { + auto res = TNative::Create(ls,new StreamHttpRequestBody(new TObjectStream(ls.GetGC(),args[0]), true, mimeType),[](void* ptr)->void { + delete static_cast(ptr); + }); + return res; + } + return nullptr; + }); + http->DeclareFunction(gc, "TextHttpRequestBody","Create a text request body",{"text","mimeType"},[](GCList& ls, std::vector args)->TObject { + std::string text; + std::string mimeType; + if(GetArgument(args, 0, text) && GetArgument(args, 1, mimeType)) + { + auto res = TNative::Create(ls,new TextHttpRequestBody(text, mimeType),[](void* ptr)->void { + delete static_cast(ptr); + }); + return res; + } + return nullptr; + }); http->DeclareFunction(gc, "MakeRequest", "Create an http request", {"url","$extra"}, Net_Http_MakeRequest); http->DeclareFunction(gc, "ListenSimpleWithLoop", "Listen (creates application loop)", {"server","port"},Net_Http_ListenSimpleWithLoop); //FileServer svr() @@ -626,8 +833,10 @@ namespace Tesses::CrossLang return nullptr; }); dict->DeclareFunction(gc, "NetworkStream","Create a network stream",{"ipv6","datagram"},Net_NetworkStream); + smtp->DeclareFunction(gc, "Send","Send email via smtp server",{"messageStruct"},Net_Smtp_Send); gc->BarrierBegin(); dict->SetValue("Http", http); + dict->SetValue("Smtp", smtp); env->DeclareVariable("Net", dict); gc->BarrierEnd(); } diff --git a/src/runtime_methods/ogc.cpp b/src/runtime_methods/ogc.cpp index b24f442..b7fa9fc 100644 --- a/src/runtime_methods/ogc.cpp +++ b/src/runtime_methods/ogc.cpp @@ -65,5 +65,8 @@ namespace Tesses::CrossLang gc->BarrierEnd(); #endif env->permissions.canRegisterOGC=true; + + + } } \ No newline at end of file diff --git a/src/runtime_methods/std.cpp b/src/runtime_methods/std.cpp index efd8ba1..e7df067 100644 --- a/src/runtime_methods/std.cpp +++ b/src/runtime_methods/std.cpp @@ -118,18 +118,7 @@ namespace Tesses::CrossLang TVFSHeapObject* vfs; return GetArgumentHeap(args,0,vfs); } - static TObject New_Color(GCList& ls, std::vector args) - { - int64_t r,g,b,a; - if(GetArgument(args,0,r) && GetArgument(args,1,g) && GetArgument(args,2,b)) - { - if(!GetArgument(args,3,a)) { - a = 255; - } - return Tesses::Framework::Graphics::Color((uint8_t)r,(uint8_t)g,(uint8_t)b,(uint8_t)a); - } - return Tesses::Framework::Graphics::Colors::Black; - } + static TObject TypeOf(GCList& ls, std::vector args) { if(args.size() < 1) return "Undefined"; @@ -345,6 +334,30 @@ namespace Tesses::CrossLang env->permissions.canRegisterRoot=true; TDictionary* newTypes = TDictionary::Create(ls); + + newTypes->DeclareFunction(gc,"Version","Create a version object",{"$major","$minor","$patch","$build","$stage"},[](GCList& ls, std::vector args)->TObject{ + int64_t major=1; + int64_t minor=0; + int64_t patch=0; + int64_t build=0; + std::string stageS="prod"; + TVMVersionStage stage=TVMVersionStage::ProductionVersion; + GetArgument(args, 0,major); + GetArgument(args, 1,minor); + GetArgument(args, 2,patch); + GetArgument(args, 3,build); + GetArgument(args, 4,stageS); + if(stageS == "dev") + stage = TVMVersionStage::DevVersion; + else if(stageS == "alpha") + stage = TVMVersionStage::AlphaVersion; + else if(stageS == "beta") + stage = TVMVersionStage::BetaVersion; + + return TVMVersion((uint8_t)major,(uint8_t)minor,(uint8_t)patch,(uint16_t)build,stage); + }); + + env->DeclareFunction(gc, "ParseLong","Parse Long from String",{"arg","$base"},ParseLong); env->DeclareFunction(gc, "ParseDouble","Parse Double from String",{"arg"},ParseDouble); env->DeclareFunction(gc, "YieldEmumerable","Turn yield in function into enumerable",{"closure"},YieldEnumerableFunc); @@ -428,8 +441,35 @@ namespace Tesses::CrossLang return Undefined(); }); env->DeclareFunction(gc,"ByteArray","Create bytearray, with optional either size (to size it) or string argument (to fill byte array)",{"$data"},ByteArray); - newTypes->DeclareFunction(gc,"Color","Create a new color",{"red","green","blue","$alpha"},New_Color); gc->BarrierBegin(); + env->DeclareVariable("Version", TDictionary::Create(ls,{ + TDItem("Parse",TExternalMethod::Create(ls,"Parse version from string",{"versionStr"},[](GCList& ls, std::vector args)->TObject{ + std::string str; + if(GetArgument(args, 0, str)) + { + TVMVersion version; + if(TVMVersion::TryParse(str,version)) + { + return version; + } + } + return nullptr; + })), + TDItem("FromByteArray",TExternalMethod::Create(ls,"Create from ByteArray",{"byteArray","$offset"},[](GCList& ls,std::vector args)->TObject { + TByteArray* ba; + if(GetArgumentHeap(args,0, ba)) + { + int64_t offset=0; + GetArgument(args, 1, offset); + if(ba->data.size() < 5) throw VMException("ByteArray too small"); + size_t o = (size_t)offset; + if((o + 5) > ba->data.size() || (o + 5) < 5) throw VMException("ByteArray too small"); + + return TVMVersion(ba->data.data()+o); + } + return nullptr; + })) + })); env->DeclareVariable("InvokeMethod",MethodInvoker()); env->DeclareVariable("New", newTypes); gc->BarrierEnd(); diff --git a/src/runtime_methods/time.cpp b/src/runtime_methods/time.cpp index 95545d9..93a9a35 100644 --- a/src/runtime_methods/time.cpp +++ b/src/runtime_methods/time.cpp @@ -78,29 +78,7 @@ namespace Tesses::CrossLang int64_t msec; if(GetArgument(args,0,msec)) { - if((msec % 100) == 0) - { - msec /= 100; - for(int64_t i = 0; i < msec; i++) - { - usleep(100000); - } - } - else if((msec % 10) == 0) - { - msec /= 10; - for(int64_t i = 0; i < msec; i++) - { - usleep(10000); - } - } - else - { - for(int64_t i = 0; i < msec; i++) - { - usleep(1000); - } - } + usleep(1000*msec); } return nullptr; } diff --git a/src/runtime_methods/vm.cpp b/src/runtime_methods/vm.cpp index 44e8ffe..ef20d92 100644 --- a/src/runtime_methods/vm.cpp +++ b/src/runtime_methods/vm.cpp @@ -134,7 +134,9 @@ namespace Tesses::CrossLang std::vector> sources; TVMVersion version(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE); std::vector> dependencies; + std::vector> tools; std::string info; + std::string icon; TVFSHeapObject* vfsHO =nullptr; ls.GetGC()->BarrierBegin(); @@ -142,17 +144,23 @@ namespace Tesses::CrossLang TObject _version = dict->GetValue("Version"); TObject _sources = dict->GetValue("Sources"); TObject _dependencies = dict->GetValue("Dependencies"); + TObject _tools = dict->GetValue("Tools"); TObject _info = dict->GetValue("Info"); + TObject _icon = dict->GetValue("Icon"); TObject _resourceFileSystem = dict->GetValue("ResourceFileSystem"); TObject _out = dict->GetValue("Output"); + TList* _toolList; TList* _depList; TList* srcLst; GetObject(_name,name); GetObject(_info,info); + GetObject(_icon,icon); GetObjectHeap(_resourceFileSystem, vfsHO); std::string v2; if(GetObject(_version,v2)) TVMVersion::TryParse(v2, version); + else + GetObject(_version,version); if(GetObjectHeap(_dependencies,_depList)) { @@ -172,6 +180,36 @@ namespace Tesses::CrossLang { dependencies.push_back(std::pair(name2, version02)); } + else if(GetObject(_name2,name2) && GetObject(_version2,version02)) + { + dependencies.push_back(std::pair(name2, version02)); + } + } + } + + } + if(GetObjectHeap(_tools,_toolList)) + { + for(int64_t i = 0; i < _toolList->Count(); i++) + { + TObject _dep = _toolList->Get(i); + TDictionary* _depD; + if(GetObjectHeap(_dep, _depD)) + { + TObject _name2 = _depD->GetValue("Name"); + TObject _version2 = _depD->GetValue("Version"); + std::string name2; + std::string version2; + TVMVersion version02; + + if(GetObject(_name2,name2) && GetObject(_version2,version2) && TVMVersion::TryParse(version2,version02)) + { + tools.push_back(std::pair(name2, version02)); + } + else if(GetObject(_name2,name2) && GetObject(_version2,version02)) + { + tools.push_back(std::pair(name2, version02)); + } } } @@ -220,9 +258,11 @@ namespace Tesses::CrossLang CodeGen gen; gen.GenRoot(n); gen.dependencies = dependencies; + gen.tools = tools; gen.info = info; gen.name = name; gen.version = version; + gen.icon = icon; std::string outpath; TStreamHeapObject* stream; if(GetObjectHeap(_out, stream)) @@ -274,7 +314,9 @@ namespace Tesses::CrossLang dict->DeclareFunction(gc, "Compile", "Compile Source",{"dict"},VM_Compile); dict->DeclareFunction(gc, "SourceToAst", "Convert source to ast", {"source"}, VM_SourceToAst); - + dict->DeclareFunction(gc, "getRuntimeVersion","Get the runtime version",{},[](GCList& ls,std::vector args)->TObject { + return TVMVersion(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE); + }); gc->BarrierBegin(); env->DeclareVariable("VM", dict); gc->BarrierEnd(); diff --git a/src/types/closure.cpp b/src/types/closure.cpp index 017396f..8e64a99 100644 --- a/src/types/closure.cpp +++ b/src/types/closure.cpp @@ -32,6 +32,13 @@ namespace Tesses::CrossLang { if(this->marked) return; this->marked = true; this->callable->Mark(); + GC::Mark(this->tag); + } + void TCallable::Mark() + { + if(this->marked) return; + this->marked=true; + GC::Mark(this->tag); } void TClosure::Mark() { @@ -40,7 +47,7 @@ namespace Tesses::CrossLang { this->file->Mark(); this->env->Mark(); this->closure->Mark(); - + GC::Mark(this->tag); } TClosure* TClosure::Create(GCList& ls,TEnvironment* env,TFile* file,uint32_t chunkId,bool ownScope) { diff --git a/src/types/dictionary.cpp b/src/types/dictionary.cpp index e4c599d..b520f6c 100644 --- a/src/types/dictionary.cpp +++ b/src/types/dictionary.cpp @@ -72,6 +72,15 @@ namespace Tesses::CrossLang { return TEnumerator::CreateFromObject(ls,cb->Call(ls,{dict})); } + bool TDictionary::MethodExists(GCList& ls,std::string method) + { + ls.GetGC()->BarrierBegin(); + auto r = this->GetValue(method); + TCallable* callable; + bool res = GetObjectHeap(r,callable); + ls.GetGC()->BarrierEnd(); + return res; + } bool TDynamicDictionary::MethodExists(GCList& ls,std::string name) { auto dict = TDictionary::Create(ls); diff --git a/src/vm/filereader.cpp b/src/vm/filereader.cpp index dc5a02d..a6541bf 100644 --- a/src/vm/filereader.cpp +++ b/src/vm/filereader.cpp @@ -10,6 +10,7 @@ namespace Tesses::CrossLang TFile* TFile::Create(GCList& ls) { TFile* f = new TFile(); + f->icon = -1; GC* _gc = ls.GetGC(); ls.Add(f); _gc->Watch(f); @@ -18,6 +19,7 @@ namespace Tesses::CrossLang TFile* TFile::Create(GCList* ls) { TFile* f = new TFile(); + f->icon=-1; GC* _gc = ls->GetGC(); ls->Add(f); _gc->Watch(f); @@ -91,13 +93,13 @@ namespace Tesses::CrossLang std::string TFile::GetString(Tesses::Framework::Streams::Stream* stream) { uint32_t index=EnsureInt(stream); - if(index > this->strings.size()) throw VMException("String does not exist in TCrossVM file, expected string index: " + std::to_string(index) + ", total strings: " + std::to_string(this->strings.size())); + if(index >= this->strings.size()) throw VMException("String does not exist in TCrossVM file, expected string index: " + std::to_string(index) + ", total strings: " + std::to_string(this->strings.size())); return this->strings[index]; } void TFile::Load(GC* gc, Tesses::Framework::Streams::Stream* stream) { - GCList ls(gc); + uint8_t main_header[18]; Ensure(stream,main_header,sizeof(main_header)); if(strncmp((const char*)main_header,"TCROSSVM",8) != 0) throw VMException("Invalid TCrossVM image."); @@ -133,6 +135,14 @@ namespace Tesses::CrossLang TVMVersion depVersion(version_bytes); this->dependencies.push_back(std::pair(name, depVersion)); } + else if(strncmp(table_name,"TOOL",4) == 0) //compile tools (for package manager) + { + std::string name = GetString(stream); + uint8_t version_bytes[5]; + Ensure(stream,version_bytes,sizeof(version_bytes)); + TVMVersion depVersion(version_bytes); + this->tools.push_back(std::pair(name, depVersion)); + } else if(strncmp(table_name,"RESO",4) == 0) //resources (using embed) { std::vector data; @@ -140,11 +150,13 @@ namespace Tesses::CrossLang Ensure(stream,data.data(), tableLen); this->resources.push_back(data); } - else if(strncmp(table_name,"CHKS",4) == 0) //chunks + else if(strncmp(table_name,"CHKS",4) == 0 && gc != nullptr) //chunks { + GCList ls(gc); size_t chunkCount = (size_t)EnsureInt(stream); for(size_t j = 0; j < chunkCount; j++) { + auto chunk = TFileChunk::Create(ls); chunk->file = this; size_t argCount = (size_t)EnsureInt(stream); @@ -159,6 +171,7 @@ namespace Tesses::CrossLang this->chunks.push_back(chunk); } + } else if(strncmp(table_name,"FUNS",4) == 0) //functions { @@ -187,6 +200,10 @@ namespace Tesses::CrossLang this->strings.push_back(EnsureString(stream)); } } + else if(strncmp(table_name,"ICON",4) == 0) //icon + { + this->icon = (int32_t)EnsureInt(stream); + } else { Skip(stream,tableLen); diff --git a/src/vm/vm.cpp b/src/vm/vm.cpp index 2540cc4..afa327b 100644 --- a/src/vm/vm.cpp +++ b/src/vm/vm.cpp @@ -1,8 +1,11 @@ #include "CrossLang.hpp" +#include +#include #include #include #include #include +#include namespace Tesses::CrossLang { thread_local CallStackEntry* current_function=nullptr; @@ -13,6 +16,11 @@ namespace Tesses::CrossLang { { return true; } + if(std::holds_alternative(obj)) + { + auto v = std::get(obj); + return v.AsLong() != 0; + } if(std::holds_alternative(obj)) { return !std::get(obj).empty(); @@ -192,6 +200,7 @@ namespace Tesses::CrossLang { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); + if(dict != nullptr) { gc->BarrierBegin(); @@ -568,7 +577,13 @@ namespace Tesses::CrossLang { { cse.back()->Push(gc,std::get(left) < std::get(right)); } - + else if(std::holds_alternative(left) && std::holds_alternative(right)) + { + auto lver= std::get(left); + auto rver = std::get(right); + auto r = lver.CompareTo(rver); + cse.back()->Push(gc, r < 0); + } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; @@ -624,7 +639,13 @@ namespace Tesses::CrossLang { { cse.back()->Push(gc,std::get(left) > std::get(right)); } - + else if(std::holds_alternative(left) && std::holds_alternative(right)) + { + auto lver= std::get(left); + auto rver = std::get(right); + auto r = lver.CompareTo(rver); + cse.back()->Push(gc, r > 0); + } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; @@ -680,7 +701,13 @@ namespace Tesses::CrossLang { { cse.back()->Push(gc,std::get(left) <= std::get(right)); } - + else if(std::holds_alternative(left) && std::holds_alternative(right)) + { + auto lver= std::get(left); + auto rver = std::get(right); + auto r = lver.CompareTo(rver); + cse.back()->Push(gc, r <= 0); + } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; @@ -736,7 +763,14 @@ namespace Tesses::CrossLang { { cse.back()->Push(gc,std::get(left) >= std::get(right)); } - + else if(std::holds_alternative(left) && std::holds_alternative(right)) + { + auto lver= std::get(left); + auto rver = std::get(right); + auto r = lver.CompareTo(rver); + cse.back()->Push(gc, r >= 0); + } + else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; @@ -816,7 +850,13 @@ namespace Tesses::CrossLang { { cse.back()->Push(gc,std::get(left) == std::get(right)); } - + else if(std::holds_alternative(left) && std::holds_alternative(right)) + { + auto lver= std::get(left); + auto rver = std::get(right); + auto r = lver.CompareTo(rver); + cse.back()->Push(gc, r == 0); + } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; @@ -903,7 +943,13 @@ namespace Tesses::CrossLang { { cse.back()->Push(gc,std::get(left) != std::get(right)); } - + else if(std::holds_alternative(left) && std::holds_alternative(right)) + { + auto lver= std::get(left); + auto rver = std::get(right); + auto r = lver.CompareTo(rver); + cse.back()->Push(gc, r != 0); + } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; @@ -1373,7 +1419,26 @@ namespace Tesses::CrossLang { { GCList ls(gc); std::regex regex; - if(GetObject(instance,regex)) + TVMVersion version; + if(GetObject(instance, version)) + { + if(key == "ToString") + { + cse.back()->Push(gc, version.ToString()); + return false; + } + if(key == "ToByteArray") + { + TByteArray* ba = TByteArray::Create(ls); + ba->data.resize(5); + version.ToArray(ba->data.data()); + cse.back()->Push(gc,ba); + return false; + } + cse.back()->Push(gc, Undefined()); + return false; + } + else if(GetObject(instance,regex)) { if(key == "Search") { @@ -1682,9 +1747,9 @@ namespace Tesses::CrossLang { { size_t idx = (size_t)idx; if(idx < path.path.size()) - cse.back()->Push(gc, path.path[idx]); + cse.back()->Push(gc, path.path[idx]); else - cse.back()->Push(gc, nullptr); + cse.back()->Push(gc, nullptr); return false; } } @@ -1728,11 +1793,6 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, path.CollapseRelativeParents()); return false; } - if(key == "RelativeCurrentDirectory") - { - cse.back()->Push(gc, path.RelativeCurrentDirectory()); - return false; - } if(key == "IsRelative") { cse.back()->Push(gc, path.relative); @@ -3230,12 +3290,20 @@ namespace Tesses::CrossLang { } else if(list != nullptr) { + if(key == "GetEnumerator") { cse.back()->Push(gc, TListEnumerator::Create(ls,list)); return false; } - if(key == "Insert") + else if(key == "ToString") + { + + cse.back()->Push(gc,Json_Encode(list)); + return false; + + } + else if(key == "Insert") { if(args.size() != 2) { @@ -3344,9 +3412,15 @@ namespace Tesses::CrossLang { } else if(dict != nullptr) { + if(key == "ToString" && !dict->MethodExists(ls, key) && args.empty()) + { + cse.back()->Push(gc,Json_Encode(dict)); + return false; + } gc->BarrierBegin(); auto o = dict->GetValue(key); gc->BarrierEnd(); + return InvokeMethod(ls,o,dict,args); } @@ -3473,7 +3547,57 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, Undefined()); return false; } - + if(std::holds_alternative(instance)) + { + TVMVersion& version = std::get(instance); + if(key == "Major") + { + stk->Push(gc, (int64_t)version.Major()); + return false; + } + if(key == "Minor") + { + stk->Push(gc, (int64_t)version.Minor()); + return false; + } + if(key == "Patch") + { + stk->Push(gc, (int64_t)version.Patch()); + return false; + } + if(key == "Build") + { + stk->Push(gc, (int64_t)version.Build()); + return false; + } + if(key == "VersionInt") + { + stk->Push(gc,(int64_t)version.AsLong()); + return false; + } + if(key == "Stage") + { + switch(version.VersionStage()) + { + case TVMVersionStage::DevVersion: + stk->Push(gc,"dev"); + break; + case TVMVersionStage::AlphaVersion: + stk->Push(gc,"alpha"); + break; + case TVMVersionStage::BetaVersion: + stk->Push(gc,"beta"); + break; + case TVMVersionStage::ProductionVersion: + stk->Push(gc,"prod"); + break; + } + return false; + } + + stk->Push(gc, Undefined()); + return false; + } if(std::holds_alternative(instance)) { auto obj = std::get(instance).obj; @@ -3487,6 +3611,123 @@ namespace Tesses::CrossLang { auto strm = dynamic_cast(obj); auto vfs = dynamic_cast(obj); auto callstackEntry = dynamic_cast(obj); + auto file = dynamic_cast(obj); + auto chunk = dynamic_cast(obj); + + if(file != nullptr) + { + if(key == "Version") + { + cse.back()->Push(gc,file->version); + return false; + } + else if(key == "Name") + { + cse.back()->Push(gc,file->name); + return false; + } + else if(key == "Info") + { + cse.back()->Push(gc, file->info); + return false; + } + else if(key == "Dependencies") + { + auto list = TList::Create(ls); + gc->BarrierBegin(); + for(auto item : file->dependencies) + { + auto res = TDictionary::Create(ls); + res->SetValue("Name", item.first); + res->SetValue("Version", item.second); + list->Add(res); + } + gc->BarrierEnd(); + cse.back()->Push(gc, list); + return false; + } + else if(key == "Tools") + { + auto list = TList::Create(ls); + gc->BarrierBegin(); + for(auto item : file->tools) + { + auto res = TDictionary::Create(ls); + res->SetValue("Name", item.first); + res->SetValue("Version", item.second); + list->Add(res); + } + gc->BarrierEnd(); + cse.back()->Push(gc, list); + return false; + } + else if(key == "Strings") + { + auto list = TList::Create(ls); + gc->BarrierBegin(); + for(auto item : file->name) + { + list->Add(item); + } + gc->BarrierEnd(); + + cse.back()->Push(gc, list); + return false; + } + else if(key == "Chunks") + { + auto list = TList::Create(ls); + gc->BarrierBegin(); + for(auto item : file->chunks) + { + list->Add(item); + } + + gc->BarrierEnd(); + + cse.back()->Push(gc, list); + return false; + } + else if(key == "Functions") + { + auto list = TList::Create(ls); + gc->BarrierBegin(); + for(auto item : file->functions) + { + TDictionary* dict = TDictionary::Create(ls); + if(!item.first.empty()) + dict->SetValue("Documentation", item.first[0]); + TList* nameParts = TList::Create(ls); + for(size_t i = 1; i < item.first.size(); i++) + { + nameParts->Add(item.first[i]); + } + dict->SetValue("NameParts", nameParts); + dict->SetValue("ChunkId", (int64_t)item.second); + + list->Add(dict); + } + + cse.back()->Push(gc, list); + gc->BarrierEnd(); + return false; + } + else if(key == "Icon") + { + if(file->icon >= 0 && file->icon < file->resources.size()) + { + TByteArray* ba = TByteArray::Create(ls); + ba->data = file->resources[file->icon]; + cse.back()->Push(gc, ba); + return false; + } + else { + cse.back()->Push(gc, nullptr); + } + } + cse.back()->Push(gc, Undefined()); + return false; + } if(callstackEntry != nullptr) { @@ -3591,7 +3832,7 @@ namespace Tesses::CrossLang { } if(closure != nullptr) { - if(key == "args") + if(key == "Arguments") { GCList ls2(gc); TList* ls = TList::Create(ls2); @@ -3602,10 +3843,15 @@ namespace Tesses::CrossLang { cse.back()->Push(gc,ls); return false; } + if(key == "File") + { + cse.back()->Push(gc,closure->file); + return false; + } } if(externalMethod != nullptr) { - if(key == "args") + if(key == "Arguments") { GCList ls2(gc); TList* ls = TList::Create(ls2); @@ -3620,11 +3866,18 @@ namespace Tesses::CrossLang { if(tcallable != nullptr) { - if(key == "documentation") + if(key == "Documentation") { cse.back()->Push(gc, tcallable->documentation); return false; } + if(key == "Tag") + { + gc->BarrierBegin(); + cse.back()->Push(gc, tcallable->tag); + gc->BarrierEnd(); + return false; + } cse.back()->Push(gc,Undefined()); return false; } @@ -3703,7 +3956,18 @@ namespace Tesses::CrossLang { auto vfs = dynamic_cast(obj); auto strm = dynamic_cast(obj); auto dict = dynamic_cast(obj); - + auto tcallable = dynamic_cast(obj); + if(tcallable != nullptr) + { + if(key == "Tag") + { + gc->BarrierBegin(); + tcallable->tag = value; + gc->BarrierEnd(); + cse.back()->Push(gc,nullptr); + return false; + } + } if(strm != nullptr) { auto netStrm = dynamic_cast(strm->stream); @@ -4347,6 +4611,28 @@ namespace Tesses::CrossLang { return false; } + bool InterperterThread::PushRelativePath(GC* gc) + { + std::vector& cse=this->call_stack_entries; + + auto stk = cse.back(); + auto p = Framework::Filesystem::VFSPath(); + p.relative=true; + p.path={}; + stk->Push(gc, p); + return false; + } + bool InterperterThread::PushRootPath(GC* gc) + { + std::vector& cse=this->call_stack_entries; + + auto stk = cse.back(); + auto p = Framework::Filesystem::VFSPath(); + p.relative=false; + p.path={}; + stk->Push(gc, p); + return false; + } bool InterperterThread::Illegal(GC* gc) { @@ -4373,7 +4659,7 @@ namespace Tesses::CrossLang { if(!cse.empty()) { auto stk = cse.back(); - + current_function = stk; @@ -4675,7 +4961,7 @@ namespace Tesses::CrossLang { ls.GetGC()->BarrierBegin(); CallStackEntry* cse = CallStackEntry::Create(ls); cse->callable = closure; - cse->env = closure->chunkId == 0 ? closure->env : closure->env->GetSubEnvironment(ls); + cse->env = closure->chunkId == 0 ? closure->env : closure->ownScope ? closure->env->GetSubEnvironment(ls) : closure->env; cse->ip = 0; if(closure->closure->args.empty() && closure->chunkId != 0) { @@ -4717,7 +5003,7 @@ namespace Tesses::CrossLang { }; size_t required = requiredArguments(); - if(args.size() < requiredArguments()) + if(args.size() < required) { throw VMException("Called a function that expected at least " + std::to_string(required) + " args but got " + std::to_string(args.size())); } @@ -4729,10 +5015,11 @@ namespace Tesses::CrossLang { } if(i == closure->closure->args.size()-1) { + auto argName = closure->closure->args[i]; auto lsArgs = TList::Create(ls); for(;iAdd(args[i]); - cse->env->DeclareVariable(trimStart(closure->closure->args[i]), lsArgs); + cse->env->DeclareVariable(trimStart(argName), lsArgs); i = args.size(); } if(i(o); } + if(std::holds_alternative(o)) + { + return std::get(o).ToString(); + } if(std::holds_alternative(o)) { return std::to_string(std::get(o)); @@ -4786,14 +5077,28 @@ namespace Tesses::CrossLang { { auto obj = std::get(o).obj; auto dict = dynamic_cast(obj); + auto list = dynamic_cast(obj); + auto bArray = dynamic_cast(obj); if(dict != nullptr) { - GCList ls(gc); + GCList ls(gc); + if(dict->MethodExists(ls,"ToString")) return ToString(gc,dict->CallMethod(ls,"ToString",{})); - + else + { + return Json_Encode(dict); + } + } + else if(bArray != nullptr) + { + return std::string(bArray->data.begin(),bArray->data.end()); + } + else if(list != nullptr) + { + return Json_Encode(list); } } return ""; } -} \ No newline at end of file +} diff --git a/src/vm/vm_opcode_table.h b/src/vm/vm_opcode_table.h index aca5128..9f7b35e 100644 --- a/src/vm/vm_opcode_table.h +++ b/src/vm/vm_opcode_table.h @@ -1,3 +1,3 @@ #if defined(VM_OPCODE_TABLE_INLINE) -static opcode opcodes[256]={&InterperterThread::Add, &InterperterThread::Sub, &InterperterThread::Times, &InterperterThread::Divide, &InterperterThread::Mod, &InterperterThread::LShift, &InterperterThread::RShift, &InterperterThread::BOr, &InterperterThread::BAnd, &InterperterThread::BNot, &InterperterThread::Lt, &InterperterThread::Gt, &InterperterThread::Lte, &InterperterThread::Gte, &InterperterThread::Eq, &InterperterThread::NEq, &InterperterThread::LNot, &InterperterThread::Neg, &InterperterThread::XOr, &InterperterThread::Pop, &InterperterThread::Dup,&InterperterThread::Nop, &InterperterThread::PushClosure, &InterperterThread::CreateDictionary, &InterperterThread::CreateArray, &InterperterThread::AppendList, &InterperterThread::AppendDictionary, &InterperterThread::PushResource, &InterperterThread::PushLong, &InterperterThread::PushChar, &InterperterThread::PushDouble, &InterperterThread::PushString, &InterperterThread::PushNull, &InterperterThread::PushUndefined, &InterperterThread::ScopeBegin, &InterperterThread::ScopeEnd, &InterperterThread::ScopeEndTimes, &InterperterThread::PushFalse, &InterperterThread::PushTrue, &InterperterThread::SetVariable, &InterperterThread::GetVariable, &InterperterThread::DeclareVariable, &InterperterThread::SetField, &InterperterThread::GetField, &InterperterThread::ExecuteFunction, &InterperterThread::ExecuteMethod, &InterperterThread::Return, &InterperterThread::JumpConditional, &InterperterThread::Jump, &InterperterThread::JumpUndefined, &InterperterThread::Defer, &InterperterThread::TryCatch, &InterperterThread::Throw, &InterperterThread::PushScopelessClosure, &InterperterThread::Yield, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal}; +static opcode opcodes[256]={&InterperterThread::Add, &InterperterThread::Sub, &InterperterThread::Times, &InterperterThread::Divide, &InterperterThread::Mod, &InterperterThread::LShift, &InterperterThread::RShift, &InterperterThread::BOr, &InterperterThread::BAnd, &InterperterThread::BNot, &InterperterThread::Lt, &InterperterThread::Gt, &InterperterThread::Lte, &InterperterThread::Gte, &InterperterThread::Eq, &InterperterThread::NEq, &InterperterThread::LNot, &InterperterThread::Neg, &InterperterThread::XOr, &InterperterThread::Pop, &InterperterThread::Dup,&InterperterThread::Nop, &InterperterThread::PushClosure, &InterperterThread::CreateDictionary, &InterperterThread::CreateArray, &InterperterThread::AppendList, &InterperterThread::AppendDictionary, &InterperterThread::PushResource, &InterperterThread::PushLong, &InterperterThread::PushChar, &InterperterThread::PushDouble, &InterperterThread::PushString, &InterperterThread::PushNull, &InterperterThread::PushUndefined, &InterperterThread::ScopeBegin, &InterperterThread::ScopeEnd, &InterperterThread::ScopeEndTimes, &InterperterThread::PushFalse, &InterperterThread::PushTrue, &InterperterThread::SetVariable, &InterperterThread::GetVariable, &InterperterThread::DeclareVariable, &InterperterThread::SetField, &InterperterThread::GetField, &InterperterThread::ExecuteFunction, &InterperterThread::ExecuteMethod, &InterperterThread::Return, &InterperterThread::JumpConditional, &InterperterThread::Jump, &InterperterThread::JumpUndefined, &InterperterThread::Defer, &InterperterThread::TryCatch, &InterperterThread::Throw, &InterperterThread::PushScopelessClosure, &InterperterThread::Yield, &InterperterThread::PushRootPath, &InterperterThread::PushRelativePath, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal}; #endif \ No newline at end of file