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

ArkScript-lang / Ark / 20132698241

11 Dec 2025 12:12PM UTC coverage: 90.722% (+0.1%) from 90.587%
20132698241

push

github

SuperFola
chore(tests): update expected tests

8096 of 8924 relevant lines covered (90.72%)

180142.91 hits per line

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

89.47
/src/arkreactor/Error/Diagnostics.cpp
1
#include <Ark/Error/Diagnostics.hpp>
2

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

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

15
namespace Ark::Diagnostics
16
{
17
    using namespace Ark::literals;
18

19
    void showFileLocation(std::ostream& os, const ErrorLocation& loc)
273✔
20
    {
273✔
21
        if (loc.filename != ARK_NO_NAME_FILE)
273✔
22
            fmt::print(os, "In file {}:{}\n", loc.filename, loc.start.line + 1);
273✔
23
    }
273✔
24

25
    void hintWithContext(std::ostream& os, const std::optional<CodeErrorContext>& maybe_context, const bool colorize, const bool start)
12✔
26
    {
12✔
27
        if (!maybe_context)
12✔
28
            return;
×
29

30
        fmt::print(os, "{}", Printer::GhostLinePrefix);
12✔
31
        fmt::print(
36✔
32
            os,
12✔
33
            "{: <{}}{}\n",
12✔
34
            // padding os spaces
35
            " ",
36
            std::max(1_z, maybe_context->at.start.column),  // fixing padding when the error is on the first character
12✔
37
            // underline the parent of the error in red
38
            fmt::styled(
24✔
39
                start
23✔
40
                    ? (maybe_context->is_macro_expansion ? "┌─ macro expansion started here" : "┌─ expression started here")
11✔
41
                    : "└─ ... and ended here",
42
                colorize ? fmt::fg(fmt::color::red) : fmt::text_style()));
12✔
43
    }
12✔
44

45
    void makeContext(
273✔
46
        const ErrorLocation& loc,
47
        std::ostream& os,
48
        const std::optional<CodeErrorContext>& maybe_context,  // can not be populated at runtime, only compile time
49
        const bool colorize)
50
    {
273✔
51
        assert(!(maybe_context && loc.wholeLineIsError()) && "Can not create error context when a context is given AND the whole line has to be underlined");
273✔
52

53
        Printer source_printer(loc.filename, loc.start.line, loc.maybeEndLine(), colorize);
273✔
54
        if (!source_printer.hasContent())
273✔
55
        {
56
            showFileLocation(os, loc);
×
57
            return;
×
58
        }
59

60
        const bool ctx_same_file = maybe_context && maybe_context->filename == loc.filename;
273✔
61
        const bool ctx_in_window = ctx_same_file && maybe_context && source_printer.coversLine(maybe_context->at.start.line);
273✔
62

63
        if (ctx_same_file && !ctx_in_window)
273✔
64
            source_printer.extendWindow(maybe_context->at.start.line);
3✔
65
        else if (maybe_context && !ctx_same_file && !maybe_context->filename.empty())
270✔
66
        {
67
            // show the location of the parent of our error first
68
            fmt::print(os, "Error originated from file {}:{}\n", maybe_context->filename, maybe_context->at.start.line + 1);
1✔
69

70
            std::optional<decltype(internal::FilePos::line)> maybe_end_line = std::nullopt;
1✔
71
            if (maybe_context->at.end)
1✔
72
                maybe_end_line = maybe_context->at.end->line;
1✔
73
            Printer printer(maybe_context->filename, maybe_context->at.start.line, maybe_end_line, colorize);
1✔
74

75
            while (printer.hasContent())
5✔
76
            {
77
                if (printer.isNextLineTheFirstLineOfTarget())
4✔
78
                    hintWithContext(os, maybe_context, colorize, /* start= */ true);
1✔
79
                printer.printLine(os);
4✔
80
                if (printer.isLastLineOfTarget())
4✔
81
                    hintWithContext(os, maybe_context, colorize, /* start= */ false);
1✔
82
            }
83

84
            fmt::print(os, "\n");
1✔
85
        }
1✔
86

87
        showFileLocation(os, loc);
273✔
88

89
        while (source_printer.hasContent())
986✔
90
        {
91
            const std::size_t i = source_printer.current();
713✔
92
            const std::string& line = source_printer.currentLine();
713✔
93

94
            // if the error context is in the current file, point to it as the parent of our error
95
            if (ctx_same_file && i == maybe_context->at.start.line && i < loc.start.line)
713✔
96
                hintWithContext(os, maybe_context, colorize, /* start= */ true);
10✔
97
            source_printer.printLine(os);
713✔
98

99
            // show where the error occurred
100
            if (source_printer.isTargetLine() && !line.empty())
713✔
101
            {
102
                if (!loc.wholeLineIsError())
276✔
103
                {
104
                    const std::size_t line_first_char = (line.find_first_not_of(" \t\v") == std::string::npos) ? 0 : line.find_first_not_of(" \t\v");
141✔
105

106
                    const std::size_t col_start = (i == loc.start.line) ? loc.start.column : line_first_char + 1;
141✔
107
                    // due to the `!loc.wholeLineIsError()` check, we are guaranteed to have a value in loc.end
108
                    const std::size_t col_end = (i == loc.end->line) ? loc.end->column : line.size();
141✔
109

110
                    // ignore the last line that is sometimes erroneous in multiline contexts
111
                    if (i == loc.end->line && loc.end->line != loc.start.line && col_start >= col_end)
141✔
112
                        continue;
3✔
113
                    fmt::print(os, "{}", Printer::GhostLinePrefix);
138✔
114

115
                    // show the error where it's at, using the normal process, if there is no context OR
116
                    // if the context line is different from the error line
117
                    if (!maybe_context || maybe_context->at.start.line != loc.start.line)
138✔
118
                        fmt::print(
372✔
119
                            os,
124✔
120
                            "{: <{}}{:~<{}}\n",
124✔
121
                            // padding of spaces
122
                            " ",
123
                            std::max(1_z, std::min(col_start, col_end)),  // fixing padding when the error is on the first character
124✔
124
                            // underline the error in red
125
                            fmt::styled("^", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()),
124✔
126
                            col_start < col_end ? col_end - col_start : 1);
124✔
127
                    // cppcheck-suppress knownConditionTrueFalse ; suppressing error so that the condition is explicit to the reader
128
                    else if (maybe_context && maybe_context->at.start.line == loc.start.line && i == loc.start.line)
14✔
129
                    {
130
                        const auto padding_size = std::max(1_z, maybe_context->at.start.column);
14✔
131
                        const std::string inner_padding =
14✔
132
                            // -2 to account for the │ and then └
133
                            (loc.start.column < padding_size || loc.start.column - padding_size < 2)
26✔
134
                            ? ""
2✔
135
                            : std::string(std::max(1_z, loc.start.column - padding_size - 1), ' ');
12✔
136

137
                        fmt::print(
28✔
138
                            os,
14✔
139
                            "{: <{}}{}{}{}\n",
14✔
140
                            // padding of spaces
141
                            " ",
142
                            padding_size,
143
                            // indicate where the parent is, with color
144
                            fmt::styled("│", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()),
14✔
145
                            // yet another padding of spaces between the parent and error column (if need be)
146
                            inner_padding,
147
                            // underline the error in red
148
                            fmt::styled("└─ error", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()));
14✔
149
                        // new line, some spacing between the error and the parent
150
                        fmt::print(
28✔
151
                            os,
14✔
152
                            "{}{: <{}}{}\n", Printer::GhostLinePrefix,
14✔
153
                            " ",
154
                            padding_size,
155
                            fmt::styled("│", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()));
14✔
156
                        // new line, now show the "expression started here for the source"
157
                        fmt::print(
28✔
158
                            os,
14✔
159
                            "{}{: <{}}{}\n",
14✔
160
                            Printer::GhostLinePrefix,
161
                            // padding of spaces
162
                            " ",
163
                            padding_size,
164
                            fmt::styled(
28✔
165
                                maybe_context->is_macro_expansion ? "└─ macro expansion started here" : "└─ expression started here",
14✔
166
                                colorize ? fmt::fg(fmt::color::red) : fmt::text_style()));
14✔
167
                    }
14✔
168
                }
141✔
169
                else
170
                {
171
                    fmt::print(os, "{}", Printer::GhostLinePrefix);
135✔
172

173
                    // first non-whitespace character of the line
174
                    // +1 for the leading whitespace after `    |` before the code
175
                    const std::size_t col_start = line.find_first_not_of(" \t\v") + 1;
135✔
176

177
                    // highlight the current line but skip any leading whitespace
178
                    fmt::print(
270✔
179
                        os,
135✔
180
                        "{: <{}}{:~<{}}\n",
135✔
181
                        // padding of spaces
182
                        " ",
183
                        col_start,
184
                        // underline the whole line in red
185
                        fmt::styled("^", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()),
135✔
186
                        line.size() - col_start);
135✔
187
                }
135✔
188
            }
273✔
189
        }
713✔
190
    }
273✔
191

192
    void helper(std::ostream& os, const std::string& message, const bool colorize,
144✔
193
                const std::string& filename, const internal::FileSpan& at,
194
                const std::optional<CodeErrorContext>& maybe_context = std::nullopt)
195
    {
144✔
196
        makeContext(
288✔
197
            ErrorLocation {
144✔
198
                .filename = filename,
144✔
199
                .start = at.start,
144✔
200
                .end = at.end },
144✔
201
            os, maybe_context, colorize);
144✔
202

203
        for (const auto& text : Utils::splitString(message, '\n'))
288✔
204
            fmt::print(os, "        {}\n", text);
144✔
205
    }
144✔
206

207
    std::string makeContextWithNode(const std::string& message, const internal::Node& node)
×
208
    {
×
209
        std::stringstream ss;
×
210

211
        helper(
×
212
            ss,
×
213
            message,
×
214
            true,
215
            node.filename(),
×
216
            node.position());
×
217

218
        return ss.str();
×
219
    }
×
220

221
    void generate(const CodeError& e, std::ostream& os, bool colorize)
144✔
222
    {
144✔
223
#ifdef ARK_BUILD_EXE
224
        if (const char* nocolor = std::getenv("NOCOLOR"); nocolor != nullptr)
144✔
225
            colorize = false;
×
226
#endif
227

228
        helper(
432✔
229
            os,
144✔
230
            e.what(),
144✔
231
            colorize,
144✔
232
            e.context.filename,
144✔
233
            e.context.at,
144✔
234
            e.additional_context);
144✔
235
    }
144✔
236
}
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