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