Phasor 2.2.0
Stack VM based Programming Language
Loading...
Searching...
No Matches
Value.hpp
Go to the documentation of this file.
1#pragma once
2#include <iostream>
3#include <string>
4#include <variant>
5#include <unordered_map>
6#include <memory>
7#include <vector>
8
9
10namespace Phasor
11{
12
26
32class Value
33{
34 public:
36 {
37 std::string structName;
38 std::unordered_map<std::string, Value> fields;
39 };
40 using ArrayInstance = std::vector<Value>;
41
42 private:
43 using DataType = std::variant<std::monostate, bool, int64_t, double, std::string,
44 std::shared_ptr<StructInstance>, std::shared_ptr<ArrayInstance>>;
45
47
48 public:
50 Value() : data(std::monostate{})
51 {
52 }
53
54 Value(bool b) : data(b)
55 {
56 }
57
58 Value(int64_t i) : data(i)
59 {
60 }
61
62 Value(int i) : data(static_cast<int64_t>(i))
63 {
64 }
65
66 Value(double d) : data(d)
67 {
68 }
69
70 Value(const std::string &s) : data(s)
71 {
72 }
73
74 Value(const char *s) : data(std::string(s))
75 {
76 }
77
78 Value(std::shared_ptr<StructInstance> s) : data(std::move(s))
79 {
80 }
81
82 Value(std::shared_ptr<ArrayInstance> a) : data(std::move(a))
83 {
84 }
85
88 {
89 if (std::holds_alternative<std::monostate>(data))
90 return ValueType::Null;
91 if (std::holds_alternative<bool>(data))
92 return ValueType::Bool;
93 if (std::holds_alternative<int64_t>(data))
94 return ValueType::Int;
95 if (std::holds_alternative<double>(data))
96 return ValueType::Float;
97 if (std::holds_alternative<std::string>(data))
98 return ValueType::String;
99 if (std::holds_alternative<std::shared_ptr<StructInstance>>(data))
100 return ValueType::Struct;
101 if (std::holds_alternative<std::shared_ptr<ArrayInstance>>(data))
102 return ValueType::Array;
103 return ValueType::Null; // Should not be reached if default constructed
104 }
105
107 bool isNull() const
108 {
109 return getType() == ValueType::Null;
110 }
111
112 bool isBool() const
113 {
114 return getType() == ValueType::Bool;
115 }
116
117 bool isInt() const
118 {
119 return getType() == ValueType::Int;
120 }
121
122 bool isFloat() const
123 {
124 return getType() == ValueType::Float;
125 }
126
127 bool isString() const
128 {
129 return getType() == ValueType::String;
130 }
131
132 bool isNumber() const
133 {
134 return isInt() || isFloat();
135 }
136
137 bool isArray() const
138 {
139 return std::holds_alternative<std::shared_ptr<ArrayInstance>>(data);
140 }
141
143 bool asBool() const
144 {
145 return std::get<bool>(data);
146 }
147
148 int64_t asInt() const
149 {
150 if (isInt())
151 return std::get<int64_t>(data);
152 if (isFloat())
153 return static_cast<int64_t>(std::get<double>(data));
154 return 0;
155 }
156
157 double asFloat() const
158 {
159 if (isFloat())
160 return std::get<double>(data);
161 if (isInt())
162 return static_cast<double>(std::get<int64_t>(data));
163 return 0.0;
164 }
165
166 std::string asString() const
167 {
168 if (isString())
169 return std::get<std::string>(data);
170 return toString();
171 }
172
173 std::shared_ptr<ArrayInstance> asArray()
174 {
175 return std::get<std::shared_ptr<ArrayInstance>>(data);
176 }
177
179 const std::shared_ptr<const ArrayInstance> asArray() const
180 {
181 return std::get<std::shared_ptr<ArrayInstance>>(data);
182 }
183
185 Value operator+(const Value &other) const
186 {
187 if (isInt() && other.isInt())
188 return Value(asInt() + other.asInt());
189 if (isNumber() && other.isNumber())
190 return Value(asFloat() + other.asFloat());
191 if (isString() && other.isString())
192 return Value(asString() + other.asString());
193 throw std::runtime_error("Cannot add these value types");
194 }
195
197 Value operator-(const Value &other) const
198 {
199 if (isInt() && other.isInt())
200 return Value(asInt() - other.asInt());
201 if (isNumber() && other.isNumber())
202 return Value(asFloat() - other.asFloat());
203 throw std::runtime_error("Cannot subtract these value types");
204 }
205
207 Value operator*(const Value &other) const
208 {
209 if (isInt() && other.isInt())
210 return Value(asInt() * other.asInt());
211 if (isNumber() && other.isNumber())
212 return Value(asFloat() * other.asFloat());
213 throw std::runtime_error("Cannot multiply these value types");
214 }
215
217 Value operator/(const Value &other) const
218 {
219 if (isInt() && other.isInt())
220 {
221 if (other.asInt() == 0)
222 throw std::runtime_error("Division by zero");
223 return Value(asInt() / other.asInt());
224 }
225 if (isNumber() && other.isNumber())
226 {
227 if (other.asFloat() == 0.0)
228 throw std::runtime_error("Division by zero");
229 return Value(asFloat() / other.asFloat());
230 }
231 throw std::runtime_error("Cannot divide these value types");
232 }
233
235 Value operator%(const Value &other) const
236 {
237 if (isInt() && other.isInt())
238 {
239 if (other.asInt() == 0)
240 throw std::runtime_error("Modulo by zero");
241 return Value(asInt() % other.asInt());
242 }
243 throw std::runtime_error("Modulo requires integer operands");
244 }
245
248 {
249 if (isInt())
250 return Value(-asInt());
251 if (isFloat())
252 return Value(-asFloat());
253 throw std::runtime_error("Cannot negate this value type");
254 }
255
258 {
259 return Value(!isTruthy());
260 }
261
263 Value logicalAnd(const Value &other) const
264 {
265 return Value(isTruthy() && other.isTruthy());
266 }
267
269 Value logicalOr(const Value &other) const
270 {
271 return Value(isTruthy() || other.isTruthy());
272 }
273
275 bool isTruthy() const
276 {
277 if (isNull())
278 return false;
279 if (isBool())
280 return asBool();
281 if (isInt())
282 return asInt() != 0;
283 if (isFloat())
284 return asFloat() != 0.0;
285 if (isString()) {
286 if (asString() == "true" || asString() == "1")
287 return true;
288 else if (asString() == "false" || asString() == "0")
289 return false;
290 return !asString().empty();
291 }
292 return false;
293 }
294
296 bool operator==(const Value &other) const
297 {
298 if (getType() != other.getType())
299 return false;
300 if (isNull())
301 return true;
302 if (isBool())
303 return asBool() == other.asBool();
304 if (isInt())
305 return asInt() == other.asInt();
306 if (isFloat())
307 return asFloat() == other.asFloat();
308 if (isString())
309 return asString() == other.asString();
310 if (isArray())
311 {
312 if (!other.isArray()) return false;
313 const auto &self_arr = *asArray();
314 const auto &other_arr = *other.asArray();
315 return self_arr == other_arr;
316 }
317 return false;
318 }
319
321 bool operator!=(const Value &other) const
322 {
323 return !(*this == other);
324 }
325
327 bool operator<(const Value &other) const
328 {
329 if (isInt() && other.isInt())
330 return asInt() < other.asInt();
331 if (isNumber() && other.isNumber())
332 return asFloat() < other.asFloat();
333 if (isString() && other.isString())
334 return asString() < other.asString();
335 throw std::runtime_error("Cannot compare these value types ");
336 }
337
339 bool operator>(const Value &other) const
340 {
341 if (isInt() && other.isInt())
342 return asInt() > other.asInt();
343 if (isNumber() && other.isNumber())
344 return asFloat() > other.asFloat();
345 if (isString() && other.isString())
346 return asString() > other.asString();
347 throw std::runtime_error("Cannot compare these value types ");
348 }
349
351 bool operator<=(const Value &other) const
352 {
353 return !(*this > other);
354 }
355
356 bool operator>=(const Value &other) const
357 {
358 return !(*this < other);
359 }
360
362 std::string toString() const
363 {
364 if (isNull())
365 return "null";
366 if (isBool())
367 return asBool() ? "true" : "false";
368 if (isInt())
369 return std::to_string(asInt());
370 if (isFloat())
371 return std::to_string(asFloat());
372 if (isString())
373 return asString();
374 if (isArray())
375 {
376 std::string result = "[";
377 const auto &arr = *asArray();
378 for (size_t i = 0; i < arr.size(); ++i)
379 {
380 result += arr[i].toString();
381 if (i < arr.size() - 1)
382 {
383 result += ", ";
384 }
385 }
386 result += "]";
387 return result;
388 }
389 return "unknown";
390 }
391
393 const char *c_str() const
394 {
395 if (!isString())
396 throw std::runtime_error("c_str() can only be called on string values");
397 return std::get<std::string>(data).c_str();
398 }
399
401 friend std::ostream &operator<<(std::ostream &os, const Value &v)
402 {
403 os << v.toString();
404 return os;
405 }
406
407 bool isStruct() const
408 {
409 return std::holds_alternative<std::shared_ptr<StructInstance>>(data);
410 }
411
412 std::shared_ptr<StructInstance> asStruct()
413 {
414 return std::get<std::shared_ptr<StructInstance>>(data);
415 }
416
417 const std::shared_ptr<const StructInstance> asStruct() const
418 {
419 return std::get<std::shared_ptr<StructInstance>>(data);
420 }
421
422 static Value createStruct(const std::string &name)
423 {
424 return Value(std::make_shared<StructInstance>(StructInstance{name}));
425 }
426
427 static Value createArray(std::vector<Value> elements = {})
428 {
429 return Value(std::make_shared<ArrayInstance>(std::move(elements)));
430 }
431
432 Value getField(const std::string &name) const
433 {
434 if (!std::holds_alternative<std::shared_ptr<StructInstance>>(data))
435 throw std::runtime_error("getField() called on non-struct value");
436 auto s = std::get<std::shared_ptr<StructInstance>>(data);
437 auto it = s->fields.find(name);
438 if (it == s->fields.end())
439 return Value();
440 return it->second;
441 }
442
443 void setField(const std::string &name, Value value)
444 {
445 if (!std::holds_alternative<std::shared_ptr<StructInstance>>(data))
446 throw std::runtime_error("setField() called on non-struct value");
447 auto s = std::get<std::shared_ptr<StructInstance>>(data);
448 s->fields[name] = std::move(value);
449 }
450
451 bool hasField(const std::string &name) const
452 {
453 if (!std::holds_alternative<std::shared_ptr<StructInstance>>(data))
454 return false;
455 auto s = std::get<std::shared_ptr<StructInstance>>(data);
456 return s->fields.find(name) != s->fields.end();
457 }
458};
459} // namespace Phasor
bool isTruthy() const
Helper to determine truthiness.
Definition Value.hpp:275
const char * c_str() const
Convert to C Style String.
Definition Value.hpp:393
std::shared_ptr< StructInstance > asStruct()
Definition Value.hpp:412
std::string toString() const
Convert to string for printing.
Definition Value.hpp:362
const std::shared_ptr< const StructInstance > asStruct() const
Definition Value.hpp:417
Value operator-() const
Unary negation.
Definition Value.hpp:247
double asFloat() const
Get the value as a double.
Definition Value.hpp:157
Value(std::shared_ptr< StructInstance > s)
Struct constructor.
Definition Value.hpp:78
Value(int i)
Integer constructor.
Definition Value.hpp:62
bool isStruct() const
Definition Value.hpp:407
bool isNumber() const
Check if the value is a number.
Definition Value.hpp:132
std::string asString() const
Get the value as a string.
Definition Value.hpp:166
friend std::ostream & operator<<(std::ostream &os, const Value &v)
Print to output stream.
Definition Value.hpp:401
std::shared_ptr< ArrayInstance > asArray()
Get the value as an array.
Definition Value.hpp:173
Value operator/(const Value &other) const
Divide two values.
Definition Value.hpp:217
bool operator>=(const Value &other) const
Greater than or equal to comparison.
Definition Value.hpp:356
Value operator-(const Value &other) const
Subtract two values.
Definition Value.hpp:197
std::vector< Value > ArrayInstance
Definition Value.hpp:40
bool hasField(const std::string &name) const
Definition Value.hpp:451
Value(int64_t i)
Integer constructor.
Definition Value.hpp:58
void setField(const std::string &name, Value value)
Definition Value.hpp:443
bool operator<=(const Value &other) const
Less than or equal to comparison.
Definition Value.hpp:351
bool isNull() const
Check if the value is null.
Definition Value.hpp:107
int64_t asInt() const
Get the value as an integer.
Definition Value.hpp:148
bool isBool() const
Check if the value is a boolean.
Definition Value.hpp:112
Value(bool b)
Boolean constructor.
Definition Value.hpp:54
DataType data
Definition Value.hpp:46
bool isFloat() const
Check if the value is a double.
Definition Value.hpp:122
static Value createStruct(const std::string &name)
Definition Value.hpp:422
bool isArray() const
Check if the value is an array.
Definition Value.hpp:137
ValueType getType() const
Get the type of the value.
Definition Value.hpp:87
const std::shared_ptr< const ArrayInstance > asArray() const
Get the value as an array (const).
Definition Value.hpp:179
Value logicalAnd(const Value &other) const
Logical AND.
Definition Value.hpp:263
bool asBool() const
Get the value as a boolean.
Definition Value.hpp:143
Value(const std::string &s)
String constructor.
Definition Value.hpp:70
bool operator<(const Value &other) const
Less than comparison.
Definition Value.hpp:327
Value operator*(const Value &other) const
Multiply two values.
Definition Value.hpp:207
bool operator>(const Value &other) const
Greater than comparison.
Definition Value.hpp:339
Value operator!() const
Logical negation.
Definition Value.hpp:257
Value(double d)
Double constructor.
Definition Value.hpp:66
bool operator==(const Value &other) const
Comparison operations.
Definition Value.hpp:296
bool operator!=(const Value &other) const
Inequality comparison.
Definition Value.hpp:321
Value operator%(const Value &other) const
Modulo two values.
Definition Value.hpp:235
std::variant< std::monostate, bool, int64_t, double, std::string, std::shared_ptr< StructInstance >, std::shared_ptr< ArrayInstance > > DataType
Definition Value.hpp:43
static Value createArray(std::vector< Value > elements={})
Definition Value.hpp:427
Value(std::shared_ptr< ArrayInstance > a)
Array constructor.
Definition Value.hpp:82
Value operator+(const Value &other) const
Add two values.
Definition Value.hpp:185
Value()
Default constructor.
Definition Value.hpp:50
Value getField(const std::string &name) const
Definition Value.hpp:432
bool isString() const
Check if the value is a string.
Definition Value.hpp:127
Value(const char *s)
String constructor.
Definition Value.hpp:74
Value logicalOr(const Value &other) const
Logical OR.
Definition Value.hpp:269
bool isInt() const
Check if the value is an integer.
Definition Value.hpp:117
The Phasor Programming Language and Runtime.
Definition AST.hpp:8
ValueType
Runtime value types for the VM.
Definition Value.hpp:17
std::unordered_map< std::string, Value > fields
Definition Value.hpp:38