Add thumbnailer support and TVMVersion and TFile are now accessable from language

This commit is contained in:
2025-03-28 22:01:56 -05:00
parent 0a87476cfa
commit 0af37d2b9f
29 changed files with 1706 additions and 101 deletions

2
.clangd Normal file
View File

@ -0,0 +1,2 @@
CompileFlags: # Tweak the parse settings, example directory given to show format
Add: ["-Iinclude"]

View File

@ -75,5 +75,8 @@
"thread": "cpp",
"bitset": "cpp",
"regex": "cpp"
}
},
"clangd.fallbackFlags": [
"-Iinclude"
]
}

View File

@ -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 <tesses@tesses.net>")

View File

@ -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)

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

4
crosslang.thumbnailer Normal file
View File

@ -0,0 +1,4 @@
[Thumbnailer Entry]
TryExec=crossthumbnailer
Exec=crossthumbnailer %i %o
MimeType=application/crvm;

17
crosslang.xml Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/crvm">
<sub-class-of type="application/octet-stream"/>
<comment>CrossLang Executable</comment>
<comment xml:lang="en">CrossLang Executable</comment>
<glob pattern="*.crvm"/>
<icon name="crosslang"/>
</mime-type>
<mime-type type="text/tcross">
<sub-class-of type="text/plain"/>
<comment>CrossLang Source</comment>
<comment xml:lang="en">CrossLang Source</comment>
<glob pattern="*.tcross"/>
<icon name="crosslang"/>
</mime-type>
</mime-info>

563
docs/README.md Normal file
View File

@ -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();
```

View File

@ -1,5 +1,6 @@
#pragma once
#include <cstddef>
#include <initializer_list>
#include <vector>
#include <cstdint>
#include <string>
@ -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::pair<std::string,TVMVersion>,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<std::string> strs;
std::vector<std::string> res;
std::vector<std::pair<std::vector<uint32_t>, std::vector<ByteCodeInstruction*>>> chunks;
std::vector<std::pair<std::vector<uint32_t>,uint32_t>> funcs;
std::vector<ObjectEntry> objectEntries;
@ -509,9 +522,11 @@ class CodeGen {
void GenPop(std::vector<ByteCodeInstruction*>& instrs,SyntaxNode n);
public:
std::vector<std::pair<std::string, TVMVersion>> dependencies;
std::vector<std::pair<std::string, TVMVersion>> 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<int64_t,double,char,bool,std::string,std::regex,Tesses::Framework::Filesystem::VFSPath,std::nullptr_t,Undefined,MethodInvoker,THeapObjectHolder,Tesses::Framework::Graphics::Color>;
using TObject = std::variant<int64_t,double,char,bool,std::string,std::regex,Tesses::Framework::Filesystem::VFSPath,std::nullptr_t,Undefined,MethodInvoker,THeapObjectHolder,TVMVersion>;
class TRootEnvironment;
class GC;
class GC {
@ -739,7 +755,6 @@ class GC {
TFile* file;
std::vector<uint8_t> code;
std::vector<std::string> args;
std::string name;
void Mark();
};
@ -764,10 +779,12 @@ class GC {
std::vector<std::string> strings;
std::vector<std::pair<std::vector<std::string>, uint32_t>> functions;
std::vector<std::pair<std::string,TVMVersion>> dependencies;
std::vector<std::pair<std::string,TVMVersion>> tools;
std::vector<std::vector<uint8_t>> 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<TObject> items;
static TList* Create(GCList* gc);
static TList* Create(GCList& gc);
template<typename Itterator>
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<typename Itterator>
static TList* Create(GCList& gc, Itterator begin, Itterator end)
{
return Create(&gc,begin,end);
}
static TList* Create(GCList* gc, std::initializer_list<TObject> il)
{
return Create(gc,il.begin(),il.end());
}
static TList* Create(GCList& gc, std::initializer_list<TObject> 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<std::string, TObject>;
class TDictionary : public THeapObject
{
@ -803,8 +846,38 @@ class GC {
std::unordered_map<std::string,TObject> items;
static TDictionary* Create(GCList* gc);
static TDictionary* Create(GCList& gc);
template<typename Itterator>
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<typename Itterator>
static TDictionary* Create(GCList& gc, Itterator begin, Itterator end)
{
return Create(&gc,begin,end);
}
static TDictionary* Create(GCList* gc, std::initializer_list<TDItem> il)
{
return Create(gc,il.begin(),il.end());
}
static TDictionary* Create(GCList& gc, std::initializer_list<TDItem> 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<TObject> 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);
};

View File

@ -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<std::string> 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)

View File

@ -103,14 +103,14 @@ static json_t* Serialize2(SyntaxNode node)
{
char c = std::get<char>(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<Undefined>(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;
}

View File

@ -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;
@ -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];

View File

@ -1,5 +1,6 @@
#include "CrossLang.hpp"
#include <iostream>
#include <stdexcept>
namespace Tesses::CrossLang
{
std::string LexTokenType_ToString(LexTokenType t)
@ -138,6 +139,7 @@ namespace Tesses::CrossLang
node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{});
else
node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{ParseExpression()});
EnsureSymbol("}");
}
else if(IsSymbol("("))
@ -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<SyntaxNode> 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"))
{

View File

@ -8,6 +8,7 @@ void Help(const char* filename)
printf("USAGE: %s [OPTIONS] <dirasroot> <archive.crvm>\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<std::string> 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;
}

View File

@ -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<std::filesystem::path> source;
std::filesystem::path resourceDir = std::filesystem::current_path() / "res";
std::vector<std::pair<std::string, TVMVersion>> dependencies;
std::vector<std::pair<std::string, TVMVersion>> 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<std::string,TVMVersion>(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);
{

View File

@ -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++)
{

61
src/crossthumbnailer.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "CrossLang.hpp"
#include <TessesFramework/Common.hpp>
#include <TessesFramework/Filesystem/LocalFS.hpp>
#include <TessesFramework/Filesystem/VFS.hpp>
#include <TessesFramework/Streams/Stream.hpp>
#include <ios>
#include <iostream>
#include <fstream>
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;
}

View File

@ -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;
}

View File

@ -80,7 +80,7 @@ namespace Tesses::CrossLang
return json_null();
}
static TObject Json_Encode(GCList& ls2, std::vector<TObject> args)
static TObject JsonEncode(GCList& ls2, std::vector<TObject> args)
{
if(args.size() >= 1)
{
@ -141,7 +141,7 @@ namespace Tesses::CrossLang
}
return Undefined();
}
static TObject Json_Decode(GCList& ls2,std::vector<TObject> args)
static TObject JsonDecode(GCList& ls2,std::vector<TObject> args)
{
if(args.size() > 0 && std::holds_alternative<std::string>(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();

View File

@ -1,4 +1,10 @@
#include "CrossLang.hpp"
#include <TessesFramework/Crypto/ClientTLSStream.hpp>
#include <TessesFramework/Http/HttpClient.hpp>
#include <TessesFramework/Mail/Smtp.hpp>
#include <TessesFramework/Streams/MemoryStream.hpp>
#include <TessesFramework/Streams/NetworkStream.hpp>
#include <TessesFramework/Streams/Stream.hpp>
#include <sys/types.h>
#include <csignal>
#include <iostream>
@ -6,8 +12,33 @@
#include <cstring>
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<Tesses::CrossLang::TObject> args2)->TObject {
return TStreamHeapObject::Create(ls2, ctx->OpenResponseStream());
});
dict->DeclareFunction(gc, "ParseFormData","Parse the form data",{},[ctx](GCList& ls, std::vector<TObject> 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<Tesses::CrossLang::TObject> args2)->TObject{
return ctx->NeedToParseFormData();
});
@ -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<TObject> args)->TObject{
ctx->WriteHeaders();
return nullptr;
});
// dict->DeclareFunction(gc,"getUrlWithQuery","Get original path with query parameters",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {return ctx->GetUrlWithQuery();});
dict->DeclareFunction(gc,"StartWebSocketSession","Start websocket session",{"dict"}, [ctx](GCList& ls,std::vector<TObject> args)->TObject {
TDictionary* dict;
@ -583,6 +629,143 @@ namespace Tesses::CrossLang
return nullptr;
}
static TObject Net_Smtp_Send(GCList& ls, std::vector<TObject> 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 = "<h1>Hello, world</h1>"
},
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<std::string,SMTPBody*>(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<TObject> 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<StreamHttpRequestBody*>(ptr);
});
return res;
}
return nullptr;
});
http->DeclareFunction(gc, "TextHttpRequestBody","Create a text request body",{"text","mimeType"},[](GCList& ls, std::vector<TObject> 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<TextHttpRequestBody*>(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();
}

View File

@ -65,5 +65,8 @@ namespace Tesses::CrossLang
gc->BarrierEnd();
#endif
env->permissions.canRegisterOGC=true;
}
}

View File

@ -118,18 +118,7 @@ namespace Tesses::CrossLang
TVFSHeapObject* vfs;
return GetArgumentHeap(args,0,vfs);
}
static TObject New_Color(GCList& ls, std::vector<TObject> 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<TObject> 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<TObject> 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<TObject> 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<TObject> 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();

View File

@ -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;
}

View File

@ -134,7 +134,9 @@ namespace Tesses::CrossLang
std::vector<std::pair<std::string,std::string>> sources;
TVMVersion version(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE);
std::vector<std::pair<std::string,TVMVersion>> dependencies;
std::vector<std::pair<std::string,TVMVersion>> 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<std::string>(_name,name);
GetObject<std::string>(_info,info);
GetObject<std::string>(_icon,icon);
GetObjectHeap(_resourceFileSystem, vfsHO);
std::string v2;
if(GetObject<std::string>(_version,v2))
TVMVersion::TryParse(v2, version);
else
GetObject(_version,version);
if(GetObjectHeap<TList*>(_dependencies,_depList))
{
@ -172,6 +180,36 @@ namespace Tesses::CrossLang
{
dependencies.push_back(std::pair<std::string,TVMVersion>(name2, version02));
}
else if(GetObject<std::string>(_name2,name2) && GetObject(_version2,version02))
{
dependencies.push_back(std::pair<std::string,TVMVersion>(name2, version02));
}
}
}
}
if(GetObjectHeap<TList*>(_tools,_toolList))
{
for(int64_t i = 0; i < _toolList->Count(); i++)
{
TObject _dep = _toolList->Get(i);
TDictionary* _depD;
if(GetObjectHeap<TDictionary*>(_dep, _depD))
{
TObject _name2 = _depD->GetValue("Name");
TObject _version2 = _depD->GetValue("Version");
std::string name2;
std::string version2;
TVMVersion version02;
if(GetObject<std::string>(_name2,name2) && GetObject<std::string>(_version2,version2) && TVMVersion::TryParse(version2,version02))
{
tools.push_back(std::pair<std::string,TVMVersion>(name2, version02));
}
else if(GetObject<std::string>(_name2,name2) && GetObject(_version2,version02))
{
tools.push_back(std::pair<std::string,TVMVersion>(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<TStreamHeapObject*>(_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<TObject> args)->TObject {
return TVMVersion(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE);
});
gc->BarrierBegin();
env->DeclareVariable("VM", dict);
gc->BarrierEnd();

View File

@ -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)
{

View File

@ -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);

View File

@ -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<std::string,TVMVersion>(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<std::string,TVMVersion>(name, depVersion));
}
else if(strncmp(table_name,"RESO",4) == 0) //resources (using embed)
{
std::vector<uint8_t> 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);

View File

@ -1,8 +1,11 @@
#include "CrossLang.hpp"
#include <TessesFramework/Filesystem/VFS.hpp>
#include <cstddef>
#include <iostream>
#include <cmath>
#include <cstring>
#include <sstream>
#include <variant>
namespace Tesses::CrossLang {
thread_local CallStackEntry* current_function=nullptr;
@ -13,6 +16,11 @@ namespace Tesses::CrossLang {
{
return true;
}
if(std::holds_alternative<TVMVersion>(obj))
{
auto v = std::get<TVMVersion>(obj);
return v.AsLong() != 0;
}
if(std::holds_alternative<std::string>(obj))
{
return !std::get<std::string>(obj).empty();
@ -192,6 +200,7 @@ namespace Tesses::CrossLang {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary*>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
if(dict != nullptr)
{
gc->BarrierBegin();
@ -568,7 +577,13 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc,std::get<int64_t>(left) < std::get<double>(right));
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r < 0);
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
@ -624,7 +639,13 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc,std::get<int64_t>(left) > std::get<double>(right));
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r > 0);
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
@ -680,7 +701,13 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc,std::get<int64_t>(left) <= std::get<double>(right));
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r <= 0);
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
@ -736,6 +763,13 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc,std::get<int64_t>(left) >= std::get<double>(right));
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r >= 0);
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
@ -816,7 +850,13 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc,std::get<char>(left) == std::get<char>(right));
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r == 0);
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
@ -903,7 +943,13 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc,std::get<char>(left) != std::get<char>(right));
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r != 0);
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(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")
{
@ -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,10 +3412,16 @@ 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);
}
else if(callable != nullptr)
@ -3473,7 +3547,57 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, Undefined());
return false;
}
if(std::holds_alternative<TVMVersion>(instance))
{
TVMVersion& version = std::get<TVMVersion>(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<THeapObjectHolder>(instance))
{
auto obj = std::get<THeapObjectHolder>(instance).obj;
@ -3487,6 +3611,123 @@ namespace Tesses::CrossLang {
auto strm = dynamic_cast<TStreamHeapObject*>(obj);
auto vfs = dynamic_cast<TVFSHeapObject*>(obj);
auto callstackEntry = dynamic_cast<CallStackEntry*>(obj);
auto file = dynamic_cast<TFile*>(obj);
auto chunk = dynamic_cast<TFileChunk*>(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<TVFSHeapObject*>(obj);
auto strm = dynamic_cast<TStreamHeapObject*>(obj);
auto dict = dynamic_cast<TDictionary*>(obj);
auto tcallable = dynamic_cast<TCallable*>(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<Tesses::Framework::Streams::NetworkStream*>(strm->stream);
@ -4347,6 +4611,28 @@ namespace Tesses::CrossLang {
return false;
}
bool InterperterThread::PushRelativePath(GC* gc)
{
std::vector<CallStackEntry*>& 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<CallStackEntry*>& 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(;i<args.size(); i++)
lsArgs->Add(args[i]);
cse->env->DeclareVariable(trimStart(closure->closure->args[i]), lsArgs);
cse->env->DeclareVariable(trimStart(argName), lsArgs);
i = args.size();
}
if(i<args.size())
@ -4755,6 +5042,10 @@ namespace Tesses::CrossLang {
{
return std::get<std::string>(o);
}
if(std::holds_alternative<TVMVersion>(o))
{
return std::get<TVMVersion>(o).ToString();
}
if(std::holds_alternative<int64_t>(o))
{
return std::to_string(std::get<int64_t>(o));
@ -4786,11 +5077,25 @@ namespace Tesses::CrossLang {
{
auto obj = std::get<THeapObjectHolder>(o).obj;
auto dict = dynamic_cast<TDictionary*>(obj);
auto list = dynamic_cast<TList*>(obj);
auto bArray = dynamic_cast<TByteArray*>(obj);
if(dict != nullptr)
{
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);
}
}

File diff suppressed because one or more lines are too long