Do more docs
This commit is contained in:
@ -45,7 +45,7 @@ endif()
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
TessesFramework
|
||||
GIT_REPOSITORY https://onedev.site.tesses.net/tesses-framework.git
|
||||
GIT_REPOSITORY httpgc, envs://onedev.site.tesses.net/tesses-framework.git
|
||||
)
|
||||
FetchContent_MakeAvailable(TessesFramework)
|
||||
else()
|
||||
@ -155,12 +155,15 @@ endif()
|
||||
|
||||
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(GNUInstallDirs)cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
if(CROSSLANG_ENABLE_STATIC)
|
||||
project(MyPlugin)
|
||||
|
||||
add_library(crosslang_static STATIC ${CROSSLANG_SOURCE})
|
||||
CROSSLANG_LINK_DEPS(crosslang_static)
|
||||
find_package(TessesCrossLang REQUIRED)
|
||||
|
||||
add_library(MyPlugin SHARED lib.cpp)
|
||||
|
||||
target_link_libraries(MyPlugin PUBLIC TessesCrossLang::crosslang_shared)
|
||||
if(CROSSLANG_FETCHCONTENT)
|
||||
target_link_libraries(crosslang_static PUBLIC tessesframework)
|
||||
else()
|
||||
|
||||
1
docs/CPP_LAYER.md
Normal file
1
docs/CPP_LAYER.md
Normal file
@ -0,0 +1 @@
|
||||
# C++ Layer
|
||||
232
docs/EXTENDING_RUNTIME.md
Normal file
232
docs/EXTENDING_RUNTIME.md
Normal file
@ -0,0 +1,232 @@
|
||||
Extending the runtime
|
||||
=====================
|
||||
|
||||
See [this](CPP_LAYER.md)
|
||||
|
||||
There are a couple ways of doing this
|
||||
|
||||
- Creating a shared library (only works if using shared libs)
|
||||
- Embeding the runtime
|
||||
- Forking crosslang and adding functionality (I don't support pull requests at this time)
|
||||
|
||||
### Shared Library
|
||||
|
||||
This assumes you are on linux, if on windows use MyPlugin.dll on mac libMyPlugin.dylib in crosslang project (it would be a good idea to check Env.Platform)
|
||||
|
||||
CMakeLists.txt:
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(MyPlugin)
|
||||
|
||||
find_package(TessesCrossLang REQUIRED)
|
||||
|
||||
add_library(MyPlugin SHARED lib.cpp)
|
||||
|
||||
target_link_libraries(MyPlugin PUBLIC TessesCrossLang::crosslang_shared)
|
||||
```
|
||||
|
||||
lib.cpp:
|
||||
```c++
|
||||
#include <CrossLang.hpp>
|
||||
|
||||
using namespace Tesses::CrossLang;
|
||||
|
||||
void MyPlugin(GC* gc, TRootEnvironment* env)
|
||||
{
|
||||
GCList ls(gc);
|
||||
TDictionary* dict = TDictionary::Create(ls,{
|
||||
TDItem("MyFunction", TExternalMethod::Create(ls, "A description for function",{"myLong","$optionalList"},[](GCList& ls, std::vector<TObject> args)->TObject {
|
||||
int64_t n;
|
||||
if(GetArgument(args,0,n))
|
||||
{
|
||||
TList* myLs;
|
||||
if(GetArgumentHeap(args,1,myLs))
|
||||
{
|
||||
//do something with the list
|
||||
myLs->Add(n);
|
||||
return TList::Create(ls, {n,myLs});
|
||||
}
|
||||
|
||||
|
||||
return TList::Create(ls, {n});
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}))
|
||||
});
|
||||
|
||||
gc->BarrierBegin();
|
||||
env->SetVariable("MyPlugin",dict);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
|
||||
CROSSLANG_PLUGIN(MyPlugin);
|
||||
|
||||
```
|
||||
|
||||
main.tcross:
|
||||
```go
|
||||
func main(args)
|
||||
{
|
||||
Reflection.LoadNativePlugin(FS.MakeFull("libMyPlugin.so"));
|
||||
|
||||
var res = MyPlugin.MyFunction(42);
|
||||
if(TypeOf(res) == "List")
|
||||
{
|
||||
Console.WriteLine(res);
|
||||
}
|
||||
|
||||
var res = MyPlugin.MyFunction(42,["Hello","John"]);
|
||||
if(TypeOf(res) == "List")
|
||||
{
|
||||
Console.WriteLine(res);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Embeding the runtime
|
||||
|
||||
CMakeLists.txt:
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(MyCrossLangBinary)
|
||||
|
||||
find_package(TessesCrossLang REQUIRED)
|
||||
|
||||
add_executable(MyCrossLangBinary SHARED app.cpp)
|
||||
|
||||
target_link_libraries(MyCrossLangBinary PUBLIC TessesCrossLang::crosslang_shared) # or crosslang_static for static linking
|
||||
|
||||
|
||||
```
|
||||
|
||||
app.cpp:
|
||||
```c++
|
||||
#include <CrossLang.hpp>
|
||||
|
||||
using namespace Tesses::CrossLang;
|
||||
using namespace Tesses::Framework;
|
||||
|
||||
void MyPlugin(GC* gc, TRootEnvironment* env)
|
||||
{
|
||||
GCList ls(gc);
|
||||
TDictionary* dict = TDictionary::Create(ls,{
|
||||
TDItem("MyFunction", TExternalMethod::Create(ls, "A description for function",{"myLong","$optionalList"},[](GCList& ls, std::vector<TObject> args)->TObject {
|
||||
int64_t n;
|
||||
if(GetArgument(args,0,n))
|
||||
{
|
||||
TList* myLs;
|
||||
if(GetArgumentHeap(args,1,myLs))
|
||||
{
|
||||
//do something with the list
|
||||
myLs->Add(n);
|
||||
return TList::Create(ls, {n,myLs});
|
||||
}
|
||||
|
||||
|
||||
return TList::Create(ls, {n});
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}))
|
||||
});
|
||||
|
||||
gc->BarrierBegin();
|
||||
env->SetVariable("MyPlugin",dict);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
TF_Init();
|
||||
if(argc < 2)
|
||||
{
|
||||
printf("USAGE: %s <filename.crvm> <args...>\n",argv[0]);
|
||||
return 1;
|
||||
}
|
||||
GC gc;
|
||||
gc.RegisterEverythingCallback(MyPlugin);
|
||||
gc.Start();
|
||||
GCList ls(gc);
|
||||
TRootEnvironment* env = TRootEnvironment::Create(ls,TDictionary::Create(ls));
|
||||
Tesses::Framework::Filesystem::LocalFilesystem fs;
|
||||
TStd::RegisterStd(&gc,env);
|
||||
env->LoadFileWithDependencies(&gc, &fs, fs.SystemToVFSPath(argv[1]));
|
||||
|
||||
TList* args = TList::Create(ls);
|
||||
for(int arg=1;arg<argc;arg++)
|
||||
args->Add(std::string(argv[arg]));
|
||||
|
||||
auto res = env->CallFunction(ls,"main",{args});
|
||||
int64_t iresult;
|
||||
if(GetObject(res,iresult))
|
||||
return (int)iresult;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
main.tcross (needs to be compiled with crossc):
|
||||
```go
|
||||
func main(args)
|
||||
{
|
||||
//no reflection necessary
|
||||
|
||||
var res = MyPlugin.MyFunction(42);
|
||||
if(TypeOf(res) == "List")
|
||||
{
|
||||
Console.WriteLine(res);
|
||||
}
|
||||
|
||||
var res = MyPlugin.MyFunction(42,["Hello","John"]);
|
||||
if(TypeOf(res) == "List")
|
||||
{
|
||||
Console.WriteLine(res);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Forking (implementing it in runtime library itself)
|
||||
- edit include/CrossLang.hpp
|
||||
- in TStd class insert, static void RegisterMyPlugin(GC* gc, TRootEnvironment* env); where MyPlugin is whatever you want
|
||||
- edit src/runtime_methods/std.cpp
|
||||
- in TStd::RegisterStd before register everything call TStd::RegisterMyPlugin(gc, env);
|
||||
- in CMakeLists.txt within list(APPEND CROSSLANG_SOURCE **Many Source Files**) you must add src/runtime_methods/myplugin.cpp
|
||||
|
||||
myplugin.cpp:
|
||||
```c++
|
||||
#include <CrossLang.hpp>
|
||||
namespace Tesses::CrossLang
|
||||
{
|
||||
void TStd::RegisterMyPlugin(GC* gc, TRootEnvironment* env)
|
||||
{
|
||||
GCList ls(gc);
|
||||
TDictionary* dict = TDictionary::Create(ls,{
|
||||
TDItem("MyFunction", TExternalMethod::Create(ls, "A description for function",{"myLong","$optionalList"},[](GCList& ls, std::vector<TObject> args)->TObject {
|
||||
int64_t n;
|
||||
if(GetArgument(args,0,n))
|
||||
{
|
||||
TList* myLs;
|
||||
if(GetArgumentHeap(args,1,myLs))
|
||||
{
|
||||
//do something with the list
|
||||
myLs->Add(n);
|
||||
return TList::Create(ls, {n,myLs});
|
||||
}
|
||||
|
||||
|
||||
return TList::Create(ls, {n});
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}))
|
||||
});
|
||||
|
||||
gc->BarrierBegin();
|
||||
env->SetVariable("MyPlugin",dict);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
}
|
||||
```
|
||||
605
docs/HANDBOOK.md
Normal file
605
docs/HANDBOOK.md
Normal file
@ -0,0 +1,605 @@
|
||||
## 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
|
||||
//you can create functions on dictionaries so long as they are on root environment (they are declared there before root scope is evaluated so this is possible)
|
||||
My.Func.Joel = 59; //Because My.Func.Is.A.Few.Deep creates the dictionaries via runtime
|
||||
|
||||
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 = new ByteArray(1);
|
||||
ba[0] = 42;
|
||||
Console.WriteLine(ba.ToString()); //prints *
|
||||
```
|
||||
|
||||
###### ByteArray from string
|
||||
|
||||
```js
|
||||
var bA = new 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 = new 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();
|
||||
```
|
||||
|
||||
#### Html Litterals
|
||||
```go
|
||||
//comments are just crosslang ones
|
||||
|
||||
//we will be setting to myHtml for the html (returns a string) (it is already html escaped)
|
||||
myHtml = <h1>{someStringExpression}</h1>;
|
||||
|
||||
//a link, in this example we have a dictionary named node with string fields href and text
|
||||
//lets say node.text equaled List<int> and href contained ./mypage?name=Joel&file=steve.bin myHtml would be equal to "<a target=\"_blank\" href=\"./mypage?name=Joel&file=steve.bin\">List<int></a>" (the \ are just there to make this a valid string for demonstration purposes, there aren't really backslashes)
|
||||
myHtml = <a target="_blank" href={node.href}>{node.text}</a>;
|
||||
|
||||
|
||||
//for (works like for loop but is in html form, the for part is not rendered in the final string)
|
||||
myHtml = <for(var i = 0; i < 42; i++)>
|
||||
<h6>{i}</h6>
|
||||
</for>;
|
||||
|
||||
//each
|
||||
myHtml = <each(var item : list)></each>;
|
||||
|
||||
//do
|
||||
myHtml = <do(expr == 42)></do>;
|
||||
|
||||
//while
|
||||
myHtml = <while(expr == 42)></while>;
|
||||
|
||||
//if
|
||||
|
||||
myHtml = <if(expr == 42)>
|
||||
<true>
|
||||
//if expr is 42
|
||||
</true>
|
||||
<false>
|
||||
//if expr is not 42
|
||||
//you would use another if here instead of else if
|
||||
</false>
|
||||
</if>;
|
||||
|
||||
myHtml = <null>Hello</null>; //would just be Hello (useful for templating as it works just like div but the null part is not emited into string)
|
||||
|
||||
myHtml = <raw(stringExpr)>; //allowing you to emit unescaped html from string into html litteral (useful for templating)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
566
docs/README.md
566
docs/README.md
@ -1,563 +1,7 @@
|
||||
## 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();
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Tesses CrossLang
|
||||
|
||||
This is the docs for my language
|
||||
|
||||
- [Handbook](HANDBOOK.md)
|
||||
- [C++ Layer](CPP_LAYER.md)
|
||||
- [Extend the runtime](EXTENDING_RUNTIME.md)
|
||||
@ -158,7 +158,7 @@ namespace Tesses::CrossLang
|
||||
|
||||
}
|
||||
this->EnsureSymbol(">");
|
||||
if(tagName != "if" && tagName != "true" && tagName != "false" && tagName != "for" && tagName != "while" && tagName != "do" && tagName != "each")
|
||||
if(tagName != "if" && tagName != "true" && tagName != "false" && tagName != "for" && tagName != "while" && tagName != "do" && tagName != "each" && tagName != "null")
|
||||
{
|
||||
std::string myVal = "</";
|
||||
myVal += tagName;
|
||||
@ -290,6 +290,14 @@ namespace Tesses::CrossLang
|
||||
}
|
||||
nodes.push_back(AdvancedSyntaxNode::Create(IfStatement,false,{expr,truth,falsey}));
|
||||
}
|
||||
else if(tagName == "null")
|
||||
{
|
||||
EnsureSymbol(">");
|
||||
std::vector<SyntaxNode> _nodes;
|
||||
parseFn(_nodes,"null");
|
||||
nodes.push_back(AdvancedSyntaxNode::Create(ScopeNode,false,_nodes));
|
||||
|
||||
}
|
||||
else if(tagName == "while")
|
||||
{
|
||||
|
||||
|
||||
@ -4,60 +4,6 @@
|
||||
|
||||
namespace Tesses::CrossLang
|
||||
{
|
||||
static TObject FS_SubdirFilesystem(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
TVFSHeapObject* vfsho;
|
||||
|
||||
Tesses::Framework::Filesystem::VFSPath path;
|
||||
|
||||
if(GetArgumentHeap(args,0,vfsho) && GetArgumentAsPath(args,1,path))
|
||||
{
|
||||
return TVFSHeapObject::Create(ls,new Tesses::Framework::Filesystem::SubdirFilesystem(new TObjectVFS(ls.GetGC(),vfsho),path,true));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static TObject FS_MountableFilesystem(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
TVFSHeapObject* vfsho;
|
||||
|
||||
if(GetArgumentHeap(args,0,vfsho))
|
||||
{
|
||||
return TVFSHeapObject::Create(ls,new Tesses::Framework::Filesystem::MountableFilesystem(new TObjectVFS(ls.GetGC(),vfsho),true));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static TObject FS_MemoryStream(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
bool writable;
|
||||
if(GetArgument(args,0,writable))
|
||||
{
|
||||
return TStreamHeapObject::Create(ls,new Tesses::Framework::Streams::MemoryStream(writable));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static TObject FS_CreateMemoryFilesystem(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
return TVFSHeapObject::Create(ls, new Tesses::Framework::Filesystem::MemoryFilesystem());
|
||||
}
|
||||
|
||||
static TObject FS_CreateFilesystem(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
TDictionary* dict;
|
||||
if(GetArgumentHeap(args,0,dict))
|
||||
{
|
||||
return TVFSHeapObject::Create(ls, new TObjectVFS(ls.GetGC(),dict));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static TObject FS_CreateStream(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
TDictionary* dict;
|
||||
if(GetArgumentHeap(args,0,dict))
|
||||
{
|
||||
return TStreamHeapObject::Create(ls, new TObjectStream(ls.GetGC(),dict));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static TObject FS_MakeFull(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
Tesses::Framework::Filesystem::VFSPath path;
|
||||
@ -126,6 +72,27 @@ namespace Tesses::CrossLang
|
||||
}
|
||||
return "";
|
||||
}
|
||||
static TObject FS_ReadAllBytes(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
Tesses::Framework::Filesystem::VFSPath path;
|
||||
TVFSHeapObject* vfs;
|
||||
if(GetArgumentHeap(args,0,vfs) && GetArgumentAsPath(args,1,path))
|
||||
{
|
||||
auto txtFile = vfs->vfs->OpenFile(path,"rb");
|
||||
if(txtFile == nullptr) return nullptr;
|
||||
auto res = TByteArray::Create(ls);
|
||||
std::array<uint8_t,1024> data;
|
||||
size_t read;
|
||||
do {
|
||||
read = txtFile->ReadBlock(data.data(),data.size());
|
||||
res->data.insert(res->data.end(),data.begin(),data.begin()+read);
|
||||
} while(read != 0);
|
||||
delete txtFile;
|
||||
return res;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
static TObject FS_WriteAllText(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
@ -143,6 +110,22 @@ namespace Tesses::CrossLang
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static TObject FS_WriteAllBytes(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
Tesses::Framework::Filesystem::VFSPath path;
|
||||
|
||||
TVFSHeapObject* vfs;
|
||||
|
||||
TByteArray* bArray;
|
||||
if(GetArgumentHeap(args,0,vfs) && GetArgumentAsPath(args,1,path) && GetArgumentHeap(args,2,bArray))
|
||||
{
|
||||
auto txtFile = vfs->vfs->OpenFile(path,"wb");
|
||||
if(txtFile == nullptr) return nullptr;
|
||||
txtFile->WriteBlock(bArray->data.data(),bArray->data.size());
|
||||
delete txtFile;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static TObject FS_getCurrentPath(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
@ -178,13 +161,9 @@ namespace Tesses::CrossLang
|
||||
dict->DeclareFunction(gc, "ReadAllText","Read all text from file", {"fs","filename"},FS_ReadAllText);
|
||||
dict->DeclareFunction(gc, "WriteAllText","Write all text to file", {"fs","filename","content"},FS_WriteAllText);
|
||||
|
||||
dict->DeclareFunction(gc, "MountableFilesystem","Create a mountable filesystem",{"root"}, FS_MountableFilesystem);
|
||||
dict->DeclareFunction(gc, "SubdirFilesystem","Create a subdir filesystem",{"fs","subdir"}, FS_SubdirFilesystem);
|
||||
dict->DeclareFunction(gc, "MemoryStream","Create a memory stream",{"writable"}, FS_MemoryStream);
|
||||
dict->DeclareFunction(gc, "CreateStream","Create stream", {"strm"},FS_CreateStream);
|
||||
dict->DeclareFunction(gc, "CreateFilesystem","Create filesystem", {"fs"},FS_CreateFilesystem);
|
||||
|
||||
dict->DeclareFunction(gc, "CreateMemoryFilesystem","Create in memory filesystem", {},FS_CreateMemoryFilesystem);
|
||||
dict->DeclareFunction(gc, "ReadAllBytes","Read all bytes from file", {"fs","filename"},FS_ReadAllBytes);
|
||||
dict->DeclareFunction(gc, "WriteAllBytes","Write all bytes to file", {"fs","filename","content"},FS_WriteAllBytes);
|
||||
|
||||
dict->DeclareFunction(gc, "CreateArchive", "Create a crvm archive",{"fs","strm","name","version","info"},FS_CreateArchive);
|
||||
dict->DeclareFunction(gc,"ExtractArchive", "Extract a crvm archive",{"strm","vfs"},FS_ExtractArchive);
|
||||
env->DeclareVariable("FS", dict);
|
||||
|
||||
@ -118,7 +118,61 @@ namespace Tesses::CrossLang
|
||||
TVFSHeapObject* vfs;
|
||||
return GetArgumentHeap(args,0,vfs);
|
||||
}
|
||||
|
||||
static TObject New_SubdirFilesystem(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
TVFSHeapObject* vfsho;
|
||||
|
||||
Tesses::Framework::Filesystem::VFSPath path;
|
||||
|
||||
if(GetArgumentHeap(args,0,vfsho) && GetArgumentAsPath(args,1,path))
|
||||
{
|
||||
return TVFSHeapObject::Create(ls,new Tesses::Framework::Filesystem::SubdirFilesystem(new TObjectVFS(ls.GetGC(),vfsho),path,true));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static TObject New_MountableFilesystem(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
TVFSHeapObject* vfsho;
|
||||
|
||||
if(GetArgumentHeap(args,0,vfsho))
|
||||
{
|
||||
return TVFSHeapObject::Create(ls,new Tesses::Framework::Filesystem::MountableFilesystem(new TObjectVFS(ls.GetGC(),vfsho),true));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static TObject New_MemoryStream(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
bool writable;
|
||||
if(GetArgument(args,0,writable))
|
||||
{
|
||||
return TStreamHeapObject::Create(ls,new Tesses::Framework::Streams::MemoryStream(writable));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static TObject New_MemoryFilesystem(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
return TVFSHeapObject::Create(ls, new Tesses::Framework::Filesystem::MemoryFilesystem());
|
||||
}
|
||||
|
||||
static TObject New_Filesystem(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
TDictionary* dict;
|
||||
if(GetArgumentHeap(args,0,dict))
|
||||
{
|
||||
return TVFSHeapObject::Create(ls, new TObjectVFS(ls.GetGC(),dict));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static TObject New_Stream(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
TDictionary* dict;
|
||||
if(GetArgumentHeap(args,0,dict))
|
||||
{
|
||||
return TStreamHeapObject::Create(ls, new TObjectStream(ls.GetGC(),dict));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static TObject TypeOf(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
if(args.size() < 1) return "Undefined";
|
||||
@ -334,6 +388,15 @@ namespace Tesses::CrossLang
|
||||
|
||||
env->permissions.canRegisterRoot=true;
|
||||
TDictionary* newTypes = TDictionary::Create(ls);
|
||||
|
||||
newTypes->DeclareFunction(gc, "MountableFilesystem","Create a mountable filesystem",{"root"}, New_MountableFilesystem);
|
||||
newTypes->DeclareFunction(gc, "SubdirFilesystem","Create a subdir filesystem",{"fs","subdir"}, New_SubdirFilesystem);
|
||||
newTypes->DeclareFunction(gc, "MemoryStream","Create a memory stream",{"writable"}, New_MemoryStream);
|
||||
newTypes->DeclareFunction(gc, "Stream","Create stream", {"strm"},New_Stream);
|
||||
newTypes->DeclareFunction(gc, "Filesystem","Create filesystem", {"fs"},New_Filesystem);
|
||||
|
||||
newTypes->DeclareFunction(gc, "MemoryFilesystem","Create in memory filesystem", {},New_MemoryFilesystem);
|
||||
|
||||
|
||||
newTypes->DeclareFunction(gc,"Version","Create a version object",{"$major","$minor","$patch","$build","$stage"},[](GCList& ls, std::vector<TObject> args)->TObject{
|
||||
int64_t major=1;
|
||||
@ -375,7 +438,7 @@ namespace Tesses::CrossLang
|
||||
env->DeclareFunction(gc, "TypeIsVFS","Get whether object is a virtual filesystem",{"object"},TypeIsVFS);
|
||||
|
||||
|
||||
env->DeclareFunction(gc, "Regex", "Create regex object",{"regex"},[](GCList& ls,std::vector<TObject> args)->TObject {
|
||||
newTypes->DeclareFunction(gc, "Regex", "Create regex object",{"regex"},[](GCList& ls,std::vector<TObject> args)->TObject {
|
||||
std::string str;
|
||||
if(GetArgument(args,0,str))
|
||||
{
|
||||
@ -384,7 +447,7 @@ namespace Tesses::CrossLang
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
env->DeclareFunction(gc, "Mutex", "Create mutex",{}, [](GCList& ls,std::vector<TObject> args)->TObject {
|
||||
newTypes->DeclareFunction(gc, "Mutex", "Create mutex",{}, [](GCList& ls,std::vector<TObject> args)->TObject {
|
||||
ls.GetGC()->BarrierBegin();
|
||||
auto mtx = TDictionary::Create(ls);
|
||||
auto native = TNative::Create(ls, new Tesses::Framework::Threading::Mutex(),[](void* ptr)->void{
|
||||
@ -428,7 +491,7 @@ namespace Tesses::CrossLang
|
||||
ls.GetGC()->BarrierEnd();
|
||||
return mtx;
|
||||
});
|
||||
env->DeclareFunction(gc, "Thread","Create thread",{"callback"},[](GCList& ls, std::vector<TObject> args)-> TObject
|
||||
newTypes->DeclareFunction(gc, "Thread","Create thread",{"callback"},[](GCList& ls, std::vector<TObject> args)-> TObject
|
||||
{
|
||||
if(args.size() == 1 && std::holds_alternative<THeapObjectHolder>(args[0]))
|
||||
{
|
||||
@ -440,7 +503,7 @@ 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,"ByteArray","Create bytearray, with optional either size (to size it) or string argument (to fill byte array)",{"$data"},ByteArray);
|
||||
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{
|
||||
|
||||
Reference in New Issue
Block a user