• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ArkScript-lang / Ark / 14647441324

24 Apr 2025 05:07PM UTC coverage: 83.165% (+2.7%) from 80.417%
14647441324

push

github

SuperFola
feat(vm): compressing identical traces when displaying the stacktrace of an error

21 of 21 new or added lines in 1 file covered. (100.0%)

270 existing lines in 10 files now uncovered.

6580 of 7912 relevant lines covered (83.16%)

79046.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.8
/src/arkreactor/Exceptions.cpp
1
#include <Ark/Exceptions.hpp>
2

3
#include <sstream>
4
#include <algorithm>
5
#include <fmt/core.h>
6
#include <fmt/color.h>
7
#include <fmt/ostream.h>
8

9
#include <Ark/Constants.hpp>
10
#include <Ark/Utils.hpp>
11
#include <Ark/Files.hpp>
12
#include <Ark/Literals.hpp>
13
#include <Ark/Compiler/AST/Node.hpp>
14

15
namespace Ark::Diagnostics
16
{
17
    struct LineColorContextCounts
170✔
18
    {
19
        int open_parentheses = 0;
170✔
20
        int open_square_braces = 0;
170✔
21
        int open_curly_braces = 0;
170✔
22
    };
23

24
    inline bool isPairableChar(const char c)
×
25
    {
×
26
        return c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}';
×
27
    }
28

29
    void colorizeLine(const std::string& line, LineColorContextCounts& line_color_context_counts, std::ostream& ss)
×
30
    {
×
31
        // clang-format off
32
        constexpr std::array pairing_color {
×
33
            fmt::color::light_blue,
34
            fmt::color::light_green,
35
            fmt::color::light_salmon,
36
            fmt::color::light_yellow,
37
            fmt::color::light_cyan,
38
            fmt::color::light_coral
39
        };
40
        // clang-format on
41
        constexpr std::size_t pairing_color_size = pairing_color.size();
×
42

43
        for (const char& c : line)
×
44
        {
45
            if (isPairableChar(c))
×
46
            {
47
                std::size_t pairing_color_index = 0;
×
48

49
                switch (c)
×
50
                {
×
51
                    case '(':
52
                        pairing_color_index = static_cast<std::size_t>(std::abs(line_color_context_counts.open_parentheses)) % pairing_color_size;
×
53
                        line_color_context_counts.open_parentheses++;
×
54
                        break;
×
55
                    case ')':
56
                        line_color_context_counts.open_parentheses--;
×
57
                        pairing_color_index = static_cast<std::size_t>(std::abs(line_color_context_counts.open_parentheses)) % pairing_color_size;
×
58
                        break;
×
59
                    case '[':
60
                        pairing_color_index = static_cast<std::size_t>(std::abs(line_color_context_counts.open_square_braces)) % pairing_color_size;
×
61
                        line_color_context_counts.open_square_braces++;
×
62
                        break;
×
63
                    case ']':
64
                        line_color_context_counts.open_square_braces--;
×
65
                        pairing_color_index = static_cast<std::size_t>(std::abs(line_color_context_counts.open_square_braces)) % pairing_color_size;
×
66
                        break;
×
67
                    case '{':
68
                        pairing_color_index = static_cast<std::size_t>(std::abs(line_color_context_counts.open_curly_braces)) % pairing_color_size;
×
69
                        line_color_context_counts.open_curly_braces++;
×
70
                        break;
×
71
                    case '}':
72
                        line_color_context_counts.open_curly_braces--;
×
73
                        pairing_color_index = static_cast<std::size_t>(std::abs(line_color_context_counts.open_curly_braces)) % pairing_color_size;
×
74
                        break;
×
75
                    default:
76
                        break;
×
77
                }
×
78

79
                fmt::print(ss, "{}", fmt::styled(c, fmt::fg(pairing_color[pairing_color_index])));
×
80
            }
×
81
            else
82
                fmt::print(ss, "{}", c);
×
83
        }
×
84
    }
×
85

86
    void makeContext(std::ostream& os, const std::string& code, const std::size_t target_line, const std::size_t col_start, const std::size_t sym_size, const bool whole_line, const bool colorize)
170✔
87
    {
170✔
88
        using namespace Ark::literals;
89

90
        const std::vector<std::string> ctx = Utils::splitString(code, '\n');
170✔
91
        if (target_line >= ctx.size())
170✔
92
            return;
×
93

94
        const std::size_t first_line = target_line >= 3 ? target_line - 3 : 0;
170✔
95
        const std::size_t last_line = (target_line + 3) <= ctx.size() ? target_line + 3 : ctx.size();
170✔
96
        std::size_t overflow = (col_start + sym_size < ctx[target_line].size()) ? 0 : col_start + sym_size - ctx[target_line].size();  // number of characters that are on more lines below
170✔
97
        LineColorContextCounts line_color_context_counts;
170✔
98

99
        for (auto i = first_line; i < last_line; ++i)
593✔
100
        {
101
            fmt::print(os, "{: >5} |{}", i + 1, !ctx[i].empty() ? " " : "");
423✔
102
            if (colorize)
423✔
103
                colorizeLine(ctx[i], line_color_context_counts, os);
×
104
            else
105
                fmt::print(os, "{}", ctx[i]);
423✔
106
            fmt::print(os, "\n");
423✔
107

108
            if (i == target_line || (i > target_line && overflow > 0))
423✔
109
            {
110
                fmt::print(os, "      |");
172✔
111

112
                if (!whole_line)
172✔
113
                {
114
                    // if we have an overflow then we start at the beginning of the line
115
                    const std::size_t curr_col_start = (overflow == 0) ? col_start : 0;
114✔
116
                    // if we have an overflow, it is used as the end of the line
117
                    const std::size_t col_end = (i == target_line) ? std::min<std::size_t>(col_start + sym_size, ctx[target_line].size())
116✔
118
                                                                   : std::min<std::size_t>(overflow, ctx[i].size());
2✔
119
                    // update the overflow to avoid going here again if not needed
120
                    overflow = (overflow > ctx[i].size()) ? overflow - ctx[i].size() : 0;
114✔
121

122
                    fmt::print(
342✔
123
                        os,
114✔
124
                        "{: <{}}{:~<{}}\n",
114✔
125
                        // padding of spaces
126
                        " ",
127
                        std::max(1_z, curr_col_start),  // fixing padding when the error is on the first character
114✔
128
                        // underline the error in red
129
                        fmt::styled("^", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()),
114✔
130
                        col_end - curr_col_start);
114✔
131
                }
114✔
132
                else
133
                {
134
                    // first non-whitespace character of the line
135
                    // +1 for the leading whitespace after `    |` before the code
136
                    const std::size_t curr_col_start = ctx[i].find_first_not_of(" \t\v") + 1;
58✔
137

138
                    // highlight the current line but skip any leading whitespace
139
                    fmt::print(
116✔
140
                        os,
58✔
141
                        "{: <{}}{:~<{}}\n",
58✔
142
                        // padding of spaces
143
                        " ",
144
                        curr_col_start,
145
                        // underline the whole line in red
146
                        fmt::styled("^", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()),
58✔
147
                        ctx[target_line].size() - curr_col_start);
58✔
148
                }
58✔
149
            }
172✔
150
        }
423✔
151
    }
170✔
152

153
    template <typename T>
154
    void helper(std::ostream& os, const std::string& message, const bool colorize, const std::string& filename, const std::string& code, const T& expr,
113✔
155
                const std::size_t line, std::size_t column, const std::size_t sym_size)
156
    {
113✔
157
        if (filename != ARK_NO_NAME_FILE)
113✔
158
            fmt::print(os, "In file {}\n", filename);
113✔
159
        fmt::print(os, "At {} @ {}:{}\n", expr, line + 1, column);
113✔
160

161
        if (!code.empty())
113✔
162
            makeContext(os, code, line, column, sym_size, /* whole_line= */ false, colorize);
112✔
163

164
        const auto message_lines = Utils::splitString(message, '\n');
113✔
165
        for (const auto& text : message_lines)
226✔
166
            fmt::print(os, "        {}\n", text);
113✔
167
    }
113✔
168

UNCOV
169
    std::string makeContextWithNode(const std::string& message, const internal::Node& node)
×
UNCOV
170
    {
×
UNCOV
171
        std::stringstream ss;
×
172

173
        std::size_t size = 3;
×
UNCOV
174
        if (node.isStringLike())
×
UNCOV
175
            size = node.string().size();
×
176

UNCOV
177
        helper(
×
UNCOV
178
            ss,
×
179
            message,
×
180
            true,
181
            node.filename(),
×
182
            (node.filename() == ARK_NO_NAME_FILE) ? "" : Utils::readFile(node.filename()),
×
UNCOV
183
            node.repr(),
×
UNCOV
184
            node.line(),
×
UNCOV
185
            node.col(),
×
UNCOV
186
            size);
×
187

UNCOV
188
        return ss.str();
×
UNCOV
189
    }
×
190

191
    void generate(const CodeError& e, std::ostream& os, bool colorize)
113✔
192
    {
113✔
193
        if (const char* nocolor = std::getenv("NOCOLOR"); nocolor != nullptr)
113✔
UNCOV
194
            colorize = false;
×
195

196
        std::string escaped_symbol;
113✔
197
        if (e.symbol.has_value())
113✔
198
        {
199
            switch (e.symbol.value().codepoint())
39✔
UNCOV
200
            {
×
UNCOV
201
                case '\n': escaped_symbol = "'\\n'"; break;
×
UNCOV
202
                case '\r': escaped_symbol = "'\\r'"; break;
×
UNCOV
203
                case '\t': escaped_symbol = "'\\t'"; break;
×
204
                case '\v': escaped_symbol = "'\\v'"; break;
10✔
205
                case '\0': escaped_symbol = "EOF"; break;
12✔
206
                case ' ': escaped_symbol = "' '"; break;
29✔
207
                default:
208
                    escaped_symbol = e.symbol.value().c_str();
27✔
209
            }
39✔
210
        }
39✔
211
        else
212
            escaped_symbol = e.expr;
74✔
213

214
        std::string file_content;
113✔
215
        if (e.filename != ARK_NO_NAME_FILE)
113✔
216
            file_content = Utils::readFile(e.filename);
113✔
217

218
        helper(
339✔
219
            os,
113✔
220
            e.what(),
113✔
221
            colorize,
113✔
222
            e.filename,
113✔
223
            file_content,
224
            escaped_symbol,
225
            e.line,
113✔
226
            e.col,
113✔
227
            e.expr.size());
113✔
228
    }
113✔
229
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc