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

ArkScript-lang / Ark / 17095454925

20 Aug 2025 10:15AM UTC coverage: 87.175% (-0.3%) from 87.426%
17095454925

Pull #571

github

web-flow
Merge 582ae8a8d into 120045f7e
Pull Request #571: Feat/better parser position tracking

594 of 697 new or added lines in 17 files covered. (85.22%)

5 existing lines in 2 files now uncovered.

7545 of 8655 relevant lines covered (87.18%)

129898.3 hits per line

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

93.41
/src/arkscript/JsonCompiler.cpp
1
#include <CLI/JsonCompiler.hpp>
2

3
#include <string>
4
#include <vector>
5
#include <ranges>
6
#include <Ark/Error/Exceptions.hpp>
7

8
#include <fmt/ranges.h>
9
#include <fmt/format.h>
10

11
using namespace Ark::internal;
12

13
JsonCompiler::JsonCompiler(const unsigned debug, const std::vector<std::filesystem::path>& lib_env, const uint16_t features) :
11✔
14
    m_welder(debug, lib_env, features)
11✔
15
{}
11✔
16

17
void JsonCompiler::feed(const std::string& filename)
11✔
18
{
11✔
19
    m_welder.computeASTFromFile(filename);
11✔
20
}
11✔
21

22
std::string JsonCompiler::compile()
11✔
23
{
11✔
24
    return _compile(m_welder.ast());
11✔
25
}
26

27
std::string JsonCompiler::_compile(const Node& node)
668✔
28
{
668✔
29
    std::string json;
668✔
30

31
    switch (node.nodeType())
668✔
32
    {
292✔
33
        case NodeType::Symbol:
34
        {
35
            json += fmt::format(
292✔
36
                R"({{"type": "Symbol", "name": "{}"}})",
292✔
37
                node.string());
292✔
38
            break;
292✔
39
        }
6✔
40

41
        case NodeType::Spread:
42
        {
43
            json += fmt::format(
6✔
44
                R"({{"type": "Spread", "name": "{}"}})",
6✔
45
                node.string());
6✔
46
            break;
6✔
47
        }
5✔
48

49
        case NodeType::Capture:
50
        {
51
            json += fmt::format(
5✔
52
                R"({{"type": "Capture", "name": "{}"}})",
5✔
53
                node.string());
5✔
54
            break;
5✔
55
        }
4✔
56

57
        case NodeType::Field:
58
        {
59
            json += R"({"type": "Field", "children": )";
4✔
60
            json += toJsonList(node, 0) + "}";
4✔
61
            break;
4✔
62
        }
52✔
63

64
        case NodeType::String:
65
        {
66
            json += fmt::format(
52✔
67
                R"({{"type": "String", "value": "{}"}})",
52✔
68
                node.string());
52✔
69
            break;
52✔
70
        }
76✔
71

72
        case NodeType::Number:
73
        {
74
            json += fmt::format(
76✔
75
                R"({{"type": "Number", "value": {}}})",
76✔
76
                node.number());
76✔
77
            break;
76✔
78
        }
215✔
79

80
        case NodeType::List:
81
        {
82
            if (!node.constList().empty() && node.constList()[0].nodeType() == NodeType::Keyword)
215✔
83
            {
84
                Node keyword = node.constList()[0];
90✔
85
                switch (keyword.keyword())
90✔
86
                {
18✔
87
                    case Keyword::Fun:
88
                    {
89
                        // (fun (args) (body))
90
                        std::string args;
18✔
91
                        Node args_node = node.constList()[1];
18✔
92
                        if (args_node.nodeType() == NodeType::List)
18✔
93
                        {
94
                            args = "[";
17✔
95
                            for (std::size_t i = 0, end = args_node.constList().size(); i < end; ++i)
41✔
96
                            {
97
                                args += _compile(args_node.constList()[i]);
24✔
98
                                if (end > 1 && i != end - 1)
24✔
99
                                    args += ", ";
8✔
100
                            }
24✔
101
                            args += "]";
17✔
102
                        }
17✔
103
                        else
104
                            args = _compile(args_node);
1✔
105

106
                        json += fmt::format(
36✔
107
                            R"({{"type": "Fun", "args": {}, "body": {}}})",
18✔
108
                            args, _compile(node.constList()[2]));
18✔
109
                        break;
110
                    }
39✔
111

112
                    case Keyword::Let:
113
                    {
114
                        // (let name value)
115
                        json += fmt::format(
42✔
116
                            R"({{"type": "Let", "name": {}, "value": {}}})",
21✔
117
                            _compile(node.constList()[1]), _compile(node.constList()[2]));
21✔
118
                        break;
21✔
119
                    }
3✔
120

121
                    case Keyword::Mut:
122
                    {
123
                        // (mut name value)
124
                        json += fmt::format(
6✔
125
                            R"({{"type": "Mut", "name": {}, "value": {}}})",
3✔
126
                            _compile(node.constList()[1]), _compile(node.constList()[2]));
3✔
127
                        break;
3✔
128
                    }
5✔
129

130
                    case Keyword::Set:
131
                    {
132
                        // (set name value)
133
                        json += fmt::format(
10✔
134
                            R"({{"type": "Set", "name": {}, "value": {}}})",
5✔
135
                            _compile(node.constList()[1]), _compile(node.constList()[2]));
5✔
136
                        break;
5✔
137
                    }
5✔
138

139
                    case Keyword::If:
140
                    {
141
                        // (if condition then else)
142
                        if (node.constList().size() == 4)
5✔
143
                            json += fmt::format(
10✔
144
                                R"({{"type": "If", "condition": {}, "then": {}, "else": {}}})",
5✔
145
                                _compile(node.constList()[1]), _compile(node.constList()[2]), _compile(node.constList()[3]));
5✔
146
                        else
147
                            json += fmt::format(
×
148
                                R"({{"type": "If", "condition": {}, "then": {}}})",
×
149
                                _compile(node.constList()[1]), _compile(node.constList()[2]));
×
150
                        break;
5✔
151
                    }
2✔
152

153
                    case Keyword::While:
154
                    {
155
                        // (while condition body)
156
                        json += fmt::format(
4✔
157
                            R"({{"type": "While", "condition": {}, "body": {}}})",
2✔
158
                            _compile(node.constList()[1]), _compile(node.constList()[2]));
2✔
159
                        break;
2✔
160
                    }
30✔
161

162
                    case Keyword::Begin:
163
                    {
164
                        // (begin body)
165
                        json += R"({"type": "Begin", "children": )";
30✔
166
                        json += toJsonList(node, 1) + "}";
30✔
167
                        break;
30✔
168
                    }
5✔
169

170
                    case Keyword::Import:
171
                    {
172
                        // (import pkg.value)
173
                        // (import pkg.value :sym)
174
                        // (import pkg.value:*)
175
                        std::string package = node.constList()[1].constList().front().string();
5✔
176
                        for (const auto& sym : node.constList()[1].constList() | std::views::drop(1))
10✔
177
                            package += "." + sym.string();
5✔
178

179
                        bool is_glob = node.constList()[2].nodeType() == NodeType::Symbol && node.constList()[2].string() == "*";
5✔
180
                        std::vector<std::string> syms;
5✔
181
                        if (node.constList()[2].nodeType() == NodeType::List)
5✔
182
                            std::ranges::transform(
8✔
183
                                node.constList()[2].constList(),
4✔
184
                                std::back_inserter(syms),
4✔
185
                                [](const auto& sym) {
2✔
186
                                    return fmt::format("{:?}", sym.string());
2✔
187
                                });
188

189
                        json += fmt::format(
10✔
190
                            R"({{"type": "Import", "package": "{}", "glob": {}, "symbols": [{}]}})",
5✔
191
                            package,
192
                            is_glob,
193
                            fmt::join(syms, ", "));
5✔
194
                        break;
195
                    }
6✔
196

197
                    case Keyword::Del:
198
                    {
199
                        // (del value)
200
                        json += fmt::format(
2✔
201
                            R"({{"type": "Del", "value": {}}})",
1✔
202
                            _compile(node.constList()[1]));
1✔
203
                        break;
1✔
204
                    }
205
                }
90✔
206
            }
90✔
207
            else if (node.constList().size() > 1 && node.constList()[0].nodeType() == NodeType::Symbol)
125✔
208
            {
209
                // (foo bar 1)
210
                json += fmt::format(
240✔
211
                    R"({{"type": "FunctionCall", "name": {}, "args": {}}})",
120✔
212
                    _compile(node.constList()[0]),
120✔
213
                    toJsonList(node, 1));
120✔
214
            }
120✔
215
            else
216
                json += toJsonList(node, 0);
5✔
217

218
            break;
215✔
219
        }
18✔
220

221
        case NodeType::Macro:
222
        {
223
            if (const auto& first = node.constList()[0]; first.nodeType() == NodeType::Symbol)
36✔
224
            {
225
                json += fmt::format(
28✔
226
                    R"({{"type": "Macro", "name": {}, )",
14✔
227
                    _compile(node.constList()[0]));
14✔
228
                if (node.constList().size() == 2)
14✔
229
                    json += fmt::format(R"("value": {}}})", _compile(node.constList()[1]));
7✔
230
                else
231
                    json += fmt::format(
14✔
232
                        R"("args": {}, "body": {}}})",
7✔
233
                        toJsonList(node.constList()[1], 0),
7✔
234
                        _compile(node.constList()[2]));
7✔
235
            }
14✔
236
            else if (first.nodeType() == NodeType::Keyword)
4✔
237
            {
238
                if (first.keyword() == Keyword::If)
4✔
239
                    json += fmt::format(
8✔
240
                        R"({{"type": "MacroCondition", "condition": {}, "then": {}, "else": {}}})",
4✔
241
                        _compile(node.constList()[1]),
4✔
242
                        _compile(node.constList()[2]),
4✔
243
                        node.constList().size() == 4 ? _compile(node.constList()[3]) : R"({"type": "Symbol", "name": "nil"})");
4✔
244
            }
4✔
245
            break;
18✔
246
        }
×
247

248
        case NodeType::Unused:
249
            break;
×
250

251
        default:
252
            throw Ark::Error(fmt::format(
×
253
                "Not handled NodeType::{} ({} at {}:{}), please report this error on GitHub",
×
254
                nodeTypes[static_cast<std::size_t>(node.nodeType())].data(),
×
255
                node.filename(),
×
NEW
256
                node.position().start.line,
×
NEW
257
                node.position().start.column));
×
258
    }
668✔
259
    return json;
668✔
260
}
668✔
261

262
std::string JsonCompiler::toJsonList(const Node& node, const std::size_t start)
166✔
263
{
166✔
264
    std::vector<std::string> json;
166✔
265
    for (std::size_t i = start, end = node.constList().size(); i < end; ++i)
547✔
266
    {
267
        if (node.constList()[i].nodeType() != NodeType::Unused)
381✔
268
            json.push_back(_compile(node.constList()[i]));
377✔
269
    }
381✔
270
    return fmt::format("[{}]", fmt::join(json, ", "));
166✔
271
}
166✔
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