Add classes
This commit is contained in:
19
.vscode/c_cpp_properties.json
vendored
19
.vscode/c_cpp_properties.json
vendored
@ -4,9 +4,24 @@
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/include"
|
||||
"${workspaceFolder}/include",
|
||||
"/usr/include/glib-2.0/girepository",
|
||||
"/usr/include/glib-2.0"
|
||||
],
|
||||
"defines": [
|
||||
"CROSSLANG_ENABLE_JSON=1",
|
||||
"CROSSLANG_ENABLE_THREADING=1",
|
||||
"CROSSLANG_ENABLE_FILE_IO=1",
|
||||
"CROSSLANG_ENABLE_NETWORK=1",
|
||||
"CROSSLANG_ENABLE_TERMIOS=1",
|
||||
"CROSSLANG_ENABLE_MBED=1",
|
||||
"CROSSLANG_ENABLE_SQLITE=1",
|
||||
"CROSSLANG_ENABLE_SDL2=1",
|
||||
"CROSSLANG_ENABLE_PROCESS=1",
|
||||
"CROSSLANG_ENABLE_FFI=1",
|
||||
"CROSSLANG_ENABLE_SHARED=1",
|
||||
"CROSSLANG_ENABLE_GOBJECT_FFI=1"
|
||||
],
|
||||
"defines": ["CROSSLANG_ENABLE_JSON=1","CROSSLANG_ENABLE_THREADING=1","CROSSLANG_ENABLE_FILE_IO=1","CROSSLANG_ENABLE_NETWORK=1","CROSSLANG_ENABLE_TERMIOS=1","CROSSLANG_ENABLE_MBED=1","CROSSLANG_ENABLE_SQLITE=1","CROSSLANG_ENABLE_SDL2=1","-DCROSSLANG_ENABLE_PROCESS=1"],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "gnu++23",
|
||||
|
||||
@ -23,6 +23,7 @@ option(CROSSLANG_ENABLE_TIME "Enable Time" ON)
|
||||
option(CROSSLANG_SHARED_EXECUTABLES "Link with libcrosslang_shared" ON)
|
||||
option(CROSSLANG_FETCHCONTENT "Use fetchcontent" ON)
|
||||
option(CROSSLANG_ENABLE_CONFIG_ENVVAR "Allow setting config directory via the environment variable CROSSLANG_CONFIG" ON)
|
||||
option(CROSSLANG_ENABLE_FFI "Enable libffi" OFF)
|
||||
|
||||
option(CROSSLANG_CUSTOM_CONSOLE "Enable custom Console" OFF)
|
||||
|
||||
@ -60,7 +61,21 @@ FetchContent_MakeAvailable(TessesFramework)
|
||||
else()
|
||||
find_package(TessesFramework REQUIRED)
|
||||
endif()
|
||||
|
||||
if(CROSSLANG_ENABLE_FFI)
|
||||
find_package(PkgConfig)
|
||||
endif()
|
||||
|
||||
if(CROSSLANG_ENABLE_FFI AND CROSSLANG_ENABLE_SHARED)
|
||||
pkg_check_modules(LIBFFI REQUIRED IMPORTED_TARGET libffi)
|
||||
endif()
|
||||
function(CROSSLANG_LINK_DEPS CROSSLANG_TARGET_NAME)
|
||||
if(CROSSLANG_ENABLE_FFI AND CROSSLANG_ENABLE_SHARED)
|
||||
|
||||
target_compile_definitions(${CROSSLANG_TARGET_NAME} PUBLIC CROSSLANG_ENABLE_FFI)
|
||||
target_link_libraries(${CROSSLANG_TARGET_NAME} PUBLIC PkgConfig::LIBFFI)
|
||||
|
||||
endif()
|
||||
if(CROSSLANG_ENABLE_TIME)
|
||||
target_compile_definitions(${CROSSLANG_TARGET_NAME} PUBLIC CROSSLANG_ENABLE_TIME)
|
||||
endif()
|
||||
@ -123,6 +138,7 @@ src/runtime_methods/ogc.cpp
|
||||
src/runtime_methods/path.cpp
|
||||
src/runtime_methods/env.cpp
|
||||
src/runtime_methods/process.cpp
|
||||
src/types/any.cpp
|
||||
src/types/datetime.cpp
|
||||
src/types/ittr.cpp
|
||||
src/types/closure.cpp
|
||||
@ -134,6 +150,8 @@ src/types/rootenvironment.cpp
|
||||
src/types/subenvironment.cpp
|
||||
src/types/vfsheapobject.cpp
|
||||
src/types/streamheapobject.cpp
|
||||
src/types/class.cpp
|
||||
src/types/classenvironment.cpp
|
||||
src/vm/filereader.cpp
|
||||
src/vm/gc.cpp
|
||||
src/vm/gclist.cpp
|
||||
@ -232,7 +250,7 @@ endif()
|
||||
if(CROSSLANG_ENABLE_BINARIES)
|
||||
if(CROSSLANG_ENABLE_SHARED AND CROSSLANG_SHARED_EXECUTABLES)
|
||||
set(CMAKE_MACOSX_RPATH 1)
|
||||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
||||
add_executable(crossc src/crosslangcompiler.cpp ${CROSSLANG_WIN32_EXE_SRC})
|
||||
add_executable(crossvm src/crosslangvm.cpp ${CROSSLANG_WIN32_EXE_SRC})
|
||||
add_executable(crossint src/crosslanginterperter.cpp ${CROSSLANG_WIN32_EXE_SRC})
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
#include <regex>
|
||||
#include <time.h>
|
||||
#include <cstdbool>
|
||||
#include <any>
|
||||
|
||||
/**
|
||||
* @brief CrossLang Runtime Major version
|
||||
@ -53,6 +54,8 @@
|
||||
*
|
||||
*/
|
||||
namespace Tesses::CrossLang {
|
||||
constexpr std::string_view VMName = "CrossLangVM";
|
||||
constexpr std::string_view VMHowToGet = "https://crosslang.tesseslanguage.com/";
|
||||
/**
|
||||
* @brief Escape a crosslang string (for generating source code)
|
||||
*
|
||||
@ -841,16 +844,24 @@ class CharInstruction : public ByteCodeInstruction {
|
||||
|
||||
using SyntaxNode = std::variant<int64_t, double, std::string, char, bool, std::nullptr_t, Undefined, AdvancedSyntaxNode>;
|
||||
|
||||
class ObjectEntry {
|
||||
public:
|
||||
std::vector<std::string> name;
|
||||
std::string doc;
|
||||
std::vector<std::pair<std::string,SyntaxNode>> variables;
|
||||
std::vector<std::pair<std::pair<std::string,std::string>,uint32_t>> funcs;
|
||||
std::vector<std::pair<std::pair<std::string,std::string>,uint32_t>> static_funcs;
|
||||
|
||||
|
||||
struct CodeGenClassEntry {
|
||||
uint8_t type;
|
||||
uint32_t documentation;
|
||||
uint32_t name;
|
||||
std::vector<uint32_t> arguments;
|
||||
uint32_t closure;
|
||||
};
|
||||
|
||||
struct CodeGenClass {
|
||||
uint32_t documentation;
|
||||
std::vector<uint32_t> name;
|
||||
std::vector<uint32_t> inherits;
|
||||
std::vector<CodeGenClassEntry> entries;
|
||||
};
|
||||
|
||||
|
||||
class CodeGen {
|
||||
uint32_t id;
|
||||
uint32_t NewId();
|
||||
@ -867,7 +878,8 @@ class CodeGen {
|
||||
|
||||
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;
|
||||
std::vector<CodeGenClass> classes;
|
||||
|
||||
|
||||
void GenNode(std::vector<ByteCodeInstruction*>& instructions, SyntaxNode n,int32_t scope, int32_t contscope, int32_t brkscope, int32_t contI, int32_t brkI);
|
||||
void GenPop(std::vector<ByteCodeInstruction*>& instrs,SyntaxNode n);
|
||||
@ -1202,22 +1214,25 @@ constexpr std::string_view CaseStatement = "caseStatement";
|
||||
*/
|
||||
constexpr std::string_view DefaultStatement = "defaultStatement";
|
||||
/**
|
||||
* @brief Object statement (like class but not having inheritence) (not implemented)
|
||||
* @brief Class statement (not implemented)
|
||||
*
|
||||
*/
|
||||
constexpr std::string_view ObjectStatement = "objectStatement";
|
||||
constexpr std::string_view ClassStatement = "classStatement";
|
||||
/**
|
||||
* @brief Static statement (static methods in object statement)
|
||||
* @brief Method statement (in class statement)
|
||||
*
|
||||
*/
|
||||
constexpr std::string_view StaticStatement = "staticStatement";
|
||||
|
||||
constexpr std::string_view MethodStatement = "methodStatement";
|
||||
/**
|
||||
* @brief Method declaration method fun() {} in object statement
|
||||
* @brief Abstract method statement (in class statement)
|
||||
*
|
||||
*/
|
||||
|
||||
constexpr std::string_view MethodDeclaration = "methodDeclaration";
|
||||
constexpr std::string_view AbstractMethodStatement = "abstractMethodStatement";
|
||||
/**
|
||||
* @brief Field statement (in class statement)
|
||||
*
|
||||
*/
|
||||
constexpr std::string_view FieldStatement = "fieldStatement";
|
||||
/**
|
||||
* @brief Root path expression / "path" / "to" / "file" (fullfils the first /)
|
||||
*
|
||||
@ -1454,19 +1469,58 @@ class GC {
|
||||
static TByteArray* Create(GCList* gc);
|
||||
static TByteArray* Create(GCList& gc);
|
||||
};
|
||||
enum class TClassModifier {
|
||||
Private,
|
||||
Protected,
|
||||
Public,
|
||||
Static
|
||||
};
|
||||
class TClassEntry {
|
||||
public:
|
||||
|
||||
TClassModifier modifier;
|
||||
bool isFunction;
|
||||
bool isAbstract;
|
||||
std::vector<std::string> args;
|
||||
std::string documentation;
|
||||
std::string name;
|
||||
|
||||
uint32_t chunkId;
|
||||
};
|
||||
class TClass {
|
||||
public:
|
||||
std::string documentation;
|
||||
std::vector<std::string> name;
|
||||
std::vector<std::string> inherits;
|
||||
std::vector<TClassEntry> entry;
|
||||
|
||||
};
|
||||
class TClassObjectEntry {
|
||||
public:
|
||||
TClassModifier modifier;
|
||||
bool canSet;
|
||||
std::string name;
|
||||
std::string owner;
|
||||
TObject value;
|
||||
|
||||
};
|
||||
|
||||
class TFile : public THeapObject
|
||||
{
|
||||
public:
|
||||
|
||||
static TFile* Create(GCList* gc);
|
||||
static TFile* Create(GCList& gc);
|
||||
std::vector<TFileChunk*> chunks;
|
||||
|
||||
std::vector<std::string> strings;
|
||||
std::vector<std::pair<std::string,std::string>> vms;
|
||||
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::pair<std::string,std::vector<uint8_t>>> sections;
|
||||
std::vector<std::vector<uint8_t>> resources;
|
||||
std::vector<TClass> classes;
|
||||
std::string name;
|
||||
TVMVersion version;
|
||||
std::string info;
|
||||
@ -1480,6 +1534,8 @@ class GC {
|
||||
|
||||
std::string GetString(Tesses::Framework::Streams::Stream* strm);
|
||||
void Mark();
|
||||
|
||||
void EnsureCanRunInCrossLang();
|
||||
};
|
||||
|
||||
class TList : public THeapObject
|
||||
@ -1597,9 +1653,18 @@ class GC {
|
||||
TObject Eval(GCList& ls,std::string code);
|
||||
virtual bool HasVariable(std::string key)=0;
|
||||
virtual bool HasVariableRecurse(std::string key)=0;
|
||||
|
||||
|
||||
virtual bool HasVariableOrFieldRecurse(std::string key,bool setting=false)=0;
|
||||
virtual TObject GetVariable(std::string key)=0;
|
||||
|
||||
virtual TObject GetVariable(GCList& ls, std::string key)=0;
|
||||
virtual TObject SetVariable(GCList& ls, std::string key, TObject v)=0;
|
||||
|
||||
virtual void SetVariable(std::string key, TObject value)=0;
|
||||
TDictionary* EnsureDictionary(GC* gc, std::string key);
|
||||
virtual void DeclareVariable(std::string key, TObject value)=0;
|
||||
void DeclareVariable(GC* gc,std::vector<std::string> key, TObject value);
|
||||
virtual TRootEnvironment* GetRootEnvironment()=0;
|
||||
virtual TEnvironment* GetParentEnvironment()=0;
|
||||
virtual TSubEnvironment* GetSubEnvironment(TDictionary* dict);
|
||||
@ -1613,6 +1678,54 @@ class GC {
|
||||
TObject CallFunction(GCList& ls, std::string key, std::vector<TObject> args);
|
||||
|
||||
};
|
||||
class TClassEnvironment;
|
||||
class TClassObject : public THeapObject
|
||||
{
|
||||
TClassObjectEntry* GetEntry(std::string classN, std::string key);
|
||||
public:
|
||||
TFile* file;
|
||||
uint32_t classIndex;
|
||||
TEnvironment* ogEnv;
|
||||
TClassEnvironment* env;
|
||||
std::string name;
|
||||
std::vector<std::string> inherit_tree;
|
||||
std::vector<TClassObjectEntry> entries;
|
||||
|
||||
static TClassObject* Create(GCList& ls, TFile* f, uint32_t classIndex, TEnvironment* env, std::vector<TObject> args);
|
||||
static TClassObject* Create(GCList* ls, TFile* f, uint32_t classIndex, TEnvironment* env, std::vector<TObject> args);
|
||||
|
||||
TObject GetValue(std::string className, std::string name);
|
||||
void SetValue(std::string className, std::string name,TObject value);
|
||||
bool HasValue(std::string className,std::string name);
|
||||
bool HasField(std::string className,std::string name);
|
||||
bool HasMethod(std::string className,std::string name);
|
||||
std::string TypeName();
|
||||
void Mark();
|
||||
};
|
||||
class TClassEnvironment : public TEnvironment
|
||||
{
|
||||
TEnvironment* env;
|
||||
TClassObject* clsObj;
|
||||
public:
|
||||
static TClassEnvironment* Create(GCList* gc,TEnvironment* env,TClassObject* obj);
|
||||
static TClassEnvironment* Create(GCList& gc,TEnvironment* env,TClassObject* obj);
|
||||
TClassEnvironment(TEnvironment* env,TClassObject* obj);
|
||||
bool HasVariable(std::string key);
|
||||
bool HasVariableRecurse(std::string key);
|
||||
bool HasVariableOrFieldRecurse(std::string key, bool setting=false);
|
||||
|
||||
TObject GetVariable(std::string key);
|
||||
void SetVariable(std::string key, TObject value);
|
||||
TObject GetVariable(GCList& ls, std::string key);
|
||||
TObject SetVariable(GCList& ls, std::string key, TObject v);
|
||||
|
||||
void DeclareVariable(std::string key, TObject value);
|
||||
TRootEnvironment* GetRootEnvironment();
|
||||
TEnvironment* GetParentEnvironment();
|
||||
|
||||
void Mark();
|
||||
};
|
||||
|
||||
|
||||
class EnvironmentPermissions {
|
||||
public:
|
||||
@ -1647,6 +1760,9 @@ class GC {
|
||||
EnvironmentPermissions permissions;
|
||||
|
||||
std::vector<std::pair<std::string, TVMVersion>> dependencies;
|
||||
std::vector<std::pair<TFile*, uint32_t>> classes;
|
||||
|
||||
bool TryFindClass(std::vector<std::string>& name, size_t& index);
|
||||
|
||||
void LoadFileWithDependencies(GC* gc,Tesses::Framework::Filesystem::VFS* vfs, TFile* f);
|
||||
void LoadFileWithDependencies(GC* gc,Tesses::Framework::Filesystem::VFS* vfs, Tesses::Framework::Filesystem::VFSPath path);
|
||||
@ -1657,8 +1773,13 @@ class GC {
|
||||
TRootEnvironment(TDictionary* dict);
|
||||
bool HasVariable(std::string key);
|
||||
bool HasVariableRecurse(std::string key);
|
||||
bool HasVariableOrFieldRecurse(std::string key,bool setting=false);
|
||||
|
||||
TObject GetVariable(std::string key);
|
||||
void SetVariable(std::string key, TObject value);
|
||||
|
||||
TObject GetVariable(GCList& ls, std::string key);
|
||||
TObject SetVariable(GCList& ls, std::string key, TObject v);
|
||||
void DeclareVariable(std::string key, TObject value);
|
||||
TRootEnvironment* GetRootEnvironment();
|
||||
TEnvironment* GetParentEnvironment();
|
||||
@ -1696,8 +1817,13 @@ class GC {
|
||||
TSubEnvironment(TEnvironment* env,TDictionary* dict);
|
||||
bool HasVariable(std::string key);
|
||||
bool HasVariableRecurse(std::string key);
|
||||
bool HasVariableOrFieldRecurse(std::string key, bool setting=false);
|
||||
|
||||
TObject GetVariable(std::string key);
|
||||
void SetVariable(std::string key, TObject value);
|
||||
TObject GetVariable(GCList& ls, std::string key);
|
||||
TObject SetVariable(GCList& ls, std::string key, TObject v);
|
||||
|
||||
void DeclareVariable(std::string key, TObject value);
|
||||
TRootEnvironment* GetRootEnvironment();
|
||||
TEnvironment* GetParentEnvironment();
|
||||
@ -1944,6 +2070,7 @@ class GC {
|
||||
TFile* file;
|
||||
uint32_t chunkId;
|
||||
TEnvironment* env;
|
||||
std::string className;
|
||||
TObject Call(GCList& ls,std::vector<TObject> args);
|
||||
void Mark();
|
||||
};
|
||||
@ -2121,6 +2248,43 @@ class GC {
|
||||
return error_message.c_str();
|
||||
}
|
||||
};
|
||||
class TAny : public THeapObject {
|
||||
public:
|
||||
std::any any;
|
||||
TObject other;
|
||||
|
||||
static TAny* Create(GCList& ls);
|
||||
static TAny* Create(GCList* ls);
|
||||
void Mark();
|
||||
};
|
||||
class TNativeObject : public THeapObject
|
||||
{
|
||||
public:
|
||||
template<typename T,typename... TArgs>
|
||||
static T* Create(GCList& ls,TArgs... args)
|
||||
{
|
||||
T* obj = new T(args...);
|
||||
GC* gc = ls.GetGC();
|
||||
ls.Add(obj);
|
||||
gc->Watch(obj);
|
||||
return obj;
|
||||
}
|
||||
template<typename T,typename... TArgs>
|
||||
static T* Create(GCList* ls,TArgs... args)
|
||||
{
|
||||
T* obj = new T(args...);
|
||||
GC* gc = ls->GetGC();
|
||||
ls->Add(obj);
|
||||
gc->Watch(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
virtual TObject CallMethod(GCList& ls,std::string name, std::vector<TObject> args)=0;
|
||||
virtual std::string TypeName()=0;
|
||||
virtual bool ToBool();
|
||||
virtual bool Equals(GC* gc, TObject right);
|
||||
virtual ~TNativeObject();
|
||||
};
|
||||
class TNative : public THeapObject
|
||||
{
|
||||
std::atomic<bool> destroyed;
|
||||
@ -2138,6 +2302,8 @@ class GC {
|
||||
~TNative();
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ThreadHandle : public THeapObject {
|
||||
public:
|
||||
Tesses::Framework::Threading::Thread* thrd;
|
||||
|
||||
@ -65,7 +65,8 @@ namespace Tesses::CrossLang
|
||||
|
||||
if(!this->icon.empty())
|
||||
sections++;
|
||||
|
||||
if(!this->classes.empty())
|
||||
sections++;
|
||||
|
||||
WriteInt(stream,sections);
|
||||
uint32_t strSz=4;
|
||||
@ -181,6 +182,54 @@ namespace Tesses::CrossLang
|
||||
Write(stream,buffer.data(),buffer.size());
|
||||
}
|
||||
|
||||
if(!classes.empty())
|
||||
{
|
||||
uint32_t len = 4;
|
||||
for(auto& cls : classes)
|
||||
{
|
||||
len += 8;
|
||||
len += cls.name.size() * 4;
|
||||
len += 4;
|
||||
len += cls.inherits.size() * 4;
|
||||
len += 4;
|
||||
for(auto& clsEnt : cls.entries)
|
||||
{
|
||||
len += 17;
|
||||
for(auto& arg : clsEnt.arguments) len+=4;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(buffer,"CLSS",4);
|
||||
Write(stream,buffer,4);
|
||||
WriteInt(stream,len);
|
||||
WriteInt(stream,(uint32_t)classes.size());
|
||||
for(auto& cls : classes)
|
||||
{
|
||||
WriteInt(stream,cls.documentation);
|
||||
WriteInt(stream,(uint32_t)cls.name.size());
|
||||
for(auto namePart : cls.name) WriteInt(stream,namePart);
|
||||
|
||||
WriteInt(stream,(uint32_t)cls.inherits.size());
|
||||
for(auto inhPart : cls.inherits) WriteInt(stream,inhPart);
|
||||
|
||||
WriteInt(stream,(uint32_t)cls.entries.size());
|
||||
|
||||
for(auto& ent : cls.entries)
|
||||
{
|
||||
buffer[0] = ent.type;
|
||||
Write(stream,buffer,1);
|
||||
WriteInt(stream,ent.documentation);
|
||||
WriteInt(stream,ent.name);
|
||||
WriteInt(stream,(uint32_t)ent.arguments.size());
|
||||
for(auto ar : ent.arguments)
|
||||
{
|
||||
WriteInt(stream,ar);
|
||||
}
|
||||
WriteInt(stream,ent.closure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& reso : res)
|
||||
{
|
||||
memcpy(buffer,"RESO",4);
|
||||
@ -489,7 +538,122 @@ namespace Tesses::CrossLang
|
||||
TWO_EXPR(NotEqualsExpression, NEQ)
|
||||
TWO_EXPR(EqualsExpression, EQ)
|
||||
TWO_EXPR(XOrExpression, XOR)
|
||||
if(adv.nodeName == RelativePathExpression)
|
||||
if(adv.nodeName == ClassStatement && adv.nodes.size() >= 3 && std::holds_alternative<std::string>(adv.nodes[0]))
|
||||
{
|
||||
CodeGenClass cls;
|
||||
cls.documentation = GetString(std::get<std::string>(adv.nodes[0]));
|
||||
GetFunctionName(cls.name,adv.nodes[1]);
|
||||
GetFunctionName(cls.inherits,adv.nodes[2]);
|
||||
for(size_t i = 3; i < adv.nodes.size(); i++)
|
||||
{
|
||||
auto& node = adv.nodes[i];
|
||||
if(std::holds_alternative<AdvancedSyntaxNode>(node))
|
||||
{
|
||||
auto& adv2 = std::get<AdvancedSyntaxNode>(node);
|
||||
CodeGenClassEntry ent;
|
||||
ent.type = 0;
|
||||
if(adv2.nodes.size() >= 2 && std::holds_alternative<std::string>(adv2.nodes[0]) && std::holds_alternative<std::string>(adv2.nodes[1]))
|
||||
{
|
||||
ent.documentation=GetString(std::get<std::string>(adv2.nodes[0]));
|
||||
std::string type=std::get<std::string>(adv2.nodes[1]);
|
||||
if(type == "private") ent.type = 0;
|
||||
else if(type == "protected") ent.type = 1;
|
||||
else if(type == "public") ent.type = 2;
|
||||
else if(type == "static") ent.type = 3;
|
||||
}
|
||||
|
||||
if(adv2.nodeName == MethodStatement && adv2.nodes.size() == 4 && std::holds_alternative<AdvancedSyntaxNode>(adv2.nodes[2]) )
|
||||
{
|
||||
|
||||
|
||||
//documentation,myTkn.text,nameAndArgs,closureData
|
||||
size_t fnindex=this->chunks.size();
|
||||
ent.closure=(uint32_t)fnindex;
|
||||
this->chunks.resize(fnindex+1);
|
||||
auto& nameAndArgs= std::get<AdvancedSyntaxNode>(adv2.nodes[2]);
|
||||
if(nameAndArgs.nodeName == FunctionCallExpression && !nameAndArgs.nodes.empty() && std::holds_alternative<AdvancedSyntaxNode>(nameAndArgs.nodes[0]))
|
||||
{
|
||||
auto& getvar = std::get<AdvancedSyntaxNode>(nameAndArgs.nodes[0]);
|
||||
if(getvar.nodeName == GetVariableExpression && getvar.nodes.size() == 1 && std::holds_alternative<std::string>(getvar.nodes[0]))
|
||||
{
|
||||
|
||||
ent.name = GetString(std::get<std::string>(getvar.nodes[0]));
|
||||
if(nameAndArgs.nodes.size() > 1)
|
||||
{
|
||||
GetFunctionArgs(ent.arguments, nameAndArgs.nodes[1]);
|
||||
}
|
||||
}
|
||||
else continue;
|
||||
}
|
||||
|
||||
std::vector<ByteCodeInstruction*> fnInstructions;
|
||||
|
||||
GenNode(fnInstructions,adv2.nodes[3],0,-1,-1,-1,-1);
|
||||
|
||||
this->chunks[fnindex] = std::pair<std::vector<uint32_t>,std::vector<ByteCodeInstruction*>>(ent.arguments, fnInstructions);
|
||||
}
|
||||
else if(adv2.nodeName == AbstractMethodStatement && adv2.nodes.size() == 3 && std::holds_alternative<AdvancedSyntaxNode>(adv2.nodes[2]))
|
||||
{
|
||||
ent.closure = 0;
|
||||
ent.type |= 0b00001000;
|
||||
//documentation,myTkn.text,nameAndArgs
|
||||
auto& nameAndArgs= std::get<AdvancedSyntaxNode>(adv2.nodes[2]);
|
||||
if(nameAndArgs.nodeName == FunctionCallExpression && !nameAndArgs.nodes.empty() && std::holds_alternative<AdvancedSyntaxNode>(nameAndArgs.nodes[0]))
|
||||
{
|
||||
auto& getvar = std::get<AdvancedSyntaxNode>(nameAndArgs.nodes[0]);
|
||||
if(getvar.nodeName == GetVariableExpression && getvar.nodes.size() == 1 && std::holds_alternative<std::string>(getvar.nodes[0]))
|
||||
{
|
||||
ent.name = GetString(std::get<std::string>(getvar.nodes[0]));
|
||||
if(nameAndArgs.nodes.size() > 1)
|
||||
{
|
||||
GetFunctionArgs(ent.arguments, nameAndArgs.nodes[1]);
|
||||
}
|
||||
} else continue;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if(adv2.nodeName == FieldStatement && adv2.nodes.size() == 3 && std::holds_alternative<AdvancedSyntaxNode>(adv2.nodes[2]))
|
||||
{
|
||||
auto& setter = std::get<AdvancedSyntaxNode>(adv2.nodes[2]);
|
||||
if(setter.nodeName == GetVariableExpression && setter.nodes.size() == 1 && std::holds_alternative<std::string>(setter.nodes[0]))
|
||||
{
|
||||
ent.closure = 0;
|
||||
ent.type |= 0b00001100;
|
||||
|
||||
ent.name = GetString(std::get<std::string>(setter.nodes[0]));
|
||||
|
||||
}
|
||||
else if(setter.nodeName == AssignExpression && setter.nodes.size() == 2 && std::holds_alternative<AdvancedSyntaxNode>(setter.nodes[0]))
|
||||
{
|
||||
auto& getvar = std::get<AdvancedSyntaxNode>(setter.nodes[0]);
|
||||
if(getvar.nodeName == GetVariableExpression && getvar.nodes.size() == 1 && std::holds_alternative<std::string>(getvar.nodes[0]))
|
||||
{
|
||||
ent.type |= 0b00000100;
|
||||
ent.name = GetString(std::get<std::string>(getvar.nodes[0]));
|
||||
size_t fnindex=this->chunks.size();
|
||||
ent.closure=(uint32_t)fnindex;
|
||||
ent.arguments={};
|
||||
|
||||
this->chunks.resize(fnindex+1);
|
||||
|
||||
std::vector<ByteCodeInstruction*> fnInstructions;
|
||||
|
||||
GenNode(fnInstructions,AdvancedSyntaxNode::Create(ReturnStatement,false,{setter.nodes[1]}),0,-1,-1,-1,-1);
|
||||
|
||||
this->chunks[fnindex] = std::pair<std::vector<uint32_t>,std::vector<ByteCodeInstruction*>>({}, fnInstructions);
|
||||
}
|
||||
else continue;
|
||||
}
|
||||
else continue;
|
||||
}
|
||||
cls.entries.push_back(ent);
|
||||
}
|
||||
}
|
||||
classes.push_back(cls);
|
||||
}
|
||||
else if(adv.nodeName == RelativePathExpression)
|
||||
{
|
||||
instructions.push_back(new SimpleInstruction(Instruction::PUSHRELATIVEPATH));
|
||||
}
|
||||
|
||||
@ -928,10 +928,14 @@ namespace Tesses::CrossLang
|
||||
}
|
||||
SyntaxNode Parser::ParseNode(bool isRoot)
|
||||
{
|
||||
std::string documentation="";
|
||||
if(i < tokens.size() && !isRoot && tokens[i].type == Documentation)
|
||||
{
|
||||
auto txt = tokens[i].text;
|
||||
i++;
|
||||
if(i < tokens.size() && tokens[i].text == "class" && tokens[i].type == LexTokenType::Identifier)
|
||||
documentation = txt;
|
||||
else
|
||||
return AdvancedSyntaxNode::Create(DocumentationStatement,false,{txt,ParseNode()});
|
||||
}
|
||||
if(IsSymbol("{") || isRoot)
|
||||
@ -1056,99 +1060,93 @@ namespace Tesses::CrossLang
|
||||
}
|
||||
return AdvancedSyntaxNode::Create(EachStatement,false,{item,list,body});
|
||||
}
|
||||
if(IsIdentifier("object"))
|
||||
if(IsIdentifier("class"))
|
||||
{
|
||||
//TODO: complete this
|
||||
if(i < tokens.size())
|
||||
{
|
||||
std::string name = tokens[i++].text;
|
||||
EnsureSymbol("{");
|
||||
std::vector<SyntaxNode> name_and_methods;
|
||||
std::vector<SyntaxNode> name_and_methods={documentation};
|
||||
|
||||
auto name = ParseExpression();
|
||||
name_and_methods.push_back(name);
|
||||
|
||||
if(IsSymbol(":",true))
|
||||
{
|
||||
name_and_methods.push_back(ParseExpression());
|
||||
}
|
||||
else
|
||||
{
|
||||
name_and_methods.push_back(AdvancedSyntaxNode::Create(GetVariableExpression,true,{"ClassObject"}));
|
||||
}
|
||||
EnsureSymbol("{");
|
||||
|
||||
|
||||
while(!IsSymbol("}",false) && i < tokens.size())
|
||||
{
|
||||
std::string documentation = "";
|
||||
bool hasDocumentation=false;
|
||||
|
||||
documentation="";
|
||||
|
||||
|
||||
if(tokens[i].type == LexTokenType::Documentation)
|
||||
{
|
||||
hasDocumentation=true;
|
||||
documentation = tokens[i++].text;
|
||||
}
|
||||
|
||||
if(i < tokens.size())
|
||||
{
|
||||
if(IsIdentifier("method"))
|
||||
if(IsAnyIdentifier({"public","private","protected","static"}))
|
||||
{
|
||||
auto myTkn = tkn;
|
||||
if(IsIdentifier("abstract"))
|
||||
{
|
||||
if(myTkn.text == "static") throw SyntaxException(myTkn.lineInfo,"Static abstract function doesn't make sense");
|
||||
auto nameAndArgs = ParseExpression();
|
||||
EnsureSymbol(";");
|
||||
|
||||
|
||||
name_and_methods.push_back(AdvancedSyntaxNode::Create(AbstractMethodStatement,false,{documentation,myTkn.text,nameAndArgs}));
|
||||
|
||||
|
||||
|
||||
}
|
||||
else if(i + 1 < tokens.size() && (tokens[i+1].text == "=" || tokens[i+1].text == ";") && tokens[i+1].type == LexTokenType::Symbol)
|
||||
{
|
||||
auto setter = ParseExpression();
|
||||
EnsureSymbol(";");
|
||||
|
||||
SyntaxNode field = AdvancedSyntaxNode::Create(FieldStatement,false,{
|
||||
documentation,
|
||||
myTkn.text,
|
||||
|
||||
setter
|
||||
});
|
||||
|
||||
name_and_methods.push_back(field);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
name_and_methods.push_back(AdvancedSyntaxNode::Create(MethodStatement,false,{documentation,myTkn.text,nameAndArgs,ParseNode()}));
|
||||
|
||||
}
|
||||
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();
|
||||
name_and_methods.push_back(AdvancedSyntaxNode::Create(MethodStatement,false,{documentation,myTkn.text,nameAndArgs,AdvancedSyntaxNode::Create(ReturnStatement,false,{v})}));
|
||||
|
||||
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);
|
||||
return AdvancedSyntaxNode::Create(ClassStatement, false, name_and_methods);
|
||||
}
|
||||
else throw std::out_of_range("End of file");
|
||||
}
|
||||
|
||||
@ -86,6 +86,83 @@ void DumpFile(std::filesystem::path p)
|
||||
{
|
||||
std::cout << "Name: " << strs.at((size_t)EnsureInt(strm)) << std::endl;
|
||||
}
|
||||
else if(tableName == "CLSS")
|
||||
{
|
||||
std::cout << "Classes:\n";
|
||||
uint32_t clss_cnt= EnsureInt(strm);
|
||||
for(uint32_t j = 0; j < clss_cnt; j++)
|
||||
{
|
||||
std::cout << "\t/^" << strs.at(EnsureInt(strm)) << "^/" << std::endl;
|
||||
uint32_t fnPartsC = EnsureInt(strm);
|
||||
std::cout << "\tName: ";
|
||||
for(uint32_t k = 0; k < fnPartsC; k++)
|
||||
{
|
||||
if(k > 0) std::cout << ".";
|
||||
std::cout << strs.at(EnsureInt(strm));
|
||||
}
|
||||
std::cout << std::endl;
|
||||
fnPartsC = EnsureInt(strm);
|
||||
std::cout << "\tInherits: ";
|
||||
for(uint32_t k = 0; k < fnPartsC; k++)
|
||||
{
|
||||
if(k > 0) std::cout << ".";
|
||||
std::cout << strs.at(EnsureInt(strm));
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
uint32_t ents = EnsureInt(strm);
|
||||
|
||||
for(uint8_t k = 0; k < ents; k++)
|
||||
{
|
||||
Ensure(strm,main_header,1);
|
||||
uint8_t flags = main_header[0];
|
||||
std::cout << "\t\t/^" << strs.at(EnsureInt(strm)) << "^/" << std::endl;
|
||||
std::string fnname = strs.at(EnsureInt(strm));
|
||||
std::string fnargs;
|
||||
uint32_t argParts = EnsureInt(strm);
|
||||
|
||||
for(uint32_t l = 0; l < argParts; l++)
|
||||
{
|
||||
if(l > 0) fnargs += ", ";
|
||||
fnargs += strs.at(EnsureInt(strm));
|
||||
}
|
||||
uint32_t fnchunk = EnsureInt(strm);
|
||||
switch(flags & 3)
|
||||
{
|
||||
case 0:
|
||||
std::cout << "\t\tprivate ";
|
||||
break;
|
||||
case 1:
|
||||
std::cout << "\t\tprotected ";
|
||||
break;
|
||||
case 2:
|
||||
std::cout << "\t\tpublic ";
|
||||
break;
|
||||
case 3:
|
||||
std::cout << "\t\tstatic ";
|
||||
break;
|
||||
}
|
||||
|
||||
switch((flags >> 2) & 3)
|
||||
{
|
||||
case 0:
|
||||
std::cout << "func " << fnname << "(" << fnargs << "), chunk = " << fnchunk << std::endl;
|
||||
|
||||
break;
|
||||
case 1:
|
||||
std::cout << "field " << fnname << ", chunk = " << fnchunk << std::endl;
|
||||
break;
|
||||
case 2:
|
||||
std::cout << "abstract " << fnname << "(" << fnargs << ")" << std::endl;
|
||||
break;
|
||||
case 3:
|
||||
std::cout << "unset_field " << fnname << std::endl;
|
||||
break;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(tableName == "CHKS")
|
||||
{
|
||||
size_t chunkCount = (size_t)EnsureInt(strm);
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
#include "CrossLang.hpp"
|
||||
#if defined(CROSSLANG_ENABLE_SHARED)
|
||||
#if defined(CROSSLANG_ENABLE_FFI)
|
||||
#include <ffi.h>
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
@ -24,6 +27,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace Tesses::CrossLang
|
||||
{
|
||||
#if defined(CROSSLANG_ENABLE_SHARED)
|
||||
@ -60,6 +64,357 @@ namespace Tesses::CrossLang
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#if defined(CROSSLANG_ENABLE_FFI)
|
||||
typedef union {
|
||||
ffi_arg v_arg;
|
||||
ffi_sarg v_sarg;
|
||||
uint64_t v_u64;
|
||||
int64_t v_i64;
|
||||
double v_f64;
|
||||
void* v_ptr;
|
||||
|
||||
} ffi_tmp_type_t;
|
||||
|
||||
template<typename T>
|
||||
class ffi_my_struct_t {
|
||||
char ffi_my_struct_chr;
|
||||
T ffi_my_struct_val;
|
||||
|
||||
public:
|
||||
static int64_t GetPadding()
|
||||
{
|
||||
ffi_my_struct_t<T> s;
|
||||
return ((int64_t)&s.ffi_my_struct_val - (int64_t)&s.ffi_my_struct_chr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
ffi_tmp_type_t FFI_ConvertTObjectToFFIType(TObject& arg,std::string t)
|
||||
{
|
||||
|
||||
if(std::holds_alternative<char>(arg))
|
||||
{
|
||||
if(t == "char" || t == "i8" || t == "i16" || t == "i32")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_sarg = std::get<char>(arg)};
|
||||
}
|
||||
else if(t == "u8" || t == "u16" || t == "u32")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_arg = (uint8_t)std::get<char>(arg)};
|
||||
}
|
||||
else if(t == "u64")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_u64 = (uint8_t)std::get<char>(arg)};
|
||||
}
|
||||
else if(t == "i64")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_i64 = std::get<char>(arg)};
|
||||
}
|
||||
}
|
||||
else if(std::holds_alternative<int64_t>(arg))
|
||||
{
|
||||
if(t == "u8" || t == "u16" || t == "u32")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_arg = (ffi_arg)(uint64_t)std::get<int64_t>(arg)};
|
||||
}
|
||||
else if(t == "char" || t == "i8" || t == "i16" || t == "i32")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_sarg = (ffi_sarg)std::get<int64_t>(arg)};
|
||||
}
|
||||
else if(t == "u64")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_u64 = (uint64_t)std::get<int64_t>(arg)};
|
||||
}
|
||||
else if(t == "i64")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_i64 =std::get<int64_t>(arg)};
|
||||
}
|
||||
else if(t == "pointer" || t == "string")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_ptr = (void*)std::get<int64_t>(arg)};
|
||||
}
|
||||
}
|
||||
else if(std::holds_alternative<double>(arg))
|
||||
{
|
||||
if(t == "f64")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_f64 =std::get<double>(arg)};
|
||||
}
|
||||
}
|
||||
else if(std::holds_alternative<std::string>(arg))
|
||||
{
|
||||
if(t == "pointer" || t == "string")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_ptr = (void*)std::get<std::string>(arg).c_str()};
|
||||
}
|
||||
}
|
||||
else if(std::holds_alternative<THeapObjectHolder>(arg))
|
||||
{
|
||||
auto obj = std::get<THeapObjectHolder>(arg).obj;
|
||||
auto bA = dynamic_cast<TByteArray*>(obj);
|
||||
auto nat = dynamic_cast<TNative*>(obj);
|
||||
if(bA != nullptr)
|
||||
{
|
||||
if(t == "pointer" || t == "string")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_ptr = (void*)bA->data.data() };
|
||||
}
|
||||
}
|
||||
if(nat != nullptr)
|
||||
{
|
||||
if(t == "pointer" || t == "string")
|
||||
{
|
||||
return (ffi_tmp_type_t){.v_ptr = nat->GetPointer() };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {0};
|
||||
}
|
||||
|
||||
ffi_type* FFI_ConvertStringToFFIType(std::string t)
|
||||
{
|
||||
if(t == "char")
|
||||
{
|
||||
return &ffi_type_schar;
|
||||
}
|
||||
else if(t == "i8")
|
||||
{
|
||||
return &ffi_type_sint8;
|
||||
}
|
||||
else if(t == "u8")
|
||||
{
|
||||
return &ffi_type_uint8;
|
||||
}
|
||||
else if(t == "i16")
|
||||
{
|
||||
return &ffi_type_sint16;
|
||||
}
|
||||
else if(t == "u16")
|
||||
{
|
||||
return &ffi_type_uint16;
|
||||
}
|
||||
else if(t == "i32")
|
||||
{
|
||||
return &ffi_type_sint32;
|
||||
}
|
||||
else if(t == "u32")
|
||||
{
|
||||
return &ffi_type_uint32;
|
||||
}
|
||||
else if(t == "i64")
|
||||
{
|
||||
return &ffi_type_sint64;
|
||||
}
|
||||
else if(t == "u64")
|
||||
{
|
||||
return &ffi_type_uint64;
|
||||
}
|
||||
else if(t == "float")
|
||||
{
|
||||
return &ffi_type_float;
|
||||
}
|
||||
else if(t == "double")
|
||||
{
|
||||
return &ffi_type_double;
|
||||
}
|
||||
else if(t == "void")
|
||||
{
|
||||
return &ffi_type_void;
|
||||
}
|
||||
else if(t == "pointer" || t == "string")
|
||||
{
|
||||
return &ffi_type_pointer;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
TExternalMethod* FFI_CreateFunction(GCList& ls,TNative* native,std::string retVal,std::vector<std::string> listArgs,ffi_abi abi,bool freeRet)
|
||||
{
|
||||
ffi_type* retTypeT = FFI_ConvertStringToFFIType(retVal);
|
||||
std::vector<ffi_type*> argTypes;
|
||||
|
||||
argTypes.resize(listArgs.size());
|
||||
for(size_t i = 0; i < listArgs.size();i++)
|
||||
{
|
||||
argTypes[i] = FFI_ConvertStringToFFIType(listArgs[i]);
|
||||
}
|
||||
auto cb = TExternalMethod::Create(ls,"FFI Generated function, returns: " + retVal,listArgs, [retVal,listArgs,abi,native,freeRet,argTypes,retTypeT](GCList& ls, std::vector<TObject> args)->TObject {
|
||||
if(args.size() != listArgs.size()) throw VMException("Args must be " + std::to_string(listArgs.size()) + "but got " + std::to_string(args.size()) + ".");
|
||||
ffi_cif cif;
|
||||
|
||||
std::vector<void*> argVals;
|
||||
std::vector<ffi_tmp_type_t> tmpTypes;
|
||||
argVals.resize(listArgs.size());
|
||||
tmpTypes.resize(listArgs.size());
|
||||
for(size_t i = 0; i < argTypes.size(); i++)
|
||||
{
|
||||
|
||||
tmpTypes[i] = FFI_ConvertTObjectToFFIType(args[i],listArgs[i]);
|
||||
if(listArgs[i] == "char" || listArgs[i] == "i8" || listArgs[i] == "i16" || listArgs[i] == "i32" || listArgs[i] == "u8" || listArgs[i] == "u16" || listArgs[i] == "u32")
|
||||
{
|
||||
argVals[i] = (void*)&(tmpTypes[i].v_arg);
|
||||
}
|
||||
|
||||
else if(listArgs[i] == "u64" || listArgs[i] == "i64")
|
||||
{
|
||||
argVals[i] = (void*)&(tmpTypes[i].v_u64);
|
||||
}
|
||||
else if(listArgs[i] == "pointer" || listArgs[i] == "string")
|
||||
{
|
||||
argVals[i] = (void*)&(tmpTypes[i].v_ptr);
|
||||
}
|
||||
else if(listArgs[i] == "f64")
|
||||
{
|
||||
argVals[i] = (void*)&(tmpTypes[i].v_f64);
|
||||
}
|
||||
}
|
||||
ffi_prep_cif(&cif, abi,(unsigned int)listArgs.size(),retTypeT,(ffi_type**)argTypes.data());
|
||||
|
||||
ffi_tmp_type_t retObj;
|
||||
void* retPtr=NULL;
|
||||
if(retVal == "char" || retVal == "i8" || retVal == "u8" || retVal == "i16" || retVal == "u16" || retVal == "i32" || retVal == "u32")
|
||||
{
|
||||
retPtr = (void*)&(retObj.v_arg);
|
||||
}
|
||||
else if(retVal == "i64" || retVal == "u64")
|
||||
{
|
||||
retPtr = (void*)&(retObj.v_u64);
|
||||
}
|
||||
else if(retVal == "f64")
|
||||
{
|
||||
retPtr = (void*)&(retObj.v_f64);
|
||||
}
|
||||
else if(retVal == "pointer" || retVal == "string")
|
||||
{
|
||||
retPtr = (void*)&(retObj.v_ptr);
|
||||
}
|
||||
|
||||
|
||||
ffi_call(&cif, (void(*)())native->GetPointer() , retPtr, argVals.data());
|
||||
|
||||
|
||||
|
||||
if(retVal == "char") return (char)retObj.v_sarg;
|
||||
if(retVal == "i8" || retVal == "i16" || retVal == "i32") return (int64_t)retObj.v_sarg;
|
||||
if(retVal == "u8" || retVal == "u16" || retVal == "u32") return (int64_t)retObj.v_arg;
|
||||
if(retVal == "i64" || retVal == "u64") return retObj.v_i64;
|
||||
if(retVal == "f64") return retObj.v_f64;
|
||||
if(retVal == "string")
|
||||
{
|
||||
std::string res = (char*)retObj.v_ptr;
|
||||
if(freeRet)
|
||||
free(retObj.v_ptr);
|
||||
return res;
|
||||
}
|
||||
if(retVal == "pointer")
|
||||
{
|
||||
TNative* native3 = TNative::Create(ls,retObj.v_ptr,[freeRet](void* _ptr)->void {
|
||||
if(freeRet) free(_ptr);
|
||||
});
|
||||
native3->other = native;
|
||||
return native3;
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
cb->watch.push_back(native);
|
||||
return cb;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void RegisterFFI(GC* gc, TDictionary* dict)
|
||||
{
|
||||
dict->SetValue("SizeOfChar",(int64_t)sizeof(char));
|
||||
dict->SetValue("SizeOfShort",(int64_t)sizeof(short));
|
||||
dict->SetValue("SizeOfInt",(int64_t)sizeof(int));
|
||||
dict->SetValue("SizeOfLong",(int64_t)sizeof(long));
|
||||
dict->SetValue("SizeOfLongLong",(int64_t)sizeof(long long));
|
||||
dict->SetValue("SizeOfInt8",(int64_t)sizeof(int8_t));
|
||||
dict->SetValue("SizeOfInt16",(int64_t)sizeof(int16_t));
|
||||
dict->SetValue("SizeOfInt32",(int64_t)sizeof(int32_t));
|
||||
dict->SetValue("SizeOfInt64",(int64_t)sizeof(int64_t));
|
||||
dict->SetValue("SizeOfFloat",(int64_t)sizeof(float));
|
||||
dict->SetValue("SizeOfDouble",(int64_t)sizeof(double));
|
||||
dict->SetValue("SizeOfPointer",(int64_t)sizeof(void*));
|
||||
dict->SetValue("PaddingOfShort",ffi_my_struct_t<short>::GetPadding());
|
||||
dict->SetValue("PaddingOfInt",ffi_my_struct_t<int>::GetPadding());
|
||||
dict->SetValue("PaddingOfLong",ffi_my_struct_t<long>::GetPadding());
|
||||
dict->SetValue("PaddingOfLongLong",ffi_my_struct_t<long long>::GetPadding());
|
||||
dict->SetValue("PaddingOfInt16",ffi_my_struct_t<int16_t>::GetPadding());
|
||||
dict->SetValue("PaddingOfInt32",ffi_my_struct_t<int32_t>::GetPadding());
|
||||
dict->SetValue("PaddingOfInt64",ffi_my_struct_t<int64_t>::GetPadding());
|
||||
dict->SetValue("PaddingOfFloat",ffi_my_struct_t<float>::GetPadding());
|
||||
dict->SetValue("PaddingOfDouble",ffi_my_struct_t<double>::GetPadding());
|
||||
dict->SetValue("PaddingOfPointer",ffi_my_struct_t<void*>::GetPadding());
|
||||
|
||||
union {
|
||||
uint8_t c[2];
|
||||
uint16_t num;
|
||||
} endian;
|
||||
endian.c[0] = 0x01;
|
||||
endian.c[1] = 0xA4;
|
||||
|
||||
dict->SetValue("IsLittleEndian", (bool)(endian.num != 420));
|
||||
|
||||
|
||||
dict->DeclareFunction(gc, "Open","Open a shared object",{"path"},[](GCList& ls, std::vector<TObject> args)->TObject {
|
||||
Tesses::Framework::Filesystem::VFSPath path;
|
||||
if(GetArgumentAsPath(args,0,path))
|
||||
{
|
||||
return TNative::Create(ls,static_cast<void*>(new DL(path)),[](void* ptr)->void {
|
||||
delete static_cast<DL*>(ptr);
|
||||
});
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
dict->DeclareFunction(gc, "Symbol","Get current symbol",{"sharedObj","name"},[](GCList& ls, std::vector<TObject> args)->TObject {
|
||||
TNative* native;
|
||||
std::string name;
|
||||
if(GetArgumentHeap(args,0,native) && GetArgument(args,1,name)) {
|
||||
if(native->GetDestroyed()) return nullptr;
|
||||
DL* dl = static_cast<DL*>(native->GetPointer());
|
||||
auto native2= TNative::Create(ls,dl->Resolve<void*>(name), [](void* _e)->void {});
|
||||
native2->other = native;
|
||||
return native2;
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
dict->DeclareFunction(gc, "Close", "Closes the shared object",{"sharedObj"},[](GCList& ls, std::vector<TObject> args)->TObject {
|
||||
TNative* native;
|
||||
if(GetArgumentHeap(args,0,native)) native->Destroy();
|
||||
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
|
||||
dict->DeclareFunction(gc, "CreateFunction","Create a function", {"functionPtr","returnVal","args","$abi","$freeRet"},[](GCList& ls, std::vector<TObject> args)->TObject {
|
||||
TNative* native;
|
||||
std::string retVal;
|
||||
TList* listArgsO;
|
||||
int64_t abi=(int64_t)FFI_DEFAULT_ABI;
|
||||
bool freeRet=false;
|
||||
if(GetArgumentHeap(args,0,native) && GetArgument(args,1,retVal) && GetArgumentHeap(args,2,listArgsO))
|
||||
{
|
||||
GetArgument(args,3,abi);
|
||||
GetArgument(args,4,freeRet);
|
||||
std::vector<std::string> listArgs;
|
||||
for(int64_t i = 0; i < listArgsO->Count(); i++)
|
||||
{
|
||||
auto item = listArgsO->Get(i);
|
||||
std::string typ;
|
||||
if(GetObject(item, typ)) listArgs.push_back(typ);
|
||||
}
|
||||
|
||||
|
||||
return FFI_CreateFunction(ls,native,retVal,listArgs,(ffi_abi)abi,freeRet);
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
void LoadPlugin(GC* gc, TRootEnvironment* env, Tesses::Framework::Filesystem::VFSPath sharedObjectPath)
|
||||
{
|
||||
@ -258,6 +613,7 @@ namespace Tesses::CrossLang
|
||||
auto externalMethod = dynamic_cast<TExternalMethod*>(obj);
|
||||
auto byteArray = dynamic_cast<TByteArray*>(obj);
|
||||
auto native = dynamic_cast<TNative*>(obj);
|
||||
auto any = dynamic_cast<TAny*>(obj);
|
||||
auto vfs = dynamic_cast<TVFSHeapObject*>(obj);
|
||||
auto strm = dynamic_cast<TStreamHeapObject*>(obj);
|
||||
auto svr = dynamic_cast<TServerHeapObject*>(obj);
|
||||
@ -265,6 +621,7 @@ namespace Tesses::CrossLang
|
||||
auto rootEnv = dynamic_cast<TRootEnvironment*>(obj);
|
||||
auto subEnv = dynamic_cast<TSubEnvironment*>(obj);
|
||||
auto env = dynamic_cast<TEnvironment*>(obj);
|
||||
auto natObj = dynamic_cast<TNativeObject*>(obj);
|
||||
|
||||
|
||||
if(rootEnv != nullptr) return "RootEnvironment";
|
||||
@ -274,6 +631,7 @@ namespace Tesses::CrossLang
|
||||
if(cse != nullptr) return "YieldedClosure";
|
||||
if(dynDict != nullptr) return "DynamicDictionary";
|
||||
if(dynList != nullptr) return "DynamicList";
|
||||
if(natObj != nullptr) return natObj->TypeName();
|
||||
if(strm != nullptr)
|
||||
{
|
||||
auto netStrm = dynamic_cast<Tesses::Framework::Streams::NetworkStream*>(strm->stream);
|
||||
@ -321,7 +679,7 @@ namespace Tesses::CrossLang
|
||||
if(externalMethod != nullptr) return "ExternalMethod";
|
||||
if(byteArray != nullptr) return "ByteArray";
|
||||
if(native != nullptr) return "Native";
|
||||
|
||||
if(any != nullptr) return "Any";
|
||||
|
||||
return "HeapObject";
|
||||
}
|
||||
@ -509,7 +867,7 @@ namespace Tesses::CrossLang
|
||||
env->DeclareVariable("DateTime", date);
|
||||
|
||||
gc->BarrierEnd();
|
||||
TDictionary* newTypes = TDictionary::Create(ls);
|
||||
TDictionary* newTypes = env->EnsureDictionary(gc, "New");
|
||||
|
||||
newTypes->DeclareFunction(gc, "DateTime","Create a DateTime object, if only one arg is provided year is epoch, isLocal defaults to true unless epoch",{"year","$month","$day","$hour","$minute","$second","$isLocal"},New_DateTime);
|
||||
|
||||
@ -679,7 +1037,7 @@ namespace Tesses::CrossLang
|
||||
}))
|
||||
}));
|
||||
env->DeclareVariable("InvokeMethod",MethodInvoker());
|
||||
env->DeclareVariable("New", newTypes);
|
||||
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
void TStd::RegisterStd(GC* gc, TRootEnvironment* env)
|
||||
@ -705,6 +1063,10 @@ namespace Tesses::CrossLang
|
||||
|
||||
TDictionary* dict = TDictionary::Create(ls);
|
||||
TDictionary* gc_dict = TDictionary::Create(ls);
|
||||
#if defined(CROSSLANG_ENABLE_FFI)
|
||||
TDictionary* ffi = TDictionary::Create(ls);
|
||||
RegisterFFI(gc,ffi);
|
||||
#endif
|
||||
dict->DeclareFunction(gc,"LoadNativePlugin","Load a native plugin, requires a dynamic linker and shared build of libcrosslang",{"path"},[gc,env](GCList& ls, std::vector<TObject> args)->TObject {
|
||||
Tesses::Framework::Filesystem::VFSPath path;
|
||||
if(GetArgumentAsPath(args,0,path))
|
||||
@ -726,6 +1088,9 @@ namespace Tesses::CrossLang
|
||||
return nullptr;
|
||||
});
|
||||
gc->BarrierBegin();
|
||||
#if defined(CROSSLANG_ENABLE_FFI)
|
||||
env->SetVariable("FFI", ffi);
|
||||
#endif
|
||||
env->SetVariable("Reflection",dict);
|
||||
env->SetVariable("GC", gc_dict);
|
||||
gc->BarrierEnd();
|
||||
|
||||
28
src/types/any.cpp
Normal file
28
src/types/any.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "CrossLang.hpp"
|
||||
|
||||
namespace Tesses::CrossLang {
|
||||
TAny* TAny::Create(GCList& ls)
|
||||
{
|
||||
TAny* anyObj = new TAny();
|
||||
|
||||
GC* gc = ls.GetGC();
|
||||
ls.Add(anyObj);
|
||||
gc->Watch(anyObj);
|
||||
return anyObj;
|
||||
}
|
||||
TAny* TAny::Create(GCList* ls)
|
||||
{
|
||||
TAny* anyObj = new TAny();
|
||||
|
||||
GC* gc = ls->GetGC();
|
||||
ls->Add(anyObj);
|
||||
gc->Watch(anyObj);
|
||||
return anyObj;
|
||||
}
|
||||
void TAny::Mark()
|
||||
{
|
||||
if(this->marked) return;
|
||||
this->marked=true;
|
||||
GC::Mark(this->other);
|
||||
}
|
||||
}
|
||||
232
src/types/class.cpp
Normal file
232
src/types/class.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
#include "CrossLang.hpp"
|
||||
namespace Tesses::CrossLang
|
||||
{
|
||||
std::string TClassObject::TypeName()
|
||||
{
|
||||
std::string type = "class ";
|
||||
type += this->name;
|
||||
for(auto& item : this->inherit_tree) type += " : " + item;
|
||||
return type;
|
||||
}
|
||||
TClassObjectEntry* TClassObject::GetEntry(std::string classN, std::string key)
|
||||
{
|
||||
for(auto& item : this->entries)
|
||||
{
|
||||
if(item.name == key)
|
||||
{
|
||||
switch(item.modifier)
|
||||
{
|
||||
case TClassModifier::Private:
|
||||
if(classN != item.owner) return nullptr;
|
||||
break;
|
||||
case TClassModifier::Protected:
|
||||
if(classN.empty()) return nullptr;
|
||||
if(classN != item.owner)
|
||||
{
|
||||
for(auto inh : this->inherit_tree)
|
||||
{
|
||||
if(inh == classN) {
|
||||
|
||||
return &item;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return &item;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
TClassObject* TClassObject::Create(GCList& ls, TFile* f, uint32_t classIndex, TEnvironment* env, std::vector<TObject> args)
|
||||
{
|
||||
return Create(&ls,f,classIndex,env,args);
|
||||
}
|
||||
std::string JoinPeriod(std::vector<std::string>& p)
|
||||
{
|
||||
std::string newStr = "";
|
||||
for(size_t i = 0; i < p.size(); i++)
|
||||
{
|
||||
if(i > 0) newStr.push_back('.');
|
||||
newStr += p[i];
|
||||
}
|
||||
return newStr;
|
||||
}
|
||||
TClassObject* TClassObject::Create(GCList* ls, TFile* f, uint32_t classIndex, TEnvironment* env, std::vector<TObject> args)
|
||||
{
|
||||
if(ls == nullptr) return nullptr;
|
||||
TClassObject* obj = new TClassObject();
|
||||
obj->file = f;
|
||||
obj->classIndex = classIndex;
|
||||
obj->ogEnv=env;
|
||||
obj->env = TClassEnvironment::Create(ls,env,obj);
|
||||
obj->name = JoinPeriod(f->classes[classIndex].name);
|
||||
bool hasToString=false;
|
||||
|
||||
for(auto entry : f->classes[classIndex].entry)
|
||||
{
|
||||
if(entry.modifier == TClassModifier::Static) continue;
|
||||
TClassObjectEntry ent;
|
||||
ent.name = entry.name;
|
||||
ent.modifier = entry.modifier;
|
||||
ent.canSet = !entry.isFunction;
|
||||
ent.owner = obj->name;
|
||||
|
||||
if(entry.isFunction)
|
||||
{
|
||||
if(ent.name == "ToString") hasToString=true;
|
||||
if(entry.isAbstract)
|
||||
{
|
||||
delete obj;
|
||||
throw VMException("Method " + ent.name + " in " + ent.owner + " is abstract.");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto clos = TClosure::Create(ls,obj->env,obj->file,entry.chunkId);
|
||||
clos->documentation = entry.documentation;
|
||||
clos->className = ent.owner;
|
||||
ent.value = clos;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(entry.isAbstract) ent.value = Undefined();
|
||||
else {
|
||||
auto clos = TClosure::Create(ls,obj->env,obj->file,entry.chunkId);
|
||||
|
||||
clos->className=ent.owner;
|
||||
ent.value = clos->Call(*ls,{});
|
||||
}
|
||||
}
|
||||
|
||||
obj->entries.push_back(ent);
|
||||
}
|
||||
|
||||
TClass* clsCur = &f->classes[classIndex];
|
||||
TRootEnvironment* rEnv = env->GetRootEnvironment();
|
||||
while(!clsCur->inherits.empty() && !(clsCur->inherits.size() == 1 && clsCur->inherits[0] == "ClassObject"))
|
||||
{
|
||||
obj->inherit_tree.push_back(JoinPeriod(clsCur->inherits));
|
||||
size_t idx;
|
||||
if(rEnv->TryFindClass(clsCur->name,idx))
|
||||
{
|
||||
auto file = rEnv->classes[idx].first;
|
||||
clsCur = &rEnv->classes[idx].first->classes.at(rEnv->classes[idx].second);
|
||||
auto ownerNow = JoinPeriod(clsCur->name);
|
||||
for(auto entry : clsCur->entry)
|
||||
{
|
||||
if(entry.modifier == TClassModifier::Static) continue;
|
||||
bool cont=false;
|
||||
for(auto e : obj->entries)
|
||||
if(e.name == entry.name)
|
||||
{
|
||||
cont=true;
|
||||
break;
|
||||
}
|
||||
if(cont) continue;
|
||||
|
||||
TClassObjectEntry ent;
|
||||
ent.name = entry.name;
|
||||
ent.modifier = entry.modifier;
|
||||
ent.canSet = !entry.isFunction;
|
||||
ent.owner = ownerNow;
|
||||
|
||||
if(entry.isFunction)
|
||||
{
|
||||
|
||||
if(ent.name == "ToString") hasToString=true;
|
||||
if(entry.isAbstract)
|
||||
{
|
||||
delete obj;
|
||||
throw VMException("Method " + ent.name + " in " + ownerNow + " is abstract.");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto clos = TClosure::Create(ls,obj->env,file,entry.chunkId);
|
||||
clos->className = ownerNow;
|
||||
clos->documentation = entry.documentation;
|
||||
ent.value = clos;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(entry.isAbstract) ent.value = Undefined();
|
||||
else {
|
||||
auto clos = TClosure::Create(ls,obj->env,file,entry.chunkId);
|
||||
clos->className = ownerNow;
|
||||
ent.value = clos->Call(*ls,{});
|
||||
}
|
||||
}
|
||||
|
||||
obj->entries.push_back(ent);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if(!hasToString)
|
||||
{
|
||||
TClassObjectEntry ent;
|
||||
ent.canSet=false;
|
||||
ent.modifier = TClassModifier::Public;
|
||||
ent.name = "ToString";
|
||||
ent.owner = obj->name;
|
||||
ent.value = TExternalMethod::Create(ls,"The ToString",{},[obj](GCList& ls,std::vector<TObject> args)->TObject { return obj->TypeName();});
|
||||
obj->entries.push_back(ent);
|
||||
}
|
||||
TCallable* call=nullptr;
|
||||
std::string fnName = f->classes[classIndex].name[f->classes[classIndex].name.size()-1];
|
||||
for(auto& item : obj->entries)
|
||||
if(item.name == fnName)
|
||||
{
|
||||
GetObjectHeap(item.value,call);
|
||||
break;
|
||||
}
|
||||
ls->Add(obj);
|
||||
ls->GetGC()->Watch(obj);
|
||||
|
||||
if(call != nullptr) call->Call(*ls,args);
|
||||
return obj;
|
||||
}
|
||||
|
||||
TObject TClassObject::GetValue(std::string className, std::string key)
|
||||
{
|
||||
auto ent = GetEntry(className,key);
|
||||
if(ent == nullptr) return Undefined();
|
||||
return ent->value;
|
||||
}
|
||||
void TClassObject::SetValue(std::string className, std::string key,TObject value)
|
||||
{
|
||||
auto ent = GetEntry(className,key);
|
||||
if(ent == nullptr) return;
|
||||
if(ent->canSet) ent->value = value;
|
||||
}
|
||||
bool TClassObject::HasValue(std::string className,std::string key)
|
||||
{
|
||||
auto ent = GetEntry(className,key);
|
||||
return ent != nullptr;
|
||||
|
||||
}
|
||||
bool TClassObject::HasField(std::string className,std::string key)
|
||||
{
|
||||
auto ent = GetEntry(className,key);
|
||||
if(ent == nullptr) return false;
|
||||
return ent->canSet;
|
||||
}
|
||||
bool TClassObject::HasMethod(std::string className,std::string key)
|
||||
{
|
||||
auto ent = GetEntry(className,key);
|
||||
if(ent == nullptr) return false;
|
||||
TCallable* call;
|
||||
return GetObjectHeap(ent->value,call);
|
||||
}
|
||||
void TClassObject::Mark()
|
||||
{
|
||||
if(this->marked) return;
|
||||
this->marked=true;
|
||||
this->env->Mark();
|
||||
this->file->Mark();
|
||||
this->ogEnv->Mark();
|
||||
for(auto& item : this->entries) GC::Mark(item.value);
|
||||
|
||||
}
|
||||
}
|
||||
122
src/types/classenvironment.cpp
Normal file
122
src/types/classenvironment.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
#include "CrossLang.hpp"
|
||||
namespace Tesses::CrossLang {
|
||||
|
||||
TClassEnvironment* TClassEnvironment::Create(GCList* gc,TEnvironment* env,TClassObject* obj)
|
||||
{
|
||||
|
||||
TClassEnvironment* env2=new TClassEnvironment(env,obj);
|
||||
|
||||
GC* _gc = gc->GetGC();
|
||||
gc->Add(env2);
|
||||
_gc->Watch(env2);
|
||||
return env2;
|
||||
}
|
||||
TClassEnvironment* TClassEnvironment::Create(GCList& gc,TEnvironment* env,TClassObject* obj)
|
||||
{
|
||||
|
||||
TClassEnvironment* env2=new TClassEnvironment(env,obj);
|
||||
|
||||
GC* _gc = gc.GetGC();
|
||||
gc.Add(env2);
|
||||
_gc->Watch(env2);
|
||||
return env2;
|
||||
}
|
||||
TClassEnvironment::TClassEnvironment(TEnvironment* env,TClassObject* obj)
|
||||
{
|
||||
this->env = env;
|
||||
this->clsObj=obj;
|
||||
}
|
||||
bool TClassEnvironment::HasVariable(std::string key)
|
||||
{
|
||||
if(key == "this") return true;
|
||||
if(this->clsObj->HasValue(current_function == nullptr ? "" : current_function->callable->className,key)) return true;
|
||||
return false;
|
||||
}
|
||||
bool TClassEnvironment::HasVariableRecurse(std::string key)
|
||||
{
|
||||
if(HasVariable(key)) return true;
|
||||
return this->env->HasVariableRecurse(key);
|
||||
}
|
||||
bool TClassEnvironment::HasVariableOrFieldRecurse(std::string key, bool setting)
|
||||
{
|
||||
if(key == "this") return true;
|
||||
std::string clsName = current_function == nullptr ? "" : current_function->callable->className;
|
||||
if(clsObj->HasMethod(clsName,(setting ? "set" : "get")+key)) return true;
|
||||
if(clsObj->HasValue(clsName,key)) return true;
|
||||
return env->HasVariableOrFieldRecurse(key,setting);
|
||||
}
|
||||
|
||||
TObject TClassEnvironment::GetVariable(std::string key)
|
||||
{
|
||||
if(key == "this") return this->clsObj;
|
||||
|
||||
std::string clsName = current_function == nullptr ? "" : current_function->callable->className;
|
||||
|
||||
if(clsObj->HasValue(clsName,key)) return this->clsObj->GetValue(clsName,key);
|
||||
return env->GetVariable(key);
|
||||
}
|
||||
void TClassEnvironment::SetVariable(std::string key, TObject value)
|
||||
{
|
||||
if(key == "this") return;
|
||||
|
||||
std::string clsName = current_function == nullptr ? "" : current_function->callable->className;
|
||||
|
||||
if(clsObj->HasValue(clsName,key))
|
||||
{
|
||||
this->clsObj->SetValue(clsName,key,value);
|
||||
return;
|
||||
}
|
||||
this->env->SetVariable(key,value);
|
||||
return;
|
||||
}
|
||||
TObject TClassEnvironment::GetVariable(GCList& ls, std::string key)
|
||||
{
|
||||
if(key == "this") return this->clsObj;
|
||||
|
||||
std::string clsName = current_function == nullptr ? "" : current_function->callable->className;
|
||||
if(this->clsObj->HasMethod(clsName,"get"+key))
|
||||
{
|
||||
auto res=this->clsObj->GetValue(clsName,"get"+key);
|
||||
TCallable* call;
|
||||
if(GetObjectHeap(res,call)) return call->Call(ls,{});
|
||||
}
|
||||
if(this->clsObj->HasValue(clsName,key)) return this->clsObj->GetValue(clsName,key);
|
||||
return this->env->GetVariable(ls,key);
|
||||
}
|
||||
TObject TClassEnvironment::SetVariable(GCList& ls, std::string key, TObject v)
|
||||
{
|
||||
if(key == "this") return this->clsObj;
|
||||
|
||||
std::string clsName = current_function == nullptr ? "" : current_function->callable->className;
|
||||
if(this->clsObj->HasMethod(clsName,"set"+key))
|
||||
{
|
||||
auto res=this->clsObj->GetValue(clsName,"set"+key);
|
||||
TCallable* call;
|
||||
if(GetObjectHeap(res,call)) return call->Call(ls,{v});
|
||||
}
|
||||
if(this->clsObj->HasValue(clsName,key)) { this->clsObj->SetValue(clsName,key,v); return v;}
|
||||
return this->env->SetVariable(ls,key,v);
|
||||
}
|
||||
|
||||
void TClassEnvironment::DeclareVariable(std::string key, TObject value)
|
||||
{
|
||||
|
||||
}
|
||||
TRootEnvironment* TClassEnvironment::GetRootEnvironment()
|
||||
{
|
||||
return this->env->GetRootEnvironment();
|
||||
}
|
||||
TEnvironment* TClassEnvironment::GetParentEnvironment()
|
||||
{
|
||||
return this->env;
|
||||
}
|
||||
|
||||
void TClassEnvironment::Mark()
|
||||
{
|
||||
if(this->marked) return;
|
||||
this->marked=true;
|
||||
this->clsObj->Mark();
|
||||
this->env->Mark();
|
||||
for(auto item : this->defers) item->Mark();
|
||||
}
|
||||
}
|
||||
@ -52,6 +52,7 @@ namespace Tesses::CrossLang {
|
||||
TClosure* TClosure::Create(GCList& ls,TEnvironment* env,TFile* file,uint32_t chunkId,bool ownScope)
|
||||
{
|
||||
TClosure* closure = new TClosure();
|
||||
closure->className="";
|
||||
closure->ownScope=ownScope;
|
||||
GC* _gc = ls.GetGC();
|
||||
ls.Add(closure);
|
||||
@ -68,6 +69,7 @@ namespace Tesses::CrossLang {
|
||||
TClosure* TClosure::Create(GCList* ls,TEnvironment* env,TFile* file,uint32_t chunkId,bool ownScope)
|
||||
{
|
||||
TClosure* closure = new TClosure();
|
||||
closure->className="";
|
||||
closure->ownScope=ownScope;
|
||||
GC* _gc = ls->GetGC();
|
||||
ls->Add(closure);
|
||||
|
||||
@ -2,6 +2,11 @@
|
||||
|
||||
namespace Tesses::CrossLang
|
||||
{
|
||||
TNativeObject::~TNativeObject()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TNative::TNative(void* ptr,std::function<void(void*)> destroy)
|
||||
{
|
||||
this->ptr = ptr;
|
||||
@ -34,6 +39,18 @@ namespace Tesses::CrossLang
|
||||
this->destroy(this->ptr);
|
||||
}
|
||||
}
|
||||
bool TNativeObject::ToBool()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool TNativeObject::Equals(GC* gc, TObject right)
|
||||
{
|
||||
if(std::holds_alternative<THeapObjectHolder>(right))
|
||||
{
|
||||
return this == std::get<THeapObjectHolder>(right).obj;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
TNative* TNative::Create(GCList& ls, void* ptr,std::function<void(void*)> destroy)
|
||||
{
|
||||
TNative* native = new TNative(ptr,destroy);
|
||||
|
||||
@ -2,6 +2,69 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
namespace Tesses::CrossLang {
|
||||
bool TRootEnvironment::TryFindClass(std::vector<std::string>& name, size_t& index)
|
||||
{
|
||||
for(size_t i = 0; i < this->classes.size(); i++)
|
||||
{
|
||||
if(classes[i].first->classes.at(classes[i].second).name.size() != name.size()) continue;
|
||||
for(size_t j = 0; j < name.size(); j++)
|
||||
if(classes[i].first->classes.at(classes[i].second).name[j] != name[j]) continue;
|
||||
index=i;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool TRootEnvironment::HasVariableOrFieldRecurse(std::string key,bool setting)
|
||||
{
|
||||
std::string property=(setting? "set":"get") + key;
|
||||
if(this->HasVariable(property))
|
||||
{
|
||||
auto res = this->GetVariable(property);
|
||||
TCallable* callable;
|
||||
if(GetObjectHeap(res,callable)) return true;
|
||||
}
|
||||
|
||||
return this->HasVariable(key);
|
||||
}
|
||||
TObject TRootEnvironment::GetVariable(GCList& ls, std::string key)
|
||||
{
|
||||
ls.GetGC()->BarrierBegin();
|
||||
if(this->HasVariable("get" + key))
|
||||
{
|
||||
auto item = this->GetVariable("get"+key);
|
||||
TCallable* callable;
|
||||
if(GetObjectHeap(item,callable))
|
||||
{
|
||||
ls.GetGC()->BarrierEnd();
|
||||
return callable->Call(ls,{});
|
||||
}
|
||||
}
|
||||
|
||||
auto item = this->GetVariable(key);
|
||||
ls.GetGC()->BarrierEnd();
|
||||
|
||||
return item;
|
||||
}
|
||||
TObject TRootEnvironment::SetVariable(GCList& ls, std::string key, TObject value)
|
||||
{
|
||||
ls.GetGC()->BarrierBegin();
|
||||
if(this->HasVariable("set" + key))
|
||||
{
|
||||
auto item = this->GetVariable("set"+key);
|
||||
TCallable* callable;
|
||||
if(GetObjectHeap(item,callable))
|
||||
{
|
||||
ls.GetGC()->BarrierEnd();
|
||||
return callable->Call(ls,{value});
|
||||
}
|
||||
}
|
||||
|
||||
this->SetVariable(key,value);
|
||||
ls.GetGC()->BarrierEnd();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void TRootEnvironment::LoadDependency(GC* gc,Tesses::Framework::Filesystem::VFS* vfs, std::pair<std::string,TVMVersion> dep)
|
||||
{
|
||||
for(auto item : this->dependencies)
|
||||
@ -45,8 +108,114 @@ namespace Tesses::CrossLang {
|
||||
f->Load(ls.GetGC(),&ms);
|
||||
return this->LoadFile(ls.GetGC(), f);
|
||||
}
|
||||
TDictionary* TEnvironment::EnsureDictionary(GC* gc, std::string key)
|
||||
{
|
||||
TObject item = this->GetVariable(key);
|
||||
TDictionary* dict;
|
||||
if(GetObjectHeap(item,dict)) return dict;
|
||||
GCList ls(gc);
|
||||
dict = TDictionary::Create(ls);
|
||||
this->DeclareVariable(key, dict);
|
||||
return dict;
|
||||
}
|
||||
void TEnvironment::DeclareVariable(GC* gc, std::vector<std::string> name, TObject o)
|
||||
{
|
||||
if(name.size() == 0)
|
||||
throw VMException("name can't be empty.");
|
||||
|
||||
else if(name.size() == 1)
|
||||
{
|
||||
GCList ls(gc);
|
||||
|
||||
gc->BarrierBegin();
|
||||
this->DeclareVariable(name[0],o);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
GCList ls(gc);
|
||||
|
||||
TObject v = this->GetVariable(name[0]);
|
||||
TDictionary* dict=nullptr;
|
||||
if(std::holds_alternative<THeapObjectHolder>(v))
|
||||
{
|
||||
dict=dynamic_cast<TDictionary*>(std::get<THeapObjectHolder>(v).obj);
|
||||
if(dict == nullptr)
|
||||
{
|
||||
dict = TDictionary::Create(ls);
|
||||
gc->BarrierBegin();
|
||||
this->SetVariable(name[0],dict);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dict = TDictionary::Create(ls);
|
||||
gc->BarrierBegin();
|
||||
this->DeclareVariable(name[0],dict);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
|
||||
for(size_t i = 1; i < name.size()-1; i++)
|
||||
{
|
||||
gc->BarrierBegin();
|
||||
auto v = dict->GetValue(name[i]);
|
||||
gc->BarrierEnd();
|
||||
if(std::holds_alternative<THeapObjectHolder>(v))
|
||||
{
|
||||
auto dict2=dynamic_cast<TDictionary*>(std::get<THeapObjectHolder>(v).obj);
|
||||
if(dict2 == nullptr)
|
||||
{
|
||||
dict2 = TDictionary::Create(ls);
|
||||
gc->BarrierBegin();
|
||||
dict->SetValue(name[i],dict2);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
dict = dict2;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dict2 = TDictionary::Create(ls);
|
||||
gc->BarrierBegin();
|
||||
dict->SetValue(name[i],dict2);
|
||||
gc->BarrierEnd();
|
||||
dict = dict2;
|
||||
}
|
||||
}
|
||||
gc->BarrierBegin();
|
||||
dict->SetValue(name[name.size()-1],o);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
}
|
||||
|
||||
TObject TEnvironment::LoadFile(GC* gc, TFile* file)
|
||||
{
|
||||
file->EnsureCanRunInCrossLang();
|
||||
for(size_t i = 0; i < file->classes.size(); i++)
|
||||
{
|
||||
this->GetRootEnvironment()->classes.push_back(std::pair<TFile*,uint32_t>(file,(uint32_t)i));
|
||||
std::vector<std::string> clsPart={"New"};
|
||||
clsPart.insert(clsPart.end(),file->classes[i].name.begin(),file->classes[i].name.end());
|
||||
GCList ls(gc);
|
||||
std::vector<std::string> name=file->classes[i].name;
|
||||
auto rootEnv = this->GetRootEnvironment();
|
||||
this->DeclareVariable(gc, clsPart, TExternalMethod::Create(ls,"Create instance of the class",{"$$args"},[rootEnv,file,i](GCList& ls, std::vector<TObject> args)->TObject{
|
||||
return TClassObject::Create(ls, file,i,rootEnv,args);
|
||||
}));
|
||||
for(auto meth : file->classes[i].entry)
|
||||
{
|
||||
|
||||
if(meth.isFunction && meth.modifier == TClassModifier::Static)
|
||||
{
|
||||
std::vector<std::string> method=file->classes[i].name;
|
||||
method.push_back(meth.name);
|
||||
auto clo = TClosure::Create(ls,this,file,meth.chunkId);
|
||||
clo->documentation = meth.documentation;
|
||||
this->DeclareVariable(gc, method, clo);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
for(auto fn : file->functions)
|
||||
{
|
||||
|
||||
@ -59,76 +228,11 @@ namespace Tesses::CrossLang {
|
||||
|
||||
if(fn.second >= file->chunks.size()) throw VMException("ChunkId out of bounds.");
|
||||
TFileChunk* chunk = file->chunks[fn.second];
|
||||
|
||||
|
||||
if(items.size() == 0)
|
||||
throw VMException("Function name can't be empty.");
|
||||
|
||||
else if(items.size() == 1)
|
||||
{
|
||||
GCList ls(gc);
|
||||
TClosure* closure=TClosure::Create(ls,this,file,fn.second);
|
||||
closure->documentation = fn.first[0];
|
||||
gc->BarrierBegin();
|
||||
this->DeclareVariable(items[0],closure);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
GCList ls(gc);
|
||||
TClosure* closure=TClosure::Create(ls,this,file,fn.second);
|
||||
closure->documentation = fn.first[0];
|
||||
TObject v = this->GetVariable(items[0]);
|
||||
TDictionary* dict=nullptr;
|
||||
if(std::holds_alternative<THeapObjectHolder>(v))
|
||||
{
|
||||
dict=dynamic_cast<TDictionary*>(std::get<THeapObjectHolder>(v).obj);
|
||||
if(dict == nullptr)
|
||||
{
|
||||
dict = TDictionary::Create(ls);
|
||||
gc->BarrierBegin();
|
||||
this->SetVariable(items[0],dict);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dict = TDictionary::Create(ls);
|
||||
gc->BarrierBegin();
|
||||
this->DeclareVariable(items[0],dict);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
this->DeclareVariable(gc,items,closure);
|
||||
|
||||
for(size_t i = 1; i < items.size()-1; i++)
|
||||
{
|
||||
gc->BarrierBegin();
|
||||
auto v = dict->GetValue(items[i]);
|
||||
gc->BarrierEnd();
|
||||
if(std::holds_alternative<THeapObjectHolder>(v))
|
||||
{
|
||||
auto dict2=dynamic_cast<TDictionary*>(std::get<THeapObjectHolder>(v).obj);
|
||||
if(dict2 == nullptr)
|
||||
{
|
||||
dict2 = TDictionary::Create(ls);
|
||||
gc->BarrierBegin();
|
||||
dict->SetValue(items[i],dict2);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
dict = dict2;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dict2 = TDictionary::Create(ls);
|
||||
gc->BarrierBegin();
|
||||
dict->SetValue(items[i],dict2);
|
||||
gc->BarrierEnd();
|
||||
dict = dict2;
|
||||
}
|
||||
}
|
||||
gc->BarrierBegin();
|
||||
dict->SetValue(items[items.size()-1],closure);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
}
|
||||
if(!file->chunks.empty())
|
||||
{
|
||||
@ -174,7 +278,7 @@ namespace Tesses::CrossLang {
|
||||
}
|
||||
void TRootEnvironment::SetVariable(std::string key, TObject value)
|
||||
{
|
||||
return this->dict->SetValue(key,value);
|
||||
this->dict->SetValue(key,value);
|
||||
}
|
||||
void TRootEnvironment::DeclareVariable(std::string key, TObject value)
|
||||
{
|
||||
|
||||
@ -5,6 +5,88 @@ namespace Tesses::CrossLang {
|
||||
{
|
||||
return this->dict;
|
||||
}
|
||||
bool TSubEnvironment::HasVariableOrFieldRecurse(std::string key,bool setting)
|
||||
{
|
||||
std::string property=(setting? "set":"get") + key;
|
||||
if(this->HasVariable(property))
|
||||
{
|
||||
auto res = this->GetVariable(property);
|
||||
TCallable* callable;
|
||||
if(GetObjectHeap(res,callable)) return true;
|
||||
}
|
||||
|
||||
if(this->HasVariable(key)) return true;
|
||||
|
||||
return this->env->HasVariableOrFieldRecurse(key,setting);
|
||||
}
|
||||
TObject TSubEnvironment::GetVariable(GCList& ls, std::string key)
|
||||
{
|
||||
ls.GetGC()->BarrierBegin();
|
||||
if(this->HasVariable("get" + key))
|
||||
{
|
||||
auto item = this->GetVariable("get"+key);
|
||||
TCallable* callable;
|
||||
if(GetObjectHeap(item,callable))
|
||||
{
|
||||
ls.GetGC()->BarrierEnd();
|
||||
return callable->Call(ls,{});
|
||||
}
|
||||
}
|
||||
|
||||
if(this->HasVariable(key))
|
||||
{
|
||||
auto item = this->GetVariable(key);
|
||||
ls.GetGC()->BarrierEnd();
|
||||
return item;
|
||||
}
|
||||
if(this->env->HasVariableOrFieldRecurse(key))
|
||||
{
|
||||
ls.GetGC()->BarrierEnd();
|
||||
return this->env->GetVariable(ls,key);
|
||||
}
|
||||
ls.GetGC()->BarrierEnd();
|
||||
|
||||
|
||||
|
||||
return Undefined();
|
||||
}
|
||||
TObject TSubEnvironment::SetVariable(GCList& ls, std::string key, TObject value)
|
||||
{
|
||||
ls.GetGC()->BarrierBegin();
|
||||
if(this->HasVariable("set" + key))
|
||||
{
|
||||
auto item = this->GetVariable("set"+key);
|
||||
TCallable* callable;
|
||||
if(GetObjectHeap(item,callable))
|
||||
{
|
||||
ls.GetGC()->BarrierEnd();
|
||||
return callable->Call(ls,{value});
|
||||
}
|
||||
}
|
||||
|
||||
if(this->HasVariable(key))
|
||||
{
|
||||
this->SetVariable(key,value);
|
||||
ls.GetGC()->BarrierEnd();
|
||||
return value;
|
||||
}
|
||||
if(this->env->HasVariableOrFieldRecurse(key,true))
|
||||
{
|
||||
ls.GetGC()->BarrierEnd();
|
||||
return this->env->SetVariable(ls,key,value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->env->SetVariable(key,value);
|
||||
|
||||
ls.GetGC()->BarrierEnd();
|
||||
return value;
|
||||
}
|
||||
ls.GetGC()->BarrierEnd();
|
||||
|
||||
|
||||
}
|
||||
|
||||
TObject TSubEnvironment::GetVariable(std::string key)
|
||||
{
|
||||
if(this->dict->HasValue(key))
|
||||
|
||||
@ -96,6 +96,27 @@ namespace Tesses::CrossLang
|
||||
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::EnsureCanRunInCrossLang()
|
||||
{
|
||||
if(this->vms.empty()) return;
|
||||
|
||||
for(auto item : this->vms)
|
||||
{
|
||||
if(item.first == VMName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string errorMessage="The virtual machines supported are:\n";
|
||||
|
||||
for(auto item : this->vms)
|
||||
{
|
||||
errorMessage += item.first + "\n\t" + item.second + "\n";
|
||||
}
|
||||
throw VMException(errorMessage);
|
||||
}
|
||||
|
||||
void TFile::Load(GC* gc, Tesses::Framework::Streams::Stream* stream)
|
||||
{
|
||||
@ -204,9 +225,56 @@ namespace Tesses::CrossLang
|
||||
{
|
||||
this->icon = (int32_t)EnsureInt(stream);
|
||||
}
|
||||
else if(strncmp(table_name,"MACH",4) == 0) //machine
|
||||
{
|
||||
std::string name = GetString(stream);
|
||||
std::string howToGet = GetString(stream);
|
||||
this->vms.push_back(std::pair<std::string,std::string>(name,howToGet));
|
||||
}
|
||||
else if(strncmp(table_name,"CLSS",4) == 0) //classes
|
||||
{
|
||||
uint32_t clsCnt = EnsureInt(stream);
|
||||
for(uint32_t j = 0; j < clsCnt; j++)
|
||||
{
|
||||
TClass cls;
|
||||
cls.documentation= GetString(stream);
|
||||
uint32_t name_cnt = EnsureInt(stream);
|
||||
for(uint32_t k = 0; k < name_cnt; k++)
|
||||
{
|
||||
cls.name.push_back(GetString(stream));
|
||||
}
|
||||
name_cnt = EnsureInt(stream);
|
||||
for(uint32_t k = 0; k < name_cnt; k++)
|
||||
{
|
||||
cls.inherits.push_back(GetString(stream));
|
||||
}
|
||||
name_cnt = EnsureInt(stream);
|
||||
for(uint32_t k = 0; k < name_cnt; k++)
|
||||
{
|
||||
TClassEntry ent;
|
||||
Ensure(stream,main_header,1);
|
||||
uint8_t sig = main_header[0];
|
||||
ent.isAbstract = (sig & 0b00001000) != 0;
|
||||
ent.isFunction = (sig & 0b00000100) == 0;
|
||||
ent.modifier = (TClassModifier)(sig & 3);
|
||||
ent.documentation = GetString(stream);
|
||||
ent.name = GetString(stream);
|
||||
uint32_t arglen = EnsureInt(stream);
|
||||
for(uint32_t l = 0; l < arglen; l++)
|
||||
ent.args.push_back(GetString(stream));
|
||||
ent.chunkId = EnsureInt(stream);
|
||||
cls.entry.push_back(ent);
|
||||
}
|
||||
this->classes.push_back(cls);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Skip(stream,tableLen);
|
||||
std::vector<uint8_t> data;
|
||||
data.resize(tableLen);
|
||||
Ensure(stream,data.data(), tableLen);
|
||||
std::string key(std::string(table_name), 4);
|
||||
this->sections.push_back(std::pair<std::string,std::vector<uint8_t>>(key,data));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
794
src/vm/vm.cpp
794
src/vm/vm.cpp
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user