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", "thread": "cpp",
"bitset": "cpp", "bitset": "cpp",
"regex": "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(crosslang src/crosslang.cpp ${CROSSLANG_WIN32_EXE_SRC})
add_executable(crossarchiveextract src/crossarchiveextract.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(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(crossc PUBLIC crosslang_shared)
target_link_libraries(crossvm PUBLIC crosslang_shared) target_link_libraries(crossvm PUBLIC crosslang_shared)
target_link_libraries(crossint 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(crosslang PUBLIC crosslang_shared)
target_link_libraries(crossarchiveextract PUBLIC crosslang_shared) target_link_libraries(crossarchiveextract PUBLIC crosslang_shared)
target_link_libraries(crossarchivecreate PUBLIC crosslang_shared) target_link_libraries(crossarchivecreate PUBLIC crosslang_shared)
target_link_libraries(crossthumbnailer PUBLIC crosslang_shared)
elseif(CROSSLANG_ENABLE_STATIC) elseif(CROSSLANG_ENABLE_STATIC)
add_executable(crossc src/crosslangcompiler.cpp ${CROSSLANG_WIN32_EXE_SRC}) 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(crosslang src/crosslang.cpp ${CROSSLANG_WIN32_EXE_SRC})
add_executable(crossarchiveextract src/crossarchiveextract.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(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(crossc PUBLIC crosslang_static)
target_link_libraries(crossvm PUBLIC crosslang_static) target_link_libraries(crossvm PUBLIC crosslang_static)
target_link_libraries(crossint 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(crosslang PUBLIC crosslang_static)
target_link_libraries(crossarchiveextract PUBLIC crosslang_static) target_link_libraries(crossarchiveextract PUBLIC crosslang_static)
target_link_libraries(crossarchivecreate PUBLIC crosslang_static) target_link_libraries(crossarchivecreate PUBLIC crosslang_static)
target_link_libraries(crossthumbnailer PUBLIC crosslang_static)
else() else()
add_executable(crossc src/crosslangcompiler.cpp ${CROSSLANG_SOURCE} ${CROSSLANG_WIN32_EXE_SRC}) add_executable(crossc src/crosslangcompiler.cpp ${CROSSLANG_SOURCE} ${CROSSLANG_WIN32_EXE_SRC})
add_executable(crossvm src/crosslangvm.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(crosslang src/crosslang.cpp ${CROSSLANG_SOURCE} ${CROSSLANG_WIN32_EXE_SRC})
add_executable(crossarchiveextract src/crossarchiveextract.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(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(crossc)
CROSSLANG_LINK_DEPS(crossvm) CROSSLANG_LINK_DEPS(crossvm)
CROSSLANG_LINK_DEPS(crossint) CROSSLANG_LINK_DEPS(crossint)
@ -241,6 +247,7 @@ CROSSLANG_LINK_DEPS(crosslang)
CROSSLANG_LINK_DEPS(crossdump) CROSSLANG_LINK_DEPS(crossdump)
CROSSLANG_LINK_DEPS(crossarchiveextract) CROSSLANG_LINK_DEPS(crossarchiveextract)
CROSSLANG_LINK_DEPS(crossarchivecreate) CROSSLANG_LINK_DEPS(crossarchivecreate)
CROSSLANG_LINK_DEPS(crossthumbnailer)
endif() endif()
install(TARGETS crossc DESTINATION bin) install(TARGETS crossc DESTINATION bin)
install(TARGETS crossvm DESTINATION bin) install(TARGETS crossvm DESTINATION bin)
@ -249,10 +256,18 @@ install(TARGETS crossdump DESTINATION bin)
install(TARGETS crosslang DESTINATION bin) install(TARGETS crosslang DESTINATION bin)
install(TARGETS crossarchiveextract DESTINATION bin) install(TARGETS crossarchiveextract DESTINATION bin)
install(TARGETS crossarchivecreate 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" 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_DESTINATION ${CMAKE_INSTALL_LIBDIR}/binfmt.d)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/crossvm-binfmt.conf" install(FILES "${CMAKE_CURRENT_BINARY_DIR}/crossvm-binfmt.conf"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/binfmt.d) 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() endif()
include(InstallRequiredSystemLibraries) include(InstallRequiredSystemLibraries)
set(CPACK_PACKAGE_CONTACT "Mike Nolan <tesses@tesses.net>") set(CPACK_PACKAGE_CONTACT "Mike Nolan <tesses@tesses.net>")

View File

@ -1,7 +1,7 @@
Tesses Cross Language Tesses Cross Language
===================== =====================
![CrossImage](logo.png) ![CrossImage](crosslang.png)
## What is required to build this project ## What is required to build this project
- [TessesFramework](https://onedev.site.tesses.net/tesses-framework) - [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 #pragma once
#include <cstddef> #include <cstddef>
#include <initializer_list>
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
@ -144,6 +145,15 @@ namespace Tesses::CrossLang {
if(this->build < version.build) return -1; if(this->build < version.build) return -1;
return 0; 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() int CompareToRuntime()
{ {
TVMVersion version(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE); 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); 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, TRYCATCH,
THROW, THROW,
PUSHSCOPELESSCLOSURE, PUSHSCOPELESSCLOSURE,
YIELD YIELD,
PUSHROOTPATH,
PUSHRELATIVEPATH
} Instruction; } Instruction;
class ByteCodeInstruction { class ByteCodeInstruction {
@ -502,6 +514,7 @@ class CodeGen {
uint32_t GetResource(std::string res); uint32_t GetResource(std::string res);
std::vector<std::string> strs; std::vector<std::string> strs;
std::vector<std::string> res; 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>, std::vector<ByteCodeInstruction*>>> chunks;
std::vector<std::pair<std::vector<uint32_t>,uint32_t>> funcs; std::vector<std::pair<std::vector<uint32_t>,uint32_t>> funcs;
std::vector<ObjectEntry> objectEntries; std::vector<ObjectEntry> objectEntries;
@ -509,9 +522,11 @@ class CodeGen {
void GenPop(std::vector<ByteCodeInstruction*>& instrs,SyntaxNode n); void GenPop(std::vector<ByteCodeInstruction*>& instrs,SyntaxNode n);
public: public:
std::vector<std::pair<std::string, TVMVersion>> dependencies; std::vector<std::pair<std::string, TVMVersion>> dependencies;
std::vector<std::pair<std::string, TVMVersion>> tools;
TVMVersion version; TVMVersion version;
std::string name; std::string name;
std::string info; std::string info;
std::string icon;
void GenRoot(SyntaxNode n); void GenRoot(SyntaxNode n);
void Save(Tesses::Framework::Filesystem::VFS* embedFS,Tesses::Framework::Streams::Stream* output); void Save(Tesses::Framework::Filesystem::VFS* embedFS,Tesses::Framework::Streams::Stream* output);
~CodeGen(); ~CodeGen();
@ -589,7 +604,8 @@ constexpr std::string_view DefaultStatement = "defaultStatement";
constexpr std::string_view ObjectStatement = "objectStatement"; constexpr std::string_view ObjectStatement = "objectStatement";
constexpr std::string_view StaticStatement = "staticStatement"; constexpr std::string_view StaticStatement = "staticStatement";
constexpr std::string_view MethodDeclaration = "methodDeclaration"; constexpr std::string_view MethodDeclaration = "methodDeclaration";
constexpr std::string_view RootPathExpression = "rootPathExpression";
constexpr std::string_view RelativePathExpression = "relativePathExpression";
class AdvancedSyntaxNode { class AdvancedSyntaxNode {
public: public:
@ -675,7 +691,7 @@ class Parser {
class MethodInvoker { 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 TRootEnvironment;
class GC; class GC;
class GC { class GC {
@ -739,7 +755,6 @@ class GC {
TFile* file; TFile* file;
std::vector<uint8_t> code; std::vector<uint8_t> code;
std::vector<std::string> args; std::vector<std::string> args;
std::string name;
void Mark(); void Mark();
}; };
@ -764,10 +779,12 @@ class GC {
std::vector<std::string> strings; std::vector<std::string> strings;
std::vector<std::pair<std::vector<std::string>, uint32_t>> functions; 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>> dependencies;
std::vector<std::pair<std::string,TVMVersion>> tools;
std::vector<std::vector<uint8_t>> resources; std::vector<std::vector<uint8_t>> resources;
std::string name; std::string name;
TVMVersion version; TVMVersion version;
std::string info; std::string info;
int32_t icon;
void Load(GC* gc, Tesses::Framework::Streams::Stream* strm); void Load(GC* gc, Tesses::Framework::Streams::Stream* strm);
void Skip(Tesses::Framework::Streams::Stream* strm,size_t len); void Skip(Tesses::Framework::Streams::Stream* strm,size_t len);
@ -785,6 +802,32 @@ class GC {
std::vector<TObject> items; std::vector<TObject> items;
static TList* Create(GCList* gc); static TList* Create(GCList* gc);
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 int64_t Count();
virtual TObject Get(int64_t index); virtual TObject Get(int64_t index);
virtual void Set(int64_t index, TObject value); virtual void Set(int64_t index, TObject value);
@ -795,7 +838,7 @@ class GC {
virtual void Mark(); virtual void Mark();
}; };
using TDItem = std::pair<std::string, TObject>;
class TDictionary : public THeapObject class TDictionary : public THeapObject
{ {
@ -803,8 +846,38 @@ class GC {
std::unordered_map<std::string,TObject> items; std::unordered_map<std::string,TObject> items;
static TDictionary* Create(GCList* gc); static TDictionary* Create(GCList* gc);
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 HasValue(std::string key);
virtual bool MethodExists(GCList& ls,std::string key);
virtual TObject GetValue(std::string key); virtual TObject GetValue(std::string key);
virtual void SetValue(std::string key, TObject value); virtual void SetValue(std::string key, TObject value);
virtual void Mark(); virtual void Mark();
@ -823,8 +896,10 @@ class GC {
class TCallable : public THeapObject class TCallable : public THeapObject
{ {
public: public:
TObject tag;
std::string documentation; std::string documentation;
virtual TObject Call(GCList& ls,std::vector<TObject> args)=0; virtual TObject Call(GCList& ls,std::vector<TObject> args)=0;
virtual void Mark();
}; };
@ -978,6 +1053,7 @@ class GC {
this->marked=true; this->marked=true;
for(auto item : watch) for(auto item : watch)
GC::Mark(item); GC::Mark(item);
GC::Mark(this->tag);
} }
}; };
@ -1309,6 +1385,8 @@ class GC {
bool CreateArray(GC* gc); bool CreateArray(GC* gc);
bool AppendList(GC* gc); bool AppendList(GC* gc);
bool AppendDictionary(GC* gc); bool AppendDictionary(GC* gc);
bool PushRootPath(GC* gc);
bool PushRelativePath(GC* gc);
bool Pop(GC* gc); bool Pop(GC* gc);
bool Dup(GC* gc); bool Dup(GC* gc);
bool Nop(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); } #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); 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 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::vector<std::string> ignored_files;
std::string file = "/.crossarchiveignore"; std::string file = "/.crossarchiveignore";
@ -125,6 +125,8 @@ namespace Tesses::CrossLang
}; };
walkFS(std::string("/")); walkFS(std::string("/"));
if(!icon.empty())
ensureResource(icon);
uint8_t main_header[18]; uint8_t main_header[18];
memcpy(main_header,"TCROSSVM",8); memcpy(main_header,"TCROSSVM",8);
@ -132,7 +134,7 @@ namespace Tesses::CrossLang
rtVersion.ToArray(main_header+8); rtVersion.ToArray(main_header+8);
version.ToArray(main_header+13); version.ToArray(main_header+13);
strm->WriteBlock(main_header,sizeof(main_header)); 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); strm->WriteBlock((const uint8_t*)"STRS",4);
uint32_t sz=4; uint32_t sz=4;
for(auto str : strs) for(auto str : strs)

View File

@ -103,14 +103,14 @@ static json_t* Serialize2(SyntaxNode node)
{ {
char c = std::get<char>(node); char c = std::get<char>(node);
json_t* json = json_object(); 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)); json_object_set_new(json, "value", json_integer((uint8_t)c));
return json; return json;
} }
if(std::holds_alternative<Undefined>(node)) if(std::holds_alternative<Undefined>(node))
{ {
json_t* json = json_object(); 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; return json;
} }

View File

@ -42,14 +42,28 @@ namespace Tesses::CrossLang
uint32_t sections=5; uint32_t sections=5;
uint32_t name = GetString(this->name); uint32_t name = GetString(this->name);
uint32_t info = GetString(this->info); uint32_t info = GetString(this->info);
for(auto& dep : this->dependencies) for(auto& dep : this->dependencies)
{ {
GetString(dep.first); GetString(dep.first);
sections++; sections++;
} }
for(auto& tool : this->tools)
{
GetString(tool.first);
sections++;
}
if(!this->icon.empty())
{
this->GetResource(this->icon);
}
for(auto& res : this->res) for(auto& res : this->res)
sections++; sections++;
if(!this->icon.empty())
sections++;
WriteInt(stream,sections); WriteInt(stream,sections);
uint32_t strSz=4; uint32_t strSz=4;
@ -81,6 +95,15 @@ namespace Tesses::CrossLang
dep.second.ToArray(buffer); dep.second.ToArray(buffer);
Write(stream,buffer,5); 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; uint32_t fnLen=4;
@ -186,6 +209,14 @@ namespace Tesses::CrossLang
WriteInt(stream,0); 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(NotEqualsExpression, NEQ)
TWO_EXPR(EqualsExpression, EQ) TWO_EXPR(EqualsExpression, EQ)
TWO_EXPR(XOrExpression, XOR) 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!!!!!!! //THIS CODE WORKED FIRST TRY, I DON'T SEE THAT EVERY DAY, PRAISE GOD!!!!!!!
auto expr = adv.nodes[0]; auto expr = adv.nodes[0];

View File

@ -1,5 +1,6 @@
#include "CrossLang.hpp" #include "CrossLang.hpp"
#include <iostream> #include <iostream>
#include <stdexcept>
namespace Tesses::CrossLang namespace Tesses::CrossLang
{ {
std::string LexTokenType_ToString(LexTokenType t) std::string LexTokenType_ToString(LexTokenType t)
@ -135,24 +136,25 @@ namespace Tesses::CrossLang
else if(IsSymbol("{")) else if(IsSymbol("{"))
{ {
if(IsSymbol("}",false)) if(IsSymbol("}",false))
node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{}); node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{});
else else
node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{ParseExpression()}); node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{ParseExpression()});
EnsureSymbol("}"); EnsureSymbol("}");
} }
else if(IsSymbol("(")) else if(IsSymbol("("))
{ {
if(IsSymbol(")",false)) if(IsSymbol(")",false))
node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{}); node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{});
else else
node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{ParseExpression()}); node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{ParseExpression()});
EnsureSymbol(")"); EnsureSymbol(")");
} }
else if(IsIdentifier("var")) else if(IsIdentifier("var"))
{ {
if(i >= tokens.size()) throw std::out_of_range("End of file"); if(i >= tokens.size()) throw std::out_of_range("End of file");
auto variable = tokens[i]; auto variable = tokens[i];
i++; i++;
if(variable.type != LexTokenType::Identifier) throw SyntaxException(variable.lineInfo, "Expected an identifier got a " + LexTokenType_ToString(variable.type) + " \"" + variable.text + "\""); 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}); node = AdvancedSyntaxNode::Create(DeclareExpression,true,{variable.text});
} }
@ -347,6 +349,23 @@ namespace Tesses::CrossLang
{ {
return AdvancedSyntaxNode::Create(PrefixDecrementExpression,true,{ParseUnary()}); 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(); return ParseValue();
} }
@ -569,6 +588,98 @@ namespace Tesses::CrossLang
if(IsIdentifier("object")) if(IsIdentifier("object"))
{ {
//TODO: complete this //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")) if(IsIdentifier("enumerable"))
{ {

View File

@ -8,6 +8,7 @@ void Help(const char* filename)
printf("USAGE: %s [OPTIONS] <dirasroot> <archive.crvm>\n", filename); printf("USAGE: %s [OPTIONS] <dirasroot> <archive.crvm>\n", filename);
printf("OPTIONS:\n"); 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 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(" -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(" -n: Set name (MyAppOrLibName defaults to out)\n");
printf(" -h, --help: Prints help\n"); printf(" -h, --help: Prints help\n");
@ -19,6 +20,7 @@ int main(int argc, char** argv)
std::string name="out"; std::string name="out";
std::string info="{}"; std::string info="{}";
TVMVersion version; TVMVersion version;
std::string icon="";
std::vector<std::string> args; std::vector<std::string> args;
for(int i = 1; i < argc; i++) for(int i = 1; i < argc; i++)
{ {
@ -34,6 +36,14 @@ int main(int argc, char** argv)
info = argv[i]; info = argv[i];
} }
} }
else if(strcmp(argv[i], "-I") == 0)
{
i++;
if(i < argc)
{
icon = argv[i];
}
}
else if(strcmp(argv[i], "-n") == 0) else if(strcmp(argv[i], "-n") == 0)
{ {
i++; i++;
@ -77,7 +87,7 @@ int main(int argc, char** argv)
} }
FileStream strm(f,true,"wb",true); FileStream strm(f,true,"wb",true);
CrossArchiveCreate(&sdfs,&strm,name,version,info); CrossArchiveCreate(&sdfs,&strm,name,version,info,icon);
return 0; return 0;
} }

View File

@ -10,8 +10,10 @@ void Help(const char* filename)
printf("OPTIONS:\n"); printf("OPTIONS:\n");
printf(" -o: Output directory (OUTDIR, defaults to ./bin)\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 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(" -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(" -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(" -n: Set name (MyAppOrLibName defaults to out)\n");
printf(" -r: Set resource directory (RESDIR defaults to res)\n"); printf(" -r: Set resource directory (RESDIR defaults to res)\n");
printf(" -h, --help: Prints help\n"); printf(" -h, --help: Prints help\n");
@ -37,8 +39,10 @@ int main(int argc, char** argv)
std::vector<std::filesystem::path> source; std::vector<std::filesystem::path> source;
std::filesystem::path resourceDir = std::filesystem::current_path() / "res"; std::filesystem::path resourceDir = std::filesystem::current_path() / "res";
std::vector<std::pair<std::string, TVMVersion>> dependencies; std::vector<std::pair<std::string, TVMVersion>> dependencies;
std::vector<std::pair<std::string, TVMVersion>> tools;
std::string name="out"; std::string name="out";
std::string info="{}"; std::string info="{}";
std::string icon="";
TVMVersion version; TVMVersion version;
@ -72,6 +76,14 @@ int main(int argc, char** argv)
info = argv[i]; info = argv[i];
} }
} }
else if(strcmp(argv[i],"-I") == 0)
{
i++;
if(i < argc)
{
icon = argv[i];
}
}
else if(strcmp(argv[i], "-d") == 0) else if(strcmp(argv[i], "-d") == 0)
{ {
i++; 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) else if(strcmp(argv[i], "-n") == 0)
{ {
i++; i++;
@ -154,10 +200,16 @@ int main(int argc, char** argv)
gen.name = name; gen.name = name;
gen.version = version; gen.version = version;
gen.info = info; gen.info = info;
gen.icon = icon;
for(auto deps : dependencies) for(auto deps : dependencies)
{ {
gen.dependencies.push_back(deps); gen.dependencies.push_back(deps);
} }
for(auto tool : tools)
{
gen.tools.push_back(tool);
}
std::filesystem::create_directory(outputDir); std::filesystem::create_directory(outputDir);
{ {

View File

@ -53,13 +53,18 @@ void DumpFile(std::filesystem::path p)
char table_name[4]; char table_name[4];
bool hasIcon=false;
for(size_t i = 0; i < _len; i++) for(size_t i = 0; i < _len; i++)
{ {
Ensure(strm,(uint8_t*)table_name,sizeof(table_name)); Ensure(strm,(uint8_t*)table_name,sizeof(table_name));
size_t tableLen = (size_t)EnsureInt(strm); size_t tableLen = (size_t)EnsureInt(strm);
std::string tableName(table_name,4); 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); size_t strsLen = (size_t)EnsureInt(strm);
for(size_t j = 0;j < strsLen;j++) 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); 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++) 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 name;
std::string version; std::string version;
std::string info; std::string info;
std::string icon="";
TVMVersion version2; 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; return nullptr;
} }

View File

@ -80,7 +80,7 @@ namespace Tesses::CrossLang
return json_null(); 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) if(args.size() >= 1)
{ {
@ -141,7 +141,7 @@ namespace Tesses::CrossLang
} }
return Undefined(); 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])) if(args.size() > 0 && std::holds_alternative<std::string>(args[0]))
{ {
@ -155,6 +155,31 @@ namespace Tesses::CrossLang
return Undefined(); return Undefined();
} }
#endif #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) void TStd::RegisterJson(GC* gc,TRootEnvironment* env)
{ {
@ -162,8 +187,8 @@ namespace Tesses::CrossLang
#if defined(CROSSLANG_ENABLE_JSON) #if defined(CROSSLANG_ENABLE_JSON)
GCList ls(gc); GCList ls(gc);
TDictionary* dict = TDictionary::Create(ls); TDictionary* dict = TDictionary::Create(ls);
dict->DeclareFunction(gc, "Decode","Deserialize Json",{"Json string"},Json_Decode); dict->DeclareFunction(gc, "Decode","Deserialize Json",{"Json string"},JsonDecode);
dict->DeclareFunction(gc, "Encode","Serialize Json",{"any","$indent"},Json_Encode); dict->DeclareFunction(gc, "Encode","Serialize Json",{"any","$indent"},JsonEncode);
gc->BarrierBegin(); gc->BarrierBegin();

View File

@ -1,4 +1,10 @@
#include "CrossLang.hpp" #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 <sys/types.h>
#include <csignal> #include <csignal>
#include <iostream> #include <iostream>
@ -6,8 +12,33 @@
#include <cstring> #include <cstring>
using namespace Tesses::Framework::Streams; using namespace Tesses::Framework::Streams;
using namespace Tesses::Framework::Http; using namespace Tesses::Framework::Http;
using namespace Tesses::Framework::Mail;
namespace Tesses::CrossLang 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* TServerHeapObject::Create(GCList& ls, Tesses::Framework::Http::IHttpServer* svr)
{ {
TServerHeapObject* ho = new TServerHeapObject(); 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 { 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()); 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{ 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(); 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<Tesses::CrossLang::TObject> args2)->TObject{ dict->DeclareFunction(gc,"SendText","Send response text",{"text"},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
std::string text; std::string text;
if(GetArgument(args2,0,text)) if(GetArgument(args2,0,text))
ctx->SendText(text); ctx->SendText(text);
return nullptr; return nullptr;
}); });
dict->DeclareFunction(gc,"WithMimeType","Set mime type",{"mimeType"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{ dict->DeclareFunction(gc,"WithMimeType","Set mime type",{"mimeType"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
std::string text; std::string text;
if(GetArgument(args2,0,text)) if(GetArgument(args2,0,text))
ctx->WithMimeType(text); ctx->WithMimeType(text);
return dict; return dict;
}); });
dict->DeclareFunction(gc,"WithContentDisposition","Set content disposition",{"filename","inline"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{ dict->DeclareFunction(gc,"WithContentDisposition","Set content disposition",{"filename","inline"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
@ -205,6 +246,11 @@ namespace Tesses::CrossLang
ctx->SendBytes(ba->data); ctx->SendBytes(ba->data);
return nullptr; 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,"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 { dict->DeclareFunction(gc,"StartWebSocketSession","Start websocket session",{"dict"}, [ctx](GCList& ls,std::vector<TObject> args)->TObject {
TDictionary* dict; TDictionary* dict;
@ -583,6 +629,143 @@ namespace Tesses::CrossLang
return nullptr; 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) void TStd::RegisterNet(GC* gc, TRootEnvironment* env)
{ {
@ -591,6 +774,7 @@ namespace Tesses::CrossLang
TDictionary* dict = TDictionary::Create(ls); TDictionary* dict = TDictionary::Create(ls);
TDictionary* http = 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, "HtmlEncode","Html encode",{"param"}, Net_HtmlEncode);
http->DeclareFunction(gc, "UrlEncode","Url encode query param",{"param"}, Net_UrlEncode); 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, "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, "MakeRequest", "Create an http request", {"url","$extra"}, Net_Http_MakeRequest);
http->DeclareFunction(gc, "ListenSimpleWithLoop", "Listen (creates application loop)", {"server","port"},Net_Http_ListenSimpleWithLoop); http->DeclareFunction(gc, "ListenSimpleWithLoop", "Listen (creates application loop)", {"server","port"},Net_Http_ListenSimpleWithLoop);
//FileServer svr() //FileServer svr()
@ -626,8 +833,10 @@ namespace Tesses::CrossLang
return nullptr; return nullptr;
}); });
dict->DeclareFunction(gc, "NetworkStream","Create a network stream",{"ipv6","datagram"},Net_NetworkStream); 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(); gc->BarrierBegin();
dict->SetValue("Http", http); dict->SetValue("Http", http);
dict->SetValue("Smtp", smtp);
env->DeclareVariable("Net", dict); env->DeclareVariable("Net", dict);
gc->BarrierEnd(); gc->BarrierEnd();
} }

View File

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

View File

@ -118,18 +118,7 @@ namespace Tesses::CrossLang
TVFSHeapObject* vfs; TVFSHeapObject* vfs;
return GetArgumentHeap(args,0,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) static TObject TypeOf(GCList& ls, std::vector<TObject> args)
{ {
if(args.size() < 1) return "Undefined"; if(args.size() < 1) return "Undefined";
@ -345,6 +334,30 @@ namespace Tesses::CrossLang
env->permissions.canRegisterRoot=true; env->permissions.canRegisterRoot=true;
TDictionary* newTypes = TDictionary::Create(ls); 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, "ParseLong","Parse Long from String",{"arg","$base"},ParseLong);
env->DeclareFunction(gc, "ParseDouble","Parse Double from String",{"arg"},ParseDouble); env->DeclareFunction(gc, "ParseDouble","Parse Double from String",{"arg"},ParseDouble);
env->DeclareFunction(gc, "YieldEmumerable","Turn yield in function into enumerable",{"closure"},YieldEnumerableFunc); env->DeclareFunction(gc, "YieldEmumerable","Turn yield in function into enumerable",{"closure"},YieldEnumerableFunc);
@ -428,8 +441,35 @@ namespace Tesses::CrossLang
return Undefined(); return Undefined();
}); });
env->DeclareFunction(gc,"ByteArray","Create bytearray, with optional either size (to size it) or string argument (to fill byte array)",{"$data"},ByteArray); 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(); 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("InvokeMethod",MethodInvoker());
env->DeclareVariable("New", newTypes); env->DeclareVariable("New", newTypes);
gc->BarrierEnd(); gc->BarrierEnd();

View File

@ -78,29 +78,7 @@ namespace Tesses::CrossLang
int64_t msec; int64_t msec;
if(GetArgument(args,0,msec)) if(GetArgument(args,0,msec))
{ {
if((msec % 100) == 0) usleep(1000*msec);
{
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);
}
}
} }
return nullptr; return nullptr;
} }

View File

@ -134,7 +134,9 @@ namespace Tesses::CrossLang
std::vector<std::pair<std::string,std::string>> sources; std::vector<std::pair<std::string,std::string>> sources;
TVMVersion version(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE); 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>> dependencies;
std::vector<std::pair<std::string,TVMVersion>> tools;
std::string info; std::string info;
std::string icon;
TVFSHeapObject* vfsHO =nullptr; TVFSHeapObject* vfsHO =nullptr;
ls.GetGC()->BarrierBegin(); ls.GetGC()->BarrierBegin();
@ -142,17 +144,23 @@ namespace Tesses::CrossLang
TObject _version = dict->GetValue("Version"); TObject _version = dict->GetValue("Version");
TObject _sources = dict->GetValue("Sources"); TObject _sources = dict->GetValue("Sources");
TObject _dependencies = dict->GetValue("Dependencies"); TObject _dependencies = dict->GetValue("Dependencies");
TObject _tools = dict->GetValue("Tools");
TObject _info = dict->GetValue("Info"); TObject _info = dict->GetValue("Info");
TObject _icon = dict->GetValue("Icon");
TObject _resourceFileSystem = dict->GetValue("ResourceFileSystem"); TObject _resourceFileSystem = dict->GetValue("ResourceFileSystem");
TObject _out = dict->GetValue("Output"); TObject _out = dict->GetValue("Output");
TList* _toolList;
TList* _depList; TList* srcLst; TList* _depList; TList* srcLst;
GetObject<std::string>(_name,name); GetObject<std::string>(_name,name);
GetObject<std::string>(_info,info); GetObject<std::string>(_info,info);
GetObject<std::string>(_icon,icon);
GetObjectHeap(_resourceFileSystem, vfsHO); GetObjectHeap(_resourceFileSystem, vfsHO);
std::string v2; std::string v2;
if(GetObject<std::string>(_version,v2)) if(GetObject<std::string>(_version,v2))
TVMVersion::TryParse(v2, version); TVMVersion::TryParse(v2, version);
else
GetObject(_version,version);
if(GetObjectHeap<TList*>(_dependencies,_depList)) if(GetObjectHeap<TList*>(_dependencies,_depList))
{ {
@ -172,6 +180,36 @@ namespace Tesses::CrossLang
{ {
dependencies.push_back(std::pair<std::string,TVMVersion>(name2, version02)); 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; CodeGen gen;
gen.GenRoot(n); gen.GenRoot(n);
gen.dependencies = dependencies; gen.dependencies = dependencies;
gen.tools = tools;
gen.info = info; gen.info = info;
gen.name = name; gen.name = name;
gen.version = version; gen.version = version;
gen.icon = icon;
std::string outpath; std::string outpath;
TStreamHeapObject* stream; TStreamHeapObject* stream;
if(GetObjectHeap<TStreamHeapObject*>(_out, 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, "Compile", "Compile Source",{"dict"},VM_Compile);
dict->DeclareFunction(gc, "SourceToAst", "Convert source to ast", {"source"}, VM_SourceToAst); 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(); gc->BarrierBegin();
env->DeclareVariable("VM", dict); env->DeclareVariable("VM", dict);
gc->BarrierEnd(); gc->BarrierEnd();

View File

@ -32,6 +32,13 @@ namespace Tesses::CrossLang {
if(this->marked) return; if(this->marked) return;
this->marked = true; this->marked = true;
this->callable->Mark(); this->callable->Mark();
GC::Mark(this->tag);
}
void TCallable::Mark()
{
if(this->marked) return;
this->marked=true;
GC::Mark(this->tag);
} }
void TClosure::Mark() void TClosure::Mark()
{ {
@ -40,7 +47,7 @@ namespace Tesses::CrossLang {
this->file->Mark(); this->file->Mark();
this->env->Mark(); this->env->Mark();
this->closure->Mark(); this->closure->Mark();
GC::Mark(this->tag);
} }
TClosure* TClosure::Create(GCList& ls,TEnvironment* env,TFile* file,uint32_t chunkId,bool ownScope) 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})); 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) bool TDynamicDictionary::MethodExists(GCList& ls,std::string name)
{ {
auto dict = TDictionary::Create(ls); auto dict = TDictionary::Create(ls);

View File

@ -10,6 +10,7 @@ namespace Tesses::CrossLang
TFile* TFile::Create(GCList& ls) TFile* TFile::Create(GCList& ls)
{ {
TFile* f = new TFile(); TFile* f = new TFile();
f->icon = -1;
GC* _gc = ls.GetGC(); GC* _gc = ls.GetGC();
ls.Add(f); ls.Add(f);
_gc->Watch(f); _gc->Watch(f);
@ -18,6 +19,7 @@ namespace Tesses::CrossLang
TFile* TFile::Create(GCList* ls) TFile* TFile::Create(GCList* ls)
{ {
TFile* f = new TFile(); TFile* f = new TFile();
f->icon=-1;
GC* _gc = ls->GetGC(); GC* _gc = ls->GetGC();
ls->Add(f); ls->Add(f);
_gc->Watch(f); _gc->Watch(f);
@ -91,13 +93,13 @@ namespace Tesses::CrossLang
std::string TFile::GetString(Tesses::Framework::Streams::Stream* stream) std::string TFile::GetString(Tesses::Framework::Streams::Stream* stream)
{ {
uint32_t index=EnsureInt(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]; return this->strings[index];
} }
void TFile::Load(GC* gc, Tesses::Framework::Streams::Stream* stream) void TFile::Load(GC* gc, Tesses::Framework::Streams::Stream* stream)
{ {
GCList ls(gc);
uint8_t main_header[18]; uint8_t main_header[18];
Ensure(stream,main_header,sizeof(main_header)); Ensure(stream,main_header,sizeof(main_header));
if(strncmp((const char*)main_header,"TCROSSVM",8) != 0) throw VMException("Invalid TCrossVM image."); 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); TVMVersion depVersion(version_bytes);
this->dependencies.push_back(std::pair<std::string,TVMVersion>(name, depVersion)); 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) else if(strncmp(table_name,"RESO",4) == 0) //resources (using embed)
{ {
std::vector<uint8_t> data; std::vector<uint8_t> data;
@ -140,11 +150,13 @@ namespace Tesses::CrossLang
Ensure(stream,data.data(), tableLen); Ensure(stream,data.data(), tableLen);
this->resources.push_back(data); 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); size_t chunkCount = (size_t)EnsureInt(stream);
for(size_t j = 0; j < chunkCount; j++) for(size_t j = 0; j < chunkCount; j++)
{ {
auto chunk = TFileChunk::Create(ls); auto chunk = TFileChunk::Create(ls);
chunk->file = this; chunk->file = this;
size_t argCount = (size_t)EnsureInt(stream); size_t argCount = (size_t)EnsureInt(stream);
@ -159,6 +171,7 @@ namespace Tesses::CrossLang
this->chunks.push_back(chunk); this->chunks.push_back(chunk);
} }
} }
else if(strncmp(table_name,"FUNS",4) == 0) //functions else if(strncmp(table_name,"FUNS",4) == 0) //functions
{ {
@ -187,6 +200,10 @@ namespace Tesses::CrossLang
this->strings.push_back(EnsureString(stream)); this->strings.push_back(EnsureString(stream));
} }
} }
else if(strncmp(table_name,"ICON",4) == 0) //icon
{
this->icon = (int32_t)EnsureInt(stream);
}
else else
{ {
Skip(stream,tableLen); Skip(stream,tableLen);

View File

@ -1,8 +1,11 @@
#include "CrossLang.hpp" #include "CrossLang.hpp"
#include <TessesFramework/Filesystem/VFS.hpp>
#include <cstddef>
#include <iostream> #include <iostream>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
#include <variant>
namespace Tesses::CrossLang { namespace Tesses::CrossLang {
thread_local CallStackEntry* current_function=nullptr; thread_local CallStackEntry* current_function=nullptr;
@ -13,6 +16,11 @@ namespace Tesses::CrossLang {
{ {
return true; 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)) if(std::holds_alternative<std::string>(obj))
{ {
return !std::get<std::string>(obj).empty(); return !std::get<std::string>(obj).empty();
@ -192,6 +200,7 @@ namespace Tesses::CrossLang {
auto obj = std::get<THeapObjectHolder>(left).obj; auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary*>(obj); auto dict = dynamic_cast<TDictionary*>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj); auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
if(dict != nullptr) if(dict != nullptr)
{ {
gc->BarrierBegin(); gc->BarrierBegin();
@ -568,7 +577,13 @@ namespace Tesses::CrossLang {
{ {
cse.back()->Push(gc,std::get<int64_t>(left) < std::get<double>(right)); 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)) else if(std::holds_alternative<THeapObjectHolder>(left))
{ {
auto obj = std::get<THeapObjectHolder>(left).obj; 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)); 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)) else if(std::holds_alternative<THeapObjectHolder>(left))
{ {
auto obj = std::get<THeapObjectHolder>(left).obj; 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)); 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)) else if(std::holds_alternative<THeapObjectHolder>(left))
{ {
auto obj = std::get<THeapObjectHolder>(left).obj; 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)); 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)) 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)); 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)) else if(std::holds_alternative<THeapObjectHolder>(left))
{ {
auto obj = std::get<THeapObjectHolder>(left).obj; 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)); 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)) else if(std::holds_alternative<THeapObjectHolder>(left))
{ {
auto obj = std::get<THeapObjectHolder>(left).obj; auto obj = std::get<THeapObjectHolder>(left).obj;
@ -1373,7 +1419,26 @@ namespace Tesses::CrossLang {
{ {
GCList ls(gc); GCList ls(gc);
std::regex regex; 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") if(key == "Search")
{ {
@ -1682,9 +1747,9 @@ namespace Tesses::CrossLang {
{ {
size_t idx = (size_t)idx; size_t idx = (size_t)idx;
if(idx < path.path.size()) if(idx < path.path.size())
cse.back()->Push(gc, path.path[idx]); cse.back()->Push(gc, path.path[idx]);
else else
cse.back()->Push(gc, nullptr); cse.back()->Push(gc, nullptr);
return false; return false;
} }
} }
@ -1728,11 +1793,6 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, path.CollapseRelativeParents()); cse.back()->Push(gc, path.CollapseRelativeParents());
return false; return false;
} }
if(key == "RelativeCurrentDirectory")
{
cse.back()->Push(gc, path.RelativeCurrentDirectory());
return false;
}
if(key == "IsRelative") if(key == "IsRelative")
{ {
cse.back()->Push(gc, path.relative); cse.back()->Push(gc, path.relative);
@ -3230,12 +3290,20 @@ namespace Tesses::CrossLang {
} }
else if(list != nullptr) else if(list != nullptr)
{ {
if(key == "GetEnumerator") if(key == "GetEnumerator")
{ {
cse.back()->Push(gc, TListEnumerator::Create(ls,list)); cse.back()->Push(gc, TListEnumerator::Create(ls,list));
return false; 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) if(args.size() != 2)
{ {
@ -3344,10 +3412,16 @@ namespace Tesses::CrossLang {
} }
else if(dict != nullptr) else if(dict != nullptr)
{ {
if(key == "ToString" && !dict->MethodExists(ls, key) && args.empty())
{
cse.back()->Push(gc,Json_Encode(dict));
return false;
}
gc->BarrierBegin(); gc->BarrierBegin();
auto o = dict->GetValue(key); auto o = dict->GetValue(key);
gc->BarrierEnd(); gc->BarrierEnd();
return InvokeMethod(ls,o,dict,args); return InvokeMethod(ls,o,dict,args);
} }
else if(callable != nullptr) else if(callable != nullptr)
@ -3473,7 +3547,57 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, Undefined()); cse.back()->Push(gc, Undefined());
return false; 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)) if(std::holds_alternative<THeapObjectHolder>(instance))
{ {
auto obj = std::get<THeapObjectHolder>(instance).obj; auto obj = std::get<THeapObjectHolder>(instance).obj;
@ -3487,6 +3611,123 @@ namespace Tesses::CrossLang {
auto strm = dynamic_cast<TStreamHeapObject*>(obj); auto strm = dynamic_cast<TStreamHeapObject*>(obj);
auto vfs = dynamic_cast<TVFSHeapObject*>(obj); auto vfs = dynamic_cast<TVFSHeapObject*>(obj);
auto callstackEntry = dynamic_cast<CallStackEntry*>(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) if(callstackEntry != nullptr)
{ {
@ -3591,7 +3832,7 @@ namespace Tesses::CrossLang {
} }
if(closure != nullptr) if(closure != nullptr)
{ {
if(key == "args") if(key == "Arguments")
{ {
GCList ls2(gc); GCList ls2(gc);
TList* ls = TList::Create(ls2); TList* ls = TList::Create(ls2);
@ -3602,10 +3843,15 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc,ls); cse.back()->Push(gc,ls);
return false; return false;
} }
if(key == "File")
{
cse.back()->Push(gc,closure->file);
return false;
}
} }
if(externalMethod != nullptr) if(externalMethod != nullptr)
{ {
if(key == "args") if(key == "Arguments")
{ {
GCList ls2(gc); GCList ls2(gc);
TList* ls = TList::Create(ls2); TList* ls = TList::Create(ls2);
@ -3620,11 +3866,18 @@ namespace Tesses::CrossLang {
if(tcallable != nullptr) if(tcallable != nullptr)
{ {
if(key == "documentation") if(key == "Documentation")
{ {
cse.back()->Push(gc, tcallable->documentation); cse.back()->Push(gc, tcallable->documentation);
return false; return false;
} }
if(key == "Tag")
{
gc->BarrierBegin();
cse.back()->Push(gc, tcallable->tag);
gc->BarrierEnd();
return false;
}
cse.back()->Push(gc,Undefined()); cse.back()->Push(gc,Undefined());
return false; return false;
} }
@ -3703,7 +3956,18 @@ namespace Tesses::CrossLang {
auto vfs = dynamic_cast<TVFSHeapObject*>(obj); auto vfs = dynamic_cast<TVFSHeapObject*>(obj);
auto strm = dynamic_cast<TStreamHeapObject*>(obj); auto strm = dynamic_cast<TStreamHeapObject*>(obj);
auto dict = dynamic_cast<TDictionary*>(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) if(strm != nullptr)
{ {
auto netStrm = dynamic_cast<Tesses::Framework::Streams::NetworkStream*>(strm->stream); auto netStrm = dynamic_cast<Tesses::Framework::Streams::NetworkStream*>(strm->stream);
@ -4347,6 +4611,28 @@ namespace Tesses::CrossLang {
return false; 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) bool InterperterThread::Illegal(GC* gc)
{ {
@ -4373,7 +4659,7 @@ namespace Tesses::CrossLang {
if(!cse.empty()) if(!cse.empty())
{ {
auto stk = cse.back(); auto stk = cse.back();
current_function = stk;
@ -4675,7 +4961,7 @@ namespace Tesses::CrossLang {
ls.GetGC()->BarrierBegin(); ls.GetGC()->BarrierBegin();
CallStackEntry* cse = CallStackEntry::Create(ls); CallStackEntry* cse = CallStackEntry::Create(ls);
cse->callable = closure; 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; cse->ip = 0;
if(closure->closure->args.empty() && closure->chunkId != 0) if(closure->closure->args.empty() && closure->chunkId != 0)
{ {
@ -4717,7 +5003,7 @@ namespace Tesses::CrossLang {
}; };
size_t required = requiredArguments(); 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())); 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) if(i == closure->closure->args.size()-1)
{ {
auto argName = closure->closure->args[i];
auto lsArgs = TList::Create(ls); auto lsArgs = TList::Create(ls);
for(;i<args.size(); i++) for(;i<args.size(); i++)
lsArgs->Add(args[i]); lsArgs->Add(args[i]);
cse->env->DeclareVariable(trimStart(closure->closure->args[i]), lsArgs); cse->env->DeclareVariable(trimStart(argName), lsArgs);
i = args.size(); i = args.size();
} }
if(i<args.size()) if(i<args.size())
@ -4755,6 +5042,10 @@ namespace Tesses::CrossLang {
{ {
return std::get<std::string>(o); 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)) if(std::holds_alternative<int64_t>(o))
{ {
return std::to_string(std::get<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 obj = std::get<THeapObjectHolder>(o).obj;
auto dict = dynamic_cast<TDictionary*>(obj); auto dict = dynamic_cast<TDictionary*>(obj);
auto list = dynamic_cast<TList*>(obj);
auto bArray = dynamic_cast<TByteArray*>(obj);
if(dict != nullptr) if(dict != nullptr)
{ {
GCList ls(gc); GCList ls(gc);
if(dict->MethodExists(ls,"ToString"))
return ToString(gc,dict->CallMethod(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