Skip to content
Closed
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
2 changes: 1 addition & 1 deletion compiler+runtime/bin/build-clang
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ echo "Using ${make_j} cores to build"

srcdir="${PWD}"

llvm_url="https://github.com/jank-lang/llvm-project.git"
llvm_url="https://github.com/pfeodrippe/llvm-project.git"
llvm_version=22
llvm_branch="jank-snapshot/llvm${llvm_version}"

Expand Down
20 changes: 20 additions & 0 deletions compiler+runtime/src/cpp/jank/analyze/cpp_util.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include <algorithm>

#include <clang/AST/Decl.h>
#include <clang/AST/Type.h>
#include <clang/Interpreter/CppInterOp.h>
#include <clang/Sema/Sema.h>
#include <Interpreter/Compatibility.h>
Expand Down Expand Up @@ -300,6 +302,24 @@ namespace jank::analyze::cpp_util
}
/* TODO: Handle typed object refs, too. */

auto const qual_type{ clang::QualType::getFromOpaquePtr(type) };
if(auto const *typedef_type
= llvm::dyn_cast_or_null<clang::TypedefType>(qual_type.getTypePtrOrNull()))
{
if(auto const *alias_decl = typedef_type->getDecl())
{
auto alias_name{ alias_decl->getQualifiedNameAsString() };
if(!alias_name.empty())
{
if(Cpp::IsPointerType(type))
{
alias_name += "*";
}
return alias_name;
}
}
}

if(auto const scope{ Cpp::GetScopeFromType(type) }; scope)
{
auto name{ get_qualified_name(scope) };
Expand Down
10 changes: 0 additions & 10 deletions compiler+runtime/src/cpp/jank/analyze/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4351,16 +4351,6 @@ namespace jank::analyze
->add_usage(read::parse::reparse_nth(l, 0));
}

if(Cpp::IsStaticDatamember(member_scope))
{
return error::analyze_known_issue(
"A blocking Clang bug prevents access to static members in some scenarios. See "
"https://github.com/llvm/llvm-project/issues/146956 for details.",
object_source(member),
latest_expansion(macro_expansions))
->add_usage(read::parse::reparse_nth(l, 0));
}

val->val_kind = expr::cpp_value::value_kind::variable;
val->type = Cpp::GetLValueReferenceType(Cpp::GetTypeFromScope(member_scope));
val->scope = member_scope;
Expand Down
6 changes: 6 additions & 0 deletions compiler+runtime/src/cpp/jank/codegen/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,12 @@ namespace jank::codegen
R"(jank::runtime::make_box<jank::runtime::obj::uuid>("{}"))",
typed_o->to_string());
}
else if constexpr(std::same_as<T, runtime::obj::inst>)
{
util::format_to(buffer,
R"(jank::runtime::make_box<jank::runtime::obj::inst>("{}"))",
util::escape(typed_o->to_string()));
}
else if constexpr(std::same_as<T, runtime::obj::persistent_string>)
{
util::format_to(buffer,
Expand Down
247 changes: 223 additions & 24 deletions compiler+runtime/src/cpp/jank/runtime/obj/inst.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include <array>
#include <cctype>
#include <iostream>
#include <locale>
#include <sstream>
#include <string_view>

#include <jank/runtime/core/make_box.hpp>
#include <jank/runtime/obj/inst.hpp>
Expand All @@ -14,46 +17,242 @@ namespace jank::runtime::obj
{
}

#ifdef _LIBCPP_VERSION
/* The current version of libc++ within LLVM does not implement
* std::chrono::parse() (a C++20 feature). Until it is added or an alternative
* is used, inst parsing will be disabled
*
* To find progress for this feature in LLVM goto:
* https://github.com/llvm/llvm-project/issues/99982
*/
static inst_time_point inst_from_string(jtl::immutable_string const &)
namespace
{
throw make_box("'#inst' parsing not currently supported.").erase();
[[noreturn]]
void throw_inst_parse_error(jtl::immutable_string const &input)
{
throw make_box(util::format("Unrecognized date/time syntax: {}", input)).erase();
}

#ifdef _LIBCPP_VERSION

bool consume_if(std::string_view &remaining, char const expected)
{
if(!remaining.empty() && remaining.front() == expected)
{
remaining.remove_prefix(1);
return true;
}
return false;
}

bool starts_with_digits(std::string_view const &remaining, size_t const digits)
{
if(remaining.size() < digits)
{
return false;
}
for(size_t i{}; i < digits; ++i)
{
if(!std::isdigit(static_cast<unsigned char>(remaining[i])))
{
return false;
}
}
return true;
}

int parse_fixed_digits(std::string_view &remaining,
size_t const digits,
jtl::immutable_string const &original)
{
if(!starts_with_digits(remaining, digits))
{
throw_inst_parse_error(original);
}

int value{};
for(size_t i{}; i < digits; ++i)
{
auto const c(static_cast<unsigned char>(remaining[i]));
value = (value * 10) + (c - '0');
}
remaining.remove_prefix(digits);
return value;
}

int parse_fractional_millis(std::string_view &remaining, jtl::immutable_string const &original)
{
if(!consume_if(remaining, '.'))
{
return 0;
}

int value{};
size_t stored_digits{};
size_t total_digits{};
while(!remaining.empty() && std::isdigit(static_cast<unsigned char>(remaining.front())))
{
if(stored_digits < 9)
{
auto const digit(static_cast<unsigned char>(remaining.front()) - '0');
value = (value * 10) + digit;
++stored_digits;
}
++total_digits;
remaining.remove_prefix(1);
}

if(total_digits == 0)
{
throw_inst_parse_error(original);
}

if(stored_digits == 0)
{
return 0;
}

if(stored_digits > 3)
{
for(size_t i = stored_digits; i > 3; --i)
{
value /= 10;
}
}
else
{
for(size_t i = stored_digits; i < 3; ++i)
{
value *= 10;
}
}

return value;
}

int parse_timezone_offset(std::string_view &remaining, jtl::immutable_string const &original)
{
if(remaining.empty())
{
return 0;
}

auto const indicator(remaining.front());
if(indicator == 'Z' || indicator == 'z')
{
remaining.remove_prefix(1);
return 0;
}

if(indicator != '+' && indicator != '-')
{
throw_inst_parse_error(original);
}

auto const sign(indicator == '-' ? -1 : 1);
remaining.remove_prefix(1);
auto const tz_hour(parse_fixed_digits(remaining, 2, original));
int tz_minute{};

if(consume_if(remaining, ':'))
{
tz_minute = parse_fixed_digits(remaining, 2, original);
}
else if(starts_with_digits(remaining, 2))
{
tz_minute = parse_fixed_digits(remaining, 2, original);
}

if(tz_hour > 23 || tz_minute > 59)
{
throw_inst_parse_error(original);
}

return sign * ((tz_hour * 60) + tz_minute);
}
}
#else

static inst_time_point inst_from_string(jtl::immutable_string const &s)
{
static std::vector const formats{ "%FT%T%Oz", "%FT%T%z", "%FT%T", "%F" };
using namespace std::chrono;

std::string_view remaining{ s.c_str(), s.size() };

inst_time_point o;
bool parsed{ false };
auto const year(parse_fixed_digits(remaining, 4, s));

for(auto const format : formats)
int month{ 1 };
int day{ 1 };
if(consume_if(remaining, '-'))
{
std::istringstream is{ static_cast<std::string>(s) };
is.imbue(std::locale("en_US.utf-8"));
is >> std::chrono::parse(format, o);
month = parse_fixed_digits(remaining, 2, s);
if(consume_if(remaining, '-'))
{
day = parse_fixed_digits(remaining, 2, s);
}
}

if(!is.fail() && is.peek() == EOF)
int hour{};
int minute{};
int second{};
int millisecond{};

if(!remaining.empty() && (remaining.front() == 'T' || remaining.front() == 't'))
{
remaining.remove_prefix(1);
hour = parse_fixed_digits(remaining, 2, s);
if(!consume_if(remaining, ':'))
{
throw_inst_parse_error(s);
}
minute = parse_fixed_digits(remaining, 2, s);
if(!consume_if(remaining, ':'))
{
parsed = true;
break;
throw_inst_parse_error(s);
}
second = parse_fixed_digits(remaining, 2, s);
millisecond = parse_fractional_millis(remaining, s);
}

if(hour > 23 || minute > 59 || second > 59)
{
throw_inst_parse_error(s);
}

if(!parsed)
auto const offset_minutes(parse_timezone_offset(remaining, s));

if(!remaining.empty())
{
throw make_box(util::format("Unrecognized date/time syntax: {}", s)).erase();
throw_inst_parse_error(s);
}

return o;
auto const ymd(std::chrono::year{ year } / std::chrono::month{ static_cast<unsigned>(month) }
/ std::chrono::day{ static_cast<unsigned>(day) });
if(!ymd.ok())
{
throw_inst_parse_error(s);
}

auto const day_point(std::chrono::sys_days{ ymd });
auto sys_time_ms(std::chrono::sys_time<std::chrono::milliseconds>{
std::chrono::duration_cast<std::chrono::milliseconds>(day_point.time_since_epoch()) });
sys_time_ms += std::chrono::hours{ hour } + std::chrono::minutes{ minute }
+ std::chrono::seconds{ second } + std::chrono::milliseconds{ millisecond };
sys_time_ms -= std::chrono::minutes{ offset_minutes };

return inst_time_point{ std::chrono::time_point_cast<inst_time_point::duration>(sys_time_ms) };
}
#else
static inst_time_point inst_from_string(jtl::immutable_string const &s)
{
constexpr std::array formats{ "%FT%T%Oz", "%FT%T%z", "%FT%T", "%F", "%Y-%m", "%Y" };

inst_time_point parsed_value;
for(auto const *format : formats)
{
std::istringstream is{ static_cast<std::string>(s) };
is.imbue(std::locale("en_US.utf-8"));
is >> std::chrono::parse(format, parsed_value);

if(!is.fail() && is.peek() == EOF)
{
return parsed_value;
}
}

throw_inst_parse_error(s);
}
#endif

inst::inst(jtl::immutable_string const &s)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(cpp/raw "namespace jank::cpp::constructor::complex::template_instantiation
{
struct foo
{
template <typename T>
foo(T t)
: a(std::to_string(t))
{ }

std::string a{};
};
}")
(let* [arg (cpp/int 53)
d (cpp/jank.cpp.constructor.complex.template_instantiation.foo arg)]
(when (= (cpp/.-a d) "53")
:success))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(fn [] #inst "2025-09-01T20:47:03.713-00:00")
(when (= (str ((fn [] #inst "2025-09-01T20:47:03.713-00:00")))
"2025-09-01T20:47:03.713-00:00")
:success)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(when (= (str #inst "2025-09-01T20:47:03.713-00:00") "2025-09-01T20:47:03.713-00:00")
:success)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(when (= (str #inst "2025-09-01T20:47:03.713") "2025-09-01T20:47:03.713-00:00")
:success)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(when (= (str #inst "2025-09-01") "2025-09-01T00:00:00.000-00:00")
:success)
Loading
Loading