From e409970ae416e1cdbd78bb3b357d27fb88d4c0ce Mon Sep 17 00:00:00 2001 From: Mike Nolan Date: Mon, 1 Dec 2025 05:34:04 -0600 Subject: [PATCH] Add timespan --- .onedev-buildspec.yml | 7 +- CMakeLists.txt | 5 +- Packaging/Linux/version.sh | 3 +- include/CrossLang.hpp | 22 +- pkgconfig/CMakeLists.txt | 25 ++ pkgconfig/crosslang.pc.in | 13 + pkgconfig/crosslang_static.pc.in | 13 + src/compiler/lexer.cpp | 2 +- src/compiler/parser.cpp | 138 ++++++++- src/runtime_methods/io.cpp | 70 +++-- src/runtime_methods/net.cpp | 14 +- src/runtime_methods/std.cpp | 506 ++++++++++--------------------- src/types/datetime.cpp | 23 -- src/types/vfsheapobject.cpp | 8 +- src/vm/vm.cpp | 377 ++++++++++++++++++++--- 15 files changed, 759 insertions(+), 467 deletions(-) create mode 100644 pkgconfig/CMakeLists.txt create mode 100644 pkgconfig/crosslang.pc.in create mode 100644 pkgconfig/crosslang_static.pc.in delete mode 100644 src/types/datetime.cpp diff --git a/.onedev-buildspec.yml b/.onedev-buildspec.yml index c0d3dfe..311655d 100644 --- a/.onedev-buildspec.yml +++ b/.onedev-buildspec.yml @@ -25,7 +25,7 @@ jobs: name: Build Docker Image dockerfile: Dockerfile.run output: !RegistryOutput - tags: onedev.site.tesses.net/crosslang/crosslang:latest + tags: onedev.site.tesses.net/crosslang/crosslang:latest onedev.site.tesses.net/crosslang/crosslang:@commit_hash@ registryLogins: - registryUrl: '@server_url@' userName: '@job_token@' @@ -86,6 +86,8 @@ jobs: envVars: - name: GITEA_AUTH value: '@secret:GITEA_AUTH@' + - name: BUILD_NO + value: '@build_number@' useTTY: true condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !CommandStep @@ -109,6 +111,8 @@ jobs: value: '@secret:GITEA_AUTH@' - name: CPKG_KEY value: '@secret:CPKG_KEY@' + - name: BUILD_NO + value: '@build_number@' useTTY: true condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !SCPCommandStep @@ -125,6 +129,7 @@ jobs: privateKeySecret: TRUENAS_SSH commands: | cd /mnt/storage24tb/Files/Public/CrossLang + rm -f latest ln -s @build_number@ latest condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL triggers: diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e48d39..f22fafb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,6 @@ src/runtime_methods/helpers.cpp src/types/async.cpp src/types/associativearray.cpp src/types/any.cpp -src/types/datetime.cpp src/types/ittr.cpp src/types/closure.cpp src/types/dictionary.cpp @@ -445,7 +444,11 @@ set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS set(CPACK_NSIS_MUI_ICON "${CMAKE_CURRENT_SOURCE_DIR}/winicon.ico") set(CPACK_NSIS_MODIFY_PATH ON) +set(CPACK_PACKAGE_VENDOR "Tesses") set(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$DESKTOP\\\\CrossLang Interperter.lnk' '$INSTDIR\\\\bin\\\\crossint.exe'") +set(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\CrossLang Interperter.lnk' '$INSTDIR\\\\bin\\\\crossint.exe'") include(CPack) + +add_subdirectory(pkgconfig) \ No newline at end of file diff --git a/Packaging/Linux/version.sh b/Packaging/Linux/version.sh index 293fb1c..9f9d3ff 100644 --- a/Packaging/Linux/version.sh +++ b/Packaging/Linux/version.sh @@ -1 +1,2 @@ -export DEB_VERSION=1.0.0 \ No newline at end of file +export BUILD=$(($BUILD_NO-142)) +export DEB_VERSION=1.0.0-$BUILD \ No newline at end of file diff --git a/include/CrossLang.hpp b/include/CrossLang.hpp index c747900..d28e1a7 100644 --- a/include/CrossLang.hpp +++ b/include/CrossLang.hpp @@ -591,14 +591,7 @@ typedef enum { */ int Lex(std::string filename, std::istream& strm, std::vector& tokens); -/** - * @brief Undefined type - * - */ -class Undefined -{ - -}; +using Undefined = std::monostate; class AdvancedSyntaxNode; /** * @brief Bytecode instruction enumeration @@ -802,7 +795,7 @@ class CharInstruction : public ByteCodeInstruction { void Write(std::vector& data); }; -using SyntaxNode = std::variant, AdvancedSyntaxNode,std::shared_ptr,std::shared_ptr>; +using SyntaxNode = std::variant, AdvancedSyntaxNode,std::shared_ptr,std::shared_ptr>; @@ -1383,15 +1376,6 @@ class Parser { }; - class TDateTime { - Tesses::Framework::Date::DateTime* dt; - public: - TDateTime(); - TDateTime(Tesses::Framework::Date::DateTime t); - TDateTime(const TDateTime& dt); - Tesses::Framework::Date::DateTime& GetDate(); - ~TDateTime(); - }; class TBreak { }; @@ -1403,7 +1387,7 @@ class TContinue { * */ -using TObject = std::variant,std::shared_ptr,std::shared_ptr,std::shared_ptr,std::shared_ptr,std::shared_ptr>; +using TObject = std::variant,std::shared_ptr,TBreak,TContinue,std::shared_ptr,std::shared_ptr,std::shared_ptr,std::shared_ptr,std::shared_ptr,std::shared_ptr>; class TRootEnvironment; class GC; diff --git a/pkgconfig/CMakeLists.txt b/pkgconfig/CMakeLists.txt new file mode 100644 index 0000000..764bdc6 --- /dev/null +++ b/pkgconfig/CMakeLists.txt @@ -0,0 +1,25 @@ +set(PKGCONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") +set(PKGCONFIG_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}") + +set(PKGCONFIG_PROJECT_DESCRIPTION "A programming language") +set(PKGCONFIG_PROJECT_HOMEPAGE_URL "https://onedev.site.tesses.net/crosslang") + +if(CROSSLANG_ENABLE_FFI) +set(PKGCONFIG_DEPS "Requires: libffi") +else() +set(PKGCONFIG_DEPS "") +endif() + +if(CROSSLANG_ENABLE_STATIC) +configure_file(crosslang_static.pc.in crosslang_static.pc @ONLY) +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/crosslang_static.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +endif() + +if(CROSSLANG_ENABLE_SHARED) +configure_file(crosslang.pc.in crosslang.pc @ONLY) +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/crosslang.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +endif() \ No newline at end of file diff --git a/pkgconfig/crosslang.pc.in b/pkgconfig/crosslang.pc.in new file mode 100644 index 0000000..dae5c5e --- /dev/null +++ b/pkgconfig/crosslang.pc.in @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +includedir=@PKGCONFIG_INCLUDEDIR@ +libdir=@PKGCONFIG_LIBDIR@ + +Name: @PROJECT_NAME@ +Description: @PKGCONFIG_PROJECT_DESCRIPTION@ +URL: @PKGCONFIG_PROJECT_HOMEPAGE_URL@ +Version: @PROJECT_VERSION@ + +@PKGCONFIG_DEPS@ + +Cflags: -I"${includedir}" +Libs: -L"${libdir}" -lcrosslang_shared \ No newline at end of file diff --git a/pkgconfig/crosslang_static.pc.in b/pkgconfig/crosslang_static.pc.in new file mode 100644 index 0000000..ad4d174 --- /dev/null +++ b/pkgconfig/crosslang_static.pc.in @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +includedir=@PKGCONFIG_INCLUDEDIR@ +libdir=@PKGCONFIG_LIBDIR@ + +Name: @PROJECT_NAME@ +Description: @PKGCONFIG_PROJECT_DESCRIPTION@ +URL: @PKGCONFIG_PROJECT_HOMEPAGE_URL@ +Version: @PROJECT_VERSION@ + +@PKGCONFIG_DEPS@ + +Cflags: -I"${includedir}" +Libs: -L"${libdir}" -lcrosslang_static \ No newline at end of file diff --git a/src/compiler/lexer.cpp b/src/compiler/lexer.cpp index 293de2c..38a3c22 100644 --- a/src/compiler/lexer.cpp +++ b/src/compiler/lexer.cpp @@ -578,7 +578,6 @@ namespace Tesses::CrossLang } break; case '<': - case '>': case '?': if(peek == read) { @@ -645,6 +644,7 @@ namespace Tesses::CrossLang case '^': case '~': case '!': + case '>': case '*': case '%': //* diff --git a/src/compiler/parser.cpp b/src/compiler/parser.cpp index ec60f66..8ded622 100644 --- a/src/compiler/parser.cpp +++ b/src/compiler/parser.cpp @@ -114,16 +114,59 @@ namespace Tesses::CrossLang bool Parser::IsAnySymbol(std::initializer_list idents, bool pop) { + if(i < tokens.size()) { if(tokens[i].type != LexTokenType::Symbol) return false; for(auto item : idents) { - if(item == tokens[i].text) + if(item == ">") { - tkn = tokens[i]; - if(pop) i++; - return true; + if(i+1" || tokens[i+1].text == ">=") && tokens[i+1].type == LexTokenType::Symbol) continue; + } + if(item == tokens[i].text) + { + tkn = tokens[i]; + if(pop) i++; + return true; + } + } + else if(item == ">>=") + { + if(i+1 < tokens.size()) + { + if(tokens[i].text == ">" && tokens[i+1].text == ">=" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].type == LexTokenType::Symbol) + { + tkn = tokens[i]; + tkn.text = ">>="; + if(pop) i+=2; + return true; + } + } + } + else if(item == ">>") + { + if(i+1 < tokens.size()) + { + if(tokens[i].text == ">" && tokens[i+1].text == ">" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].type == LexTokenType::Symbol) + { + tkn = tokens[i]; + tkn.text = ">>"; + if(pop) i+=2; + return true; + } + } + + } + else { + if(item == tokens[i].text) + { + tkn = tokens[i]; + if(pop) i++; + return true; + } } } } @@ -134,7 +177,48 @@ namespace Tesses::CrossLang if(i < tokens.size()) { if(tokens[i].type != LexTokenType::Symbol) return false; - if(tokens[i].text == txt) + if(txt == ">") + { + if(i+1" || tokens[i+1].text == ">=") && tokens[i+1].type == LexTokenType::Symbol) return false; + } + if(txt == tokens[i].text) + { + tkn = tokens[i]; + if(pop) i++; + return true; + } + } + else if(txt == ">>=") + { + if(i+1 < tokens.size()) + { + + if(tokens[i].text == ">" && tokens[i+1].text == ">=" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].type == LexTokenType::Symbol) + { + tkn = tokens[i]; + tkn.text = ">>="; + if(pop) i+=2; + return true; + } + } + } + else if(txt == ">>") + { + if(i+1 < tokens.size()) + { + if(tokens[i].text == ">" && tokens[i+1].text == ">" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].type == LexTokenType::Symbol) + { + tkn = tokens[i]; + tkn.text = ">>"; + if(pop) i+=2; + return true; + } + } + + } + else if(tokens[i].text == txt) { tkn = tokens[i]; if(pop) i++; @@ -147,11 +231,53 @@ namespace Tesses::CrossLang { if(i < tokens.size()) { + if(tokens[i].type != LexTokenType::Symbol) { throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the " + LexTokenType_ToString(tokens[i].type) + " \"" + tokens[i].text + "\" which is not a symbol at all."); } - if(tokens[i].text != txt) + if(txt == ">") + { + if(i+1" || tokens[i+1].text == ">=") && tokens[i+1].type == LexTokenType::Symbol) + throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + tokens[i+1].text + "\"");; + } + if(txt == tokens[i].text) + { + return; + } + } + if(txt == ">>=") + { + if(i+1 < tokens.size()) + { + if(tokens[i].text == ">" && tokens[i+1].text == ">=" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].type == LexTokenType::Symbol) + { + return; + } + + throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + tokens[i+1].text + "\""); + } + + throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + "\""); + } + else if(txt == ">>") + { + if(i+1 < tokens.size()) + { + if(tokens[i].text == ">" && tokens[i+1].text == ">" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].type == LexTokenType::Symbol) + { + i+=2; + return; + } + + throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + tokens[i+1].text + "\""); + } + + throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + "\""); + } + else if(tokens[i].text != txt) { throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + "\""); diff --git a/src/runtime_methods/io.cpp b/src/runtime_methods/io.cpp index f7cd2c6..ba7bec3 100644 --- a/src/runtime_methods/io.cpp +++ b/src/runtime_methods/io.cpp @@ -70,13 +70,32 @@ namespace Tesses::CrossLang if(GetArgument(args,0,vfs) && GetArgumentAsPath(args,1,path)) { - auto txtFile = vfs->OpenFile(path,"rb"); - if(txtFile == nullptr) return ""; - Tesses::Framework::TextStreams::StreamReader reader(txtFile); - return reader.ReadToEnd(); + return Tesses::Framework::Filesystem::Helpers::ReadAllText(vfs,path); } return ""; } + + static TObject FS_ReadAllLines(GCList& ls, std::vector args) + { + Tesses::Framework::Filesystem::VFSPath path; + + std::shared_ptr vfs; + + if(GetArgument(args,0,vfs) && GetArgumentAsPath(args,1,path)) + { + std::vector lines; + + Tesses::Framework::Filesystem::Helpers::ReadAllLines(vfs,path,lines); + + ls.GetGC()->BarrierBegin(); + auto items = TList::Create(ls); + for(auto& l : lines) { items->Add(l);} + ls.GetGC()->BarrierEnd(); + return items; + } + return nullptr; + } + static TObject FS_ReadAllBytes(GCList& ls, std::vector args) { Tesses::Framework::Filesystem::VFSPath path; @@ -84,15 +103,8 @@ namespace Tesses::CrossLang if(GetArgument(args,0,vfs) && GetArgumentAsPath(args,1,path)) { - auto txtFile = vfs->OpenFile(path,"rb"); - if(txtFile == nullptr) return nullptr; auto res = TByteArray::Create(ls); - std::array data; - size_t read; - do { - read = txtFile->ReadBlock(data.data(),data.size()); - res->data.insert(res->data.end(),data.begin(),data.begin()+read); - } while(read != 0); + Tesses::Framework::Filesystem::Helpers::ReadAllBytes(vfs,path,res->data); return res; } @@ -100,6 +112,27 @@ namespace Tesses::CrossLang } + static TObject FS_WriteAllLines(GCList& ls, std::vector args) + { + Tesses::Framework::Filesystem::VFSPath path; + std::shared_ptr vfs; + + + TList* lines; + if(GetArgument(args,0,vfs) && GetArgumentAsPath(args,1,path) && GetArgumentHeap(args,2,lines)) + { + std::vector content; + ls.GetGC()->BarrierBegin(); + for(auto& item : lines->items) + { + if(std::holds_alternative(item)) + content.push_back(std::get(item)); + } + ls.GetGC()->BarrierEnd(); + Tesses::Framework::Filesystem::Helpers::WriteAllLines(vfs,path,content); + } + return nullptr; + } static TObject FS_WriteAllText(GCList& ls, std::vector args) { Tesses::Framework::Filesystem::VFSPath path; @@ -109,10 +142,7 @@ namespace Tesses::CrossLang std::string content; if(GetArgument(args,0,vfs) && GetArgumentAsPath(args,1,path) && GetArgument(args,2,content)) { - auto txtFile = vfs->OpenFile(path,"wb"); - if(txtFile == nullptr) return nullptr; - Tesses::Framework::TextStreams::StreamWriter writer(txtFile); - writer.Write(content); + Tesses::Framework::Filesystem::Helpers::WriteAllText(vfs,path,content); } return nullptr; } @@ -125,10 +155,7 @@ namespace Tesses::CrossLang TByteArray* bArray; if(GetArgument(args,0,vfs) && GetArgumentAsPath(args,1,path) && GetArgumentHeap(args,2,bArray)) { - auto txtFile = vfs->OpenFile(path,"wb"); - if(txtFile == nullptr) return nullptr; - txtFile->WriteBlock(bArray->data.data(),bArray->data.size()); - + Tesses::Framework::Filesystem::Helpers::WriteAllBytes(vfs,path,bArray->data); } return nullptr; } @@ -166,6 +193,9 @@ namespace Tesses::CrossLang dict->DeclareFunction(gc, "ReadAllText","Read all text from file", {"fs","filename"},FS_ReadAllText); dict->DeclareFunction(gc, "WriteAllText","Write all text to file", {"fs","filename","content"},FS_WriteAllText); + + dict->DeclareFunction(gc, "ReadAllLines","Read all lines from file", {"fs","filename"},FS_ReadAllLines); + dict->DeclareFunction(gc, "WriteAllLines","Write all lines to file", {"fs","filename","lines"},FS_WriteAllLines); dict->DeclareFunction(gc, "ReadAllBytes","Read all bytes from file", {"fs","filename"},FS_ReadAllBytes); dict->DeclareFunction(gc, "WriteAllBytes","Write all bytes to file", {"fs","filename","content"},FS_WriteAllBytes); diff --git a/src/runtime_methods/net.cpp b/src/runtime_methods/net.cpp index db623ab..e98c21b 100644 --- a/src/runtime_methods/net.cpp +++ b/src/runtime_methods/net.cpp @@ -99,7 +99,7 @@ namespace Tesses::CrossLang std::string value; int64_t i64; double d64; - TDateTime da; + std::shared_ptr da; if(GetArgument(args,0,key) ) { if(GetArgument(args,1,value)) @@ -109,7 +109,7 @@ namespace Tesses::CrossLang else if(GetArgument(args,1,d64)) this->dict->AddValue(key, d64); else if(GetArgument(args,1,da)) - this->dict->AddValue(key, da.GetDate()); + this->dict->AddValue(key, *da); } } else if(key == "SetValue") @@ -118,7 +118,7 @@ namespace Tesses::CrossLang std::string value; int64_t i64; double d64; - TDateTime da; + std::shared_ptr da; if(GetArgument(args,0,key) ) { if(GetArgument(args,1,value)) @@ -128,7 +128,7 @@ namespace Tesses::CrossLang else if(GetArgument(args,1,d64)) this->dict->SetValue(key, d64); else if(GetArgument(args,1,da)) - this->dict->SetValue(key, da.GetDate()); + this->dict->SetValue(key, *da); } } else if(key == "Clear") @@ -185,7 +185,7 @@ namespace Tesses::CrossLang Tesses::Framework::Date::DateTime value; if(GetArgument(args,0,key) && dict->TryGetFirstDate(key,value)) { - return value; + return std::make_shared(value); } return nullptr; } @@ -373,9 +373,9 @@ namespace Tesses::CrossLang } else if(key == "WithLastModified") { - TDateTime da; + std::shared_ptr da; if(GetArgument(args,0,da)) - ctx->WithLastModified(da.GetDate()); + ctx->WithLastModified(*da); return this; } else if(key == "WithContentDisposition") diff --git a/src/runtime_methods/std.cpp b/src/runtime_methods/std.cpp index 3b8afab..0297449 100644 --- a/src/runtime_methods/std.cpp +++ b/src/runtime_methods/std.cpp @@ -29,8 +29,19 @@ + namespace Tesses::CrossLang { + +#if defined(_WIN32) + std::string SharedExtension = ".dll"; +#elif defined(__APPLE__) + std::string SharedExtension = ".dylib"; +#else + std::string SharedExtension = ".so"; +#endif + + class TMuxex : public TNativeObject { public: @@ -60,329 +71,8 @@ namespace Tesses::CrossLang } }; - class DocumentationParser : public TNativeObject - { - public: - - std::vector> items; - DocumentationParser(std::string doc) - { - size_t i=0; - int state=-1; - std::string key={}; - std::string value={}; - - auto add = [&]()->void{ - if(value == "true") { - items.push_back(std::pair(key,true)); - } else if(value == "false") { - items.push_back(std::pair(key,false)); - } else if(value == "null") { - items.push_back(std::pair(key,nullptr)); - } else { - if(value[0] >= '0' && value[0] <= '9') - { - try { - if(value.find('.') != std::string::npos) - { - - items.push_back(std::pair(key,std::stod(value))); - } - else { - items.push_back(std::pair(key,std::stoll(value))); - } - }catch(...) {} - } - else { - items.push_back(std::pair(key,value)); - } - } - }; - - auto ReadChr = [&]() -> std::pair { - int read=i < doc.size() ? (int)doc[i++] : -1; - - if(read == -1) - { - - return std::pair(-1,false); - } - - - - if(read == '\\') - { - read = i < doc.size() ? (int)doc[i++] : -1; - - if(read == -1) - { - return std::pair(-1,true); - } - else if(read == 'n') - { - return std::pair('\n',true); - } - else if(read == 'r') - { - return std::pair('\r',true); - } - else if(read == 'f') - { - return std::pair('\f',true); - } - else if(read == 'b') - { - return std::pair('\b',true); - } - else if(read == 'a') - { - return std::pair('\a',true); - } - else if(read == '0') - { - return std::pair('\0',true); - } - else if(read == 'v') - { - return std::pair('\v',true); - } - else if(read == 'e') - { - return std::pair('\x1B',true); - } - else if(read == 't') - { - return std::pair('\t',true); - } - else if(read == 'x') - { - int r1 = i < doc.size() ? (int)doc[i++] : -1; - - if(r1 == -1) - { - return std::pair(-1,true); - } - int r2 = i < doc.size() ? (int)doc[i++] : -1; - - if(r2 == -1) - { - return std::pair(-1,true); - } - - uint8_t c = (uint8_t)std::stoi(std::string{(char)r1,(char)r2},nullptr,16); - - return std::pair(c,true); - } - else - { - return std::pair(read,true); - } - } - else - { - return std::pair(read,false); - } - }; - - - - - for(; i < doc.size(); i++) - { - if(doc[i] == '@') - { - state = 0; - key={}; - value={}; - if(i + 1 < doc.size()) - { - if(doc[i+1] == '@') - { - i++; - continue; - } - else { - i++; - for(; i < doc.size(); i++) - { - switch(doc[i]) - { - case '\'': - { - i++; - auto c = ReadChr(); - i++; - if(c.first != -1) - { - if(state == 0) - key+={(char)c.first}; - else { - this->items.push_back(std::pair(key,(char)c.first)); - state = -1; - goto outer; - } - } - } - break; - case '\"': - { - if(state == 0) - { - i++; - auto rChr = ReadChr(); - while(rChr.first != '\"' || rChr.second) - { - if(rChr.first == -1) break; - key += (char)rChr.first; - rChr = ReadChr(); - } - i--; - } - else { - i++; - auto rChr = ReadChr(); - - while(rChr.first != '\"' || rChr.second) - { - if(rChr.first == -1) break; - value += (char)rChr.first; - rChr = ReadChr(); - } - this->items.push_back(std::pair(key,value)); - state = -1; - goto outer; - } - } - break; - case ' ': - case '\n': - case '\t': - case '\r': - if(state == 0 && !key.empty()) - state=1; - else - if(state == 1 && !value.empty()) - { - add(); - state = -1; - goto outer; - } - break; - default: - if(state == 0) key += doc[i]; - else value += doc[i]; - break; - } - } - } - outer:; - } - - } - } - if(state == 1 && !value.empty()) - { - add(); - } - } - TObject CallMethod(GCList& ls, std::string key, std::vector args); - std::string TypeName() - { - return "DocumentationParser"; - } - }; - class DocumentationParserEnumerator : public TEnumerator - { - int index; - DocumentationParser* dict; - public: - static DocumentationParserEnumerator* Create(GCList& ls, DocumentationParser* dict) - { - auto dpe=new DocumentationParserEnumerator(); - auto gc = ls.GetGC(); - ls.Add(dpe); - gc->Watch(dpe); - dpe->dict = dict; - dpe->index=-1; - return dpe; - } - - bool MoveNext(GC* ls) - { - ls->BarrierBegin(); - bool r = ++index < this->dict->items.size(); - - ls->BarrierEnd(); - return r; - } - TObject GetCurrent(GCList& ls) - { - std::pair item; - ls.GetGC()->BarrierBegin(); - if(this->index > -1 && this->index < this->dict->items.size()) - { - item = this->dict->items[(size_t)this->index]; - } - ls.GetGC()->BarrierEnd(); - - return TDictionary::Create(ls,{ - TDItem("Key", item.first), - TDItem("Value", item.second) - }); - } - void Mark() - { - if(this->marked) return; - this->marked=true; - dict->Mark(); - } - }; - - - TObject DocumentationParser::CallMethod(GCList& ls, std::string key, std::vector args) - { - std::string myKey; - if(key == "GetAt" && GetArgument(args,0,myKey)) - { - for(auto item : this->items) - if(item.first == myKey) return item.second; - } - if(key == "ToString") - { - std::string n={}; - for(auto item : this->items) - { - n.push_back('@'); - n.append(item.first); - n.push_back(' '); - std::string str; - if(GetObject(item.second,str)) - { - n.append(EscapeString(str,true)); - } - else n.append(ToString(ls.GetGC(), item.second)); - n.push_back('\n'); - } - return n; - } - if(key == "GetEnumerator") - { - return DocumentationParserEnumerator::Create(ls,this); - } - return Undefined(); - - } - TObject New_DocumentationParser(GCList& ls, std::vector args) - { - std::string doc; - - if(GetArgument(args,0,doc)) - { - return TNativeObject::Create(ls, doc); - } - - return Undefined(); - } + + #if defined(CROSSLANG_ENABLE_SHARED) @@ -771,10 +461,29 @@ namespace Tesses::CrossLang } #endif + Tesses::Framework::Filesystem::VFSPath GetPluginPath(Tesses::Framework::Filesystem::VFSPath path) + { + using namespace Tesses::Framework::Filesystem; + if(!path.relative) return path; + + auto pluginConfigDir = GetCrossLangConfigDir() / "Plugins"; + if(LocalFS->DirectoryExists(pluginConfigDir)) + { + if(LocalFS->FileExists(pluginConfigDir / path + SharedExtension)) + return pluginConfigDir / path + SharedExtension; + auto path2 = pluginConfigDir / path.GetParent() / "lib" + path.GetFileName() + SharedExtension; + if(LocalFS->FileExists(path2)) return path2; + } + + return path; + } + + void LoadPlugin(GC* gc, TRootEnvironment* env, Tesses::Framework::Filesystem::VFSPath sharedObjectPath) { + #if defined(CROSSLANG_ENABLE_SHARED) - auto ptr = std::make_shared
(sharedObjectPath); + auto ptr = std::make_shared
(GetPluginPath(sharedObjectPath)); auto cb = ptr->Resolve("CrossLangPluginInit"); if(cb == nullptr) return; gc->RegisterEverythingCallback([ptr,cb](GC* gc, TRootEnvironment* env)-> void{ @@ -857,8 +566,14 @@ namespace Tesses::CrossLang static TObject TypeIsDateTime(GCList& ls, std::vector args) { if(args.empty()) return nullptr; - TDateTime* dt; - return GetArgumentHeap(args,0,dt); + std::shared_ptr dt; + return GetArgument(args,0,dt); + } + static TObject TypeIsTimeSpan(GCList& ls, std::vector args) + { + if(args.empty()) return nullptr; + std::shared_ptr dt; + return GetArgument(args,0,dt); } static TObject New_SubdirFilesystem(GCList& ls, std::vector args) { @@ -905,6 +620,25 @@ namespace Tesses::CrossLang } return nullptr; } + static TObject New_TempFS(GCList& ls, std::vector args) + { + std::shared_ptr vfs; + if(GetArgument(args,0,vfs)) + { + bool deleteOnDispose=true; + GetArgument(args,1,deleteOnDispose); + return std::make_shared(vfs,deleteOnDispose); + } + else { + bool deleteOnDispose; + if(GetArgument(args,0,deleteOnDispose)) + { + return std::make_shared(deleteOnDispose); + } + + } + return std::make_shared(); + } static TObject New_Stream(GCList& ls, std::vector args) { TDictionary* dict; @@ -921,8 +655,8 @@ namespace Tesses::CrossLang { if(args.size()==1) { - Tesses::Framework::Date::DateTime dt(year); - return dt; + return std::make_shared(year); + } else { @@ -940,12 +674,45 @@ namespace Tesses::CrossLang GetArgument(args,6,isLocal); - Tesses::Framework::Date::DateTime dt((int)year,(int)month,(int)day,(int)hour,(int)minute,(int)second,isLocal); - return dt; + return std::make_shared((int)year,(int)month,(int)day,(int)hour,(int)minute,(int)second,isLocal); } } return nullptr; } + static TObject New_TimeSpan(GCList& ls, std::vector args) + { + + int64_t arg1; + if(GetArgument(args,0,arg1)) + { + if(args.size()==1) + { + return std::make_shared(arg1); + } + else if(args.size() >= 3) + { + int64_t arg2; + int64_t arg3; + if(GetArgument(args,1,arg2) && GetArgument(args,2,arg3)) + { + int64_t arg4; + if(GetArgument(args,3,arg4)) + { + return std::make_shared((int)arg1,(int)arg2,(int)arg3,(int)arg4); + + } + else + { + return std::make_shared((int)arg1,(int)arg2,(int)arg3);; + + } + } + } + + } + return nullptr; + } + std::string GetObjectTypeString(TObject _obj) { if(std::holds_alternative(_obj)) return "Regex"; @@ -960,7 +727,8 @@ namespace Tesses::CrossLang if(std::holds_alternative(_obj)) return "Path"; if(std::holds_alternative(_obj)) return "Version"; - if(std::holds_alternative(_obj)) return "DateTime"; + if(std::holds_alternative>(_obj)) return "DateTime"; + if(std::holds_alternative>(_obj)) return "TimeSpan"; if(std::holds_alternative>(_obj)) { auto strm = std::get>(_obj); @@ -1003,15 +771,14 @@ namespace Tesses::CrossLang if(vfs != nullptr) { auto localVFS = std::dynamic_pointer_cast(vfs); - auto mountableVFS = std::dynamic_pointer_cast(vfs); - - auto subFS = std::dynamic_pointer_cast(vfs); + auto tempFS = std::dynamic_pointer_cast(vfs); if(localVFS != nullptr) return "LocalFilesystem"; if(subFS != nullptr) return "SubdirFilesystem"; if(mountableVFS != nullptr) return "MountableFilesystem"; + if(tempFS != nullptr) return "TempFS"; } @@ -1209,11 +976,11 @@ namespace Tesses::CrossLang static TObject DateTime_getNow(GCList& ls, std::vector args) { - return Tesses::Framework::Date::DateTime::Now(); + return std::make_shared(Tesses::Framework::Date::DateTime::Now()); } static TObject DateTime_getNowUTC(GCList& ls, std::vector args) { - return Tesses::Framework::Date::DateTime::NowUTC(); + return std::make_shared(Tesses::Framework::Date::DateTime::NowUTC()); } static TObject DateTime_getNowEpoch(GCList& ls, std::vector args) { @@ -1226,7 +993,7 @@ namespace Tesses::CrossLang Tesses::Framework::Date::DateTime dt; if(GetArgument(args,0,d) && Tesses::Framework::Date::DateTime::TryParseHttpDate(d,dt)) { - return dt; + return std::make_shared(dt); } return nullptr; } @@ -1234,6 +1001,56 @@ namespace Tesses::CrossLang { return TTask::Create(ls); } + static TObject TimeSpan_Parse(GCList& ls, std::vector args) + { + std::string t; + Tesses::Framework::Date::TimeSpan ts; + if(GetArgument(args,0,t) && Tesses::Framework::Date::TimeSpan::TryParse(t,ts)) + { + return std::make_shared(ts); + } + return nullptr; + } + static TObject TimeSpan_FromSeconds(GCList& ls, std::vector args) + { + int64_t n; + + if(GetArgument(args,0,n)) + { + return std::make_shared(n); + } + return nullptr; + } + static TObject TimeSpan_FromMinutes(GCList& ls, std::vector args) + { + int64_t n; + + if(GetArgument(args,0,n)) + { + return std::make_shared(n*60); + } + return nullptr; + } + static TObject TimeSpan_FromHours(GCList& ls, std::vector args) + { + int64_t n; + + if(GetArgument(args,0,n)) + { + return std::make_shared(n*3600); + } + return nullptr; + } + static TObject TimeSpan_FromDays(GCList& ls, std::vector args) + { + int64_t n; + + if(GetArgument(args,0,n)) + { + return std::make_shared(n*86400); + } + return nullptr; + } void TStd::RegisterRoot(GC* gc, TRootEnvironment* env) { GCList ls(gc); @@ -1250,10 +1067,18 @@ namespace Tesses::CrossLang date->DeclareFunction(gc, "getNowEpoch","Get the time_t time now",{},DateTime_getNowEpoch); date->DeclareFunction(gc, "TryParseHttpDate","Parse the http date",{},DateTime_TryParseHttpDate); - date->SetValue("Zone", (int64_t)Tesses::Framework::Date::GetTimeZone()); date->SetValue("SupportsDaylightSavings",Tesses::Framework::Date::TimeZoneSupportDST()); + + + auto ts = env->EnsureDictionary(gc, "TimeSpan"); + ts->DeclareFunction(gc, "Parse", "Parse timespan",{"tsStr"}, TimeSpan_Parse); + ts->DeclareFunction(gc,"FromSeconds","Create timespan from seconds", {"seconds"}, TimeSpan_FromSeconds); + ts->DeclareFunction(gc,"FromMinutes","Create timespan from minutes", {"minutes"}, TimeSpan_FromMinutes); + ts->DeclareFunction(gc,"FromHours","Create timespan from hours", {"hours"}, TimeSpan_FromHours); + ts->DeclareFunction(gc,"FromDays","Create timespan from days", {"days"}, TimeSpan_FromDays); + auto task = env->EnsureDictionary(gc,"Task"); @@ -1275,11 +1100,13 @@ namespace Tesses::CrossLang 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); + newTypes->DeclareFunction(gc, "TimeSpan","Create a DateTime object, if only one arg is provided days is totalSeconds, if there are only three arguments days will be hours, hours will be minutes, minutes will be seconds (according to the argument documentation)",{"days","$hours","$minutes","$seconds"},New_TimeSpan); newTypes->DeclareFunction(gc, "MountableFilesystem","Create a mountable filesystem",{"root"}, New_MountableFilesystem); newTypes->DeclareFunction(gc, "SubdirFilesystem","Create a subdir filesystem",{"fs","subdir"}, New_SubdirFilesystem); newTypes->DeclareFunction(gc, "MemoryStream","Create a memory stream",{"writable"}, New_MemoryStream); newTypes->DeclareFunction(gc, "Filesystem","Create filesystem", {"fs"},New_Filesystem); + newTypes->DeclareFunction(gc, "TempFS","Create a temp directory",{"",""}, New_TempFS); newTypes->DeclareFunction(gc, "Stream","Create stream", {"strm"},New_Stream); newTypes->DeclareFunction(gc, "MemoryFilesystem","Create in memory filesystem", {},New_MemoryFilesystem); @@ -1326,7 +1153,7 @@ namespace Tesses::CrossLang env->DeclareFunction(gc, "TypeIsStream","Get whether object is a stream",{"object"},TypeIsStream); env->DeclareFunction(gc, "TypeIsVFS","Get whether object is a virtual filesystem",{"object"},TypeIsVFS); env->DeclareFunction(gc, "TypeIsDateTime","Get whether object is a DateTime",{"object"},TypeIsDateTime); - + env->DeclareFunction(gc, "TypeIsTimeSpan","Get whether object is a TimeSpan",{"object"},TypeIsTimeSpan); newTypes->DeclareFunction(gc, "Regex", "Create regex object",{"regex"},[](GCList& ls,std::vector args)->TObject { @@ -1372,7 +1199,6 @@ namespace Tesses::CrossLang newTypes->DeclareFunction(gc,"AArray","alias for new AssociativeArray",{},[](GCList& ls, std::vector args)->TObject { return TAssociativeArray::Create(ls); }); - newTypes->DeclareFunction(gc,"DocumentationParser","Parse documentation blocks",{"documentationString"},New_DocumentationParser); newTypes->DeclareFunction(gc,"ByteArray","Create bytearray, with optional either size (to size it) or string argument (to fill byte array)",{"$data"},ByteArray); newTypes->DeclareFunction(gc,"Task","Create a task for async, to manually create an async object",{},New_Task); diff --git a/src/types/datetime.cpp b/src/types/datetime.cpp deleted file mode 100644 index 972ccf5..0000000 --- a/src/types/datetime.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "CrossLang.hpp" -namespace Tesses::CrossLang { - TDateTime::TDateTime() - { - this->dt=new Tesses::Framework::Date::DateTime(); - } - TDateTime::TDateTime(Tesses::Framework::Date::DateTime t) - { - this->dt = new Tesses::Framework::Date::DateTime(t); - } - TDateTime::TDateTime(const TDateTime& dt) - { - this->dt = new Tesses::Framework::Date::DateTime(*dt.dt); - } - Tesses::Framework::Date::DateTime& TDateTime::GetDate() - { - return *this->dt; - } - TDateTime::~TDateTime() - { - delete this->dt; - } -} \ No newline at end of file diff --git a/src/types/vfsheapobject.cpp b/src/types/vfsheapobject.cpp index 32e4c02..a504ccb 100644 --- a/src/types/vfsheapobject.cpp +++ b/src/types/vfsheapobject.cpp @@ -476,14 +476,14 @@ namespace Tesses::CrossLang { { this->ls->GetGC()->BarrierBegin(); res = dict->GetValue("LastWrite"); - TDateTime d; + std::shared_ptr d; if(GetObject(res,d)) - lastWrite =d.GetDate(); + lastWrite =*d; res = dict->GetValue("LastAccess"); if(GetObject(res,d)) - lastWrite =d.GetDate(); + lastWrite = *d; this->ls->GetGC()->BarrierEnd(); } @@ -497,7 +497,7 @@ namespace Tesses::CrossLang { if(GetObjectHeap(this->obj, dict)) { GCList ls(this->ls->GetGC()); - dict->CallMethod(ls, "SetDate",{path,lastWrite,lastAccess}); + dict->CallMethod(ls, "SetDate",{path,std::make_shared(lastWrite),std::make_shared(lastAccess)}); } } diff --git a/src/vm/vm.cpp b/src/vm/vm.cpp index 01879e7..88d6da7 100644 --- a/src/vm/vm.cpp +++ b/src/vm/vm.cpp @@ -45,12 +45,16 @@ namespace Tesses::CrossLang { { return std::get(obj) != 0; } - else if(std::holds_alternative(obj)) + else if(std::holds_alternative>(obj)) { - auto& dt = std::get(obj).GetDate(); - return !(dt.Year() == 1970 && dt.Month() == 1 && dt.Day() == 1 && dt.Hour() == 0 && dt.Minute() == 0 && dt.Second() == 0 && !dt.IsLocal()); + auto& dt = std::get>(obj); + return !(dt->Year() == 1970 && dt->Month() == 1 && dt->Day() == 1 && dt->Hour() == 0 && dt->Minute() == 0 && dt->Second() == 0 && !dt->IsLocal()); } + else if(std::holds_alternative>(obj)) + { + return std::get>(obj)->TotalSeconds() != 0; + } else if(std::holds_alternative(obj)) { auto o = std::get(obj).obj; @@ -60,7 +64,6 @@ namespace Tesses::CrossLang { auto ba = dynamic_cast(o); 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); @@ -153,9 +156,13 @@ namespace Tesses::CrossLang { { return std::get(left) == std::get(right); } - else if(std::holds_alternative(left) && std::holds_alternative(right)) + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) { - return std::get(left).GetDate().ToEpoch() == std::get(right).GetDate().ToEpoch(); + return std::get>(left)->ToEpoch() == std::get>(right)->ToEpoch(); + } + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) + { + return std::get>(left)->TotalSeconds() == std::get>(right)->TotalSeconds(); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { @@ -457,6 +464,18 @@ namespace Tesses::CrossLang { { cse.back()->Push(gc, (int64_t)(std::get(left) - std::get(right))); } + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) + { + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,std::make_shared((*l) - (*r))); + } + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) + { + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,std::make_shared((*l) - (*r))); + } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; @@ -1083,9 +1102,18 @@ namespace Tesses::CrossLang { { cse.back()->Push(gc, std::get(left) < std::get(right)); } - else if(std::holds_alternative(left) && std::holds_alternative(right)) + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) { - cse.back()->Push(gc, std::get(left).GetDate().ToEpoch() < std::get(right).GetDate().ToEpoch()); + + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,l->ToEpoch() < r->ToEpoch()); + } + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) + { + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,l->TotalSeconds() < r->TotalSeconds()); } else if(std::holds_alternative(left)) { @@ -1194,9 +1222,18 @@ namespace Tesses::CrossLang { { cse.back()->Push(gc, std::get(left) > std::get(right)); } - else if(std::holds_alternative(left) && std::holds_alternative(right)) + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) { - cse.back()->Push(gc, std::get(left).GetDate().ToEpoch() > std::get(right).GetDate().ToEpoch()); + + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,l->ToEpoch() > r->ToEpoch()); + } + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) + { + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,l->TotalSeconds() > r->TotalSeconds()); } else if(std::holds_alternative(left)) { @@ -1305,9 +1342,18 @@ namespace Tesses::CrossLang { { cse.back()->Push(gc, std::get(left) <= std::get(right)); } - else if(std::holds_alternative(left) && std::holds_alternative(right)) + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) { - cse.back()->Push(gc, std::get(left).GetDate().ToEpoch() <= std::get(right).GetDate().ToEpoch()); + + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,l->ToEpoch() <= r->ToEpoch()); + } + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) + { + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,l->TotalSeconds() <= r->TotalSeconds()); } else if(std::holds_alternative(left)) { @@ -1418,9 +1464,18 @@ namespace Tesses::CrossLang { { cse.back()->Push(gc, std::get(left) >= std::get(right)); } - else if(std::holds_alternative(left) && std::holds_alternative(right)) + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) { - cse.back()->Push(gc, std::get(left).GetDate().ToEpoch() >= std::get(right).GetDate().ToEpoch()); + + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,l->ToEpoch() >= r->ToEpoch()); + } + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) + { + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,l->TotalSeconds() >= r->TotalSeconds()); } else if(std::holds_alternative(left)) { @@ -1549,9 +1604,18 @@ namespace Tesses::CrossLang { auto r = lver.CompareTo(rver); cse.back()->Push(gc, r == 0); } - else if(std::holds_alternative(left) && std::holds_alternative(right)) + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) { - cse.back()->Push(gc, std::get(left).GetDate().ToEpoch() == std::get(right).GetDate().ToEpoch()); + + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,(l->ToEpoch() == r->ToEpoch()) && (l->IsLocal() == r->IsLocal())); + } + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) + { + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,l->TotalSeconds() == r->TotalSeconds()); } else if(std::holds_alternative(left)) { @@ -1714,9 +1778,18 @@ namespace Tesses::CrossLang { auto r = lver.CompareTo(rver); cse.back()->Push(gc, r != 0); } - else if(std::holds_alternative(left) && std::holds_alternative(right)) + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) { - cse.back()->Push(gc, std::get(left).GetDate().ToEpoch() != std::get(right).GetDate().ToEpoch()); + + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,!((l->ToEpoch() == r->ToEpoch()) && (l->IsLocal() == r->IsLocal()))); + } + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) + { + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,l->TotalSeconds() != r->TotalSeconds()); } else if(std::holds_alternative(left)) { @@ -2262,6 +2335,24 @@ namespace Tesses::CrossLang { { cse.back()->Push(gc,std::get(left) + std::get(right)); } + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) + { + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,std::make_shared((*l) + (*r))); + } + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) + { + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,std::make_shared((*l) + (*r))); + } + else if(std::holds_alternative>(left) && std::holds_alternative>(right)) + { + auto& l = std::get>(left); + auto& r = std::get>(right); + cse.back()->Push(gc,std::make_shared((*l) + (*r))); + } else if(std::holds_alternative(left) && std::holds_alternative(right)) { std::string str={}; @@ -3224,9 +3315,24 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, Undefined()); return false; } - else if(std::holds_alternative(instance)) + else if(std::holds_alternative>(instance)) { - auto& date = std::get(instance).GetDate(); + auto& time = std::get>(instance); + if(key == "ToString") + { + bool slim = false; + GetArgument(args,0,slim); + + cse.back()->Push(gc, time->ToString(slim)); + + return false; + } + cse.back()->Push(gc, Undefined()); + return false; + } + else if(std::holds_alternative>(instance)) + { + auto& date = std::get>(instance); if(key == "ToString") @@ -3234,38 +3340,129 @@ namespace Tesses::CrossLang { std::string fmt; if(GetArgument(args,0,fmt)) { - cse.back()->Push(gc, date.ToString(fmt)); + cse.back()->Push(gc, date->ToString(fmt)); } else { - cse.back()->Push(gc, date.ToString()); + cse.back()->Push(gc, date->ToString()); } return false; } if(key == "ToHttpDate") { - cse.back()->Push(gc, date.ToHttpDate()); + cse.back()->Push(gc, date->ToHttpDate()); return false; } if(key == "ToEpoch") { - cse.back()->Push(gc, date.ToEpoch()); + cse.back()->Push(gc, date->ToEpoch()); return false; } if(key == "ToLocal") { - cse.back()->Push(gc, date.ToLocal()); + cse.back()->Push(gc, std::make_shared(date->ToLocal())); return false; } if(key == "ToUTC") { - cse.back()->Push(gc, date.ToUTC()); + cse.back()->Push(gc, std::make_shared(date->ToUTC())); return false; } cse.back()->Push(gc, nullptr); return false; } + else if(std::holds_alternative>(instance)) + { + auto textReader = std::get>(instance); + if(key == "Rewind") + { + cse.back()->Push(gc,textReader->Rewind()); + return false; + } + if(key == "ReadBlock") + { + int64_t sz; + if(GetArgument(args,0,sz)) + { + std::string block; + if(textReader->ReadBlock(block,(size_t)sz)) + { + cse.back()->Push(gc, block); + return false; + } + } + cse.back()->Push(gc, nullptr); + return false; + } + if(key == "ReadChar") + { + cse.back()->Push(gc,(int64_t)textReader->ReadChar()); + return false; + } + if(key == "ReadLine") + { + std::string line; + if(textReader->ReadLine(line)) + { + cse.back()->Push(gc, line); + return false; + } + cse.back()->Push(gc, nullptr); + return false; + } + if(key == "ReadAllLines") + { + std::vector lines; + textReader->ReadAllLines(lines); + gc->BarrierBegin(); + TList* list = TList::Create(ls); + for(auto& item : lines) list->Add(item); + gc->BarrierEnd(); + return list; + } + if(key == "ReadToEnd") + { + std::string text; + textReader->ReadToEnd(text); + cse.back()->Push(gc,text); + return false; + } + if(key == "CopyTo") + { + std::shared_ptr writer; + if(GetArgument(args,0,writer)) + { + textReader->CopyTo(*writer); + } + } + cse.back()->Push(gc, Undefined()); + return false; + } + else if(std::holds_alternative>(instance)) + { + auto textWriter=std::get>(instance); + if(key == "Write") + { + if(args.size()>0) + textWriter->Write(ToString(gc,args[0])); + } + if(key == "WriteLine") + { + if(args.size()>0) + textWriter->WriteLine(ToString(gc,args[0])); + } + if(key == "WriteData") + { + if(args.size()>0) + { + auto s=ToString(gc,args[0]); + textWriter->WriteData(s.c_str(),s.size()); + } + } + cse.back()->Push(gc, nullptr); + return false; + } else if(std::holds_alternative>(instance)) { auto strm = std::get>(instance); @@ -3697,11 +3894,11 @@ namespace Tesses::CrossLang { if(key == "SetDate") { Tesses::Framework::Filesystem::VFSPath path; - TDateTime lastWrite; - TDateTime lastAccess; + std::shared_ptr lastWrite; + std::shared_ptr lastAccess; if(GetArgumentAsPath(args,0,path) && GetArgument(args,1,lastWrite) && GetArgument(args,2,lastAccess)) { - vfs->SetDate(path,lastWrite.GetDate(), lastAccess.GetDate()); + vfs->SetDate(path,*lastWrite, *lastAccess); } cse.back()->Push(gc, nullptr); return false; @@ -3718,8 +3915,8 @@ namespace Tesses::CrossLang { auto dict = TDictionary::Create(ls); ls.GetGC()->BarrierBegin(); - dict->SetValue("LastWrite", TDateTime(lastWrite)); - dict->SetValue("LastAccess", TDateTime(lastAccess)); + dict->SetValue("LastWrite", std::make_shared(lastWrite)); + dict->SetValue("LastAccess", std::make_shared(lastAccess)); ls.GetGC()->BarrierEnd(); cse.back()->Push(gc, dict); @@ -5364,6 +5561,33 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, Undefined()); return false; } + if(std::holds_alternative>(instance)) + { + auto vfs = std::get>(instance); + auto tmpFS=std::dynamic_pointer_cast(vfs); + if(tmpFS) + { + if(key == "TempDirectoryName") + { + + cse.back()->Push(gc,tmpFS->TempDirectoryName()); + return false; + } + } + cse.back()->Push(gc,Undefined()); + return false; + } + if(std::holds_alternative>(instance)) + { + auto writer = std::get>(instance); + if(key == "NewLine") + { + cse.back()->Push(gc,writer->newline); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + } if(std::holds_alternative>(instance)) { auto strm = std::get>(instance); @@ -5373,7 +5597,7 @@ namespace Tesses::CrossLang { if(key == "CanRead") { - ; + cse.back()->Push(gc, strm->CanRead()); return false; @@ -5476,47 +5700,93 @@ namespace Tesses::CrossLang { stk->Push(gc, Undefined()); return false; } - if(std::holds_alternative(instance)) + if(std::holds_alternative>(instance)) { - auto& date = std::get(instance).GetDate(); + auto time = std::get>(instance); + if(key == "Days") + { + stk->Push(gc, (int64_t)time->Days()); + return false; + } + if(key == "Hours") + { + stk->Push(gc, (int64_t)time->Hours()); + return false; + } + + if(key == "Minutes") + { + stk->Push(gc, (int64_t)time->Minutes()); + return false; + } + if(key == "Seconds") + { + stk->Push(gc, (int64_t)time->Seconds()); + return false; + } + + if(key == "TotalHours") + { + stk->Push(gc, time->TotalHours()); + return false; + } + + if(key == "TotalMinutes") + { + stk->Push(gc, time->TotalMinutes()); + return false; + } + + if(key == "TotalSeconds") + { + stk->Push(gc, time->TotalSeconds()); + return false; + } + + stk->Push(gc, Undefined()); + return false; + } + if(std::holds_alternative>(instance)) + { + auto& date = std::get>(instance); if(key == "IsLocal") { - stk->Push(gc, date.IsLocal()); + stk->Push(gc, date->IsLocal()); return false; } if(key == "Year") { - stk->Push(gc, (int64_t)date.Year()); + stk->Push(gc, (int64_t)date->Year()); return false; } if(key == "Month") { - stk->Push(gc, (int64_t)date.Month()); + stk->Push(gc, (int64_t)date->Month()); return false; } if(key == "Day") { - stk->Push(gc, (int64_t)date.Day()); + stk->Push(gc, (int64_t)date->Day()); return false; } if(key == "Hour") { - stk->Push(gc, (int64_t)date.Hour()); + stk->Push(gc, (int64_t)date->Hour()); return false; } if(key == "Minute") { - stk->Push(gc, (int64_t)date.Minute()); + stk->Push(gc, (int64_t)date->Minute()); return false; } if(key == "Second") { - stk->Push(gc, (int64_t)date.Second()); + stk->Push(gc, (int64_t)date->Second()); return false; } if(key == "DayOfWeek") { - stk->Push(gc, (int64_t)date.DayOfWeek()); + stk->Push(gc, (int64_t)date->DayOfWeek()); return false; } @@ -5971,6 +6241,21 @@ namespace Tesses::CrossLang { } std::string key = std::get(_key); + if(std::holds_alternative>(instance)) + { + auto writer = std::get>(instance); + if(key == "NewLine") + { + if(std::holds_alternative(value)) + { + writer->newline = std::get(value); + } + cse.back()->Push(gc,writer->newline); + return false; + } + cse.back()->Push(gc,Undefined()); + return false; + } if(std::holds_alternative>(instance)) { auto strm = std::get>(instance); @@ -7604,9 +7889,13 @@ namespace Tesses::CrossLang { { return std::get(o) ? "true" : "false"; } - if(std::holds_alternative(o)) + if(std::holds_alternative>(o)) { - return std::get(o).GetDate().ToString(); + return std::get>(o)->ToString(); + } + if(std::holds_alternative>(o)) + { + return std::get>(o)->ToString(false); } if(std::holds_alternative(o)) {