diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index ce5199f..3b67b92 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -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", diff --git a/CMakeLists.txt b/CMakeLists.txt index 70d7e79..ce02fa5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}) diff --git a/include/CrossLang.hpp b/include/CrossLang.hpp index 8fe2b32..c6a8412 100644 --- a/include/CrossLang.hpp +++ b/include/CrossLang.hpp @@ -17,6 +17,7 @@ #include #include #include +#include /** * @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; -class ObjectEntry { - public: - std::vector name; - std::string doc; - std::vector> variables; - std::vector,uint32_t>> funcs; - std::vector,uint32_t>> static_funcs; + +struct CodeGenClassEntry { + uint8_t type; + uint32_t documentation; + uint32_t name; + std::vector arguments; + uint32_t closure; }; +struct CodeGenClass { + uint32_t documentation; + std::vector name; + std::vector inherits; + std::vector entries; +}; + + class CodeGen { uint32_t id; uint32_t NewId(); @@ -867,7 +878,8 @@ class CodeGen { std::vector, std::vector>> chunks; std::vector,uint32_t>> funcs; - std::vector objectEntries; + std::vector classes; + void GenNode(std::vector& instructions, SyntaxNode n,int32_t scope, int32_t contscope, int32_t brkscope, int32_t contI, int32_t brkI); void GenPop(std::vector& 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 args; + std::string documentation; + std::string name; + + uint32_t chunkId; + }; + class TClass { + public: + std::string documentation; + std::vector name; + std::vector inherits; + std::vector 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 chunks; std::vector strings; + std::vector> vms; std::vector, uint32_t>> functions; std::vector> dependencies; std::vector> tools; + std::vector>> sections; std::vector> resources; + std::vector 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 key, TObject value); virtual TRootEnvironment* GetRootEnvironment()=0; virtual TEnvironment* GetParentEnvironment()=0; virtual TSubEnvironment* GetSubEnvironment(TDictionary* dict); @@ -1613,7 +1678,55 @@ class GC { TObject CallFunction(GCList& ls, std::string key, std::vector 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 inherit_tree; + std::vector entries; + + static TClassObject* Create(GCList& ls, TFile* f, uint32_t classIndex, TEnvironment* env, std::vector args); + static TClassObject* Create(GCList* ls, TFile* f, uint32_t classIndex, TEnvironment* env, std::vector 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: EnvironmentPermissions(); @@ -1647,6 +1760,9 @@ class GC { EnvironmentPermissions permissions; std::vector> dependencies; + std::vector> classes; + + bool TryFindClass(std::vector& 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 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 + 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 + 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 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 destroyed; @@ -2138,6 +2302,8 @@ class GC { ~TNative(); }; + + class ThreadHandle : public THeapObject { public: Tesses::Framework::Threading::Thread* thrd; diff --git a/src/compiler/codegen.cpp b/src/compiler/codegen.cpp index 9028c08..7a89390 100644 --- a/src/compiler/codegen.cpp +++ b/src/compiler/codegen.cpp @@ -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(adv.nodes[0])) + { + CodeGenClass cls; + cls.documentation = GetString(std::get(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(node)) + { + auto& adv2 = std::get(node); + CodeGenClassEntry ent; + ent.type = 0; + if(adv2.nodes.size() >= 2 && std::holds_alternative(adv2.nodes[0]) && std::holds_alternative(adv2.nodes[1])) + { + ent.documentation=GetString(std::get(adv2.nodes[0])); + std::string type=std::get(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(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(adv2.nodes[2]); + if(nameAndArgs.nodeName == FunctionCallExpression && !nameAndArgs.nodes.empty() && std::holds_alternative(nameAndArgs.nodes[0])) + { + auto& getvar = std::get(nameAndArgs.nodes[0]); + if(getvar.nodeName == GetVariableExpression && getvar.nodes.size() == 1 && std::holds_alternative(getvar.nodes[0])) + { + + ent.name = GetString(std::get(getvar.nodes[0])); + if(nameAndArgs.nodes.size() > 1) + { + GetFunctionArgs(ent.arguments, nameAndArgs.nodes[1]); + } + } + else continue; + } + + std::vector fnInstructions; + + GenNode(fnInstructions,adv2.nodes[3],0,-1,-1,-1,-1); + + this->chunks[fnindex] = std::pair,std::vector>(ent.arguments, fnInstructions); + } + else if(adv2.nodeName == AbstractMethodStatement && adv2.nodes.size() == 3 && std::holds_alternative(adv2.nodes[2])) + { + ent.closure = 0; + ent.type |= 0b00001000; + //documentation,myTkn.text,nameAndArgs + auto& nameAndArgs= std::get(adv2.nodes[2]); + if(nameAndArgs.nodeName == FunctionCallExpression && !nameAndArgs.nodes.empty() && std::holds_alternative(nameAndArgs.nodes[0])) + { + auto& getvar = std::get(nameAndArgs.nodes[0]); + if(getvar.nodeName == GetVariableExpression && getvar.nodes.size() == 1 && std::holds_alternative(getvar.nodes[0])) + { + ent.name = GetString(std::get(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(adv2.nodes[2])) + { + auto& setter = std::get(adv2.nodes[2]); + if(setter.nodeName == GetVariableExpression && setter.nodes.size() == 1 && std::holds_alternative(setter.nodes[0])) + { + ent.closure = 0; + ent.type |= 0b00001100; + + ent.name = GetString(std::get(setter.nodes[0])); + + } + else if(setter.nodeName == AssignExpression && setter.nodes.size() == 2 && std::holds_alternative(setter.nodes[0])) + { + auto& getvar = std::get(setter.nodes[0]); + if(getvar.nodeName == GetVariableExpression && getvar.nodes.size() == 1 && std::holds_alternative(getvar.nodes[0])) + { + ent.type |= 0b00000100; + ent.name = GetString(std::get(getvar.nodes[0])); + size_t fnindex=this->chunks.size(); + ent.closure=(uint32_t)fnindex; + ent.arguments={}; + + this->chunks.resize(fnindex+1); + + std::vector fnInstructions; + + GenNode(fnInstructions,AdvancedSyntaxNode::Create(ReturnStatement,false,{setter.nodes[1]}),0,-1,-1,-1,-1); + + this->chunks[fnindex] = std::pair,std::vector>({}, 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)); } diff --git a/src/compiler/parser.cpp b/src/compiler/parser.cpp index 8c4dcb2..01978ae 100644 --- a/src/compiler/parser.cpp +++ b/src/compiler/parser.cpp @@ -928,11 +928,15 @@ 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++; - return AdvancedSyntaxNode::Create(DocumentationStatement,false,{txt,ParseNode()}); + 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 name_and_methods; + std::vector 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 nameAndArgs = ParseExpression(); - - if(IsSymbol("{",false)) + auto myTkn = tkn; + if(IsIdentifier("abstract")) { - auto r = AdvancedSyntaxNode::Create(MethodDeclaration,false,{nameAndArgs,ParseNode()}); - if(hasDocumentation) - { - name_and_methods.push_back(AdvancedSyntaxNode::Create(DocumentationStatement,false,{documentation,r})); - } - else - { - name_and_methods.push_back(r); - } - } - else - { - auto v = ParseExpression(); - + if(myTkn.text == "static") throw SyntaxException(myTkn.lineInfo,"Static abstract function doesn't make sense"); + auto nameAndArgs = 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); - } + + + name_and_methods.push_back(AdvancedSyntaxNode::Create(AbstractMethodStatement,false,{documentation,myTkn.text,nameAndArgs})); + + + } - } - else if(IsIdentifier("static")) - { - auto nameAndArgs = ParseExpression(); - - if(IsSymbol("{",false)) + else if(i + 1 < tokens.size() && (tokens[i+1].text == "=" || tokens[i+1].text == ";") && tokens[i+1].type == LexTokenType::Symbol) { - 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(); - + auto setter = ParseExpression(); EnsureSymbol(";"); - auto r= AdvancedSyntaxNode::Create(StaticStatement,false,{nameAndArgs,AdvancedSyntaxNode::Create(ReturnStatement,false,{v})}); - if(hasDocumentation) + + SyntaxNode field = AdvancedSyntaxNode::Create(FieldStatement,false,{ + documentation, + myTkn.text, + + setter + }); + + name_and_methods.push_back(field); + + } + else + { + auto nameAndArgs = ParseExpression(); + + if(IsSymbol("{",false)) { - name_and_methods.push_back(AdvancedSyntaxNode::Create(DocumentationStatement,false,{documentation,r})); + + + name_and_methods.push_back(AdvancedSyntaxNode::Create(MethodStatement,false,{documentation,myTkn.text,nameAndArgs,ParseNode()})); + } - else + else { - name_and_methods.push_back(r); + auto v = ParseExpression(); + EnsureSymbol(";"); + name_and_methods.push_back(AdvancedSyntaxNode::Create(MethodStatement,false,{documentation,myTkn.text,nameAndArgs,AdvancedSyntaxNode::Create(ReturnStatement,false,{v})})); + } + } } } } 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"); } diff --git a/src/crosslangdump.cpp b/src/crosslangdump.cpp index 86feec3..2ae7080 100644 --- a/src/crosslangdump.cpp +++ b/src/crosslangdump.cpp @@ -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); diff --git a/src/runtime_methods/std.cpp b/src/runtime_methods/std.cpp index 5ac07a9..f935d0e 100644 --- a/src/runtime_methods/std.cpp +++ b/src/runtime_methods/std.cpp @@ -1,5 +1,8 @@ #include "CrossLang.hpp" #if defined(CROSSLANG_ENABLE_SHARED) +#if defined(CROSSLANG_ENABLE_FFI) +#include +#endif #if defined(_WIN32) #include @@ -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 + class ffi_my_struct_t { + char ffi_my_struct_chr; + T ffi_my_struct_val; + + public: + static int64_t GetPadding() + { + ffi_my_struct_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(arg)) + { + if(t == "char" || t == "i8" || t == "i16" || t == "i32") + { + return (ffi_tmp_type_t){.v_sarg = std::get(arg)}; + } + else if(t == "u8" || t == "u16" || t == "u32") + { + return (ffi_tmp_type_t){.v_arg = (uint8_t)std::get(arg)}; + } + else if(t == "u64") + { + return (ffi_tmp_type_t){.v_u64 = (uint8_t)std::get(arg)}; + } + else if(t == "i64") + { + return (ffi_tmp_type_t){.v_i64 = std::get(arg)}; + } + } + else if(std::holds_alternative(arg)) + { + if(t == "u8" || t == "u16" || t == "u32") + { + return (ffi_tmp_type_t){.v_arg = (ffi_arg)(uint64_t)std::get(arg)}; + } + else if(t == "char" || t == "i8" || t == "i16" || t == "i32") + { + return (ffi_tmp_type_t){.v_sarg = (ffi_sarg)std::get(arg)}; + } + else if(t == "u64") + { + return (ffi_tmp_type_t){.v_u64 = (uint64_t)std::get(arg)}; + } + else if(t == "i64") + { + return (ffi_tmp_type_t){.v_i64 =std::get(arg)}; + } + else if(t == "pointer" || t == "string") + { + return (ffi_tmp_type_t){.v_ptr = (void*)std::get(arg)}; + } + } + else if(std::holds_alternative(arg)) + { + if(t == "f64") + { + return (ffi_tmp_type_t){.v_f64 =std::get(arg)}; + } + } + else if(std::holds_alternative(arg)) + { + if(t == "pointer" || t == "string") + { + return (ffi_tmp_type_t){.v_ptr = (void*)std::get(arg).c_str()}; + } + } + else if(std::holds_alternative(arg)) + { + auto obj = std::get(arg).obj; + auto bA = dynamic_cast(obj); + auto nat = dynamic_cast(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 listArgs,ffi_abi abi,bool freeRet) + { + ffi_type* retTypeT = FFI_ConvertStringToFFIType(retVal); + std::vector 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 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 argVals; + std::vector 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::GetPadding()); + dict->SetValue("PaddingOfInt",ffi_my_struct_t::GetPadding()); + dict->SetValue("PaddingOfLong",ffi_my_struct_t::GetPadding()); + dict->SetValue("PaddingOfLongLong",ffi_my_struct_t::GetPadding()); + dict->SetValue("PaddingOfInt16",ffi_my_struct_t::GetPadding()); + dict->SetValue("PaddingOfInt32",ffi_my_struct_t::GetPadding()); + dict->SetValue("PaddingOfInt64",ffi_my_struct_t::GetPadding()); + dict->SetValue("PaddingOfFloat",ffi_my_struct_t::GetPadding()); + dict->SetValue("PaddingOfDouble",ffi_my_struct_t::GetPadding()); + dict->SetValue("PaddingOfPointer",ffi_my_struct_t::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 args)->TObject { + Tesses::Framework::Filesystem::VFSPath path; + if(GetArgumentAsPath(args,0,path)) + { + return TNative::Create(ls,static_cast(new DL(path)),[](void* ptr)->void { + delete static_cast(ptr); + }); + } + return nullptr; + }); + dict->DeclareFunction(gc, "Symbol","Get current symbol",{"sharedObj","name"},[](GCList& ls, std::vector 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(native->GetPointer()); + auto native2= TNative::Create(ls,dl->Resolve(name), [](void* _e)->void {}); + native2->other = native; + return native2; + } + return nullptr; + }); + dict->DeclareFunction(gc, "Close", "Closes the shared object",{"sharedObj"},[](GCList& ls, std::vector 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 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 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(obj); auto byteArray = dynamic_cast(obj); auto native = dynamic_cast(obj); + auto any = dynamic_cast(obj); auto vfs = dynamic_cast(obj); auto strm = dynamic_cast(obj); auto svr = dynamic_cast(obj); @@ -265,6 +621,7 @@ namespace Tesses::CrossLang auto rootEnv = dynamic_cast(obj); auto subEnv = dynamic_cast(obj); auto env = dynamic_cast(obj); + auto natObj = dynamic_cast(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(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 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(); diff --git a/src/types/any.cpp b/src/types/any.cpp new file mode 100644 index 0000000..42860d7 --- /dev/null +++ b/src/types/any.cpp @@ -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); + } +} \ No newline at end of file diff --git a/src/types/class.cpp b/src/types/class.cpp new file mode 100644 index 0000000..1bdaa18 --- /dev/null +++ b/src/types/class.cpp @@ -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 args) + { + return Create(&ls,f,classIndex,env,args); + } + std::string JoinPeriod(std::vector& 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 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 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); + + } +} \ No newline at end of file diff --git a/src/types/classenvironment.cpp b/src/types/classenvironment.cpp new file mode 100644 index 0000000..dac73da --- /dev/null +++ b/src/types/classenvironment.cpp @@ -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(); + } +} \ No newline at end of file diff --git a/src/types/closure.cpp b/src/types/closure.cpp index 8e64a99..db8dfc8 100644 --- a/src/types/closure.cpp +++ b/src/types/closure.cpp @@ -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); diff --git a/src/types/native.cpp b/src/types/native.cpp index a1e576b..df8b75a 100644 --- a/src/types/native.cpp +++ b/src/types/native.cpp @@ -2,6 +2,11 @@ namespace Tesses::CrossLang { + TNativeObject::~TNativeObject() + { + + } + TNative::TNative(void* ptr,std::function 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(right)) + { + return this == std::get(right).obj; + } + return false; + } TNative* TNative::Create(GCList& ls, void* ptr,std::function destroy) { TNative* native = new TNative(ptr,destroy); diff --git a/src/types/rootenvironment.cpp b/src/types/rootenvironment.cpp index 9be8166..deac241 100644 --- a/src/types/rootenvironment.cpp +++ b/src/types/rootenvironment.cpp @@ -2,6 +2,69 @@ #include #include namespace Tesses::CrossLang { + bool TRootEnvironment::TryFindClass(std::vector& 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 dep) { for(auto item : this->dependencies) @@ -45,9 +108,115 @@ 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 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(v)) + { + dict=dynamic_cast(std::get(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(v)) + { + auto dict2=dynamic_cast(std::get(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) { - for(auto fn : file->functions) + file->EnsureCanRunInCrossLang(); + for(size_t i = 0; i < file->classes.size(); i++) + { + this->GetRootEnvironment()->classes.push_back(std::pair(file,(uint32_t)i)); + std::vector clsPart={"New"}; + clsPart.insert(clsPart.end(),file->classes[i].name.begin(),file->classes[i].name.end()); + GCList ls(gc); + std::vector 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 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 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) { std::string name; @@ -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]; + GCList ls(gc); + TClosure* closure=TClosure::Create(ls,this,file,fn.second); + closure->documentation = fn.first[0]; + this->DeclareVariable(gc,items,closure); - - 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(v)) - { - dict=dynamic_cast(std::get(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(); - } - - for(size_t i = 1; i < items.size()-1; i++) - { - gc->BarrierBegin(); - auto v = dict->GetValue(items[i]); - gc->BarrierEnd(); - if(std::holds_alternative(v)) - { - auto dict2=dynamic_cast(std::get(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) { diff --git a/src/types/subenvironment.cpp b/src/types/subenvironment.cpp index cc68bd4..166657d 100644 --- a/src/types/subenvironment.cpp +++ b/src/types/subenvironment.cpp @@ -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)) diff --git a/src/vm/filereader.cpp b/src/vm/filereader.cpp index a6541bf..233913c 100644 --- a/src/vm/filereader.cpp +++ b/src/vm/filereader.cpp @@ -55,7 +55,7 @@ namespace Tesses::CrossLang for(auto item : this->chunks) item->Mark(); - + } void TFile::Skip(Tesses::Framework::Streams::Stream* stream,size_t len) { @@ -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(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 data; + data.resize(tableLen); + Ensure(stream,data.data(), tableLen); + std::string key(std::string(table_name), 4); + this->sections.push_back(std::pair>(key,data)); } } diff --git a/src/vm/vm.cpp b/src/vm/vm.cpp index d52da6c..82f79b1 100644 --- a/src/vm/vm.cpp +++ b/src/vm/vm.cpp @@ -57,6 +57,13 @@ namespace Tesses::CrossLang { auto nat = dynamic_cast(o); auto thrd = dynamic_cast(o); auto dt = dynamic_cast(o); + auto natObj = dynamic_cast(o); + + auto any = dynamic_cast(o); + auto cls = dynamic_cast(o); + if(cls!=nullptr) return true; + if(natObj != nullptr) return natObj->ToBool(); + if(any != nullptr) return any->any.has_value(); if(ls != nullptr) { @@ -156,6 +163,37 @@ namespace Tesses::CrossLang { auto dynDict = dynamic_cast(obj); auto native = dynamic_cast(obj); + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue("","operator=="); + gc->BarrierEnd(); + TCallable* callable; + + if(GetObjectHeap(obj,callable)) + { + return ToBool(callable->Call(ls,{})); + + } + else if(std::holds_alternative(right)) { + return false; + } + else if(std::holds_alternative(right)) + { + return false; + } + else if(std::holds_alternative(right)) + { + return cls == std::get(right).obj; + } + } + else + if(natObj != nullptr) + { + return natObj->Equals(gc, right); + } if(dict != nullptr) { gc->BarrierBegin(); @@ -405,7 +443,37 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + + + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator-"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator-",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator-"); @@ -459,7 +527,37 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + + + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator*"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator*",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator*"); @@ -537,7 +635,45 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator/"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else + if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator/",{right})); + return false; + } + else + + + if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator/",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator/"); @@ -592,7 +728,38 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + + auto natObj = dynamic_cast(obj); + + + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator%"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator%",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator%"); @@ -635,9 +802,38 @@ namespace Tesses::CrossLang { { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); - - auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto dynDict = dynamic_cast(obj); + + auto natObj = dynamic_cast(obj); + + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator-"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator-",{})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject negfn = dict->GetValue("operator-"); @@ -692,7 +888,36 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator!"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else + if(natObj != nullptr) + { + cse.back()->Push(gc, !natObj->ToBool()); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject negfn = dict->GetValue("operator!"); @@ -736,7 +961,35 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator~"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator~",{})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject negfn = dict->GetValue("operator~"); @@ -819,8 +1072,35 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator<"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator<",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator<"); @@ -904,7 +1184,35 @@ namespace Tesses::CrossLang { auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator>"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator>",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator>"); @@ -987,7 +1295,35 @@ namespace Tesses::CrossLang { auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator<="); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator<=",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator<="); @@ -1072,7 +1408,36 @@ namespace Tesses::CrossLang { auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator>="); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else + if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator>=",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator>="); @@ -1174,9 +1539,35 @@ namespace Tesses::CrossLang { auto dynDict = dynamic_cast(obj); auto native = dynamic_cast(obj); - - - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator=="); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->Equals(gc,right)); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator=="); @@ -1311,9 +1702,37 @@ namespace Tesses::CrossLang { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto native = dynamic_cast(obj); - + auto natObj = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator!="); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else + if(natObj != nullptr) + { + cse.back()->Push(gc, !natObj->Equals(gc,right)); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator!="); @@ -1393,7 +1812,35 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator<<"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator<<",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator<<"); @@ -1436,7 +1883,36 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator>>"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else + if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator>>",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator>>"); @@ -1479,7 +1955,36 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator|"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator|",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator|"); @@ -1522,7 +2027,36 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator^"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else + if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator^",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator^"); @@ -1565,7 +2099,35 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator&"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator&",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator&"); @@ -1705,7 +2267,35 @@ namespace Tesses::CrossLang { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - if(dict != nullptr) + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"operator+"); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{right}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{right})); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + + } + else if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,"operator+",{right})); + return false; + } + else if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator+"); @@ -2551,6 +3141,13 @@ namespace Tesses::CrossLang { auto svr = dynamic_cast(obj); + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(natObj != nullptr) + { + cse.back()->Push(gc, natObj->CallMethod(ls,key,args)); + return false; + } if(callstackEntry != nullptr) { @@ -4131,6 +4728,26 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, Undefined()); return false; } + else if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,key); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,args); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,args)); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + } else if(dict != nullptr) { if(key == "ToString" && !dict->MethodExists(ls, key) && args.empty()) @@ -4391,7 +5008,35 @@ namespace Tesses::CrossLang { auto callstackEntry = dynamic_cast(obj); auto file = dynamic_cast(obj); auto chunk = dynamic_cast(obj); - + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"get"+key); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{})); + return false; + } + cse.back()->Push(gc,cls->GetValue(cse.back()->callable->className,key)); + return false; + + } + else + if(natObj != nullptr) + { + cse.back()->Push(gc,natObj->CallMethod(ls,"get"+key,{})); + return false; + } if(file != nullptr) { @@ -4453,6 +5098,46 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, list); return false; } + else if(key == "Sections") + { + TList* sections = TList::Create(ls); + gc->BarrierBegin(); + for(auto& item : file->sections) + { + TByteArray* ba = TByteArray::Create(ls); + ba->data = item.second; + sections->Add(TDictionary::Create(ls,{ + TDItem("Name", item.first), + TDItem("Data", ba) + })); + } + gc->BarrierEnd(); + + cse.back()->Push(gc, sections); + return false; + } + else if(key == "SupportedVMs") + { + TList* supported = TList::Create(ls); + gc->BarrierBegin(); + if(file->vms.empty()) + { + supported->Add(TDictionary::Create(ls,{ + TDItem("Name",std::string(VMName)), + TDItem("HowToGet",std::string(VMHowToGet)) + })); + } + else { + for(auto item : file->vms) + supported->Add(TDictionary::Create(ls,{ + TDItem("Name",item.first), + TDItem("HowToGet",item.second) + })); + } + gc->BarrierEnd(); + cse.back()->Push(gc, supported); + return false; + } else if(key == "Chunks") { auto list = TList::Create(ls); @@ -4760,7 +5445,36 @@ namespace Tesses::CrossLang { auto strm = dynamic_cast(obj); auto dict = dynamic_cast(obj); auto dynDict = dynamic_cast(obj); - + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + gc->BarrierBegin(); + auto obj=cls->GetValue(cse.back()->callable->className,"set"+key); + gc->BarrierEnd(); + TClosure* clos; + TCallable* callable; + if(GetObjectHeap(obj,clos)) + { + this->AddCallStackEntry(ls,clos,{value}); + return true; + } + else if(GetObjectHeap(obj,callable)) + { + cse.back()->Push(gc,callable->Call(ls,{value})); + return false; + } + cls->SetValue(cse.back()->callable->className,key,value); + cse.back()->Push(gc,value); + return false; + + } + else + if(natObj != nullptr) + { + cse.back()->Push(gc,natObj->CallMethod(ls,"set"+key,{value})); + return false; + } auto tcallable = dynamic_cast(obj); if(tcallable != nullptr) { @@ -4849,7 +5563,7 @@ namespace Tesses::CrossLang { { gc->BarrierBegin(); stk->Push(gc, - stk->env->GetVariable(std::get(key))); + stk->env->GetVariable(ls,std::get(key))); gc->BarrierEnd(); } else @@ -4872,8 +5586,8 @@ namespace Tesses::CrossLang { if(std::holds_alternative(key)) { gc->BarrierBegin(); - stk->env->SetVariable(std::get(key),value); - stk->Push(gc, value); + stk->Push(gc,stk->env->SetVariable(ls,std::get(key),value)); + gc->BarrierEnd(); } else if(GetObjectHeap(key,mls)) @@ -4896,7 +5610,7 @@ namespace Tesses::CrossLang { { auto val = valueLs->Get(i); result->SetValue(mkey, val); - stk->env->SetVariable(mkey,val); + stk->env->SetVariable(ls,mkey,val); } } stk->Push(gc,result); @@ -4917,7 +5631,7 @@ namespace Tesses::CrossLang { auto val = valueDynList->GetAt(ls,i); gc->BarrierBegin(); result->SetValue(mkey, val); - stk->env->SetVariable(mkey,val); + stk->env->SetVariable(ls,mkey,val); } } stk->Push(gc,result); @@ -4935,7 +5649,7 @@ namespace Tesses::CrossLang { { auto val = valueDict->GetValue(mkey); result->SetValue(mkey, val); - stk->env->SetVariable(mkey,val); + stk->env->SetVariable(ls,mkey,val); } } stk->Push(gc,result); @@ -4955,7 +5669,7 @@ namespace Tesses::CrossLang { gc->BarrierBegin(); result->SetValue(mkey, val); - stk->env->SetVariable(mkey,val); + stk->env->SetVariable(ls,mkey,val); } } stk->Push(gc,result); @@ -4968,7 +5682,7 @@ namespace Tesses::CrossLang { auto item = mls->Get(i); if(GetObject(item,mkey)) { - stk->env->SetVariable(mkey, value); + stk->env->SetVariable(ls,mkey, value); } } stk->Push(gc, value); @@ -5489,6 +6203,7 @@ namespace Tesses::CrossLang { gc->BarrierBegin(); GCList ls(gc); TClosure* closure = TClosure::Create(ls,stk->env,stk->callable->file,n,true); + closure->className = cse.back()->callable->className; stk->Push(gc,closure); gc->BarrierEnd(); } @@ -5516,6 +6231,7 @@ namespace Tesses::CrossLang { gc->BarrierBegin(); GCList ls(gc); TClosure* closure = TClosure::Create(ls,stk->env,stk->callable->file,n,false); + closure->className = stk->callable->className; stk->Push(gc,closure); gc->BarrierEnd(); } @@ -6187,6 +6903,24 @@ namespace Tesses::CrossLang { auto dict = dynamic_cast(obj); auto list = dynamic_cast(obj); auto bArray = dynamic_cast(obj); + auto natObj = dynamic_cast(obj); + auto cls = dynamic_cast(obj); + if(cls != nullptr) + { + auto res = cls->GetValue("","ToString"); + TCallable* call; + GCList ls(gc); + if(GetObjectHeap(res,call)) return ToString(gc, call->Call(ls,{})); + return cls->TypeName(); + } + if(natObj != nullptr) + { + GCList ls(gc); + TObject o=natObj->CallMethod(ls,"ToString",{}); + + + return ToString(gc, o); + } if(dict != nullptr) {