ArkScript
A small, fast, functional and scripting language for video games
Value.hpp
Go to the documentation of this file.
1/**
2 * @file Value.hpp
3 * @author Default value type handled by the virtual machine
4 * @brief
5 * @version 1.2
6 * @date 2024-04-20
7 *
8 * @copyright Copyright (c) 2020-2024
9 *
10 */
11
12#ifndef ARK_VM_VALUE_HPP
13#define ARK_VM_VALUE_HPP
14
15#include <vector>
16#include <variant>
17#include <string>
18#include <cinttypes>
19#include <array>
20
23#include <Ark/Platform.hpp>
24
25namespace Ark
26{
27 class VM;
28
29 // Note: we can have at most 0x7f (127) different types
30 // because type index is stored on the 7 right most bits of a uint8_t in the class Value.
31 // Order is also important because we are doing some optimizations to check ranges
32 // of types based on their integer values.
33 enum class ValueType
34 {
35 List = 0,
36 Number = 1,
37 String = 2,
38 PageAddr = 3,
39 CProc = 4,
40 Closure = 5,
41 User = 6,
42
43 Nil = 7,
44 True = 8,
45 False = 9,
46 Undefined = 10,
47 Reference = 11,
48 InstPtr = 12,
49
50 Any = 99 ///< Used only for typechecking
51 };
52
53 const std::array<std::string, 13> types_to_str = {
54 "List", "Number", "String", "Function",
55 "CProc", "Closure", "UserType", "Nil",
56 "Bool", "Bool", "Undefined", "Reference",
57 "InstPtr"
58 };
59
61 {
62 public:
63 using ProcType = Value (*)(std::vector<Value>&, VM*);
64 using Iterator = std::vector<Value>::iterator;
65
66 using Value_t = std::variant<
67 double, // 8 bytes
68 std::string, // 32 bytes
69 internal::PageAddr_t, // 2 bytes
70 ProcType, // 8 bytes
71 internal::Closure, // 24 bytes
72 UserType, // 24 bytes
73 std::vector<Value>, // 24 bytes
74 Value* // 8 bytes
75 >; // +8 bytes overhead
76 // total 40 bytes
77
78 /**
79 * @brief Construct a new Value object
80 *
81 */
82 Value() noexcept;
83
84 /**
85 * @brief Construct a new Value object
86 *
87 * @param type the value type which is going to be held
88 */
89 explicit Value(ValueType type) noexcept;
90
91 /**
92 * @brief Construct a new Value object
93 * @details Use at your own risks. Asking for a value type N and putting a non-matching value
94 * will result in errors at runtime.
95 *
96 * @tparam T
97 * @param type value type wanted
98 * @param value value needed
99 */
100 template <typename T>
101 Value(ValueType type, T&& value) noexcept :
102 m_const_type(static_cast<uint8_t>(type)),
103 m_value(value)
104 {}
105
106 explicit Value(int value) noexcept;
107 explicit Value(float value) noexcept;
108 explicit Value(double value) noexcept;
109 explicit Value(const std::string& value) noexcept;
110 explicit Value(const char* value) noexcept;
111 explicit Value(internal::PageAddr_t value) noexcept;
112 explicit Value(ProcType value) noexcept;
113 explicit Value(std::vector<Value>&& value) noexcept;
114 explicit Value(internal::Closure&& value) noexcept;
115 explicit Value(UserType&& value) noexcept;
116 explicit Value(Value* ref) noexcept;
117
118 [[nodiscard]] ValueType valueType() const noexcept { return static_cast<ValueType>(type_num()); }
119 [[nodiscard]] bool isFunction() const noexcept
120 {
121 const auto type = valueType();
122 return type == ValueType::PageAddr || type == ValueType::Closure || type == ValueType::CProc ||
123 (type == ValueType::Reference && reference()->isFunction());
124 }
125
126 [[nodiscard]] double number() const { return std::get<double>(m_value); }
127 [[nodiscard]] const std::string& string() const { return std::get<std::string>(m_value); }
128 [[nodiscard]] const std::vector<Value>& constList() const { return std::get<std::vector<Value>>(m_value); }
129 [[nodiscard]] const UserType& usertype() const { return std::get<UserType>(m_value); }
130 [[nodiscard]] std::vector<Value>& list() { return std::get<std::vector<Value>>(m_value); }
131 [[nodiscard]] std::string& stringRef() { return std::get<std::string>(m_value); }
132 [[nodiscard]] UserType& usertypeRef() { return std::get<UserType>(m_value); }
133 [[nodiscard]] Value* reference() const { return std::get<Value*>(m_value); }
134
135 /**
136 * @brief Add an element to the list held by the value (if the value type is set to list)
137 *
138 * @param value
139 */
140 void push_back(const Value& value);
141
142 /**
143 * @brief Add an element to the list held by the value (if the value type is set to list)
144 *
145 * @param value
146 */
147 void push_back(Value&& value);
148
149 std::string toString(VM& vm) const noexcept;
150
151 friend ARK_API_INLINE bool operator==(const Value& A, const Value& B) noexcept;
152 friend ARK_API_INLINE bool operator<(const Value& A, const Value& B) noexcept;
153 friend ARK_API_INLINE bool operator!(const Value& A) noexcept;
154
155 friend class Ark::VM;
156
157 private:
158 uint8_t m_const_type; ///< First bit if for constness, right most bits are for type
160
161 [[nodiscard]] constexpr uint8_t type_num() const noexcept { return m_const_type & 0x7f; }
162
163 [[nodiscard]] internal::PageAddr_t pageAddr() const { return std::get<internal::PageAddr_t>(m_value); }
164 [[nodiscard]] const ProcType& proc() const { return std::get<ProcType>(m_value); }
165 [[nodiscard]] const internal::Closure& closure() const { return std::get<internal::Closure>(m_value); }
166 [[nodiscard]] internal::Closure& refClosure() { return std::get<internal::Closure>(m_value); }
167
168 [[nodiscard]] bool isConst() const noexcept { return m_const_type & (1 << 7); }
169 void setConst(const bool value) noexcept
170 {
171 if (value)
172 m_const_type |= 1 << 7;
173 else
174 m_const_type = type_num();
175 }
176 };
177
178 inline bool operator==(const Value& A, const Value& B) noexcept
179 {
180 // values should have the same type
181 if (A.type_num() != B.type_num())
182 return false;
183 // all the types >= Nil are Nil itself, True, False, Undefined
184 if (A.type_num() >= static_cast<uint8_t>(ValueType::Nil))
185 return true;
186
187 return A.m_value == B.m_value;
188 }
189
190 inline bool operator<(const Value& A, const Value& B) noexcept
191 {
192 if (A.type_num() != B.type_num())
193 return (A.type_num() - B.type_num()) < 0;
194 return A.m_value < B.m_value;
195 }
196
197 inline bool operator!=(const Value& A, const Value& B) noexcept
198 {
199 return !(A == B);
200 }
201
202 inline bool operator!(const Value& A) noexcept
203 {
204 switch (A.valueType())
205 {
206 case ValueType::List:
207 return A.constList().empty();
208
210 return !A.number();
211
213 return A.string().empty();
214
215 case ValueType::User:
216 case ValueType::Nil:
217 case ValueType::False:
218 return true;
219
220 case ValueType::True:
221 return false;
222
223 default:
224 return false;
225 }
226 }
227}
228
229#endif
Subtype of the value type, handling closures.
#define ARK_API
Definition: Module.hpp:28
ArkScript configuration macros.
#define ARK_API_INLINE
Definition: Platform.hpp:51
Subtype of the value, capable of handling any C++ type.
A class to be use C++ objects in ArkScript.
Definition: UserType.hpp:48
The ArkScript virtual machine, executing ArkScript bytecode.
Definition: VM.hpp:41
const std::vector< Value > & constList() const
Definition: Value.hpp:128
std::vector< Value > & list()
Definition: Value.hpp:130
constexpr uint8_t type_num() const noexcept
Definition: Value.hpp:161
uint8_t m_const_type
First bit if for constness, right most bits are for type.
Definition: Value.hpp:158
bool isConst() const noexcept
Definition: Value.hpp:168
internal::Closure & refClosure()
Definition: Value.hpp:166
const ProcType & proc() const
Definition: Value.hpp:164
std::variant< double, std::string, internal::PageAddr_t, ProcType, internal::Closure, UserType, std::vector< Value >, Value * > Value_t
Definition: Value.hpp:75
Value * reference() const
Definition: Value.hpp:133
const internal::Closure & closure() const
Definition: Value.hpp:165
double number() const
Definition: Value.hpp:126
bool isFunction() const noexcept
Definition: Value.hpp:119
Value(*)(std::vector< Value > &, VM *) ProcType
Definition: Value.hpp:63
void setConst(const bool value) noexcept
Definition: Value.hpp:169
std::vector< Value >::iterator Iterator
Definition: Value.hpp:64
ValueType valueType() const noexcept
Definition: Value.hpp:118
const std::string & string() const
Definition: Value.hpp:127
const UserType & usertype() const
Definition: Value.hpp:129
Value_t m_value
Definition: Value.hpp:159
internal::PageAddr_t pageAddr() const
Definition: Value.hpp:163
UserType & usertypeRef()
Definition: Value.hpp:132
std::string & stringRef()
Definition: Value.hpp:131
Closure management.
Definition: Closure.hpp:37
uint16_t PageAddr_t
Definition: Closure.hpp:30
Definition: Builtins.hpp:21
const auto False
ArkScript False value.
Definition: VM.hpp:310
bool operator!(const Value &A) noexcept
Definition: Value.hpp:202
const auto Nil
ArkScript Nil value.
Definition: VM.hpp:308
bool operator==(const Value &A, const Value &B) noexcept
Definition: Value.hpp:178
ValueType
Definition: Value.hpp:34
@ Any
Used only for typechecking.
const auto True
ArkScript True value.
Definition: VM.hpp:312
bool operator!=(const Value &A, const Value &B) noexcept
Definition: Value.hpp:197
bool operator<(const Value &A, const Value &B) noexcept
Definition: Value.hpp:190
const std::array< std::string, 13 > types_to_str
Definition: Value.hpp:53