diff --git a/CHANGELOG.md b/CHANGELOG.md index 92d5dfe52..862bd3b46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,48 @@ ### Added - new builtin to extract the bytes of a string: builtin__string:bytes -- math:fromBase to convert a number from a given base to base 10 -- string:surrogate? and string:privateUse? to check if an unicode character is in one of those planes +- new builtins `builtin__time:timeToDate` and `builtin__time:parseDate` to convert a timestamp to a date, and parse a string date as a timestamp +- standard library + - math:fromBase to convert a number from a given base to base 10 + - string:surrogate? and string:privateUse? to check if a Unicode character is in one of those planes + - list:findAfter to search for an element in a list after a given index + - list:findIf to search for an element in a list using a predicate + - list:search to search for a set of contiguous elements in a list + - list:minMax to get the minimum and maximum values of a list of numbers in a single call + - list:sorted? to check if a list is sorted + - list:lowerBound, list:upperBound + - list:binarySearch + - list:shiftLeft, list:shiftRight + - datetime library + - timezoneOffsets + - timezoneOffset + - makeUTCTimestamp + - timestamps: year0, year1970, year200 + - toUTCTimestamp + - asUTCDate, asLocalDate + - plusSeconds, minusSeconds + - plusMinutes, minusMinutes + - plusHours, minusHours + - plusDays, minusDays + - plusWeeks, minusWeeks + - plusMonths, minusMonths + - plusYears, minusYears + - atStartOfDay, atEndOfDay + - today, yesterday, tomorrow + - nextDay, previousDay + - delta, asDelta + - asSeconds + - plusDelta, minusDelta + - year, month, day, hour, minute, second, millisecond, dayOfWeek, dayOfYear + - leapYear? + - monthLength, yearLength + - asISO8601 + - parse, parseAs ### Changed - math:toBase handles 0 correctly - math:countDigits returns 1 for 0 +- builtin__list:find can take an optional third argument, to specify at which index to start looking from ### Removed diff --git a/CMakeLists.txt b/CMakeLists.txt index e670bc31c..c0ceb416f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(ark CXX) +project(ark CXX C) # ArkScript version (have to manually update it) set(ARK_VERSION_MAJOR 4) @@ -170,6 +170,11 @@ endif () add_subdirectory("${ark_SOURCE_DIR}/thirdparties/ankerl_unordered_dense" EXCLUDE_FROM_ALL) target_link_libraries(ArkReactor PUBLIC unordered_dense::unordered_dense) +add_library(newlib STATIC ${ark_SOURCE_DIR}/thirdparties/newlib/src/gmtime_r.c) +target_include_directories(newlib SYSTEM PUBLIC ${ark_SOURCE_DIR}/thirdparties/newlib/include) +target_include_directories(ArkReactor SYSTEM PUBLIC ${ark_SOURCE_DIR}/thirdparties/newlib/include) +target_link_libraries(ArkReactor PRIVATE newlib) + if (UNIX OR LINUX) find_package(Threads) target_link_libraries(ArkReactor PRIVATE ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) diff --git a/include/Ark/Builtins/Builtins.hpp b/include/Ark/Builtins/Builtins.hpp index 15a998ba0..955e43774 100644 --- a/include/Ark/Builtins/Builtins.hpp +++ b/include/Ark/Builtins/Builtins.hpp @@ -62,6 +62,8 @@ namespace Ark::internal::Builtins namespace Time { ARK_BUILTIN(timeSinceEpoch); + ARK_BUILTIN(timestampToDate); + ARK_BUILTIN(parseDate); } namespace System diff --git a/lib/std b/lib/std index 8b5af97d9..c29c23a6b 160000 --- a/lib/std +++ b/lib/std @@ -1 +1 @@ -Subproject commit 8b5af97d9f46202c724f4b8a1aab9eb196d01680 +Subproject commit c29c23a6b85f5db683f602c80c7eb7c88bcf79af diff --git a/src/arkreactor/Builtins/Builtins.cpp b/src/arkreactor/Builtins/Builtins.cpp index 0e7e73f1c..ac398afe9 100644 --- a/src/arkreactor/Builtins/Builtins.cpp +++ b/src/arkreactor/Builtins/Builtins.cpp @@ -51,6 +51,8 @@ namespace Ark::internal::Builtins // Time { "time", Value(Time::timeSinceEpoch) }, + { "builtin__time:timeToDate", Value(Time::timestampToDate) }, + { "builtin__time:parseDate", Value(Time::parseDate) }, // System { "builtin__sys:platform", platform }, diff --git a/src/arkreactor/Builtins/List.cpp b/src/arkreactor/Builtins/List.cpp index bc84143e0..f52b58f62 100644 --- a/src/arkreactor/Builtins/List.cpp +++ b/src/arkreactor/Builtins/List.cpp @@ -5,6 +5,7 @@ #include #include +#include namespace Ark::internal::Builtins::List { @@ -22,14 +23,25 @@ namespace Ark::internal::Builtins::List Value findInList(std::vector& n, VM* vm [[maybe_unused]]) { - if (!types::check(n, ValueType::List, ValueType::Any)) + if (!types::check(n, ValueType::List, ValueType::Any) && + !types::check(n, ValueType::List, ValueType::Any, ValueType::Number)) throw types::TypeCheckingError( "list:find", - { { types::Contract { { types::Typedef("list", ValueType::List), types::Typedef("value", ValueType::Any) } } } }, + { { types::Contract { + { types::Typedef("list", ValueType::List), + types::Typedef("value", ValueType::Any) } }, + types::Contract { + { types::Typedef("list", ValueType::List), + types::Typedef("value", ValueType::Any), + types::Typedef("index", ValueType::Number) } } } }, n); - if (const auto it = std::ranges::find(n[0].list(), n[1]); it != n[0].list().end()) - return Value(static_cast(std::distance(n[0].list().begin(), it))); + const long offset = n.size() == 3 ? static_cast(n[2].number()) : 0L; + if (std::cmp_less(offset, n[0].list().size())) + { + if (const auto it = std::ranges::find(n[0].list().begin() + offset, n[0].list().end(), n[1]); it != n[0].list().end()) + return Value(static_cast(std::distance(n[0].list().begin() + offset, it) + offset)); + } return Value(-1); } @@ -50,8 +62,9 @@ namespace Ark::internal::Builtins::List if (!types::check(n, ValueType::Number, ValueType::Any)) throw types::TypeCheckingError( "list:fill", - { { types::Contract { { types::Typedef("size", ValueType::Number), - types::Typedef("value", ValueType::Any) } } } }, + { { types::Contract { + { types::Typedef("size", ValueType::Number), + types::Typedef("value", ValueType::Any) } } } }, n); const auto c = static_cast(n[0].number()); @@ -68,9 +81,10 @@ namespace Ark::internal::Builtins::List if (!types::check(n, ValueType::List, ValueType::Number, ValueType::Any)) throw types::TypeCheckingError( "list:setAt", - { { types::Contract { { types::Typedef("list", ValueType::List), - types::Typedef("index", ValueType::Number), - types::Typedef("value", ValueType::Any) } } } }, + { { types::Contract { + { types::Typedef("list", ValueType::List), + types::Typedef("index", ValueType::Number), + types::Typedef("value", ValueType::Any) } } } }, n); auto& list = n[0].list(); diff --git a/src/arkreactor/Builtins/Time.cpp b/src/arkreactor/Builtins/Time.cpp index b5d907e0a..d3c0c3219 100644 --- a/src/arkreactor/Builtins/Time.cpp +++ b/src/arkreactor/Builtins/Time.cpp @@ -1,9 +1,14 @@ #include +#include +#include +#include + #undef abs #include +#include -#include +#include namespace Ark::internal::Builtins::Time { @@ -15,6 +20,7 @@ namespace Ark::internal::Builtins::Time * =end * @author https://github.com/SuperFola */ + // cppcheck-suppress constParameterReference Value timeSinceEpoch(std::vector& n [[maybe_unused]], VM* vm [[maybe_unused]]) { const auto now = std::chrono::system_clock::now(); @@ -22,4 +28,89 @@ namespace Ark::internal::Builtins::Time const auto microseconds = std::chrono::duration_cast(epoch); return Value(static_cast(microseconds.count()) / 1000000); } + + Value timestampToDate(std::vector& n, VM* vm [[maybe_unused]]) + { + if (!types::check(n, ValueType::Number, ValueType::Any)) + throw types::TypeCheckingError( + "timeToDate", + { { types::Contract { + { types::Typedef("timestamp", ValueType::Number), + types::Typedef("utc?", ValueType::Any) } } } }, + n); + + // FIXME: offset time by X seconds? + // const bool is_utc = n[1] == True; + + nl_tm calendar_time {}; + // FIXME: is_utc ? std::gmtime(&time) : std::localtime(&time); + nl_gmtime_r(static_cast(n[0].number()), &calendar_time); + + int week = calendar_time.tm_wday; + if (week == 0) // Sunday + week = 6; + else + --week; // 0-5: Monday-Saturday + + internal::Dict dict; + const double ms = n[0].number() - static_cast(static_cast(n[0].number())); + + dict.set(Value("millisecond"), Value(static_cast(1000.0 * ms))); + dict.set(Value("second"), Value(calendar_time.tm_sec)); + dict.set(Value("minute"), Value(calendar_time.tm_min)); + dict.set(Value("hour"), Value(calendar_time.tm_hour)); + dict.set(Value("day"), Value(calendar_time.tm_mday)); + dict.set(Value("month"), Value(calendar_time.tm_mon + 1)); + dict.set(Value("year"), Value(calendar_time.tm_year + 1900)); + dict.set(Value("week_day"), Value(week)); + dict.set(Value("year_day"), Value(calendar_time.tm_yday)); + dict.set(Value("is_dst"), calendar_time.tm_isdst ? True : False); + + return Value(std::move(dict)); + } + + int64_t makeTimestamp(const int tm_sec, const int tm_min, const int tm_hour, const int tm_mday, const int tm_mon, const int tm_year) + { + constexpr int MonthsPerYear = 12; + static const std::array cumulative_days = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + const long year = 1900 + tm_year + tm_mon / MonthsPerYear; + int64_t result = (year - 1970) * 365 + cumulative_days[static_cast(tm_mon % MonthsPerYear)]; + result += (year - 1968) / 4; + result -= (year - 1900) / 100; + result += (year - 1600) / 400; + if ((year % 4) == 0 && + ((year % 100) != 0 || (year % 400) == 0) && + (tm_mon % MonthsPerYear) < 2) + result--; + result += tm_mday - 1; + result *= 24; + result += tm_hour; + result *= 60; + result += tm_min; + result *= 60; + result += tm_sec; + return result; + } + + Value parseDate(std::vector& n, VM* vm [[maybe_unused]]) + { + if (!types::check(n, ValueType::String) && !types::check(n, ValueType::String, ValueType::String)) + throw types::TypeCheckingError( + "parseDate", + { { types::Contract { + { types::Typedef("date", ValueType::String) } }, + types::Contract { + { types::Typedef("date", ValueType::String), + types::Typedef("format", ValueType::String) } } } }, + n); + + std::tm t = {}; + std::istringstream ss(n[0].string()); + ss >> std::get_time(&t, n.size() == 1 ? "%Y-%m-%dT%H:%M:%S" : n[1].string().c_str()); + + if (ss.fail()) + return Nil; + return Value(makeTimestamp(t.tm_sec, t.tm_min, t.tm_hour, t.tm_mday, t.tm_mon, t.tm_year)); + } } diff --git a/tests/unittests/resources/CompilerSuite/ir/99bottles.expected b/tests/unittests/resources/CompilerSuite/ir/99bottles.expected index feea5ee20..0aa2c278f 100644 --- a/tests/unittests/resources/CompilerSuite/ir/99bottles.expected +++ b/tests/unittests/resources/CompilerSuite/ir/99bottles.expected @@ -37,7 +37,7 @@ page_0 LOAD_CONST 3 LOAD_FAST 4 LOAD_FAST 4 - CALL_BUILTIN 27, 3 + CALL_BUILTIN 29, 3 .L7: CALL_BUILTIN 9, 1 .L6: @@ -50,7 +50,7 @@ page_0 PUSH_RETURN_ADDRESS L9 LOAD_CONST 4 LOAD_FAST 4 - CALL_BUILTIN 27, 2 + CALL_BUILTIN 29, 2 .L9: CALL_BUILTIN 9, 1 .L8: diff --git a/tests/unittests/resources/CompilerSuite/ir/breakpoints.expected b/tests/unittests/resources/CompilerSuite/ir/breakpoints.expected index 8999a7f5d..d4e04adcf 100644 --- a/tests/unittests/resources/CompilerSuite/ir/breakpoints.expected +++ b/tests/unittests/resources/CompilerSuite/ir/breakpoints.expected @@ -62,7 +62,7 @@ page_1 LOAD_FAST_BY_INDEX 0 LOAD_FAST_BY_INDEX 1 LOAD_FAST_BY_INDEX 2 - CALL_BUILTIN 27, 4 + CALL_BUILTIN 29, 4 .L1: CALL_BUILTIN 9, 1 .L0: diff --git a/tests/unittests/resources/CompilerSuite/ir/operators_as_builtins.expected b/tests/unittests/resources/CompilerSuite/ir/operators_as_builtins.expected index 908810d01..af666e403 100644 --- a/tests/unittests/resources/CompilerSuite/ir/operators_as_builtins.expected +++ b/tests/unittests/resources/CompilerSuite/ir/operators_as_builtins.expected @@ -1,7 +1,5 @@ page_0 PUSH_RETURN_ADDRESS L0 - BUILTIN 87 - BUILTIN 88 BUILTIN 89 BUILTIN 90 BUILTIN 91 @@ -25,6 +23,8 @@ page_0 BUILTIN 109 BUILTIN 110 BUILTIN 111 + BUILTIN 112 + BUILTIN 113 CALL_BUILTIN 9, 25 .L0: POP 0 diff --git a/tests/unittests/resources/CompilerSuite/ir/plugin.expected b/tests/unittests/resources/CompilerSuite/ir/plugin.expected index 77c9c2126..1ee1867de 100644 --- a/tests/unittests/resources/CompilerSuite/ir/plugin.expected +++ b/tests/unittests/resources/CompilerSuite/ir/plugin.expected @@ -8,7 +8,7 @@ page_0 .L1: EQ 0 LOAD_CONST 3 - CALL_BUILTIN 26, 2 + CALL_BUILTIN 28, 2 .L0: POP 0 HALT 0 diff --git a/tests/unittests/resources/CompilerSuite/optimized_ir/99bottles.expected b/tests/unittests/resources/CompilerSuite/optimized_ir/99bottles.expected index 2131676dc..2227e444b 100644 --- a/tests/unittests/resources/CompilerSuite/optimized_ir/99bottles.expected +++ b/tests/unittests/resources/CompilerSuite/optimized_ir/99bottles.expected @@ -2,7 +2,7 @@ page_0 LOAD_CONST_STORE 0, 0 LOAD_CONST_STORE 1, 2 LOAD_CONST_STORE 2, 4 - BUILTIN 22 + BUILTIN 24 STORE 6 STORE_FROM 8, 7 STORE_FROM 10, 9 @@ -37,7 +37,7 @@ page_0 LOAD_CONST 6 LOAD_FAST 13 LOAD_FAST 13 - CALL_BUILTIN 27, 3 + CALL_BUILTIN 29, 3 .L10: CALL_BUILTIN 9, 1 .L9: @@ -47,7 +47,7 @@ page_0 PUSH_RETURN_ADDRESS L12 LOAD_CONST 7 LOAD_FAST 13 - CALL_BUILTIN 27, 2 + CALL_BUILTIN 29, 2 .L12: CALL_BUILTIN 9, 1 .L11: @@ -58,19 +58,19 @@ page_0 HALT 0 page_1 - CALL_BUILTIN_WITHOUT_RETURN_ADDRESS 23, 1 + CALL_BUILTIN_WITHOUT_RETURN_ADDRESS 25, 1 .L0: RET 0 HALT 0 page_2 - CALL_BUILTIN_WITHOUT_RETURN_ADDRESS 24, 1 + CALL_BUILTIN_WITHOUT_RETURN_ADDRESS 26, 1 .L1: RET 0 HALT 0 page_3 - CALL_BUILTIN_WITHOUT_RETURN_ADDRESS 25, 1 + CALL_BUILTIN_WITHOUT_RETURN_ADDRESS 27, 1 .L2: RET 0 HALT 0 diff --git a/tests/unittests/resources/CompilerSuite/optimized_ir/builtins.expected b/tests/unittests/resources/CompilerSuite/optimized_ir/builtins.expected index 8565951cf..3aa746ef3 100644 --- a/tests/unittests/resources/CompilerSuite/optimized_ir/builtins.expected +++ b/tests/unittests/resources/CompilerSuite/optimized_ir/builtins.expected @@ -5,7 +5,7 @@ page_0 HALT 0 page_1 - CALL_BUILTIN_WITHOUT_RETURN_ADDRESS 58, 1 + CALL_BUILTIN_WITHOUT_RETURN_ADDRESS 60, 1 .L0: RET 0 HALT 0 diff --git a/tests/unittests/resources/DiagnosticsSuite/runtime/backtrace_builtin.expected b/tests/unittests/resources/DiagnosticsSuite/runtime/backtrace_builtin.expected index a0322a85f..31ff04fd6 100644 --- a/tests/unittests/resources/DiagnosticsSuite/runtime/backtrace_builtin.expected +++ b/tests/unittests/resources/DiagnosticsSuite/runtime/backtrace_builtin.expected @@ -6,16 +6,16 @@ Signature Arguments → `list' (expected List), got "live" (String) -In file /lib/std/List.ark:63 - 60 | # (list:sort [4 2 3]) # [1 2 4] - 61 | # =end - 62 | # @author https://github.com/SuperFola - 63 | (let sort (fun (_L) (builtin__list:sort _L))) +In file /lib/std/List.ark:206 + 203 | # (list:sort [4 2 3]) # [1 2 4] + 204 | # =end + 205 | # @author https://github.com/SuperFola + 206 | (let sort (fun (_L) (builtin__list:sort _L))) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 64 | - 65 | # @brief Generate a List of n copies of an element + 207 | + 208 | # @brief Check if a List is sorted -[ 2] In function `list:sort' (/lib/std/List.ark:63) +[ 2] In function `list:sort' (/lib/std/List.ark:206) [ 1] In global scope (tests/unittests/resources/DiagnosticsSuite/runtime/backtrace_builtin.ark:3) Current scope variables values: diff --git a/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_num.ark b/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_num.ark new file mode 100644 index 000000000..ead7929bc --- /dev/null +++ b/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_num.ark @@ -0,0 +1 @@ +(builtin__time:parseDate 1) diff --git a/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_num.expected b/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_num.expected new file mode 100644 index 000000000..a8b447094 --- /dev/null +++ b/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_num.expected @@ -0,0 +1,19 @@ +Function parseDate expected between 1 argument and 2 arguments +Call + ↳ (parseDate 1) +Signature + ↳ (parseDate date) +Arguments + → `date' (expected String), got 1 (Number) + +Alternative 2: +Signature + ↳ (parseDate date format) +Arguments + → `date' (expected String), got 1 (Number) + → `format' (expected String) was not provided + +In file tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_num.ark:1 + 1 | (builtin__time:parseDate 1) + | ^~~~~~~~~~~~~~~~~~~~~~~~~~ + 2 | diff --git a/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_str_num.ark b/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_str_num.ark new file mode 100644 index 000000000..0d9a15b85 --- /dev/null +++ b/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_str_num.ark @@ -0,0 +1 @@ +(builtin__time:parseDate "1" 1) diff --git a/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_str_num.expected b/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_str_num.expected new file mode 100644 index 000000000..8a5f2c9f2 --- /dev/null +++ b/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_str_num.expected @@ -0,0 +1,20 @@ +Function parseDate expected between 1 argument and 2 arguments +Call + ↳ (parseDate "1" 1) +Signature + ↳ (parseDate date) +Arguments + → `date' (expected String) ✓ + → unexpected additional args: 1 (Number) + +Alternative 2: +Signature + ↳ (parseDate date format) +Arguments + → `date' (expected String) ✓ + → `format' (expected String), got 1 (Number) + +In file tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timeparsedate_str_num.ark:1 + 1 | (builtin__time:parseDate "1" 1) + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 2 | diff --git a/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timetodate.ark b/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timetodate.ark new file mode 100644 index 000000000..aff7f04e7 --- /dev/null +++ b/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timetodate.ark @@ -0,0 +1 @@ +(builtin__time:timeToDate "1" true) diff --git a/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timetodate.expected b/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timetodate.expected new file mode 100644 index 000000000..5080fda21 --- /dev/null +++ b/tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timetodate.expected @@ -0,0 +1,13 @@ +Function timeToDate expected 2 arguments +Call + ↳ (timeToDate "1" true) +Signature + ↳ (timeToDate timestamp utc?) +Arguments + → `timestamp' (expected Number), got "1" (String) + → `utc?' (expected any) ✓ + +In file tests/unittests/resources/DiagnosticsSuite/typeChecking/builtin_timetodate.ark:1 + 1 | (builtin__time:timeToDate "1" true) + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 2 | diff --git a/tests/unittests/resources/DiagnosticsSuite/typeChecking/listfind_str_num.expected b/tests/unittests/resources/DiagnosticsSuite/typeChecking/listfind_str_num.expected index a557a293c..e631a6332 100644 --- a/tests/unittests/resources/DiagnosticsSuite/typeChecking/listfind_str_num.expected +++ b/tests/unittests/resources/DiagnosticsSuite/typeChecking/listfind_str_num.expected @@ -1,4 +1,4 @@ -Function list:find expected 2 arguments +Function list:find expected between 2 arguments and 3 arguments Call ↳ (list:find "hello" 1) Signature @@ -7,6 +7,14 @@ Arguments → `list' (expected List), got "hello" (String) → `value' (expected any) ✓ +Alternative 2: +Signature + ↳ (list:find list value index) +Arguments + → `list' (expected List), got "hello" (String) + → `value' (expected any) ✓ + → `index' (expected Number) was not provided + In file tests/unittests/resources/DiagnosticsSuite/typeChecking/listfind_str_num.ark:1 1 | (builtin__list:find "hello" 1) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/thirdparties/README.md b/thirdparties/README.md index d5b7ec046..5454bdd3d 100644 --- a/thirdparties/README.md +++ b/thirdparties/README.md @@ -9,5 +9,6 @@ Includes * [picosha2](https://github.com/okdshin/PicoSHA2), MIT License * [replxx](https://github.com/AmokHuginnsson/replxx/blob/master/LICENSE.md), MIT License + specifities * [ut](https://github.com/boost-ext/ut), BSL 1.0 +* newlib, BSD & MIT License ([COPYING.NEWLIB](https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=COPYING.NEWLIB;h=2bf6f0bed40635a9398b5a4d9b0828d59bf1213f;hb=HEAD)) All used by [Ark](https://github.com/ArkScript-lang/Ark) diff --git a/thirdparties/newlib/include/newlib/gmtime_r.h b/thirdparties/newlib/include/newlib/gmtime_r.h new file mode 100644 index 000000000..1b63db094 --- /dev/null +++ b/thirdparties/newlib/include/newlib/gmtime_r.h @@ -0,0 +1,10 @@ +#ifndef NEWLIB_GMTIME_R_H +#define NEWLIB_GMTIME_R_H + +#include + +extern "C" { +struct nl_tm* nl_gmtime_r(const long tim_p, struct nl_tm* __restrict res); +} + +#endif // NEWLIB_GMTIME_R_H diff --git a/thirdparties/newlib/include/newlib/local.h b/thirdparties/newlib/include/newlib/local.h new file mode 100644 index 000000000..706efe63d --- /dev/null +++ b/thirdparties/newlib/include/newlib/local.h @@ -0,0 +1,37 @@ +#ifndef NEWLIB_LOCAL_H +#define NEWLIB_LOCAL_H + +/* local header used by libc/time routines */ +#include + +#define SECSPERMIN 60L +#define MINSPERHOUR 60L +#define HOURSPERDAY 24L +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY) +#define DAYSPERWEEK 7 +#define MONSPERYEAR 12 + +#define YEAR_BASE 1900 +#define EPOCH_YEAR 1970 +#define EPOCH_WDAY 4 +#define EPOCH_YEARS_SINCE_LEAP 2 +#define EPOCH_YEARS_SINCE_CENTURY 70 +#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370 + +#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) + +struct nl_tm +{ + int tm_hour; + int tm_min; + int tm_sec; + int tm_wday; + int tm_yday; + int tm_year; + int tm_mon; + int tm_mday; + int tm_isdst; +}; + +#endif // NEWLIB_LOCAL_H diff --git a/thirdparties/newlib/src/gmtime_r.c b/thirdparties/newlib/src/gmtime_r.c new file mode 100644 index 000000000..96d493a9d --- /dev/null +++ b/thirdparties/newlib/src/gmtime_r.c @@ -0,0 +1,98 @@ +/* + * gmtime_r.c + * Original Author: Adapted from tzcode maintained by Arthur David Olson. + * Modifications: + * - Changed to mktm_r and added __tzcalc_limits - 04/10/02, Jeff Johnston + * - Fixed bug in mday computations - 08/12/04, Alex Mogilnikov + * - Fixed bug in __tzcalc_limits - 08/12/04, Alex Mogilnikov + * - Move code from _mktm_r() to gmtime_r() - 05/09/14, Freddie Chopin + * - Fixed bug in calculations for dates after year 2069 or before year 1901. Ideas for + * solution taken from musl's __secs_to_tm() - 07/12/2014, Freddie Chopin + * + * - Use faster algorithm from civil_from_days() by Howard Hinnant - 12/06/2014, + * Freddie Chopin + * + * Converts the calendar time pointed to by tim_p into a broken-down time + * expressed as local time. Returns a pointer to a structure containing the + * broken-down time. + */ + +#include + +/* Move epoch from 01.01.1970 to 01.03.0000 (yes, Year 0) - this is the first + * day of a 400-year long "era", right after additional day of leap year. + * This adjustment is required only for date calculation, so instead of + * modifying time_t value (which would require 64-bit operations to work + * correctly) it's enough to adjust the calculated number of days since epoch. + */ +#define EPOCH_ADJUSTMENT_DAYS 719468L +/* year to which the adjustment was made */ +#define ADJUSTED_EPOCH_YEAR 0 +/* 1st March of year 0 is Wednesday */ +#define ADJUSTED_EPOCH_WDAY 3 +/* there are 97 leap years in 400-year periods. ((400 - 97) * 365 + 97 * 366) */ +#define DAYS_PER_ERA 146097L +/* there are 24 leap years in 100-year periods. ((100 - 24) * 365 + 24 * 366) */ +#define DAYS_PER_CENTURY 36524L +/* there is one leap year every 4 years */ +#define DAYS_PER_4_YEARS (3 * 365 + 366) +/* number of days in a non-leap year */ +#define DAYS_PER_YEAR 365 +/* number of days in January */ +#define DAYS_IN_JANUARY 31 +/* number of days in non-leap February */ +#define DAYS_IN_FEBRUARY 28 +/* number of years per era */ +#define YEARS_PER_ERA 400 + +struct nl_tm* +nl_gmtime_r(const long lcltime, + struct nl_tm* __restrict res) +{ + long days, rem; + int era, weekday, year; + unsigned erayear, yearday, month, day; + unsigned long eraday; + + days = lcltime / SECSPERDAY + EPOCH_ADJUSTMENT_DAYS; + rem = lcltime % SECSPERDAY; + if (rem < 0) + { + rem += SECSPERDAY; + --days; + } + + /* compute hour, min, and sec */ + res->tm_hour = (int)(rem / SECSPERHOUR); + rem %= SECSPERHOUR; + res->tm_min = (int)(rem / SECSPERMIN); + res->tm_sec = (int)(rem % SECSPERMIN); + + /* compute day of week */ + if ((weekday = ((ADJUSTED_EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) + weekday += DAYSPERWEEK; + res->tm_wday = weekday; + + /* compute year, month, day & day of year */ + /* for description of this algorithm see + * http://howardhinnant.github.io/date_algorithms.html#civil_from_days */ + era = (days >= 0 ? days : days - (DAYS_PER_ERA - 1)) / DAYS_PER_ERA; + eraday = days - era * DAYS_PER_ERA; /* [0, 146096] */ + erayear = (eraday - eraday / (DAYS_PER_4_YEARS - 1) + eraday / DAYS_PER_CENTURY - + eraday / (DAYS_PER_ERA - 1)) / + 365; /* [0, 399] */ + yearday = eraday - (DAYS_PER_YEAR * erayear + erayear / 4 - erayear / 100); /* [0, 365] */ + month = (5 * yearday + 2) / 153; /* [0, 11] */ + day = yearday - (153 * month + 2) / 5 + 1; /* [1, 31] */ + month += month < 10 ? 2 : -10; + year = ADJUSTED_EPOCH_YEAR + erayear + era * YEARS_PER_ERA + (month <= 1); + + res->tm_yday = yearday >= DAYS_PER_YEAR - DAYS_IN_JANUARY - DAYS_IN_FEBRUARY ? yearday - (DAYS_PER_YEAR - DAYS_IN_JANUARY - DAYS_IN_FEBRUARY) : yearday + DAYS_IN_JANUARY + DAYS_IN_FEBRUARY + isleap(erayear); + res->tm_year = year - YEAR_BASE; + res->tm_mon = month; + res->tm_mday = day; + + res->tm_isdst = 0; + + return (res); +}