Skip to content

Commit

Permalink
Add initial highlighted code snippets
Browse files Browse the repository at this point in the history
  • Loading branch information
jeaye committed Jan 3, 2025
1 parent eeab30e commit ad7f0ac
Show file tree
Hide file tree
Showing 12 changed files with 378 additions and 122 deletions.
5 changes: 4 additions & 1 deletion compiler+runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ set(
-Wno-implicit-fallthrough
-Wno-covered-switch-default
-Wno-invalid-offsetof
# TODO: Ignore deprecations
-Wno-deprecated-declarations
-Wno-c++23-extensions
-fno-common
-fno-rtti
-fexceptions
Expand Down Expand Up @@ -154,7 +155,9 @@ add_library(
src/cpp/jank/util/clang_format.cpp
src/cpp/jank/util/string_builder.cpp
src/cpp/jank/profile/time.cpp
src/cpp/jank/ui/highlight.cpp
src/cpp/jank/error.cpp
src/cpp/jank/error/report.cpp
src/cpp/jank/read/source.cpp
src/cpp/jank/read/lex.cpp
src/cpp/jank/read/parse.cpp
Expand Down
8 changes: 8 additions & 0 deletions compiler+runtime/include/cpp/jank/error/report.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

#include <jank/error.hpp>

namespace jank::error
{
void report(error_ptr e);
}
1 change: 1 addition & 0 deletions compiler+runtime/include/cpp/jank/runtime/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ namespace jank::runtime
native_persistent_string output_dir;
module::loader module_loader;

var_ptr current_file_var{};
var_ptr current_ns_var{};
var_ptr in_ns_var{};
var_ptr compile_files_var{};
Expand Down
19 changes: 19 additions & 0 deletions compiler+runtime/include/cpp/jank/ui/highlight.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include <memory>

namespace ftxui
{
using Element = std::shared_ptr<struct Node>;
}

namespace jank
{
struct native_persistent_string;

namespace ui
{
ftxui::Element
highlight(native_persistent_string const &code, size_t const line_start, size_t const line_end);
}
}
3 changes: 1 addition & 2 deletions compiler+runtime/src/cpp/jank/analyze/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ namespace jank
native_persistent_string const &message,
read::source const &source)
{
/* TODO: File name. */
return runtime::make_box<error::base>(gc{}, kind, message, source);
}
}
Expand Down Expand Up @@ -1018,7 +1017,7 @@ namespace jank::analyze
if(found_var.is_none())
{
return make_error(error::kind::analysis_unresolved_var,
fmt::format("unable to resolve var '{}'", qualified_sym->to_string()),
fmt::format("Unable to resolve var '{}'", qualified_sym->to_string()),
meta_source(o));
}

Expand Down
24 changes: 17 additions & 7 deletions compiler+runtime/src/cpp/jank/error.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include <jank/error.hpp>
#include <jank/runtime/context.hpp>
#include <jank/runtime/core/to_string.hpp>

namespace jank::error
{
Expand All @@ -22,25 +24,33 @@ namespace jank
{
error_ptr make_error(error::kind const kind, native_persistent_string const &message)
{
/* TODO: File name. */
return runtime::make_box<error::base>(gc{}, kind, message, read::source{ "", {}, {} });
auto const file{ runtime::__rt_ctx->current_file_var->deref() };
return runtime::make_box<error::base>(gc{},
kind,
message,
read::source{ runtime::to_string(file), {}, {} });
}

error_ptr make_error(error::kind const kind,
native_persistent_string const &message,
read::source_position const &start)
{
/* TODO: File name. */
/* NOLINTNEXTLINE(cppcoreguidelines-slicing) */
return runtime::make_box<error::base>(gc{}, kind, message, read::source{ "", start, start });
auto const file{ runtime::__rt_ctx->current_file_var->deref() };
return runtime::make_box<error::base>(gc{},
kind,
message,
read::source{ runtime::to_string(file), start, start });
}

error_ptr make_error(error::kind const kind,
native_persistent_string const &message,
read::source_position const &start,
read::source_position const &end)
{
/* NOLINTNEXTLINE(cppcoreguidelines-slicing) */
return runtime::make_box<error::base>(gc{}, kind, message, read::source{ "", start, end });
auto const file{ runtime::__rt_ctx->current_file_var->deref() };
return runtime::make_box<error::base>(gc{},
kind,
message,
read::source{ runtime::to_string(file), start, end });
}
}
138 changes: 138 additions & 0 deletions compiler+runtime/src/cpp/jank/error/report.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#include <iostream>
#include <algorithm>

#include <fmt/format.h>

#include <ftxui/dom/elements.hpp>
#include <ftxui/screen/screen.hpp>
#include <ftxui/screen/string.hpp>

#include <jank/util/mapped_file.hpp>
#include <jank/error/report.hpp>
#include <jank/ui/highlight.hpp>
#include <jank/native_persistent_string/fmt.hpp>

namespace jank::error
{
using namespace jank;
using namespace jank::runtime;
using namespace ftxui;

Element snippet(error_ptr const e)
{
static constexpr size_t max_body_lines{ 5 };
static constexpr size_t min_body_lines{ 1 };

static constexpr size_t max_top_margin_lines{ 2 };

/* Top margin:
* Min: 1 line
* Max: 2 lines
*
* If the count goes negative, use one blank line.
*
* Bottom margin:
* Always 0
*
* Code body:
* Min: 1 line
* Max: 5 lines
*
* If the error spans more than the max, just show up to the max.
*/

auto const body_range{
std::min(std::max(e->source.end.line - e->source.start.line, min_body_lines), max_body_lines)
};
auto const top_margin{ std::min(e->source.start.line - 1, max_top_margin_lines) };
auto const line_start{ e->source.start.line - top_margin };
auto const line_end{ e->source.start.line + body_range };

std::vector<Element> line_numbers;
for(auto i{ static_cast<ssize_t>(line_start) }; i < static_cast<ssize_t>(line_end); ++i)
{
if(i < 1)
{
line_numbers.emplace_back(text(" "));
}
else
{
line_numbers.emplace_back(text(std::to_string(i)));
}
}

auto const file(util::map_file(e->source.file_path));
if(file.is_err())
{
/* TODO: Return result. */
throw std::runtime_error{ fmt::format("unable to map file {} due to error: {}",
e->source.file_path,
file.expect_err()) };
}

return window(
text(
fmt::format(" {}:{}:{} ", e->source.file_path, e->source.start.line, e->source.start.col)),
hbox(
{ vbox(line_numbers) | color(Color::GrayLight),
separator(),
ui::highlight({ file.expect_ok().head, file.expect_ok().size }, line_start, line_end) }));
}

void report(error_ptr const e)
{
static constexpr size_t max_width{ 80 };

auto header{ [&](std::string const &title) {
auto const padding_count(max_width - 2 - title.size());
std::string padding;
for(size_t i{}; i < padding_count; ++i)
{
padding.insert(padding.size(), "");
}
return hbox({
text(""),
text(title) | color(Color::BlueLight),
text(" "),
text(padding),
});
} };

auto error{ vbox({ header(kind_str(e->kind)),
hbox({
text("error: ") | bold | color(Color::Red),
text(e->message) | bold,
}) }) };

/* TODO: Context. */
//auto context{ vbox(
// { header("context"),
// vbox({
// hbox({ text("compiling module "), text("kitten.main") | color(Color::Yellow) }),
// hbox({
// text("└─ requiring module "),
// text("kitten.nap") | color(Color::Yellow),

// }),
// hbox({
// text(" └─ compiling function "),
// text("kitten.nap/") | color(Color::Yellow),
// text("nap") | color(Color::Green),
// }),
// }) }) };

auto document{ vbox({
error,
text("\n"),
snippet(e),
text("\n"),
//context(),
}) };

document = document | size(WIDTH, LESS_THAN, max_width);

auto screen{ Screen::Create(Dimension::Full(), Dimension::Fit(document)) };
Render(screen, document);
std::cout << screen.ToString() << '\0' << std::endl;
}
}
23 changes: 18 additions & 5 deletions compiler+runtime/src/cpp/jank/read/lex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include <jank/read/lex.hpp>
#include <jank/runtime/object.hpp>
#include <jank/runtime/context.hpp>
#include <jank/runtime/core/to_string.hpp>

using namespace std::string_view_literals;

Expand Down Expand Up @@ -284,18 +286,29 @@ namespace jank::read::lex
native_persistent_string const &message,
movable_position const &start)
{
/* TODO: File name. */
/* NOLINTNEXTLINE(cppcoreguidelines-slicing) */
return runtime::make_box<error::base>(gc{}, kind, message, source{ "", start, start });
auto const file{ runtime::__rt_ctx->current_file_var->deref() };
return runtime::make_box<error::base>(gc{},
kind,
message,
/* NOLINTNEXTLINE(cppcoreguidelines-slicing) */
source{ runtime::to_string(file), start, start });
}

static error_ptr make_error(error::kind const kind,
native_persistent_string const &message,
movable_position const &start,
movable_position const &end)
{
/* NOLINTNEXTLINE(cppcoreguidelines-slicing) */
return runtime::make_box<error::base>(gc{}, kind, message, source{ "", start, end });
auto const file{ runtime::__rt_ctx->current_file_var->deref() };
fmt::println("make_error message '{}' file '{}'",
message.c_str(),
runtime::to_string(file).c_str());
__builtin_debugtrap();
return runtime::make_box<error::base>(gc{},
kind,
message,
/* NOLINTNEXTLINE(cppcoreguidelines-slicing) */
source{ runtime::to_string(file), start, end });
}

option<error_ptr> processor::check_whitespace(native_bool const found_space)
Expand Down
11 changes: 6 additions & 5 deletions compiler+runtime/src/cpp/jank/read/parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ namespace jank::read::parse
->push_thread_bindings(obj::persistent_hash_map::create_unique(
std::make_pair(splicing_allowed_var, obj::boolean::true_const())))
.expect_ok();
util::scope_exit const finally{ [&]() { __rt_ctx->pop_thread_bindings().expect_ok(); } };
util::scope_exit const finally{ [] { __rt_ctx->pop_thread_bindings().expect_ok(); } };

runtime::detail::native_transient_vector ret;
for(auto it(begin()); it != end(); ++it)
Expand All @@ -314,6 +314,7 @@ namespace jank::read::parse
}

expected_closer = prev_expected_closer;

return object_source_info{
make_box<obj::persistent_list>(std::in_place, ret.rbegin(), ret.rend()),
start_token,
Expand All @@ -332,7 +333,7 @@ namespace jank::read::parse
->push_thread_bindings(obj::persistent_hash_map::create_unique(
std::make_pair(splicing_allowed_var, obj::boolean::true_const())))
.expect_ok();
util::scope_exit const finally{ [&]() { __rt_ctx->pop_thread_bindings().expect_ok(); } };
util::scope_exit const finally{ [] { __rt_ctx->pop_thread_bindings().expect_ok(); } };

runtime::detail::native_transient_vector ret;
for(auto it(begin()); it != end(); ++it)
Expand Down Expand Up @@ -368,7 +369,7 @@ namespace jank::read::parse
->push_thread_bindings(obj::persistent_hash_map::create_unique(
std::make_pair(splicing_allowed_var, obj::boolean::true_const())))
.expect_ok();
util::scope_exit const finally{ [&]() { __rt_ctx->pop_thread_bindings().expect_ok(); } };
util::scope_exit const finally{ [] { __rt_ctx->pop_thread_bindings().expect_ok(); } };

runtime::detail::native_persistent_array_map ret;
for(auto it(begin()); it != end(); ++it)
Expand Down Expand Up @@ -605,7 +606,7 @@ namespace jank::read::parse
->push_thread_bindings(obj::persistent_hash_map::create_unique(
std::make_pair(splicing_allowed_var, obj::boolean::true_const())))
.expect_ok();
util::scope_exit const finally{ [&]() { __rt_ctx->pop_thread_bindings().expect_ok(); } };
util::scope_exit const finally{ [] { __rt_ctx->pop_thread_bindings().expect_ok(); } };

runtime::detail::native_transient_hash_set ret;
for(auto it(begin()); it != end(); ++it)
Expand Down Expand Up @@ -930,7 +931,7 @@ namespace jank::read::parse
(splice ? "clojure.core/unquote-splicing" : "clojure.core/unquote"))
->equal(*item);
},
[]() { return false; },
[] { return false; },
form);
}

Expand Down
11 changes: 11 additions & 0 deletions compiler+runtime/src/cpp/jank/runtime/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ namespace jank::runtime
, module_loader{ *this, opts.module_path }
{
auto const core(intern_ns(make_box<obj::symbol>("clojure.core")));

auto const file_sym(make_box<obj::symbol>("clojure.core/*file*"));
current_file_var = core->intern_var(file_sym);
current_file_var->bind_root(make_box("NO_SOURCE_PATH"));
current_file_var->dynamic.store(true);

auto const ns_sym(make_box<obj::symbol>("clojure.core/*ns*"));
current_ns_var = core->intern_var(ns_sym);
current_ns_var->bind_root(core);
Expand Down Expand Up @@ -139,6 +145,11 @@ namespace jank::runtime
fmt::format("unable to map file {} due to error: {}", path, file.expect_err())
};
}

binding_scope const preserve{ *this,
obj::persistent_hash_map::create_unique(
std::make_pair(current_file_var, make_box(path))) };

return eval_string({ file.expect_ok().head, file.expect_ok().size });
}

Expand Down
Loading

0 comments on commit ad7f0ac

Please sign in to comment.