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

ArkScript-lang / Ark / 17621217597

10 Sep 2025 05:06PM UTC coverage: 90.868% (+0.02%) from 90.848%
17621217597

push

github

SuperFola
feat(vm, tests): improving the stack overflow error message, and adding proper tests for it

7960 of 8760 relevant lines covered (90.87%)

158460.88 hits per line

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

42.16
/src/arkreactor/Error/PrettyPrinting.cpp
1
#include <Ark/Error/PrettyPrinting.hpp>
2

3
#include <Ark/Constants.hpp>
4
#include <Ark/Utils/Files.hpp>
5
#include <Ark/Utils/Utils.hpp>
6

7
#include <array>
8
#include <cassert>
9

10
#include <fmt/color.h>
11
#include <fmt/ostream.h>
12

13
namespace Ark::Diagnostics
14
{
15
    [[nodiscard]] bool isPairableChar(const char c)
×
16
    {
×
17
        return c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}';
×
18
    }
19

20
    void colorizeLine(const std::string& line, LineColorContextCounts& ctx, std::ostream& os)
×
21
    {
×
22
        // clang-format off
23
        constexpr std::array pairing_color {
×
24
            fmt::color::light_blue,
25
            fmt::color::light_green,
26
            fmt::color::light_salmon,
27
            fmt::color::light_yellow,
28
            fmt::color::light_cyan,
29
            fmt::color::light_coral
30
        };
31
        // clang-format on
32
        constexpr std::size_t pairing_color_size = pairing_color.size();
×
33

34
        for (const char c : line)
×
35
        {
36
            if (isPairableChar(c))
×
37
            {
38
                int idx = 0;
×
39

40
                switch (c)
×
41
                {
×
42
                    case '(':
43
                        idx = ctx.open_parentheses;
×
44
                        ctx.open_parentheses++;
×
45
                        break;
×
46
                    case ')':
47
                        ctx.open_parentheses--;
×
48
                        idx = ctx.open_parentheses;
×
49
                        break;
×
50
                    case '[':
51
                        idx = ctx.open_square_braces;
×
52
                        ctx.open_square_braces++;
×
53
                        break;
×
54
                    case ']':
55
                        ctx.open_square_braces--;
×
56
                        idx = ctx.open_square_braces;
×
57
                        break;
×
58
                    case '{':
59
                        idx = ctx.open_curly_braces;
×
60
                        ctx.open_curly_braces++;
×
61
                        break;
×
62
                    case '}':
63
                        ctx.open_curly_braces--;
×
64
                        idx = ctx.open_curly_braces;
×
65
                        break;
×
66
                    default:
67
                        break;
×
68
                }
×
69

70
                const std::size_t pairing_color_index = static_cast<std::size_t>(std::abs(idx)) % pairing_color_size;
×
71
                fmt::print(os, "{}", fmt::styled(c, fmt::fg(pairing_color[pairing_color_index])));
×
72
            }
×
73
            else
74
                fmt::print(os, "{}", c);
×
75
        }
×
76
    }
×
77

78
    Printer::Printer(
538✔
79
        const std::string& filename, const std::size_t target_line,
80
        const std::optional<std::size_t> end_target_line, const bool colorize) :
81
        m_should_colorize(colorize)
269✔
82
    {
269✔
83
        const std::string code = filename == ARK_NO_NAME_FILE ? "" : Utils::readFile(filename);
269✔
84
        m_source = Utils::splitString(code, '\n');
269✔
85

86
        m_window = Window(target_line, end_target_line.value_or(target_line), m_source.size());
269✔
87
        m_current_line = m_window.start;
269✔
88
    }
269✔
89

90
    std::string Printer::sliceCode(const internal::FilePos start, const std::optional<internal::FilePos>& end) const
×
91
    {
×
92
        std::string code;
×
93
        if (!end)
×
94
        {
95
            code = m_source[start.line];
×
96
            Utils::ltrim(Utils::rtrim(code));
×
97
        }
×
98
        else
99
        {
100
            if (start.line == end->line)
×
101
                code = m_source[start.line].substr(start.column, end->column);
×
102
            else
103
            {
104
                code = m_source[start.line].substr(start.column);
×
105

106
                if (end->line - start.line > 1)
×
107
                {
108
                    for (std::size_t i = start.line + 1; i <= end->line - 1; ++i)
×
109
                    {
110
                        code += "\n";
×
111
                        code += m_source[i];
×
112
                    }
×
113
                }
×
114
                code += "\n" + m_source[end->line].substr(0, end->column);
×
115
            }
116
        }
117

118
        return code;
×
119
    }
×
120

121
    void Printer::extendWindow(const std::size_t line_to_include)
3✔
122
    {
3✔
123
        // showing the context will require an ellipsis, to avoid showing too many lines in the error message
124
        if (line_to_include + 3 < m_window.start)
3✔
125
            m_window.skip_start_at = line_to_include + 3;
3✔
126
        m_window.resume_at = m_window.start;
3✔
127

128
        assert(line_to_include <= m_window.start && "line_to_include has to be before the start of our base context, source of errors are always before our errors");
3✔
129
        // due to how context works, if it points to the same file,
130
        // we are guaranteed it will be before our error
131
        m_window.start = line_to_include >= 3 ? line_to_include - 3 : 0;
3✔
132
        m_current_line = m_window.start;
3✔
133
    }
3✔
134

135
    void Printer::printLine(std::ostream& os)
703✔
136
    {
703✔
137
        if (!hasContent())
703✔
138
            return;
×
139

140
        if (m_window.hasSkip() &&
763✔
141
            m_current_line >= m_window.skip_start_at.value() &&
42✔
142
            m_current_line < m_window.resume_at.value())
30✔
143
        {
144
            // do not print the current line, we want to skip 1 or more lines
145
            ++m_current_line;
14✔
146
            return;
14✔
147
        }
148

149
        // show current line with its number
150
        fmt::print(os, "{: >5} |{}", m_current_line + 1, !m_source[m_current_line].empty() ? " " : "");
689✔
151
        if (m_should_colorize)
689✔
152
            colorizeLine(m_source[m_current_line], m_color_ctx, os);
×
153
        else
154
            fmt::print(os, "{}", m_source[m_current_line]);
689✔
155
        fmt::print(os, "\n");
689✔
156

157
        ++m_current_line;
689✔
158

159
        // if skip_start_at is equal to the next line to print, and we have to skip,
160
        // display an ellipsis
161
        if (m_window.skip_start_at &&
717✔
162
            m_current_line == m_window.skip_start_at.value())
28✔
163
            fmt::print(os, "  ... |\n");
3✔
164
    }
703✔
165

166
    bool Printer::isTargetLine() const
703✔
167
    {
703✔
168
        return m_window.target + 1 <= m_current_line && m_current_line <= m_window.target_end + 1;
703✔
169
    }
170

171
    bool Printer::hasContent() const
1,944✔
172
    {
1,944✔
173
        return m_current_line < m_window.end && !m_source.empty() && m_window.target < m_window.end;
1,944✔
174
    }
175

176
    bool Printer::coversLine(const std::size_t line_number) const
16✔
177
    {
16✔
178
        return m_window.start <= line_number && line_number < m_window.end;
16✔
179
    }
180

181
}
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