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

ArkScript-lang / Ark / 16973336667

14 Aug 2025 06:21PM UTC coverage: 87.426% (-0.007%) from 87.433%
16973336667

push

github

SuperFola
fix(cli): fixed arkscript cli to properly receive script arguments and pass them along to the running code

Also added sys:programName to store the program name separatly from the arguments

13 of 15 new or added lines in 2 files covered. (86.67%)

1 existing line in 1 file now uncovered.

7648 of 8748 relevant lines covered (87.43%)

129267.77 hits per line

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

70.55
/src/arkreactor/VM/State.cpp
1
#include <Ark/VM/State.hpp>
2

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

7
#ifdef _MSC_VER
8
#    pragma warning(push)
9
#    pragma warning(disable : 4996)
10
#endif
11

12
#include <Proxy/Picosha2.hpp>
13
#include <Ark/Compiler/BytecodeReader.hpp>
14
#include <fmt/core.h>
15
#include <fmt/color.h>
16

17
namespace Ark
18
{
19
    State::State(const std::vector<std::filesystem::path>& libenv) noexcept :
831✔
20
        m_debug_level(0),
277✔
21
        m_libenv(libenv),
277✔
22
        m_filename(ARK_NO_NAME_FILE),
277✔
23
        m_max_page_size(0)
277✔
24
    {
277✔
25
        // default value for builtin__sys:args is empty list
26
        const Value val(ValueType::List);
277✔
27
        m_binded[std::string(internal::Language::SysArgs)] = val;
277✔
28

29
        m_binded[std::string(internal::Language::SysProgramName)] = Value("");
277✔
30
    }
277✔
31

32
    bool State::feed(const std::string& bytecode_filename)
172✔
33
    {
172✔
34
        if (!Utils::fileExists(bytecode_filename))
172✔
35
            return false;
×
36

37
        return feed(Utils::readFileAsBytes(bytecode_filename));
172✔
38
    }
172✔
39

40
    bool State::feed(const bytecode_t& bytecode)
181✔
41
    {
181✔
42
        BytecodeReader bcr;
181✔
43
        bcr.feed(bytecode);
181✔
44
        if (!bcr.checkMagic())
181✔
45
            return false;
×
46

47
        m_bytecode = bytecode;
181✔
48

49
        try
50
        {
51
            configure(bcr);
181✔
52
            return true;
181✔
53
        }
×
54
        catch (const std::exception& e)  // FIXME I don't like this shit
55
        {
56
            fmt::println("{}", e.what());
×
57
            return false;
×
58
        }
×
59
    }
181✔
60

61
    bool State::compile(const std::string& file, const std::string& output, const uint16_t features) const
268✔
62
    {
268✔
63
        Welder welder(m_debug_level, m_libenv, features);
268✔
64
        for (const auto& p : m_binded)
804✔
65
            welder.registerSymbol(p.first);
536✔
66

67
        if (!welder.computeASTFromFile(file))
268✔
68
            return false;
×
69
        if (!welder.generateBytecode())
206✔
70
            return false;
×
71

72
        const std::string destination = output.empty() ? (file.substr(0, file.find_last_of('.')) + ".arkc") : output;
172✔
73
        if (!welder.saveBytecodeToFile(destination))
172✔
74
            return false;
×
75

76
        return true;
172✔
77
    }
268✔
78

79
    bool State::doFile(const std::string& file_path, const uint16_t features)
268✔
80
    {
268✔
81
        if (!Utils::fileExists(file_path))
268✔
82
        {
NEW
83
            fmt::print(fmt::fg(fmt::color::red), "Can not find file '{}'\n", file_path);
×
84
            return false;
×
85
        }
86
        m_filename = file_path;
268✔
87
        m_binded[std::string(internal::Language::SysProgramName)] = Value(std::filesystem::path(m_filename).filename().string());
364✔
88

89
        const bytecode_t bytecode = Utils::readFileAsBytes(file_path);
268✔
90
        BytecodeReader bcr;
268✔
91
        bcr.feed(bytecode);
268✔
92
        if (!bcr.checkMagic())  // couldn't read magic number, it's a source file
268✔
93
        {
94
            // check if it's in the arkscript cache
95
            const std::string filename = std::filesystem::path(file_path).filename().replace_extension(".arkc").string();
268✔
96
            const std::filesystem::path cache_directory = std::filesystem::path(file_path).parent_path() / ARK_CACHE_DIRNAME;
268✔
97
            const std::string bytecode_path = (cache_directory / filename).string();
268✔
98

99
            if (!exists(cache_directory))
268✔
100
                create_directory(cache_directory);
16✔
101

102
            if (compile(file_path, bytecode_path, features) && feed(bytecode_path))
268✔
103
                return true;
172✔
104
        }
268✔
105
        else if (feed(bytecode))  // it's a bytecode file
×
106
            return true;
×
107
        return false;
×
108
    }
364✔
109

110
    bool State::doString(const std::string& code, const uint16_t features)
9✔
111
    {
9✔
112
        Welder welder(m_debug_level, m_libenv, features);
9✔
113
        for (const auto& p : m_binded)
33✔
114
            welder.registerSymbol(p.first);
24✔
115

116
        if (!welder.computeASTFromString(code))
9✔
117
            return false;
×
118
        if (!welder.generateBytecode())
9✔
119
            return false;
×
120
        return feed(welder.bytecode());
9✔
121
    }
9✔
122

123
    void State::loadFunction(const std::string& name, Procedure::CallbackType&& function) noexcept
6✔
124
    {
6✔
125
        m_binded[name] = Value(std::move(function));
6✔
126
    }
6✔
127

128
    void State::setArgs(const std::vector<std::string>& args) noexcept
10✔
129
    {
10✔
130
        Value val(ValueType::List);
10✔
131
        std::ranges::transform(args, std::back_inserter(val.list()), [](const std::string& arg) {
13✔
132
            return Value(arg);
3✔
133
        });
134

135
        m_binded[std::string(internal::Language::SysArgs)] = val;
10✔
136
    }
10✔
137

138
    void State::setDebug(const unsigned level) noexcept
×
139
    {
×
140
        m_debug_level = level;
×
141
    }
×
142

143
    void State::setLibDirs(const std::vector<std::filesystem::path>& libenv) noexcept
×
144
    {
×
145
        m_libenv = libenv;
×
146
    }
×
147

148
    void State::configure(const BytecodeReader& bcr)
181✔
149
    {
181✔
150
        using namespace internal;
151

152
        const auto [major, minor, patch] = bcr.version();
181✔
153
        if (major != ARK_VERSION_MAJOR)
181✔
154
        {
155
            std::string str_version = std::to_string(major) + "." +
×
156
                std::to_string(minor) + "." +
×
157
                std::to_string(patch);
×
158
            throwStateError(fmt::format("Compiler and VM versions don't match: got {} while running {}", str_version, ARK_VERSION));
×
159
        }
×
160

161
        const auto bytecode_hash = bcr.sha256();
181✔
162

163
        std::vector<unsigned char> hash(picosha2::k_digest_size);
181✔
164
        picosha2::hash256(m_bytecode.begin() + bytecode::HeaderSize + picosha2::k_digest_size, m_bytecode.end(), hash);
181✔
165
        // checking integrity
166
        for (std::size_t j = 0; j < picosha2::k_digest_size; ++j)
5,973✔
167
        {
168
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
169
            if (hash[j] != bytecode_hash[j])
5,792✔
170
                throwStateError("Integrity check failed");
×
171
#endif
172
        }
5,792✔
173

174
        const auto syms = bcr.symbols();
181✔
175
        const auto vals = bcr.values(syms);
181✔
176
        const auto files = bcr.filenames(vals);
181✔
177
        const auto inst_locs = bcr.instLocations(files);
181✔
178
        const auto [pages, _] = bcr.code(inst_locs);
219,236✔
179

180
        m_symbols = syms.symbols;
181✔
181
        m_constants = vals.values;
181✔
182
        m_filenames = files.filenames;
181✔
183
        m_inst_locations = inst_locs.locations;
181✔
184

185
        m_max_page_size = 0;
181✔
186
        for (const bytecode_t& page : pages)
2,903✔
187
        {
188
            if (page.size() > m_max_page_size)
2,541✔
189
                m_max_page_size = page.size();
202✔
190
        }
2,541✔
191

192
        // Make m_code as a big contiguous chunk of instructions,
193
        // aligned on the biggest page size.
194
        // This might have a downside when we have a single big page and
195
        // a bunch of smaller ones, though I couldn't measure it while testing.
196
        m_code.resize(m_max_page_size * pages.size(), Instruction::NOP);
181✔
197
        for (std::size_t i = 0, end = pages.size(); i < end; ++i)
2,903✔
198
        {
199
            for (std::size_t j = 0, end_j = pages[i].size(); j < end_j; ++j)
221,234✔
200
                m_code[i * m_max_page_size + j] = pages[i][j];
216,152✔
201
        }
2,541✔
202
    }
181✔
203

204
    void State::reset() noexcept
×
205
    {
×
206
        m_symbols.clear();
×
207
        m_constants.clear();
×
208
        m_filenames.clear();
×
209
        m_inst_locations.clear();
×
210
        m_max_page_size = 0;
×
211
        m_code.clear();
×
212
        m_binded.clear();
×
213

214
        // default value for builtin__sys:args is empty list
215
        const Value val(ValueType::List);
×
216
        m_binded[std::string(internal::Language::SysArgs)] = val;
×
217

NEW
218
        m_binded[std::string(internal::Language::SysProgramName)] = Value("");
×
UNCOV
219
    }
×
220
}
221

222
#ifdef _MSC_VER
223
#    pragma warning(pop)
224
#endif
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