5#include <unordered_map>
13 output.reserve(input.size());
15 for (
char c : input) {
17 case '\n': output +=
"\\n";
break;
18 case '\t': output +=
"\\t";
break;
19 case '\r': output +=
"\\r";
break;
20 case '\0': output +=
"\\0";
break;
21 case '\\': output +=
"\\\\";
break;
22 case '\"': output +=
"\\\"";
break;
23 case '\'': output +=
"\\'";
break;
24 case '\a': output +=
"\\a";
break;
25 case '\b': output +=
"\\b";
break;
26 case '\f': output +=
"\\f";
break;
27 case '\v': output +=
"\\v";
break;
29 if (c < 0x20 || c == 0x7F) {
31 snprintf(buf,
sizeof(buf),
"\\x%02X", (
unsigned char)c);
72 std::unordered_map<std::string, Value>
fields;
77 using DataType = std::variant<std::monostate, bool, int64_t, double, std::string, std::shared_ptr<StructInstance>,
78 std::shared_ptr<ArrayInstance>>;
112 Value(std::shared_ptr<StructInstance> s) :
data(std::move(s))
116 Value(std::shared_ptr<ArrayInstance> a) :
data(std::move(a))
123 if (std::holds_alternative<std::monostate>(
data))
125 if (std::holds_alternative<bool>(
data))
127 if (std::holds_alternative<int64_t>(
data))
129 if (std::holds_alternative<double>(
data))
131 if (std::holds_alternative<std::string>(
data))
133 if (std::holds_alternative<std::shared_ptr<StructInstance>>(
data))
135 if (std::holds_alternative<std::shared_ptr<ArrayInstance>>(
data))
145 return Value(
"null");
147 return Value(
"bool");
151 return Value(
"float");
153 return Value(
"string");
155 return Value(
"struct");
157 return Value(
"array");
159 return Value(
"unknown");
196 return std::holds_alternative<std::shared_ptr<ArrayInstance>>(
data);
202 return std::get<bool>(
data);
208 return std::get<int64_t>(
data);
210 return static_cast<int64_t
>(std::get<double>(
data));
217 return std::get<double>(
data);
219 return static_cast<double>(std::get<int64_t>(
data));
226 return std::get<std::string>(
data);
232 return std::get<std::shared_ptr<ArrayInstance>>(
data);
236 const std::shared_ptr<const ArrayInstance>
asArray()
const
238 return std::get<std::shared_ptr<ArrayInstance>>(
data);
250 throw std::runtime_error(
"Cannot add these value types");
260 throw std::runtime_error(
"Cannot subtract these value types");
270 throw std::runtime_error(
"Cannot multiply these value types");
278 if (other.
asInt() == 0)
279 throw std::runtime_error(
"Division by zero");
285 throw std::runtime_error(
"Division by zero");
288 throw std::runtime_error(
"Cannot divide these value types");
296 if (other.
asInt() == 0)
297 throw std::runtime_error(
"Modulo by zero");
300 throw std::runtime_error(
"Modulo requires integer operands");
310 throw std::runtime_error(
"Cannot negate this value type");
366 const auto &self_arr = *
asArray();
367 const auto &other_arr = *other.
asArray();
368 return self_arr == other_arr;
376 return !(*
this == other);
388 throw std::runtime_error(
"Cannot compare these value types ");
400 throw std::runtime_error(
"Cannot compare these value types ");
406 return !(*
this > other);
411 return !(*
this < other);
420 return asBool() ?
"true" :
"false";
422 return std::to_string(
asInt());
424 return std::to_string(
asFloat());
429 std::string result =
"[";
431 for (
size_t i = 0; i < arr.size(); ++i)
433 result += arr[i].toString();
434 if (i < arr.size() - 1)
449 throw std::runtime_error(
"c_str() can only be called on string values");
450 return std::get<std::string>(
data).c_str();
462 return std::holds_alternative<std::shared_ptr<StructInstance>>(
data);
467 return std::get<std::shared_ptr<StructInstance>>(
data);
470 const std::shared_ptr<const StructInstance>
asStruct()
const
472 return std::get<std::shared_ptr<StructInstance>>(
data);
477 return Value(std::make_shared<StructInstance>(
StructInstance{.structName = name, .fields = {}}));
482 return Value(std::make_shared<ArrayInstance>(std::move(elements)));
487 if (!std::holds_alternative<std::shared_ptr<StructInstance>>(
data))
488 throw std::runtime_error(
"getField() called on non-struct value");
489 auto s = std::get<std::shared_ptr<StructInstance>>(
data);
490 auto it = s->fields.find(name);
491 if (it == s->fields.end())
498 if (!std::holds_alternative<std::shared_ptr<StructInstance>>(
data))
499 throw std::runtime_error(
"setField() called on non-struct value");
500 auto s = std::get<std::shared_ptr<StructInstance>>(
data);
501 s->fields[name] = std::move(value);
506 if (!std::holds_alternative<std::shared_ptr<StructInstance>>(
data))
508 auto s = std::get<std::shared_ptr<StructInstance>>(
data);
509 return s->fields.find(name) != s->fields.end();
517 enum class Style { Value, TypeOnly, TypeValue, Debug, Quoted };
521 constexpr auto parse(std::format_parse_context &ctx)
523 auto it = ctx.begin();
524 auto end = ctx.end();
527 while (close != end && *close !=
'}') ++close;
529 std::string_view full(&*it,
static_cast<size_t>(close - it));
530 std::string_view inner = full;
548 template <
typename FormatContext>
557 auto fwd = [&]<
typename T>(
const T &val) {
558 return std::vformat_to(ctx.out(), fmtstr, std::make_format_args(val));
606 const auto &arr = *v.
asArray();
607 std::string out =
"[";
608 for (std::size_t i = 0; i < arr.size(); ++i)
611 if (i + 1 < arr.size()) out +=
", ";
618 std::string out = s.structName +
" { ";
620 for (
const auto &[k, val] : s.fields)
622 if (!first) out +=
", ";
632 static std::string
escape(
const std::string &s)
635 out.reserve(s.size());
639 case '"': out +=
"\\\"";
break;
640 case '\\': out +=
"\\\\";
break;
641 case '\n': out +=
"\\n";
break;
642 case '\t': out +=
"\\t";
break;
std::string escapeString(const std::string &input)
A value in the Phasor VM.
bool isTruthy() const
Helper to determine truthiness.
const char * c_str() const
Convert to C Style String.
std::shared_ptr< StructInstance > asStruct()
std::string toString() const
Convert to string for printing.
const std::shared_ptr< const StructInstance > asStruct() const
Value operator-() const
Unary negation.
double asFloat() const
Get the value as a double.
Value(std::shared_ptr< StructInstance > s)
Struct constructor.
static Value typeToString(const ValueType &type)
Value(int i)
Integer constructor.
bool isNumber() const
Check if the value is a number.
std::string asString() const
Get the value as a string.
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.
Value operator/(const Value &other) const
Divide two values.
bool operator>=(const Value &other) const
Greater than or equal to comparison.
Value operator-(const Value &other) const
Subtract two values.
std::vector< Value > ArrayInstance
bool hasField(const std::string &name) const
Value(int64_t i)
Integer constructor.
void setField(const std::string &name, Value value)
bool operator<=(const Value &other) const
Less than or equal to comparison.
bool isNull() const
Check if the value is null.
int64_t asInt() const
Get the value as an integer.
bool isBool() const
Check if the value is a boolean.
Value(bool b)
Boolean constructor.
std::variant< std::monostate, bool, int64_t, double, std::string, std::shared_ptr< StructInstance >, std::shared_ptr< ArrayInstance > > DataType
bool isFloat() const
Check if the value is a double.
static Value createStruct(const std::string &name)
bool isArray() const
Check if the value is an array.
ValueType getType() const
Get the type of the value.
const std::shared_ptr< const ArrayInstance > asArray() const
Get the value as an array (const).
Value logicalAnd(const Value &other) const
Logical AND.
bool asBool() const
Get the value as a boolean.
Value(const std::string &s)
String constructor.
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.
Value operator!() const
Logical negation.
Value(double d)
Double constructor.
bool operator==(const Value &other) const
Comparison operations.
bool operator!=(const Value &other) const
Inequality comparison.
Value operator%(const Value &other) const
Modulo two values.
static Value createArray(std::vector< Value > elements={})
Value(std::shared_ptr< ArrayInstance > a)
Array constructor.
Value operator+(const Value &other) const
Add two values.
Value()
Default constructor.
Value getField(const std::string &name) const
bool isString() const
Check if the value is a string.
Value(const char *s)
String constructor.
Value logicalOr(const Value &other) const
Logical OR.
bool isInt() const
Check if the value is an integer.
The Phasor Programming Language and Runtime.
ValueType
Runtime value types for the VM.
std::unordered_map< std::string, Value > fields