| 476 | |
| 477 | |
| 478 | struct value_object_t : public value_t { |
| 479 | std::unordered_map<value, value, value_hasher, value_equivalence> unordered; |
| 480 | bool has_builtins = true; // context and loop objects do not have builtins |
| 481 | value_object_t() = default; |
| 482 | value_object_t(value & v) { |
| 483 | val_obj = v->val_obj; |
| 484 | for (const auto & pair : val_obj) { |
| 485 | unordered[pair.first] = pair.second; |
| 486 | } |
| 487 | } |
| 488 | value_object_t(const std::map<value, value> & obj) { |
| 489 | for (const auto & pair : obj) { |
| 490 | insert(pair.first, pair.second); |
| 491 | } |
| 492 | } |
| 493 | value_object_t(const std::vector<std::pair<value, value>> & obj) { |
| 494 | for (const auto & pair : obj) { |
| 495 | insert(pair.first, pair.second); |
| 496 | } |
| 497 | } |
| 498 | void insert(const std::string & key, const value & val) { |
| 499 | insert(mk_val<value_string>(key), val); |
| 500 | } |
| 501 | virtual std::string type() const override { return "Object"; } |
| 502 | virtual bool is_immutable() const override { return false; } |
| 503 | virtual const std::vector<std::pair<value, value>> & as_ordered_object() const override { return val_obj; } |
| 504 | virtual string as_string() const override { |
| 505 | std::ostringstream ss; |
| 506 | ss << "{"; |
| 507 | for (size_t i = 0; i < val_obj.size(); i++) { |
| 508 | if (i > 0) ss << ", "; |
| 509 | auto & [key, val] = val_obj.at(i); |
| 510 | ss << value_to_string_repr(key) << ": " << value_to_string_repr(val); |
| 511 | } |
| 512 | ss << "}"; |
| 513 | return ss.str(); |
| 514 | } |
| 515 | virtual bool as_bool() const override { |
| 516 | return !unordered.empty(); |
| 517 | } |
| 518 | virtual bool has_key(const value & key) override { |
| 519 | if (!key->is_immutable() || !key->is_hashable()) { |
| 520 | throw std::runtime_error("Object key of unhashable type: " + key->type()); |
| 521 | } |
| 522 | return unordered.find(key) != unordered.end(); |
| 523 | } |
| 524 | virtual void insert(const value & key, const value & val) override { |
| 525 | bool replaced = false; |
| 526 | if (is_immutable()) { |
| 527 | throw std::runtime_error("Attempting to modify immutable type"); |
| 528 | } |
| 529 | if (has_key(key)) { |
| 530 | // if key exists, replace value in ordered list instead of appending |
| 531 | for (auto & pair : val_obj) { |
| 532 | if (*(pair.first) == *key) { |
| 533 | pair.second = val; |
| 534 | replaced = true; |
| 535 | break; |