Add thumbnailer support and TVMVersion and TFile are now accessable from language
This commit is contained in:
2
.clangd
Normal file
2
.clangd
Normal file
@ -0,0 +1,2 @@
|
||||
CompileFlags: # Tweak the parse settings, example directory given to show format
|
||||
Add: ["-Iinclude"]
|
||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -75,5 +75,8 @@
|
||||
"thread": "cpp",
|
||||
"bitset": "cpp",
|
||||
"regex": "cpp"
|
||||
}
|
||||
},
|
||||
"clangd.fallbackFlags": [
|
||||
"-Iinclude"
|
||||
]
|
||||
}
|
||||
@ -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>")
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
Tesses Cross Language
|
||||
=====================
|
||||
|
||||

|
||||

|
||||
|
||||
## What is required to build this project
|
||||
- [TessesFramework](https://onedev.site.tesses.net/tesses-framework)
|
||||
|
||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
4
crosslang.thumbnailer
Normal file
4
crosslang.thumbnailer
Normal file
@ -0,0 +1,4 @@
|
||||
[Thumbnailer Entry]
|
||||
TryExec=crossthumbnailer
|
||||
Exec=crossthumbnailer %i %o
|
||||
MimeType=application/crvm;
|
||||
17
crosslang.xml
Normal file
17
crosslang.xml
Normal 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
563
docs/README.md
Normal 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();
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
};
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "CrossLang.hpp"
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
namespace Tesses::CrossLang
|
||||
{
|
||||
std::string LexTokenType_ToString(LexTokenType t)
|
||||
@ -135,24 +136,25 @@ namespace Tesses::CrossLang
|
||||
else if(IsSymbol("{"))
|
||||
{
|
||||
if(IsSymbol("}",false))
|
||||
node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{});
|
||||
node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{});
|
||||
else
|
||||
node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{ParseExpression()});
|
||||
node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{ParseExpression()});
|
||||
|
||||
EnsureSymbol("}");
|
||||
}
|
||||
else if(IsSymbol("("))
|
||||
{
|
||||
if(IsSymbol(")",false))
|
||||
node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{});
|
||||
node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{});
|
||||
else
|
||||
node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{ParseExpression()});
|
||||
node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{ParseExpression()});
|
||||
EnsureSymbol(")");
|
||||
}
|
||||
else if(IsIdentifier("var"))
|
||||
{
|
||||
if(i >= tokens.size()) throw std::out_of_range("End of file");
|
||||
auto variable = tokens[i];
|
||||
i++;
|
||||
auto variable = tokens[i];
|
||||
i++;
|
||||
if(variable.type != LexTokenType::Identifier) throw SyntaxException(variable.lineInfo, "Expected an identifier got a " + LexTokenType_ToString(variable.type) + " \"" + variable.text + "\"");
|
||||
node = AdvancedSyntaxNode::Create(DeclareExpression,true,{variable.text});
|
||||
}
|
||||
@ -347,6 +349,23 @@ namespace Tesses::CrossLang
|
||||
{
|
||||
return AdvancedSyntaxNode::Create(PrefixDecrementExpression,true,{ParseUnary()});
|
||||
}
|
||||
else if(IsSymbol("/"))
|
||||
{
|
||||
if(this->i < this->tokens.size() && (this->tokens[this->i].type == LexTokenType::String || this->tokens[this->i].type == LexTokenType::Identifier))
|
||||
{
|
||||
return AdvancedSyntaxNode::Create(DivideExpression,true,{
|
||||
AdvancedSyntaxNode::Create(RootPathExpression,true,{}),
|
||||
ParseValue()
|
||||
});
|
||||
}
|
||||
else {
|
||||
return AdvancedSyntaxNode::Create(RootPathExpression,true,{});
|
||||
}
|
||||
}
|
||||
else if(IsSymbol("."))
|
||||
{
|
||||
return AdvancedSyntaxNode::Create(RelativePathExpression, true, {});
|
||||
}
|
||||
|
||||
return ParseValue();
|
||||
}
|
||||
@ -569,6 +588,98 @@ namespace Tesses::CrossLang
|
||||
if(IsIdentifier("object"))
|
||||
{
|
||||
//TODO: complete this
|
||||
if(i < tokens.size())
|
||||
{
|
||||
std::string name = tokens[i++].text;
|
||||
EnsureSymbol("{");
|
||||
std::vector<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"))
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
|
||||
{
|
||||
|
||||
@ -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
61
src/crossthumbnailer.cpp
Normal 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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
});
|
||||
@ -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{
|
||||
std::string text;
|
||||
if(GetArgument(args2,0,text))
|
||||
ctx->SendText(text);
|
||||
ctx->SendText(text);
|
||||
return nullptr;
|
||||
});
|
||||
dict->DeclareFunction(gc,"WithMimeType","Set mime type",{"mimeType"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
|
||||
std::string text;
|
||||
if(GetArgument(args2,0,text))
|
||||
ctx->WithMimeType(text);
|
||||
ctx->WithMimeType(text);
|
||||
return dict;
|
||||
});
|
||||
dict->DeclareFunction(gc,"WithContentDisposition","Set content disposition",{"filename","inline"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
|
||||
@ -205,6 +246,11 @@ namespace Tesses::CrossLang
|
||||
ctx->SendBytes(ba->data);
|
||||
return nullptr;
|
||||
});
|
||||
dict->DeclareFunction(gc,"WriteHeaders","Send the headers",{},[ctx](GCList& ls, std::vector<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();
|
||||
}
|
||||
|
||||
@ -65,5 +65,8 @@ namespace Tesses::CrossLang
|
||||
gc->BarrierEnd();
|
||||
#endif
|
||||
env->permissions.canRegisterOGC=true;
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
353
src/vm/vm.cpp
353
src/vm/vm.cpp
@ -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")
|
||||
{
|
||||
@ -1682,9 +1747,9 @@ namespace Tesses::CrossLang {
|
||||
{
|
||||
size_t idx = (size_t)idx;
|
||||
if(idx < path.path.size())
|
||||
cse.back()->Push(gc, path.path[idx]);
|
||||
cse.back()->Push(gc, path.path[idx]);
|
||||
else
|
||||
cse.back()->Push(gc, nullptr);
|
||||
cse.back()->Push(gc, nullptr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1728,11 +1793,6 @@ namespace Tesses::CrossLang {
|
||||
cse.back()->Push(gc, path.CollapseRelativeParents());
|
||||
return false;
|
||||
}
|
||||
if(key == "RelativeCurrentDirectory")
|
||||
{
|
||||
cse.back()->Push(gc, path.RelativeCurrentDirectory());
|
||||
return false;
|
||||
}
|
||||
if(key == "IsRelative")
|
||||
{
|
||||
cse.back()->Push(gc, path.relative);
|
||||
@ -3230,12 +3290,20 @@ namespace Tesses::CrossLang {
|
||||
}
|
||||
else if(list != nullptr)
|
||||
{
|
||||
|
||||
if(key == "GetEnumerator")
|
||||
{
|
||||
cse.back()->Push(gc, TListEnumerator::Create(ls,list));
|
||||
return false;
|
||||
}
|
||||
if(key == "Insert")
|
||||
else if(key == "ToString")
|
||||
{
|
||||
|
||||
cse.back()->Push(gc,Json_Encode(list));
|
||||
return false;
|
||||
|
||||
}
|
||||
else if(key == "Insert")
|
||||
{
|
||||
if(args.size() != 2)
|
||||
{
|
||||
@ -3344,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);
|
||||
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
Reference in New Issue
Block a user