This commit is contained in:
2025-02-08 12:10:15 -06:00
parent 3f337239e4
commit 2782f9af13
22 changed files with 21034 additions and 14 deletions

View File

@ -20,6 +20,7 @@ option(CROSSLANG_SHARED_EXECUTABLES "Link with libcrosslang_shared" ON)
option(CROSSLANG_CUSTOM_CONSOLE "Enable custom Console" OFF)
if(CROSSLANG_CUSTOM_CONSOLE)
set(CROSSLANG_ENABLE_BINARIES OFF)
set(CROSSLANG_ENABLE_SHARED OFF)
@ -74,6 +75,7 @@ target_include_directories(${CROSSLANG_TARGET_NAME}
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
endfunction()
list(APPEND CROSSLANG_SOURCE
@ -94,6 +96,7 @@ src/runtime_methods/ogc.cpp
src/runtime_methods/path.cpp
src/runtime_methods/env.cpp
src/runtime_methods/process.cpp
src/runtime_methods/time.cpp
src/types/ittr.cpp
src/types/closure.cpp
src/types/dictionary.cpp

View File

@ -4,5 +4,3 @@ include("${CMAKE_CURRENT_LIST_DIR}/TessesCrossLangTargets.cmake")
check_required_components(TessesCrossLang)
find_package(TessesFramework REQUIRED)
endif()

View File

@ -8,6 +8,11 @@ Tesses Cross Language
- Jansson (but can be turned off but is strongly recommended otherwise many programs will not work)
- CMake
## What libraries have I embeaded from other people
- [HodwardHinnart's date]() (in folder src/HodwardHinnart_date, modified tz.cpp to point to correct header)
- [Sqlite]() (in folder src/sqlite also uses demo VFS (at least on Wii))
- [Sago's platform_folders]() (in folder src/sago)
- [subprocess](https://github.com/sheredom/subprocess.h) (as file src/runtime_methods/subprocess.h)
## Use in docker (use my container)
```bash
sudo docker pull -t onedev.site.tesses.net/crosslang/crosslang:latest

View File

@ -14,6 +14,7 @@
#include <cstring>
#include <TessesFramework/TessesFramework.hpp>
#include <regex>
#include <time.h>
#define TVM_MAJOR 1
#define TVM_MINOR 0
#define TVM_PATCH 0
@ -363,7 +364,8 @@ typedef enum {
DEFER,
TRYCATCH,
THROW,
PUSHSCOPELESSCLOSURE
PUSHSCOPELESSCLOSURE,
YIELD
} Instruction;
class ByteCodeInstruction {
@ -568,6 +570,11 @@ constexpr std::string_view ParenthesesExpression = "parenthesesExpression";
constexpr std::string_view ThrowStatement = "throwStatement";
constexpr std::string_view TryStatement = "tryStatement";
constexpr std::string_view DeferStatement = "deferStatement";
constexpr std::string_view YieldStatement = "yieldStatement";
constexpr std::string_view EnumerableStatement = "enumerableStatement";
constexpr std::string_view SwitchStatement = "switchStatement";
constexpr std::string_view CaseStatement = "caseStatement";
constexpr std::string_view DefaultStatement = "defaultStatement";
class AdvancedSyntaxNode {
public:
std::string nodeName;
@ -634,6 +641,7 @@ class Parser {
};
class THeapObjectHolder
{
public:
@ -771,6 +779,7 @@ class GC {
virtual void Mark();
};
class TDictionary : public THeapObject
{
@ -848,6 +857,7 @@ class GC {
bool canRegisterPath;
bool canRegisterOGC;
bool canRegisterEnv;
bool canRegisterTime;
bool sqlite3Scoped;
bool locked;
};
@ -894,8 +904,10 @@ class GC {
static void RegisterOGC(GC* gc, TRootEnvironment* env);
static void RegisterEnv(GC* gc, TRootEnvironment* env);
static void RegisterProcess(GC* gc, TRootEnvironment* env);
static void RegisterTime(GC* gc, TRootEnvironment* env);
};
class TSubEnvironment : public TEnvironment
{
TEnvironment* env;
@ -972,6 +984,20 @@ class GC {
static TCustomEnumerator* Create(GCList* ls,TDictionary* dict);
};
class TYieldEnumerator : public TEnumerator
{
bool hasStarted;
TObject enumerator;
TObject current;
public:
bool MoveNext(GC* ls);
TObject GetCurrent(GCList& ls);
void Mark();
static TYieldEnumerator* Create(GCList& ls,TObject v);
static TYieldEnumerator* Create(GCList* ls,TObject v);
};
class TStringEnumerator : public TEnumerator
{
@ -1193,10 +1219,13 @@ class GC {
TClosure* callable;
uint32_t ip;
uint32_t scopes;
bool mustReturn;
void Mark();
void Push(GC* gc,TObject v);
TObject Pop(GCList& gcl);
TObject Resume(GCList& ls);
};
extern thread_local CallStackEntry* current_function;
@ -1246,6 +1275,7 @@ class GC {
bool PushResource(GC* gc);
bool Illegal(GC* gc);
bool Throw(GC* gc);
bool Yield(GC* gc);
bool Jump(GC* gc);
bool JumpConditional(GC* gc);
bool JumpUndefined(GC* gc);

View File

@ -1,4 +1,4 @@
<svg width="100" height="100">
<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' aria-hidden='true' role='img' class='iconify iconify--logos' width="100" height="100">
<polygon points="50,0,100,25,100,75,50,100,0,75,0,25" style="fill:orange;stroke:black;stroke-width:3" />
<polygon points="45,20,55,20,55,35,80,35,80,45,55,45,55,85,45,85,45,45,20,45,20,35,45,35" style="fill:white;stroke:black;stroke-width:3"/>
</svg>

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 428 B

View File

@ -0,0 +1,34 @@
#ifndef CHRONO_IO_H
#define CHRONO_IO_H
// The MIT License (MIT)
//
// Copyright (c) 2016, 2017 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Our apologies. When the previous paragraph was written, lowercase had not yet
// been invented (that would involve another several millennia of evolution).
// We did not mean to shout.
// This functionality has moved to "date.h"
#include "date.h"
#endif // CHRONO_IO_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
//
// ios.h
// DateTimeLib
//
// The MIT License (MIT)
//
// Copyright (c) 2016 Alexander Kormanovsky
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef ios_hpp
#define ios_hpp
#if __APPLE__
# include <TargetConditionals.h>
# if TARGET_OS_IPHONE
# include <string>
namespace date
{
namespace iOSUtils
{
std::string get_tzdata_path();
std::string get_current_timezone();
} // namespace iOSUtils
} // namespace date
# endif // TARGET_OS_IPHONE
#else // !__APPLE__
# define TARGET_OS_IPHONE 0
#endif // !__APPLE__
#endif // ios_hpp

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,952 @@
#ifndef PTZ_H
#define PTZ_H
// The MIT License (MIT)
//
// Copyright (c) 2017 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// This header allows Posix-style time zones as specified for TZ here:
// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03
//
// Posix::time_zone can be constructed with a posix-style string and then used in
// a zoned_time like so:
//
// zoned_time<system_clock::duration, Posix::time_zone> zt{"EST5EDT,M3.2.0,M11.1.0",
// system_clock::now()};
// or:
//
// Posix::time_zone tz{"EST5EDT,M3.2.0,M11.1.0"};
// zoned_time<system_clock::duration, Posix::time_zone> zt{tz, system_clock::now()};
//
// In C++17 CTAD simplifies this to:
//
// Posix::time_zone tz{"EST5EDT,M3.2.0,M11.1.0"};
// zoned_time zt{tz, system_clock::now()};
//
// Extension to the Posix rules to allow a constant daylight saving offset:
//
// If the rule set is missing (everything starting with ','), then
// there must be exactly one abbreviation (std or daylight) with
// length 3 or greater, and that will be used as the constant offset. If
// there are two, the std abbreviation is silently set to "", and the
// result is constant daylight saving. If there are zero abbreviations
// with no rule set, an exception is thrown.
//
// Example:
// "EST5" yields a constant offset of -5h with 0h save and "EST abbreviation.
// "5EDT" yields a constant offset of -4h with 1h save and "EDT" abbreviation.
// "EST5EDT" and "5EDT4" are both equal to "5EDT".
//
// Note, Posix-style time zones are not recommended for all of the reasons described here:
// https://stackoverflow.com/tags/timezone/info
//
// They are provided here as a non-trivial custom time zone example, and if you really
// have to have Posix time zones, you're welcome to use this one.
#include "date/tz.h"
#include <algorithm>
#include <cctype>
#include <ostream>
#include <string>
namespace Posix
{
namespace detail
{
#if HAS_STRING_VIEW
using string_t = std::string_view;
#else // !HAS_STRING_VIEW
using string_t = std::string;
#endif // !HAS_STRING_VIEW
class rule;
void throw_invalid(const string_t& s, unsigned i, const string_t& message);
unsigned read_date(const string_t& s, unsigned i, rule& r);
unsigned read_name(const string_t& s, unsigned i, std::string& name);
unsigned read_signed_time(const string_t& s, unsigned i, std::chrono::seconds& t);
unsigned read_unsigned_time(const string_t& s, unsigned i, std::chrono::seconds& t);
unsigned read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u,
const string_t& message = string_t{});
class rule
{
enum {off, J, M, N};
date::month m_;
date::weekday wd_;
unsigned short n_ : 14;
unsigned short mode_ : 2;
std::chrono::duration<std::int32_t> time_ = std::chrono::hours{2};
public:
rule() : mode_(off) {}
bool ok() const {return mode_ != off;}
date::local_seconds operator()(date::year y) const;
std::string to_string() const;
friend std::ostream& operator<<(std::ostream& os, const rule& r);
friend unsigned read_date(const string_t& s, unsigned i, rule& r);
friend bool operator==(const rule& x, const rule& y);
};
inline
bool
operator==(const rule& x, const rule& y)
{
if (x.mode_ != y.mode_)
return false;
switch (x.mode_)
{
case rule::J:
case rule::N:
return x.n_ == y.n_;
case rule::M:
return x.m_ == y.m_ && x.n_ == y.n_ && x.wd_ == y.wd_;
default:
return true;
}
}
inline
bool
operator!=(const rule& x, const rule& y)
{
return !(x == y);
}
inline
date::local_seconds
rule::operator()(date::year y) const
{
using date::local_days;
using date::January;
using date::days;
using date::last;
using sec = std::chrono::seconds;
date::local_seconds t;
switch (mode_)
{
case J:
t = local_days{y/January/0} + days{n_ + (y.is_leap() && n_ > 59)} + sec{time_};
break;
case M:
t = (n_ == 5 ? local_days{y/m_/wd_[last]} : local_days{y/m_/wd_[n_]}) + sec{time_};
break;
case N:
t = local_days{y/January/1} + days{n_} + sec{time_};
break;
default:
assert(!"rule called with bad mode");
}
return t;
}
inline
std::string
rule::to_string() const
{
using namespace std::chrono;
auto print_offset = [](seconds off)
{
std::string nm;
if (off != hours{2})
{
date::hh_mm_ss<seconds> offset{off};
nm = '/';
nm += std::to_string(offset.hours().count());
if (offset.minutes() != minutes{0} || offset.seconds() != seconds{0})
{
nm += ':';
if (offset.minutes() < minutes{10})
nm += '0';
nm += std::to_string(offset.minutes().count());
if (offset.seconds() != seconds{0})
{
nm += ':';
if (offset.seconds() < seconds{10})
nm += '0';
nm += std::to_string(offset.seconds().count());
}
}
}
return nm;
};
std::string nm;
switch (mode_)
{
case rule::J:
nm = 'J';
nm += std::to_string(n_);
break;
case rule::M:
nm = 'M';
nm += std::to_string(static_cast<unsigned>(m_));
nm += '.';
nm += std::to_string(n_);
nm += '.';
nm += std::to_string(wd_.c_encoding());
break;
case rule::N:
nm = std::to_string(n_);
break;
default:
break;
}
nm += print_offset(time_);
return nm;
}
inline
std::ostream&
operator<<(std::ostream& os, const rule& r)
{
switch (r.mode_)
{
case rule::J:
os << 'J' << r.n_ << date::format(" %T", r.time_);
break;
case rule::M:
if (r.n_ == 5)
os << r.m_/r.wd_[date::last];
else
os << r.m_/r.wd_[r.n_];
os << date::format(" %T", r.time_);
break;
case rule::N:
os << r.n_ << date::format(" %T", r.time_);
break;
default:
break;
}
return os;
}
} // namespace detail
class time_zone
{
std::string std_abbrev_;
std::string dst_abbrev_ = {};
std::chrono::seconds offset_;
std::chrono::seconds save_ = std::chrono::hours{1};
detail::rule start_rule_;
detail::rule end_rule_;
public:
explicit time_zone(const detail::string_t& name);
template <class Duration>
date::sys_info get_info(date::sys_time<Duration> st) const;
template <class Duration>
date::local_info get_info(date::local_time<Duration> tp) const;
template <class Duration>
date::sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
to_sys(date::local_time<Duration> tp) const;
template <class Duration>
date::sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
to_sys(date::local_time<Duration> tp, date::choose z) const;
template <class Duration>
date::local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
to_local(date::sys_time<Duration> tp) const;
friend std::ostream& operator<<(std::ostream& os, const time_zone& z);
const time_zone* operator->() const {return this;}
std::string name() const;
friend bool operator==(const time_zone& x, const time_zone& y);
private:
date::sys_seconds get_start(date::year y) const;
date::sys_seconds get_prev_start(date::year y) const;
date::sys_seconds get_next_start(date::year y) const;
date::sys_seconds get_end(date::year y) const;
date::sys_seconds get_prev_end(date::year y) const;
date::sys_seconds get_next_end(date::year y) const;
date::sys_info contant_offset() const;
};
inline
date::sys_seconds
time_zone::get_start(date::year y) const
{
return date::sys_seconds{(start_rule_(y) - offset_).time_since_epoch()};
}
inline
date::sys_seconds
time_zone::get_prev_start(date::year y) const
{
return date::sys_seconds{(start_rule_(--y) - offset_).time_since_epoch()};
}
inline
date::sys_seconds
time_zone::get_next_start(date::year y) const
{
return date::sys_seconds{(start_rule_(++y) - offset_).time_since_epoch()};
}
inline
date::sys_seconds
time_zone::get_end(date::year y) const
{
return date::sys_seconds{(end_rule_(y) - (offset_ + save_)).time_since_epoch()};
}
inline
date::sys_seconds
time_zone::get_prev_end(date::year y) const
{
return date::sys_seconds{(end_rule_(--y) - (offset_ + save_)).time_since_epoch()};
}
inline
date::sys_seconds
time_zone::get_next_end(date::year y) const
{
return date::sys_seconds{(end_rule_(++y) - (offset_ + save_)).time_since_epoch()};
}
inline
date::sys_info
time_zone::contant_offset() const
{
using date::year;
using date::sys_info;
using date::sys_days;
using date::January;
using date::December;
using date::last;
using date::days;
using std::chrono::minutes;
sys_info r;
r.begin = sys_days{year::min()/January/1};
r.end = sys_days{year::max()/December/last} + days{1} - std::chrono::seconds{1};
if (std_abbrev_.size() > 0)
{
r.abbrev = std_abbrev_;
r.offset = offset_;
r.save = {};
}
else
{
r.abbrev = dst_abbrev_;
r.offset = offset_ + save_;
r.save = date::ceil<minutes>(save_);
}
return r;
}
inline
time_zone::time_zone(const detail::string_t& s)
{
using detail::read_name;
using detail::read_signed_time;
using detail::throw_invalid;
auto i = read_name(s, 0, std_abbrev_);
auto std_name_i = i;
auto abbrev_name_i = i;
i = read_signed_time(s, i, offset_);
offset_ = -offset_;
if (i != s.size())
{
i = read_name(s, i, dst_abbrev_);
abbrev_name_i = i;
if (i != s.size())
{
if (s[i] != ',')
{
i = read_signed_time(s, i, save_);
save_ = -save_ - offset_;
}
if (i != s.size())
{
if (s[i] != ',')
throw_invalid(s, i, "Expecting end of string or ',' to start rule");
++i;
i = read_date(s, i, start_rule_);
if (i == s.size() || s[i] != ',')
throw_invalid(s, i, "Expecting ',' and then the ending rule");
++i;
i = read_date(s, i, end_rule_);
if (i != s.size())
throw_invalid(s, i, "Found unexpected trailing characters");
}
}
}
if (start_rule_.ok())
{
if (std_abbrev_.size() < 3)
throw_invalid(s, std_name_i, "Zone with rules must have a std"
" abbreviation of length 3 or greater");
if (dst_abbrev_.size() < 3)
throw_invalid(s, abbrev_name_i, "Zone with rules must have a daylight"
" abbreviation of length 3 or greater");
}
else
{
if (dst_abbrev_.size() >= 3)
{
std_abbrev_.clear();
}
else if (std_abbrev_.size() < 3)
{
throw_invalid(s, std_name_i, "Zone must have at least one abbreviation"
" of length 3 or greater");
}
else
{
dst_abbrev_.clear();
save_ = {};
}
}
}
template <class Duration>
date::sys_info
time_zone::get_info(date::sys_time<Duration> st) const
{
using date::sys_info;
using date::year_month_day;
using date::sys_days;
using date::floor;
using date::ceil;
using date::days;
using date::year;
using date::January;
using date::December;
using date::last;
using std::chrono::minutes;
sys_info r{};
r.offset = offset_;
if (start_rule_.ok())
{
auto y = year_month_day{floor<days>(st)}.year();
if (st >= get_next_start(y))
++y;
else if (st < get_prev_end(y))
--y;
auto start = get_start(y);
auto end = get_end(y);
if (start <= end) // (northern hemisphere)
{
if (start <= st && st < end)
{
r.begin = start;
r.end = end;
r.offset += save_;
r.save = ceil<minutes>(save_);
r.abbrev = dst_abbrev_;
}
else if (st < start)
{
r.begin = get_prev_end(y);
r.end = start;
r.abbrev = std_abbrev_;
}
else // st >= end
{
r.begin = end;
r.end = get_next_start(y);
r.abbrev = std_abbrev_;
}
}
else // end < start (southern hemisphere)
{
if (end <= st && st < start)
{
r.begin = end;
r.end = start;
r.abbrev = std_abbrev_;
}
else if (st < end)
{
r.begin = get_prev_start(y);
r.end = end;
r.offset += save_;
r.save = ceil<minutes>(save_);
r.abbrev = dst_abbrev_;
}
else // st >= start
{
r.begin = start;
r.end = get_next_end(y);
r.offset += save_;
r.save = ceil<minutes>(save_);
r.abbrev = dst_abbrev_;
}
}
}
else
r = contant_offset();
using seconds = std::chrono::seconds;
assert(r.begin <= floor<seconds>(st) && floor<seconds>(st) <= r.end);
return r;
}
template <class Duration>
date::local_info
time_zone::get_info(date::local_time<Duration> tp) const
{
using date::local_info;
using date::year_month_day;
using date::days;
using date::sys_days;
using date::sys_seconds;
using date::year;
using date::ceil;
using date::January;
using date::December;
using date::last;
using std::chrono::seconds;
using std::chrono::minutes;
local_info r{};
using date::floor;
if (start_rule_.ok())
{
auto y = year_month_day{floor<days>(tp)}.year();
auto start = get_start(y);
auto end = get_end(y);
auto utcs = sys_seconds{floor<seconds>(tp - offset_).time_since_epoch()};
auto utcd = sys_seconds{floor<seconds>(tp - (offset_ + save_)).time_since_epoch()};
auto northern = start <= end;
if ((utcs < start) != (utcd < start))
{
if (northern)
r.first.begin = get_prev_end(y);
else
r.first.begin = end;
r.first.end = start;
r.first.offset = offset_;
r.first.abbrev = std_abbrev_;
r.second.begin = start;
if (northern)
r.second.end = end;
else
r.second.end = get_next_end(y);
r.second.abbrev = dst_abbrev_;
r.second.offset = offset_ + save_;
r.second.save = ceil<minutes>(save_);
r.result = save_ > seconds{0} ? local_info::nonexistent
: local_info::ambiguous;
}
else if ((utcs < end) != (utcd < end))
{
if (northern)
r.first.begin = start;
else
r.first.begin = get_prev_start(y);
r.first.end = end;
r.first.offset = offset_ + save_;
r.first.save = ceil<minutes>(save_);
r.first.abbrev = dst_abbrev_;
r.second.begin = end;
if (northern)
r.second.end = get_next_start(y);
else
r.second.end = start;
r.second.abbrev = std_abbrev_;
r.second.offset = offset_;
r.result = save_ > seconds{0} ? local_info::ambiguous
: local_info::nonexistent;
}
else
r.first = get_info(utcs);
}
else
r.first = contant_offset();
return r;
}
template <class Duration>
date::sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
time_zone::to_sys(date::local_time<Duration> tp) const
{
using date::local_info;
using date::sys_time;
using date::ambiguous_local_time;
using date::nonexistent_local_time;
auto i = get_info(tp);
if (i.result == local_info::nonexistent)
throw nonexistent_local_time(tp, i);
else if (i.result == local_info::ambiguous)
throw ambiguous_local_time(tp, i);
return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
}
template <class Duration>
date::sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
time_zone::to_sys(date::local_time<Duration> tp, date::choose z) const
{
using date::local_info;
using date::sys_time;
using date::choose;
auto i = get_info(tp);
if (i.result == local_info::nonexistent)
{
return i.first.end;
}
else if (i.result == local_info::ambiguous)
{
if (z == choose::latest)
return sys_time<Duration>{tp.time_since_epoch()} - i.second.offset;
}
return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
}
template <class Duration>
date::local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
time_zone::to_local(date::sys_time<Duration> tp) const
{
using date::local_time;
using std::chrono::seconds;
using LT = local_time<typename std::common_type<Duration, seconds>::type>;
auto i = get_info(tp);
return LT{(tp + i.offset).time_since_epoch()};
}
inline
std::ostream&
operator<<(std::ostream& os, const time_zone& z)
{
using date::operator<<;
os << '{';
os << z.std_abbrev_ << ", " << z.dst_abbrev_ << date::format(", %T, ", z.offset_)
<< date::format("%T, [", z.save_) << z.start_rule_ << ", " << z.end_rule_ << ")}";
return os;
}
inline
std::string
time_zone::name() const
{
using namespace date;
using namespace std::chrono;
auto print_abbrev = [](std::string const& nm)
{
if (std::any_of(nm.begin(), nm.end(),
[](char c)
{
return !std::isalpha(c);
}))
{
return '<' + nm + '>';
}
return nm;
};
auto print_offset = [](seconds off)
{
std::string nm;
date::hh_mm_ss<seconds> offset{-off};
if (offset.is_negative())
nm += '-';
nm += std::to_string(offset.hours().count());
if (offset.minutes() != minutes{0} || offset.seconds() != seconds{0})
{
nm += ':';
if (offset.minutes() < minutes{10})
nm += '0';
nm += std::to_string(offset.minutes().count());
if (offset.seconds() != seconds{0})
{
nm += ':';
if (offset.seconds() < seconds{10})
nm += '0';
nm += std::to_string(offset.seconds().count());
}
}
return nm;
};
auto nm = print_abbrev(std_abbrev_);
nm += print_offset(offset_);
if (!dst_abbrev_.empty())
{
nm += print_abbrev(dst_abbrev_);
if (save_ != hours{1})
nm += print_offset(offset_+save_);
if (start_rule_.ok())
{
nm += ',';
nm += start_rule_.to_string();
nm += ',';
nm += end_rule_.to_string();
}
}
return nm;
}
inline
bool
operator==(const time_zone& x, const time_zone& y)
{
return x.std_abbrev_ == y.std_abbrev_ &&
x.dst_abbrev_ == y. dst_abbrev_ &&
x.offset_ == y.offset_ &&
x.save_ == y.save_ &&
x.start_rule_ == y.start_rule_ &&
x.end_rule_ == y.end_rule_;
}
inline
bool
operator!=(const time_zone& x, const time_zone& y)
{
return !(x == y);
}
namespace detail
{
inline
void
throw_invalid(const string_t& s, unsigned i, const string_t& message)
{
throw std::runtime_error(std::string("Invalid time_zone initializer.\n") +
std::string(message) + ":\n" +
std::string(s) + '\n' +
"\x1b[1;32m" +
std::string(i, '~') + '^' +
std::string(i < s.size() ? s.size()-i-1 : 0, '~') +
"\x1b[0m");
}
inline
unsigned
read_date(const string_t& s, unsigned i, rule& r)
{
using date::month;
using date::weekday;
if (i == s.size())
throw_invalid(s, i, "Expected rule but found end of string");
if (s[i] == 'J')
{
++i;
unsigned n;
i = read_unsigned(s, i, 3, n, "Expected to find the Julian day [1, 365]");
if (!(1 <= n && n <= 365))
throw_invalid(s, i-1, "Expected Julian day to be in the range [1, 365]");
r.mode_ = rule::J;
r.n_ = n;
}
else if (s[i] == 'M')
{
++i;
unsigned m;
i = read_unsigned(s, i, 2, m, "Expected to find month [1, 12]");
if (!(1 <= m && m <= 12))
throw_invalid(s, i-1, "Expected month to be in the range [1, 12]");
if (i == s.size() || s[i] != '.')
throw_invalid(s, i, "Expected '.' after month");
++i;
unsigned n;
i = read_unsigned(s, i, 1, n, "Expected to find week number [1, 5]");
if (!(1 <= n && n <= 5))
throw_invalid(s, i-1, "Expected week number to be in the range [1, 5]");
if (i == s.size() || s[i] != '.')
throw_invalid(s, i, "Expected '.' after weekday index");
++i;
unsigned wd;
i = read_unsigned(s, i, 1, wd, "Expected to find day of week [0, 6]");
if (wd > 6)
throw_invalid(s, i-1, "Expected day of week to be in the range [0, 6]");
r.mode_ = rule::M;
r.m_ = month{m};
r.wd_ = weekday{wd};
r.n_ = n;
}
else if (std::isdigit(s[i]))
{
unsigned n;
i = read_unsigned(s, i, 3, n);
if (n > 365)
throw_invalid(s, i-1, "Expected Julian day to be in the range [0, 365]");
r.mode_ = rule::N;
r.n_ = n;
}
else
throw_invalid(s, i, "Expected 'J', 'M', or a digit to start rule");
if (i != s.size() && s[i] == '/')
{
++i;
std::chrono::seconds t;
i = read_unsigned_time(s, i, t);
r.time_ = t;
}
return i;
}
inline
unsigned
read_name(const string_t& s, unsigned i, std::string& name)
{
if (i == s.size())
throw_invalid(s, i, "Expected a name but found end of string");
if (s[i] == '<')
{
++i;
while (true)
{
if (i == s.size())
throw_invalid(s, i,
"Expected to find closing '>', but found end of string");
if (s[i] == '>')
break;
name.push_back(s[i]);
++i;
}
++i;
}
else
{
while (i != s.size() && std::isalpha(s[i]))
{
name.push_back(s[i]);
++i;
}
}
return i;
}
inline
unsigned
read_signed_time(const string_t& s, unsigned i,
std::chrono::seconds& t)
{
if (i == s.size())
throw_invalid(s, i, "Expected to read signed time, but found end of string");
bool negative = false;
if (s[i] == '-')
{
negative = true;
++i;
}
else if (s[i] == '+')
++i;
i = read_unsigned_time(s, i, t);
if (negative)
t = -t;
return i;
}
inline
unsigned
read_unsigned_time(const string_t& s, unsigned i, std::chrono::seconds& t)
{
using std::chrono::seconds;
using std::chrono::minutes;
using std::chrono::hours;
if (i == s.size())
throw_invalid(s, i, "Expected to read unsigned time, but found end of string");
unsigned x;
i = read_unsigned(s, i, 2, x, "Expected to find hours [0, 24]");
if (x > 24)
throw_invalid(s, i-1, "Expected hours to be in the range [0, 24]");
t = hours{x};
if (i != s.size() && s[i] == ':')
{
++i;
i = read_unsigned(s, i, 2, x, "Expected to find minutes [0, 59]");
if (x > 59)
throw_invalid(s, i-1, "Expected minutes to be in the range [0, 59]");
t += minutes{x};
if (i != s.size() && s[i] == ':')
{
++i;
i = read_unsigned(s, i, 2, x, "Expected to find seconds [0, 59]");
if (x > 59)
throw_invalid(s, i-1, "Expected seconds to be in the range [0, 59]");
t += seconds{x};
}
}
return i;
}
inline
unsigned
read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u,
const string_t& message)
{
if (i == s.size() || !std::isdigit(s[i]))
throw_invalid(s, i, message);
u = static_cast<unsigned>(s[i] - '0');
unsigned count = 1;
for (++i; count < limit && i != s.size() && std::isdigit(s[i]); ++i, ++count)
u = u * 10 + static_cast<unsigned>(s[i] - '0');
return i;
}
} // namespace detail
} // namespace Posix
namespace date
{
template <>
struct zoned_traits<Posix::time_zone>
{
#if HAS_STRING_VIEW
static
Posix::time_zone
locate_zone(std::string_view name)
{
return Posix::time_zone{name};
}
#else // !HAS_STRING_VIEW
static
Posix::time_zone
locate_zone(const std::string& name)
{
return Posix::time_zone{name};
}
static
Posix::time_zone
locate_zone(const char* name)
{
return Posix::time_zone{name};
}
#endif // !HAS_STRING_VIEW
};
} // namespace date
#endif // PTZ_H

File diff suppressed because it is too large Load Diff

View File

@ -430,6 +430,117 @@ namespace Tesses::CrossLang
TWO_EXPR(NotEqualsExpression, NEQ)
TWO_EXPR(EqualsExpression, EQ)
TWO_EXPR(XOrExpression, XOR)
if(adv.nodeName == SwitchStatement && adv.nodes.size() == 2)
{
//THIS CODE WORKED FIRST TRY, I DON'T SEE THAT EVERY DAY, PRAISE GOD!!!!!!!
auto expr = adv.nodes[0];
std::vector<SyntaxNode> nodes_before;
SyntaxNode currentCase = nullptr;
std::vector<SyntaxNode> currentNodes;
std::string defaultJmp = {};
std::vector<std::pair<std::pair<std::string,AdvancedSyntaxNode>,std::vector<SyntaxNode>>> snodes;
if(std::holds_alternative<AdvancedSyntaxNode>(adv.nodes[1]))
{
auto body = std::get<AdvancedSyntaxNode>(adv.nodes[1]);
if(body.nodeName == ScopeNode)
{
for(auto item : body.nodes)
{
if(std::holds_alternative<AdvancedSyntaxNode>(item))
{
auto no = std::get<AdvancedSyntaxNode>(item);
if(no.nodeName == CaseStatement || no.nodeName == DefaultStatement)
{
if(std::holds_alternative<AdvancedSyntaxNode>(currentCase))
{
uint32_t jmpId = NewId();
std::string jmpIdStr = "__compGenJmp";
jmpIdStr.append(std::to_string(jmpId));
snodes.push_back(std::pair<std::pair<std::string,AdvancedSyntaxNode>,std::vector<SyntaxNode>>(std::pair<std::string,AdvancedSyntaxNode>(jmpIdStr,std::get<AdvancedSyntaxNode>(currentCase)),currentNodes));
currentNodes={};
}
currentCase = no;
continue;
}
}
if(std::holds_alternative<AdvancedSyntaxNode>(currentCase))
{
currentNodes.push_back(item);
}
else
{
nodes_before.push_back(item);
}
}
if(std::holds_alternative<AdvancedSyntaxNode>(currentCase))
{
uint32_t jmpId = NewId();
std::string jmpIdStr = "__compGenJmp";
jmpIdStr.append(std::to_string(jmpId));
snodes.push_back(std::pair<std::pair<std::string,AdvancedSyntaxNode>,std::vector<SyntaxNode>>(std::pair<std::string,AdvancedSyntaxNode>(jmpIdStr,std::get<AdvancedSyntaxNode>(currentCase)),currentNodes));
currentNodes={};
}
uint32_t endId = NewId();
std::string endIdStr = "__compGenBrk";
endIdStr.append(std::to_string(endId));
for(auto item : nodes_before)
{
GenNode(instructions,item,scope,contscope,brkscope,contI,brkI);
}
for(auto item : snodes)
{
if(item.first.second.nodeName == CaseStatement)
{
auto eq = AdvancedSyntaxNode::Create(EqualsExpression,true,{
item.first.second.nodes[0],
adv.nodes[0]
});
GenNode(instructions,eq,scope,contscope,brkscope,contI,brkI);
instructions.push_back(new JumpStyleInstruction(JMPC,item.first.first));
}
if(item.first.second.nodeName == DefaultStatement)
{
if(!defaultJmp.empty()) std::cout << "ERROR: multiple default in switch statement will cause undefined behaviour, this is not an exception due to not allowing exceptions in codegen stage (the compilation shouldn't fail)" << std::endl;
defaultJmp = item.first.first;
}
}
if(defaultJmp.empty())
{
instructions.push_back(new JumpStyleInstruction(JMP,endIdStr));
}
else
{
instructions.push_back(new JumpStyleInstruction(JMP,defaultJmp));
}
for(auto item : snodes)
{
instructions.push_back(new LabelInstruction(item.first.first));
for(auto item2 : item.second)
{
GenNode(instructions,item2,scope,contscope,scope,contI,endId);
}
}
instructions.push_back(new LabelInstruction(endIdStr));
}
}
return;
}
if(adv.nodeName == TernaryExpression && adv.nodes.size() == 3)
{
uint32_t ifId = NewId();
@ -910,6 +1021,11 @@ namespace Tesses::CrossLang
GenNode(instructions,adv.nodes[0],scope,contscope,brkscope,contI,brkI);
instructions.push_back(new SimpleInstruction(RET));
}
else if(adv.nodeName == YieldStatement && adv.nodes.size() == 1)
{
GenNode(instructions,adv.nodes[0],scope,contscope,brkscope,contI,brkI);
instructions.push_back(new SimpleInstruction(YIELD));
}
else if(adv.nodeName == ParenthesesExpression && adv.nodes.size() == 1)
{
GenNode(instructions,adv.nodes[0],scope,contscope,brkscope,contI,brkI);
@ -1032,6 +1148,20 @@ namespace Tesses::CrossLang
this->chunks[fnindex] = std::pair<std::vector<uint32_t>,std::vector<ByteCodeInstruction*>>(args, fnInstructions);
instructions.push_back(new ClosureInstruction((uint32_t)fnindex));
}
else if(adv.nodeName == EnumerableStatement && adv.nodes.size() == 2 && std::holds_alternative<AdvancedSyntaxNode>(adv.nodes[0]))
{
SyntaxNode n = AdvancedSyntaxNode::Create(FunctionStatement,false,{
adv.nodes[0],
AdvancedSyntaxNode::Create(ReturnStatement,false,{
AdvancedSyntaxNode::Create(FunctionCallExpression,true,{
AdvancedSyntaxNode::Create(GetVariableExpression,true,{"YieldEmumerable"}),
AdvancedSyntaxNode::Create(ClosureExpression,true,{AdvancedSyntaxNode::Create(ParenthesesExpression,true,{}), adv.nodes[1]})
})
})
});
GenNode(instructions,n,scope,contscope,brkscope,contI,brkI);
}
else if(adv.nodeName == FunctionStatement && adv.nodes.size() == 2 && std::holds_alternative<AdvancedSyntaxNode>(adv.nodes[0]))
{
//func NAME(ARGS) {}
@ -1152,13 +1282,24 @@ namespace Tesses::CrossLang
{
documentation = std::get<std::string>(res2.nodes[0]);
auto j = std::get<AdvancedSyntaxNode>(res2.nodes[1]);
if(j.nodeName == FunctionStatement) {
if(j.nodeName == FunctionStatement || j.nodeName == EnumerableStatement) {
res2 = j;
}
}
}
}
if(res2.nodeName == EnumerableStatement)
{
res2 = AdvancedSyntaxNode::Create(FunctionStatement,false,{
res2.nodes[0],
AdvancedSyntaxNode::Create(ReturnStatement,false,{
AdvancedSyntaxNode::Create(FunctionCallExpression,true,{
AdvancedSyntaxNode::Create(GetVariableExpression,true,{"YieldEmumerable"}),
AdvancedSyntaxNode::Create(ClosureExpression,true,{AdvancedSyntaxNode::Create(ParenthesesExpression,true,{}), res2.nodes[1]})
})
})
});
}
if(res2.nodeName == FunctionStatement)
{
if(res2.nodes.size()==2)

View File

@ -471,6 +471,16 @@ namespace Tesses::CrossLang
return AdvancedSyntaxNode::Create(IfStatement, false, {cond, truthy,falsey});
}
if(IsIdentifier("switch"))
{
EnsureSymbol("(");
SyntaxNode cond = ParseExpression();
EnsureSymbol(")");
SyntaxNode body = ParseNode();
return AdvancedSyntaxNode::Create(SwitchStatement,false,{cond,body});
}
if(IsIdentifier("while"))
{
EnsureSymbol("(");
@ -547,6 +557,19 @@ namespace Tesses::CrossLang
}
return AdvancedSyntaxNode::Create(EachStatement,false,{item,list,body});
}
if(IsIdentifier("enumerable"))
{
auto nameAndArgs = ParseExpression();
if(IsSymbol("{",false))
{
return AdvancedSyntaxNode::Create(EnumerableStatement,false,{nameAndArgs,ParseNode()});
}
else
{
throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"{\" on enumerable but got the symbol or other token \"" + tokens[i].text + "\"");
}
}
if(IsIdentifier("func"))
{
auto nameAndArgs = ParseExpression();
@ -573,12 +596,39 @@ namespace Tesses::CrossLang
EnsureSymbol(";");
return AdvancedSyntaxNode::Create(ContinueStatement,false,{});
}
if(IsIdentifier("case"))
{
auto r = AdvancedSyntaxNode::Create(CaseStatement,false,{ParseExpression()});
EnsureSymbol(":");
return r;
}
if(IsIdentifier("default"))
{
auto r = AdvancedSyntaxNode::Create(DefaultStatement,false,{});
EnsureSymbol(":");
return r;
}
if(IsIdentifier("return"))
{
auto v = ParseExpression();
EnsureSymbol(";");
SyntaxNode v = Undefined();
if(!IsSymbol(";",true))
{
v = ParseExpression();
EnsureSymbol(";");
}
return AdvancedSyntaxNode::Create(ReturnStatement,false,{v});
}
if(IsIdentifier("yield"))
{
SyntaxNode v = Undefined();
if(!IsSymbol(";",true))
{
v = ParseExpression();
EnsureSymbol(";");
}
return AdvancedSyntaxNode::Create(YieldStatement,false,{v});
}
if(IsIdentifier("throw"))
{
auto v = ParseExpression();

View File

@ -12,7 +12,7 @@ namespace Tesses::CrossLang
TDictionary* enumerableItem = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
auto fn = TExternalMethod::Create(ls,"Get Enumerator for Dictionary",{"dict"},[dynDict](GCList& ls2, std::vector<TObject> args)->TObject {
auto fn = TExternalMethod::Create(ls,"Get Enumerator for Dictionary",{},[dynDict](GCList& ls2, std::vector<TObject> args)->TObject {
return dynDict->GetEnumerator(ls2);
});
fn->watch.push_back(dynDict);

View File

@ -130,6 +130,7 @@ namespace Tesses::CrossLang
if(std::holds_alternative<char>(args[0])) return "Char";
if(std::holds_alternative<MethodInvoker>(args[0])) return "MethodInvoker";
if(std::holds_alternative<std::string>(args[0])) return "String";
if(std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(args[0])) return "Path";
if(std::holds_alternative<THeapObjectHolder>(args[0]))
{
@ -147,6 +148,8 @@ namespace Tesses::CrossLang
auto vfs = dynamic_cast<TVFSHeapObject*>(obj);
auto strm = dynamic_cast<TStreamHeapObject*>(obj);
auto svr = dynamic_cast<TServerHeapObject*>(obj);
auto cse = dynamic_cast<CallStackEntry*>(obj);
if(cse != nullptr) return "YieldedClosure";
if(dynDict != nullptr) return "DynamicDictionary";
if(dynList != nullptr) return "DynamicList";
if(strm != nullptr)
@ -300,12 +303,37 @@ namespace Tesses::CrossLang
}
static TObject YieldEnumerableFunc(GCList& ls, std::vector<TObject> args)
{
TClosure* closure;
if(GetArgumentHeap(args,0,closure))
{
TDictionary* enumerableItem = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
auto fn = TExternalMethod::Create(ls,"Get Enumerator for yield",{},[closure](GCList& ls2, std::vector<TObject> args)->TObject {
return TYieldEnumerator::Create(ls2,closure);
});
fn->watch.push_back(closure);
enumerableItem->SetValue("GetEnumerator", fn);
ls.GetGC()->BarrierEnd();
return enumerableItem;
}
return Undefined();
}
void TStd::RegisterRoot(GC* gc, TRootEnvironment* env)
{
env->permissions.canRegisterRoot=true;
env->DeclareFunction(gc, "ParseLong","Parse Long from String",{"arg","$base"},ParseLong);
env->DeclareFunction(gc, "ParseDouble","Parse Double from String",{"arg"},ParseDouble);
env->DeclareFunction(gc, "YieldEmumerable","Turn yield in function into enumerable",{"closure"},YieldEnumerableFunc);
env->DeclareFunction(gc, "TypeOf","Get type of object",{"object"},TypeOf);
env->DeclareFunction(gc, "TypeIsDefined","Get whether object is not null or undefined",{"object"},TypeIsDefined);
env->DeclareFunction(gc, "TypeIsHeap","Get whether object is susceptible to garbage collection",{"object"},TypeIsHeap);
@ -406,6 +434,7 @@ namespace Tesses::CrossLang
RegisterCrypto(gc,env);
RegisterOGC(gc, env);
RegisterProcess(gc,env);
RegisterTime(gc, env);
gc->RegisterEverything(env);

View File

@ -0,0 +1,194 @@
#include "CrossLang.hpp"
#include <unistd.h>
#include "../HowardHinnant_date/date.h"
namespace Tesses::CrossLang
{
static int64_t ToLocalTime(int64_t local)
{
local -= timezone;
if(daylight)
{
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(local/86400);
bool isDST = false;
date::year_month_day ymd(epoch);
auto month = (uint32_t)ymd.month();
if(month > 3 && month < 11)
{
isDST=true;
}
else if(month == 3)
{
auto day = (uint32_t)ymd.day();
if(day > 14) isDST=true;
else if(day >= 8 && day <= 14)
{
date::year_month_weekday ymw(epoch);
auto dow=ymw.weekday().c_encoding();
auto secondSunday = day - dow;
if(secondSunday < 8) secondSunday+=7;
if(day > secondSunday) isDST=true;
else if(day == secondSunday)
{
std::chrono::duration<int64_t> local_epoch_time(local);
date::hh_mm_ss hms(local_epoch_time%86400);
if(hms.hours().count() >= 2) isDST=true;
}
}
}
else if(month == 11)
{
auto day = (uint32_t)ymd.day();
if(day >= 1 && day <= 7)
{
date::year_month_weekday ymw(epoch);
auto dow=ymw.weekday().c_encoding();
int32_t firstSunday = (int32_t)day - (int32_t)dow;
if(firstSunday < 1) firstSunday+=7;
if(day < firstSunday) isDST=true;
else if(day == firstSunday)
{
std::chrono::duration<int64_t> local_epoch_time(local);
date::hh_mm_ss hms(local_epoch_time%86400);
if(hms.hours().count() <=1) isDST=true;
}
}
}
if(isDST) local += 3600;
}
return local;
}
static TObject Time_getNow(GCList& ls, std::vector<TObject> args)
{
time_t t = time(NULL);
return (time_t)t;
}
static TObject Time_Sleep(GCList& ls, std::vector<TObject> args)
{
int64_t msec;
if(GetArgument(args,0,msec))
{
if((msec % 100) == 0)
{
msec /= 100;
for(int64_t i = 0; i < msec; i++)
{
usleep(100000);
}
}
else if((msec % 10) == 0)
{
msec /= 10;
for(int64_t i = 0; i < msec; i++)
{
usleep(10000);
}
}
else
{
for(int64_t i = 0; i < msec; i++)
{
usleep(1000);
}
}
}
return nullptr;
}
static TObject Time_LocalTime(GCList& ls, std::vector<TObject> args)
{
//THIS code isn't the best but should work
int64_t local;
if(GetArgument(args,0,local))
{
local = ToLocalTime(local);
std::chrono::duration<int64_t> local_epoch_time(local);
date::hh_mm_ss hms(local_epoch_time%86400);
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(local/86400);
//date::days<int64_t> sys_days_since_epoch = date::days<int64_t>(gmt);
// Convert sys_days to year_month_day
date::year_month_day ymd = date::year_month_day(epoch);
TDictionary* dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Hour",hms.hours().count());
dict->SetValue("Minute",hms.minutes().count());
dict->SetValue("Second",hms.seconds().count());
dict->SetValue("Day",(int64_t)(uint32_t)ymd.day());
dict->SetValue("Month",(int64_t)(uint32_t)ymd.month());
dict->SetValue("Year",(int64_t)(int32_t)ymd.year());
ls.GetGC()->BarrierEnd();
return dict;
}
return nullptr;
}
static TObject Time_GMTTime(GCList& ls, std::vector<TObject> args)
{
int64_t gmt;
if(GetArgument(args,0,gmt))
{
std::chrono::duration<int64_t> epoch_time(gmt);
date::hh_mm_ss hms(epoch_time%86400);
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(gmt/86400);
//date::days<int64_t> sys_days_since_epoch = date::days<int64_t>(gmt);
// Convert sys_days to year_month_day
date::year_month_day ymd = date::year_month_day(epoch);
TDictionary* dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Hour",hms.hours().count());
dict->SetValue("Minute",hms.minutes().count());
dict->SetValue("Second",hms.seconds().count());
dict->SetValue("Day",(int64_t)(uint32_t)ymd.day());
dict->SetValue("Month",(int64_t)(uint32_t)ymd.month());
dict->SetValue("Year",(int64_t)(int32_t)ymd.year());
ls.GetGC()->BarrierEnd();
return dict;
}
return nullptr;
}
void TStd::RegisterTime(GC* gc,TRootEnvironment* env)
{
env->permissions.canRegisterTime=true;
GCList ls(gc);
TDictionary* dict = TDictionary::Create(ls);
dict->DeclareFunction(gc, "GetLocalTime", "Get local time from epoch value",{"epoch"},Time_LocalTime);
dict->DeclareFunction(gc, "GetGMTTime","Get the GMT time from epoch value",{"epoch"},Time_GMTTime);
dict->DeclareFunction(gc, "getNow","Get the time right now, returns C's time(NULL) return value",{},Time_getNow);
dict->DeclareFunction(gc, "Sleep","Sleep for a specified amount of milliseconds (multiply seconds by 1000 to get milliseconds)", {"ms"},Time_Sleep);
gc->BarrierBegin();
dict->SetValue("Zone", (int64_t)-(timezone));
dict->SetValue("SupportsDaylightSavings",(int64_t)daylight);
env->DeclareVariable("Time", dict);
gc->BarrierEnd();
}
}

View File

@ -2,6 +2,78 @@
namespace Tesses::CrossLang
{
bool TYieldEnumerator::MoveNext(GC* ls)
{
CallStackEntry* ent;
GCList ls2(ls);
if(!this->hasStarted)
{
TClosure* clos;
if(!GetObjectHeap(this->enumerator,clos)) return false;
auto _enumerator= clos->Call(ls2,{});
ls->BarrierBegin();
this->enumerator = _enumerator;
this->hasStarted=true;
ls->BarrierEnd();
}
else {
if(GetObjectHeap(this->enumerator,ent))
{
auto _enumerator= ent->Resume(ls2);
ls->BarrierBegin();
this->enumerator = _enumerator;
ls->BarrierEnd();
} else return false;
}
if(GetObjectHeap(this->enumerator,ent))
{
ls->BarrierBegin();
this->current = ent->Pop(ls2);
ls->BarrierEnd();
return true;
}
return false;
}
TObject TYieldEnumerator::GetCurrent(GCList& ls)
{
ls.Add(this->current);
return this->current;
}
void TYieldEnumerator::Mark()
{
if(this->marked) return;
this->marked=true;
GC::Mark(this->current);
GC::Mark(this->enumerator);
}
TYieldEnumerator* TYieldEnumerator::Create(GCList& ls,TObject v)
{
TYieldEnumerator* yieldEnum = new TYieldEnumerator();
yieldEnum->current=nullptr;
yieldEnum->hasStarted=false;
yieldEnum->enumerator = v;
GC* _gc = ls.GetGC();
ls.Add(yieldEnum);
_gc->Watch(yieldEnum);
return yieldEnum;
}
TYieldEnumerator* TYieldEnumerator::Create(GCList* ls,TObject v)
{
TYieldEnumerator* yieldEnum = new TYieldEnumerator();
yieldEnum->current=nullptr;
yieldEnum->hasStarted=false;
yieldEnum->enumerator = v;
GC* _gc = ls->GetGC();
ls->Add(yieldEnum);
_gc->Watch(yieldEnum);
return yieldEnum;
}
bool TCustomEnumerator::MoveNext(GC* ls)
{

View File

@ -2,6 +2,7 @@
#include <chrono>
#include <iostream>
#include <unistd.h>
#include <time.h>
#if defined(CROSSLANG_ENABLE_SQLITE)
extern "C" {
@ -27,6 +28,7 @@ namespace Tesses::CrossLang
}
GC::GC()
{
tzset();
#if defined(CROSSLANG_ENABLE_SQLITE)
sqlite3_initialize();
#if defined(GEKKO)
@ -112,12 +114,12 @@ namespace Tesses::CrossLang
last_frame = this_frame;
this->Collect();
usleep(1000000);
}
usleep(10000);
usleep(100000);
}
GC::Collect();
});

View File

@ -6,6 +6,7 @@
namespace Tesses::CrossLang {
thread_local CallStackEntry* current_function=nullptr;
bool ToBool(TObject obj)
{
if(std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(obj))
@ -1639,6 +1640,7 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, -number);
else
cse.back()->Push(gc, number);
return false;
}
if(key == "ToDouble")
{
@ -1978,8 +1980,34 @@ namespace Tesses::CrossLang {
auto env = dynamic_cast<TEnvironment*>(obj);
auto rootEnv = dynamic_cast<TRootEnvironment*>(obj);
auto callable = dynamic_cast<TCallable*>(obj);
auto callstackEntry = dynamic_cast<CallStackEntry*>(obj);
auto svr = dynamic_cast<TServerHeapObject*>(obj);
if(callstackEntry != nullptr)
{
if(key == "Resume")
{
gc->BarrierBegin();
cse.push_back(callstackEntry);
gc->BarrierEnd();
return true;
}
if(key == "Push")
{
if(!args.empty())
callstackEntry->Push(gc, args[0]);
else
callstackEntry->Push(gc,Undefined());
return false;
}
if(key == "Pop")
{
cse.back()->Push(gc, callstackEntry->Pop(ls));
return false;
}
}
if(svr != nullptr)
{
auto mountable = dynamic_cast<Tesses::Framework::Http::MountableServer*>(svr->server);
@ -2199,6 +2227,13 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc,nullptr);
return false;
}
if(key == "RegisterTime")
{
if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterTime) && !rootEnv->permissions.locked)
TStd::RegisterTime(gc, rootEnv);
cse.back()->Push(gc,nullptr);
return false;
}
if(key == "SetSqliteRoot")
{
Tesses::Framework::Filesystem::VFSPath p;
@ -3353,6 +3388,19 @@ namespace Tesses::CrossLang {
return false;
}
bool InterperterThread::Yield(GC* gc)
{
GCList ls(gc);
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
if(!cse.empty())
{
gc->BarrierBegin();
cse.back()->mustReturn=true;
cse.back()->Push(gc, cse.back());
gc->BarrierEnd();
}
return false;
}
bool InterperterThread::ExecuteMethod(GC* gc)
{
GCList ls(gc);
@ -3439,6 +3487,33 @@ namespace Tesses::CrossLang {
auto ittr = dynamic_cast<TEnumerator*>(obj);
auto strm = dynamic_cast<TStreamHeapObject*>(obj);
auto vfs = dynamic_cast<TVFSHeapObject*>(obj);
auto callstackEntry = dynamic_cast<CallStackEntry*>(obj);
if(callstackEntry != nullptr)
{
if(key == "IP")
{
cse.back()->Push(gc, (int64_t)callstackEntry->ip);
return false;
}
if(key == "IsDone")
{
cse.back()->Push(gc, callstackEntry->ip >= callstackEntry->callable->closure->code.size());
return false;
}
if(key == "Closure")
{
cse.back()->Push(gc, callstackEntry->callable);
return false;
}
if(key == "StackEmpty")
{
cse.back()->Push(gc, callstackEntry->stack.empty());
return false;
}
cse.back()->Push(gc,Undefined());
return false;
}
if(strm != nullptr)
{
@ -3491,7 +3566,7 @@ namespace Tesses::CrossLang {
return false;
}
cse.back()->Push(gc, nullptr);
cse.back()->Push(gc, Undefined());
return false;
}
@ -3512,7 +3587,7 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, ittr->GetCurrent(ls));
return false;
}
cse.back()->Push(gc, nullptr);
cse.back()->Push(gc, Undefined());
return false;
}
if(closure != nullptr)
@ -4312,11 +4387,31 @@ namespace Tesses::CrossLang {
if(((*this).*(opcodes[stk->callable->closure->code[ip]]))(gc))
goto execute;
if(stk->mustReturn) {
stk->mustReturn=false;
if(cse.size() > 1)
{
GCList ls(gc);
TObject o = cse[cse.size()-1]->Pop(ls);
cse[cse.size()-2]->Push(gc,o);
cse.erase(cse.end()-1);
current_function = cse.back();
gc->BarrierEnd();
goto execute;
} else {
return;
}
}
if(gc->UsingNullThreads()) gc->Collect();
}
stk->mustReturn=false;
}
catch(VMByteCodeException& ex)
{
@ -4516,6 +4611,20 @@ namespace Tesses::CrossLang {
this->stack.push_back(o);
gc->BarrierEnd();
}
TObject CallStackEntry::Resume(GCList& ls)
{
auto cse = current_function;
InterperterThread* thrd=InterperterThread::Create(ls);
ls.GetGC()->BarrierBegin();
thrd->call_stack_entries.push_back(this);
ls.GetGC()->BarrierEnd();
thrd->Execute(ls.GetGC());
TObject v= thrd->call_stack_entries[0]->Pop(ls);
current_function = cse;
return v;
}
TObject CallStackEntry::Pop(GCList& gc)
{
if(this->stack.empty()) return Undefined();
@ -4546,6 +4655,7 @@ namespace Tesses::CrossLang {
CallStackEntry* CallStackEntry::Create(GCList& ls)
{
CallStackEntry* cse = new CallStackEntry();
cse->mustReturn=false;
GC* _gc = ls.GetGC();
ls.Add(cse);
_gc->Watch(cse);
@ -4555,6 +4665,7 @@ namespace Tesses::CrossLang {
CallStackEntry* CallStackEntry::Create(GCList* ls)
{
CallStackEntry* cse = new CallStackEntry();
cse->mustReturn=false;
GC* _gc = ls->GetGC();
ls->Add(cse);
_gc->Watch(cse);

File diff suppressed because one or more lines are too long