28#include <unordered_map>
64 std::unordered_map<PhsString, Value>
fields;
70 std::shared_ptr<StructInstance>,
71 std::shared_ptr<ArrayInstance>>;
113 Value(std::shared_ptr<ArrayInstance> a) :
data(std::move(a))
146 [[nodiscard]]
bool isNull() const noexcept {
return data.index() == 0; }
147 [[nodiscard]]
bool isBool() const noexcept {
return data.index() == 1; }
148 [[nodiscard]]
bool isInt() const noexcept {
return data.index() == 2; }
149 [[nodiscard]]
bool isFloat() const noexcept {
return data.index() == 3; }
150 [[nodiscard]]
bool isString() const noexcept {
return data.index() == 4; }
151 [[nodiscard]]
bool isNumber() const noexcept {
return data.index() == 2 ||
data.index() == 3; }
155 return std::holds_alternative<std::shared_ptr<ArrayInstance>>(
data);
159 [[nodiscard]]
bool asBool() const noexcept
161 return std::get<bool>(
data);
168 return std::get<i64>(
data);
172 return static_cast<i64>(std::get<f64>(
data));
181 return std::get<f64>(
data);
185 return static_cast<f64>(std::get<i64>(
data));
190 [[nodiscard]] std::string
string() const noexcept
194 return std::get<PhsString>(
data).str();
203 return std::get<PhsString>(
data);
210 return std::get<std::shared_ptr<ArrayInstance>>(
data);
214 [[nodiscard]] std::shared_ptr<const ArrayInstance>
asArray() const noexcept
216 return std::get<std::shared_ptr<ArrayInstance>>(
data);
234 throw std::runtime_error(
"Cannot add these value types");
248 throw std::runtime_error(
"Cannot subtract these value types");
263 throw std::runtime_error(
"Cannot decrement this value type");
278 throw std::runtime_error(
"Cannot increment this value type");
292 throw std::runtime_error(
"Cannot multiply these value types");
300 if (other.
asInt() == 0)
302 throw std::runtime_error(
"Division by zero");
310 throw std::runtime_error(
"Division by zero");
314 throw std::runtime_error(
"Cannot divide these value types");
322 if (other.
asInt() == 0)
324 throw std::runtime_error(
"Modulo by zero");
328 throw std::runtime_error(
"Modulo requires integer operands");
340 return {
isTruthy() && other.isTruthy()};
346 return {
isTruthy() || other.isTruthy()};
378 if (
getType() != other.getType())
388 return asBool() == other.asBool();
392 return asInt() == other.asInt();
396 return asFloat() == other.asFloat();
400 return asString() == other.asString();
404 if (!other.isArray())
408 const auto &self_arr = *
asArray();
409 const auto &other_arr = *other.asArray();
410 return self_arr == other_arr;
418 return !(*
this == other);
436 throw std::runtime_error(
"Cannot compare these value types ");
454 throw std::runtime_error(
"Cannot compare these value types ");
460 return !(*
this > other);
465 return !(*
this < other);
468 [[nodiscard]] std::string
toRepr() const noexcept
472 return "\"" +
string() +
"\"";
478 [[nodiscard]] std::string
toString() const noexcept
486 return asBool() ?
"true" :
"false";
490 return std::to_string(
asInt());
494 return std::to_string(
asFloat());
498 [[likely]]
return string();
502 std::string result =
"[";
504 for (
size_t i = 0; i < arr.size(); ++i)
506 result += arr[i].toRepr();
507 if (i < arr.size() - 1)
517 std::string result =
"{";
520 for (
const auto &[k, v] :
s.fields)
526 result +=
"\"" + k.str() +
"\": " + v.toRepr();
536 [[nodiscard]]
const char *
c_str()
const
540 [[unlikely]]
throw std::runtime_error(
"c_str() can only be called on string values");
542 return std::get<PhsString>(
data).c_str();
554 return std::holds_alternative<std::shared_ptr<StructInstance>>(
data);
559 return std::get<std::shared_ptr<StructInstance>>(
data);
562 [[nodiscard]] std::shared_ptr<const StructInstance>
asStruct() const noexcept
564 return std::get<std::shared_ptr<StructInstance>>(
data);
569 return Value(std::make_shared<StructInstance>(
StructInstance{.structName = name, .fields = {}}));
574 return {std::make_shared<ArrayInstance>(std::move(elements))};
579 if (!std::holds_alternative<std::shared_ptr<StructInstance>>(
data))
581 [[unlikely]]
throw std::runtime_error(
"getField() called on non-struct value");
583 auto s = std::get<std::shared_ptr<StructInstance>>(
data);
584 auto it =
s->fields.find(name);
585 if (it ==
s->fields.end())
594 if (!std::holds_alternative<std::shared_ptr<StructInstance>>(
data))
596 [[unlikely]]
throw std::runtime_error(
"setField() called on non-struct value");
598 auto s = std::get<std::shared_ptr<StructInstance>>(
data);
599 s->fields[name] = std::move(value);
604 if (!std::holds_alternative<std::shared_ptr<StructInstance>>(
data))
608 auto s = std::get<std::shared_ptr<StructInstance>>(
data);
609 return s->fields.contains(name);
614template <>
struct std::formatter<
Phasor::Value>
627 constexpr auto parse(std::format_parse_context &ctx)
629 auto it = ctx.begin();
630 auto end = ctx.end();
633 while (close != end && *close !=
'}')
638 std::string_view full(&*it,
static_cast<size_t>(close - it));
639 std::string_view inner = full;
647 inner = full.substr(0, full.size() - 1);
651 inner = full.substr(0, full.size() - 1);
655 inner = full.substr(0, full.size() - 1);
659 inner = full.substr(0, full.size() - 1);
678 auto fwd = [&]<
typename T>(
const T &val) {
679 return std::vformat_to(ctx.out(), fmtstr, std::make_format_args(val));
707 return std::format_to(ctx.out(),
"null");
711 return fwd(v.
asInt());
729 output.reserve(input.size());
768 if (c < 0x20 || c == 0x7F)
771 snprintf(buf,
sizeof(buf),
"\\x%02X", (
unsigned char)c);
794 const auto &arr = *v.
asArray();
795 std::string out =
"[";
796 for (std::size_t i = 0; i < arr.size(); ++i)
799 if (i + 1 < arr.size())
808 std::string out =
s.structName.str() +
" { ";
810 for (
const auto &[k, val] :
s.fields)
bool empty() const noexcept
A value in the Phasor VM.
PhsString asString() const noexcept
Get the value as a Small String.
std::string string() const noexcept
Get the value as a string.
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(f64 d)
Double constructor.
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.
static Value createStruct(const PhsString &name)
bool operator>=(const Value &other) const noexcept
Greater than or equal to comparison.
bool hasField(const PhsString &name) const noexcept
bool isFloat() const noexcept
void setField(const PhsString &name, Value value)
Value getField(const PhsString &name) const
f64 asFloat() const noexcept
Get the value as a f64.
Value(bool b)
Boolean constructor.
std::shared_ptr< const StructInstance > asStruct() const noexcept
i64 asInt() const noexcept
Get the value as an integer.
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.
bool isString() const noexcept
Value operator%(const Value &other) const
Modulo two values.
Value operator!() const noexcept
Logical negation.
static Value createArray(std::vector< Value > elements={})
Value(std::shared_ptr< ArrayInstance > a)
Array constructor.
Value(i64 i)
Integer constructor.
Value logicalOr(const Value &other) const noexcept
Logical OR.
Value operator+(const Value &other) const
Add two values.
Value(const PhsString &s)
Small Strring constructor.
Value logicalAnd(const Value &other) const noexcept
Logical AND.
bool isBool() const noexcept
Value()
Default constructor.
Value(const char *s)
String constructor.
std::string toRepr() const noexcept
std::variant< std::monostate, bool, i64, f64, PhsString, std::shared_ptr< StructInstance >, std::shared_ptr< ArrayInstance > > DataType
The Phasor Programming Language and Runtime.
ValueType
Runtime value types for the VM.
std::unordered_map< PhsString, Value > fields