Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 8 additions & 13 deletions .run/a.ark.run.xml
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="a.ark" type="CMakeRunConfiguration" factoryName="Application"
folderName="arkscript" PROGRAM_PARAMS="-fdump-ir -ddd a.ark" REDIRECT_INPUT="false" ELEVATE="false"
USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$PROJECT_DIR$"
PASS_PARENT_ENVS_2="true" PROJECT_NAME="ark" TARGET_NAME="arkscript" CONFIG_NAME="Debug"
RUN_TARGET_PROJECT_NAME="ark" RUN_TARGET_NAME="arkscript">
<envs>
<env name="MallocNanoZone" value="0"/>
</envs>
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask"
enabled="true"/>
</method>
</configuration>
<configuration default="false" name="a.ark" type="CMakeRunConfiguration" factoryName="Application" folderName="arkscript" PROGRAM_PARAMS="-fdump-ir a.ark" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$PROJECT_DIR$" PASS_PARENT_ENVS_2="true" PROJECT_NAME="ark" TARGET_NAME="arkscript" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="ark" RUN_TARGET_NAME="arkscript">
<envs>
<env name="MallocNanoZone" value="0" />
</envs>
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
</component>
41 changes: 39 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,49 @@

### 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:asUTCDate` 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
- utcOffsetMinutes
- makeUTCTimestamp
- timestamps: year0, year1970, year200
- toUTCTimestamp
- asUTCDate
- 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
- utcOffsetRepr
- 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

Expand Down
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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})
Expand Down
2 changes: 2 additions & 0 deletions include/Ark/Builtins/Builtins.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ namespace Ark::internal::Builtins
namespace Time
{
ARK_BUILTIN(timeSinceEpoch);
ARK_BUILTIN(timestampToDate);
ARK_BUILTIN(parseDate);
}

namespace System
Expand Down
2 changes: 1 addition & 1 deletion lib/std
2 changes: 2 additions & 0 deletions src/arkreactor/Builtins/Builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ namespace Ark::internal::Builtins

// Time
{ "time", Value(Time::timeSinceEpoch) },
{ "builtin__time:asUTCDate", Value(Time::timestampToDate) },
{ "builtin__time:parseDate", Value(Time::parseDate) },

// System
{ "builtin__sys:platform", platform },
Expand Down
32 changes: 23 additions & 9 deletions src/arkreactor/Builtins/List.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <fmt/core.h>

#include <Ark/TypeChecker.hpp>
#include <Ark/VM/DefaultValues.hpp>

namespace Ark::internal::Builtins::List
{
Expand All @@ -22,14 +23,25 @@ namespace Ark::internal::Builtins::List

Value findInList(std::vector<Value>& 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<int>(std::distance<decltype(n[0].list().begin())>(n[0].list().begin(), it)));
const long offset = n.size() == 3 ? static_cast<long>(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<int>(std::distance<decltype(n[0].list().begin())>(n[0].list().begin() + offset, it) + offset));
}
return Value(-1);
}

Expand All @@ -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<std::size_t>(n[0].number());
Expand All @@ -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();
Expand Down
87 changes: 86 additions & 1 deletion src/arkreactor/Builtins/Time.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
#include <Ark/Builtins/Builtins.hpp>

#include <Ark/VM/DefaultValues.hpp>
#include <Ark/VM/Value/Dict.hpp>
#include <Ark/TypeChecker.hpp>

#undef abs
#include <chrono>

#include <Ark/VM/VM.hpp>
#include <newlib/gmtime_r.h>

namespace Ark::internal::Builtins::Time
{
Expand All @@ -15,11 +19,92 @@ namespace Ark::internal::Builtins::Time
* =end
* @author https://github.com/SuperFola
*/
// cppcheck-suppress constParameterReference
Value timeSinceEpoch(std::vector<Value>& n [[maybe_unused]], VM* vm [[maybe_unused]])
{
const auto now = std::chrono::system_clock::now();
const auto epoch = now.time_since_epoch();
const auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(epoch);
return Value(static_cast<double>(microseconds.count()) / 1000000);
}

Value timestampToDate(std::vector<Value>& n, VM* vm [[maybe_unused]])
{
if (!types::check(n, ValueType::Number))
throw types::TypeCheckingError(
"asUTCDate",
{ { types::Contract {
{ types::Typedef("timestamp", ValueType::Number) } } } },
n);

nl_tm calendar_time {};
nl_gmtime_r(static_cast<long long>(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<double>(static_cast<long long>(n[0].number()));

dict.set(Value("millisecond"), Value(static_cast<int>(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<int, MonthsPerYear> 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<std::size_t>(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<Value>& 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));
}
}
2 changes: 1 addition & 1 deletion tests/unittests/TestsHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void updateExpectedFile(const TestData& data, const std::string& actual)
f.close();
}
}

void iterTestFiles(const std::string& folder, std::function<void(TestData&&)>&& test, IterTestFilesParam&& params)
{
boost::ut::test(folder) = [&] {
Expand Down
4 changes: 2 additions & 2 deletions tests/unittests/resources/CompilerSuite/ir/99bottles.expected
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
page_0
PUSH_RETURN_ADDRESS L0
BUILTIN 87
BUILTIN 88
BUILTIN 89
BUILTIN 90
BUILTIN 91
Expand All @@ -25,6 +23,8 @@ page_0
BUILTIN 109
BUILTIN 110
BUILTIN 111
BUILTIN 112
BUILTIN 113
CALL_BUILTIN 9, 25
.L0:
POP 0
Expand Down
2 changes: 1 addition & 1 deletion tests/unittests/resources/CompilerSuite/ir/plugin.expected
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading
Loading