28#include <unordered_map>
63 std::unordered_map<std::string, Value>
fields;
68 using DataType = std::variant<std::monostate, bool, int64_t, double, std::shared_ptr<std::string>,
69 std::shared_ptr<StructInstance>,
70 std::shared_ptr<ArrayInstance>>;
96 Value(
const std::string &
s) :
data(std::make_shared<std::string>(
s))
108 Value(std::shared_ptr<ArrayInstance> a) :
data(std::move(a))
141 [[nodiscard]]
bool isNull() const noexcept {
return data.index() == 0; }
142 [[nodiscard]]
bool isBool() const noexcept {
return data.index() == 1; }
143 [[nodiscard]]
bool isInt() const noexcept {
return data.index() == 2; }
144 [[nodiscard]]
bool isFloat() const noexcept {
return data.index() == 3; }
145 [[nodiscard]]
bool isString() const noexcept {
return data.index() == 4; }
146 [[nodiscard]]
bool isNumber() const noexcept {
return data.index() == 2 ||
data.index() == 3; }
150 return std::holds_alternative<std::shared_ptr<ArrayInstance>>(
data);
154 [[nodiscard]]
bool asBool() const noexcept
156 return std::get<bool>(
data);
159 [[nodiscard]] int64_t
asInt() const noexcept
163 return std::get<int64_t>(
data);
167 return static_cast<int64_t
>(std::get<double>(
data));
176 return std::get<double>(
data);
180 return static_cast<double>(std::get<int64_t>(
data));
185 [[nodiscard]] std::string
asString() const noexcept
189 return *std::get<std::shared_ptr<std::string>>(
data);
196 return std::get<std::shared_ptr<ArrayInstance>>(
data);
200 [[nodiscard]] std::shared_ptr<const ArrayInstance>
asArray() const noexcept
202 return std::get<std::shared_ptr<ArrayInstance>>(
data);
220 throw std::runtime_error(
"Cannot add these value types");
234 throw std::runtime_error(
"Cannot subtract these value types");
249 throw std::runtime_error(
"Cannot decrement this value type");
264 throw std::runtime_error(
"Cannot increment this value type");
278 throw std::runtime_error(
"Cannot multiply these value types");
286 if (other.
asInt() == 0)
288 throw std::runtime_error(
"Division by zero");
296 throw std::runtime_error(
"Division by zero");
300 throw std::runtime_error(
"Cannot divide these value types");
308 if (other.
asInt() == 0)
310 throw std::runtime_error(
"Modulo by zero");
314 throw std::runtime_error(
"Modulo requires integer operands");
326 return {
isTruthy() && other.isTruthy()};
332 return {
isTruthy() || other.isTruthy()};
364 if (
getType() != other.getType())
374 return asBool() == other.asBool();
378 return asInt() == other.asInt();
382 return asFloat() == other.asFloat();
386 return asString() == other.asString();
390 if (!other.isArray())
394 const auto &self_arr = *
asArray();
395 const auto &other_arr = *other.asArray();
396 return self_arr == other_arr;
404 return !(*
this == other);
422 throw std::runtime_error(
"Cannot compare these value types ");
440 throw std::runtime_error(
"Cannot compare these value types ");
446 return !(*
this > other);
451 return !(*
this < other);
455 [[nodiscard]] std::string
toString() const noexcept
463 return asBool() ?
"true" :
"false";
467 return std::to_string(
asInt());
471 return std::to_string(
asFloat());
479 std::string result =
"[";
481 for (
size_t i = 0; i < arr.size(); ++i)
483 result += arr[i].toString();
484 if (i < arr.size() - 1)
496 [[nodiscard]]
const char *
c_str()
const
500 [[unlikely]]
throw std::runtime_error(
"c_str() can only be called on string values");
502 return std::get<std::shared_ptr<std::string>>(
data)->
c_str();
514 return std::holds_alternative<std::shared_ptr<StructInstance>>(
data);
519 return std::get<std::shared_ptr<StructInstance>>(
data);
522 [[nodiscard]] std::shared_ptr<const StructInstance>
asStruct() const noexcept
524 return std::get<std::shared_ptr<StructInstance>>(
data);
529 return Value(std::make_shared<StructInstance>(
StructInstance{.structName = name, .fields = {}}));
534 return {std::make_shared<ArrayInstance>(std::move(elements))};
539 if (!std::holds_alternative<std::shared_ptr<StructInstance>>(
data))
541 [[unlikely]]
throw std::runtime_error(
"getField() called on non-struct value");
543 auto s = std::get<std::shared_ptr<StructInstance>>(
data);
544 auto it =
s->fields.find(name);
545 if (it ==
s->fields.end())
554 if (!std::holds_alternative<std::shared_ptr<StructInstance>>(
data))
556 [[unlikely]]
throw std::runtime_error(
"setField() called on non-struct value");
558 auto s = std::get<std::shared_ptr<StructInstance>>(
data);
559 s->fields[name] = std::move(value);
562 [[nodiscard]]
bool hasField(
const std::string &name)
const noexcept
564 if (!std::holds_alternative<std::shared_ptr<StructInstance>>(
data))
568 auto s = std::get<std::shared_ptr<StructInstance>>(
data);
569 return s->fields.contains(name);
574template <>
struct std::formatter<
Phasor::Value>
587 constexpr auto parse(std::format_parse_context &ctx)
589 auto it = ctx.begin();
590 auto end = ctx.end();
593 while (close != end && *close !=
'}')
598 std::string_view full(&*it,
static_cast<size_t>(close - it));
599 std::string_view inner = full;
607 inner = full.substr(0, full.size() - 1);
611 inner = full.substr(0, full.size() - 1);
615 inner = full.substr(0, full.size() - 1);
619 inner = full.substr(0, full.size() - 1);
638 auto fwd = [&]<
typename T>(
const T &val) {
639 return std::vformat_to(ctx.out(), fmtstr, std::make_format_args(val));
667 return std::format_to(ctx.out(),
"null");
671 return fwd(v.
asInt());
689 output.reserve(input.size());
728 if (c < 0x20 || c == 0x7F)
731 snprintf(buf,
sizeof(buf),
"\\x%02X", (
unsigned char)c);
754 const auto &arr = *v.
asArray();
755 std::string out =
"[";
756 for (std::size_t i = 0; i < arr.size(); ++i)
759 if (i + 1 < arr.size())
768 std::string out =
s.structName +
" { ";
770 for (
const auto &[k, val] :
s.fields)
A value in the Phasor VM.
const char * c_str() const
Convert to C Style String.
std::shared_ptr< StructInstance > asStruct()
Value(std::shared_ptr< StructInstance > s)
Struct constructor.
static Value typeToString(const ValueType &type)
Value(int i)
Integer constructor.
bool isNull() const noexcept
Check if the value is null.
bool isTruthy() const noexcept
Helper to determine truthiness.
friend std::ostream & operator<<(std::ostream &os, const Value &v)
Print to output stream.
std::shared_ptr< ArrayInstance > asArray()
Get the value as an array.
bool isArray() const noexcept
Check if the value is an array.
Value operator/(const Value &other) const
Divide two values.
bool operator==(const Value &other) const noexcept
Comparison operations.
Value operator-(const Value &other) const
Subtract two values.
bool operator<=(const Value &other) const noexcept
Less than or equal to comparison.
std::vector< Value > ArrayInstance
bool isInt() const noexcept
ValueType getType() const noexcept
Get the type of the value.
bool operator>=(const Value &other) const noexcept
Greater than or equal to comparison.
int64_t asInt() const noexcept
Get the value as an integer.
Value(int64_t i)
Integer constructor.
void setField(const std::string &name, Value value)
bool isFloat() const noexcept
Value(bool b)
Boolean constructor.
static Value createStruct(const std::string &name)
double asFloat() const noexcept
Get the value as a double.
std::shared_ptr< const StructInstance > asStruct() const noexcept
bool asBool() const noexcept
Get the value as a boolean.
std::shared_ptr< const ArrayInstance > asArray() const noexcept
Get the value as an array (const).
bool isNumber() const noexcept
Value(const std::string &s)
String constructor.
bool operator!=(const Value &other) const noexcept
Inequality comparison.
bool operator<(const Value &other) const
Less than comparison.
Value operator*(const Value &other) const
Multiply two values.
bool operator>(const Value &other) const
Greater than comparison.
std::string toString() const noexcept
Convert to string for printing.
Value(double d)
Double constructor.
bool isString() const noexcept
Value operator%(const Value &other) const
Modulo two values.
std::string asString() const noexcept
Get the value as a string.
Value operator!() const noexcept
Logical negation.
static Value createArray(std::vector< Value > elements={})
Value(std::shared_ptr< ArrayInstance > a)
Array constructor.
Value logicalOr(const Value &other) const noexcept
Logical OR.
Value operator+(const Value &other) const
Add two values.
Value logicalAnd(const Value &other) const noexcept
Logical AND.
bool isBool() const noexcept
std::variant< std::monostate, bool, int64_t, double, std::shared_ptr< std::string >, std::shared_ptr< StructInstance >, std::shared_ptr< ArrayInstance > > DataType
Value()
Default constructor.
Value getField(const std::string &name) const
Value(const char *s)
String constructor.
bool hasField(const std::string &name) const noexcept
The Phasor Programming Language and Runtime.
ValueType
Runtime value types for the VM.
std::unordered_map< std::string, Value > fields