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

ArkScript-lang / Ark / 13344738465

15 Feb 2025 11:50AM UTC coverage: 77.022% (-1.9%) from 78.929%
13344738465

Pull #510

github

web-flow
Merge 70d135e0e into dd2f0e5fc
Pull Request #510: wip

5695 of 7394 relevant lines covered (77.02%)

44192.48 hits per line

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

59.62
/src/arkreactor/Builtins/String.cpp
1
#include <Ark/Builtins/Builtins.hpp>
2

3
#include <utility>
4
#include <utf8.hpp>
5
#include <fmt/args.h>
6
#include <fmt/core.h>
7
#include <fmt/format.h>
8

9
#include <Ark/TypeChecker.hpp>
10
#include <Ark/VM/VM.hpp>
11

12
namespace Ark::internal::Builtins::String
13
{
14
    /**
15
     * @name string:format
16
     * @brief Format a String given replacements
17
     * @details https://fmt.dev/latest/syntax.html
18
     * @param format the String to format
19
     * @param values as any argument as you need, of any valid ArkScript type
20
     * =begin
21
     * (string:format "Hello {}, my name is {}" "world" "ArkScript")
22
     * # Hello world, my name is ArkScript
23
     *
24
     * (string:format "Test {} with {{}}" "1")
25
     * # Test 1 with {}
26
     * =end
27
     * @author https://github.com/SuperFola
28
     */
29
    Value format(std::vector<Value>& n, VM* vm)
29✔
30
    {
29✔
31
        if (n.size() < 2 || n[0].valueType() != ValueType::String)
29✔
32
            types::generateError(
1✔
33
                "string:format",
×
34
                { { types::Contract { { types::Typedef("string", ValueType::String),
×
35
                                        types::Typedef("value", ValueType::Any, /* variadic */ true) } } } },
×
36
                n);
×
37

38
        fmt::dynamic_format_arg_store<fmt::format_context> store;
29✔
39

40
        for (auto it = n.begin() + 1, it_end = n.end(); it != it_end; ++it)
62✔
41
        {
42
            if (it->valueType() == ValueType::String)
33✔
43
                store.push_back(it->stringRef());
3✔
44
            else if (it->valueType() == ValueType::Number)
30✔
45
                store.push_back(it->number());
30✔
46
            else if (it->valueType() == ValueType::Nil)
×
47
                store.push_back("nil");
×
48
            else if (it->valueType() == ValueType::True)
×
49
                store.push_back("true");
×
50
            else if (it->valueType() == ValueType::False)
×
51
                store.push_back("false");
×
52
            else
53
                store.push_back(it->toString(*vm));
×
54
        }
33✔
55

56
        try
57
        {
58
            return Value(fmt::vformat(n[0].stringRef(), store));
29✔
59
        }
1✔
60
        catch (fmt::format_error& e)
61
        {
62
            throw std::runtime_error(
2✔
63
                fmt::format("string:format: can not format \"{}\" ({} argument{} provided) because of {}",
3✔
64
                            n[0].stringRef(),
1✔
65
                            n.size() - 1,
1✔
66
                            // if we have more than one argument (not counting the string to format), plural form
67
                            n.size() > 2 ? "s" : "",
1✔
68
                            e.what()));
1✔
69
        }
1✔
70
    }
31✔
71

72
    /**
73
     * @name string:find
74
     * @brief Search a substring in a given String
75
     * @details The original String is not modified. Return -1 when not found
76
     * @param string the String to search in
77
     * @param substr the substring to search for
78
     * @param (optional) startIndex index to start searching from
79
     * =begin
80
     * (string:find "hello world" "hello")  # 0
81
     * (string:find "hello world" "aworld")  # -1
82
     * =end
83
     * @author https://github.com/SuperFola
84
     */
85
    Value findSubStr(std::vector<Value>& n, VM* vm [[maybe_unused]])
40✔
86
    {
40✔
87
        if (!types::check(n, ValueType::String, ValueType::String) &&
40✔
88
            !types::check(n, ValueType::String, ValueType::String, ValueType::Number))
24✔
89
            types::generateError(
×
90
                "string:find",
×
91
                { { types::Contract {
×
92
                        { types::Typedef("string", ValueType::String),
×
93
                          types::Typedef("substr", ValueType::String) } },
×
94
                    types::Contract {
×
95
                        { types::Typedef("string", ValueType::String),
×
96
                          types::Typedef("substr", ValueType::String),
×
97
                          types::Typedef("startIndex", ValueType::Number) } } } },
×
98
                n);
×
99

100
        const std::size_t start = n.size() == 3 ? static_cast<std::size_t>(n[2].number()) : 0;
40✔
101
        const std::size_t index = n[0].stringRef().find(n[1].stringRef(), start);
40✔
102
        if (index != std::string::npos)
40✔
103
            return Value(static_cast<int>(index));
28✔
104
        return Value(-1);
12✔
105
    }
40✔
106

107
    /**
108
     * @name string:removeAt
109
     * @brief Remove a character from a String given an index
110
     * @details The original String is not modified
111
     * @param string the String to modify
112
     * @param index the index of the character to remove (can be negative to search from the end)
113
     * =begin
114
     * (string:removeAt "hello world" 0)  # "ello world"
115
     * (string:removeAt "hello world" -1)  # "hello worl"
116
     * =end
117
     * @author https://github.com/SuperFola
118
     */
119
    Value removeAtStr(std::vector<Value>& n, VM* vm [[maybe_unused]])
1✔
120
    {
1✔
121
        if (!types::check(n, ValueType::String, ValueType::Number))
1✔
122
            types::generateError(
1✔
123
                "string:removeAt",
×
124
                { { types::Contract { { types::Typedef("string", ValueType::String), types::Typedef("index", ValueType::Number) } } } },
×
125
                n);
×
126

127
        long id = static_cast<long>(n[1].number());
1✔
128
        if (id < 0 || std::cmp_greater_equal(id, n[0].stringRef().size()))
1✔
129
            throw std::runtime_error(fmt::format("string:removeAt: index {} out of range (length: {})", id, n[0].stringRef().size()));
1✔
130

131
        n[0].stringRef().erase(static_cast<std::size_t>(id), 1);
×
132
        return n[0];
×
133
    }
2✔
134

135
    /**
136
     * @name string:ord
137
     * @brief Get the ordinal of a given character
138
     * @param char a String with a single UTF8 character
139
     * =begin
140
     * (string:ord "h")  # 104
141
     * (string:ord "Ô")  # 212
142
     * =end
143
     * @author https://github.com/SuperFola
144
     */
145
    Value ord(std::vector<Value>& n, VM* vm [[maybe_unused]])
168✔
146
    {
168✔
147
        if (!types::check(n, ValueType::String))
168✔
148
            types::generateError(
×
149
                "string:ord",
×
150
                { { types::Contract { { types::Typedef("string", ValueType::String) } } } },
×
151
                n);
×
152

153
        return Value(utf8::codepoint(n[0].stringRef().c_str()));
168✔
154
    }
×
155

156
    /**
157
     * @name string:chr
158
     * @brief Create a character from an UTF8 codepoint
159
     * @param codepoint an UTF8 codepoint (Number)
160
     * =begin
161
     * (string:chr 104)  # "h"
162
     * (string:chr 212)  # "Ô"
163
     * =end
164
     * @author https://github.com/SuperFola
165
     */
166
    Value chr(std::vector<Value>& n, VM* vm [[maybe_unused]])
54✔
167
    {
54✔
168
        if (!types::check(n, ValueType::Number))
54✔
169
            types::generateError(
×
170
                "string:chr",
×
171
                { { types::Contract { { types::Typedef("codepoint", ValueType::Number) } } } },
×
172
                n);
×
173

174
        std::array<char, 5> utf8 {};
54✔
175
        utf8::codepointToUtf8(static_cast<int>(n[0].number()), utf8.data());
54✔
176
        return Value(std::string(utf8.data()));
54✔
177
    }
54✔
178

179
    /**
180
     * @name string:setAt
181
     * @brief Modify a given string and return a new one
182
     * @details The original string is not modified
183
     * @param string the string to modify
184
     * @param index the index of the element to modify
185
     * @param value the new character
186
     * =begin
187
     * (string:setAt "hello" 1 "a")  # "hallo"
188
     * =end
189
     * @author https://github.com/SuperFola
190
     */
191
    Value setStringAt(std::vector<Value>& n, VM* vm [[maybe_unused]])
1✔
192
    {
1✔
193
        if (!types::check(n, ValueType::String, ValueType::Number, ValueType::String))
1✔
194
            types::generateError(
1✔
195
                "string:setAt",
×
196
                { { types::Contract { { types::Typedef("string", ValueType::String),
×
197
                                        types::Typedef("index", ValueType::Number),
×
198
                                        types::Typedef("value", ValueType::String) } } } },
×
199
                n);
×
200

201
        auto& string = n[0].stringRef();
1✔
202

203
        const std::size_t size = string.size();
1✔
204
        long idx = static_cast<long>(n[1].number());
1✔
205
        idx = idx < 0 ? static_cast<long>(size) + idx : idx;
1✔
206
        if (std::cmp_greater_equal(idx, size))
1✔
207
            throw std::runtime_error(
1✔
208
                fmt::format("IndexError: string:setAt index ({}) out of range (string size: {})", idx, size));
1✔
209

210
        string[static_cast<std::size_t>(idx)] = n[2].string()[0];
×
211
        return n[0];
×
212
    }
2✔
213
}
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