11#include < lbd/intp/interpreter.h>
22#include < lbd/intp/builtins.h>
33#include < lbd/error.h>
4+ #include < sstream>
45
56namespace intp ::interp {
7+ [[nodiscard]] std::string Closure::to_string () const {
8+ std::ostringstream oss;
9+ oss << " <closure: " << param << " >" ;
10+ return oss.str ();
11+ }
12+
613 std::ostream &operator <<(std::ostream &os, const Closure &closure) {
7- return os << " <closure: " << closure.param << " >" ;
14+ return os << closure.to_string ();
15+ }
16+
17+ [[nodiscard]] std::string NativeFunction::to_string () const {
18+ std::ostringstream oss;
19+ oss << " <native_fn: " << name << " " << arity << " >" ;
20+ return oss.str ();
821 }
922
1023 std::ostream &operator <<(std::ostream &os, const NativeFunction &native_fn) {
11- return os << " < native_fn: " << native_fn. name << " " << native_fn. arity << " > " ;
24+ return os << native_fn. to_string () ;
1225 }
1326
1427 static std::ostream &print_loc_prefix (std::ostream &os, const std::optional<fe::loc::Loc> &loc) {
@@ -18,6 +31,22 @@ namespace intp::interp {
1831 return os;
1932 }
2033
34+ std::string val_to_string (const Value &value) {
35+ return std::visit ([&]<typename T0 >(T0 &&arg) {
36+ using T = std::decay_t <T0 >;
37+ if constexpr (std::is_same_v<T, double >) {
38+ return std::to_string (arg);
39+ } else if constexpr (std::is_same_v<T, std::string>) {
40+ return arg;
41+ } else if constexpr (std::is_same_v<T, Closure> ||
42+ std::is_same_v<T, NativeFunction>) {
43+ return arg.to_string ();
44+ } else {
45+ STATIC_ASSERT_UNREACHABLE_T (T, " unhandled runtime value" );
46+ }
47+ }, value);
48+ }
49+
2150 std::ostream &operator <<(std::ostream &os, const Value &value) {
2251 std::visit ([&]<typename T0 >(T0 &&arg) {
2352 using T = std::decay_t <T0 >;
@@ -91,29 +120,29 @@ namespace intp::interp {
91120 table[name] = std::move (thunk);
92121 }
93122
94- void Env::dump (std::ostream &os, const bool force) const {
123+ std::vector<std::vector<std::string> > Env::to_vector (const bool force) const {
124+ std::vector<std::vector<std::string> > vec;
125+ vec.reserve (table.size ());
95126 for (const auto &[name, thunk]: table) {
96- os << " " << name << " = " ;
127+ std::string val_str = " <thunk: unevaluated> " ;
97128 try {
98129 if (force) {
99130 const Value &val = thunk->force ();
100- os << val;
101- } else {
102- if (thunk->cached ) {
103- os << *(thunk->cached ); // already computed
104- } else {
105- os << " <thunk: unevaluated>" ;
106- }
131+ val_str = val_to_string (val);
132+ } else if (thunk->cached ) {
133+ val_str = val_to_string (*thunk->cached ); // already computed
107134 }
108- } catch (const std::exception &ex ) {
109- os << " <thunk: unevaluated >" ;
135+ } catch (const std::exception &) {
136+ val_str = " <thunk: error >" ;
110137 }
111- os << std::endl ;
138+ vec. push_back ({name, val_str}) ;
112139 }
113140 if (parent) {
114- os << " info: parent environment" << std::endl;
115- parent->dump (os, force);
141+ auto parent_vec = parent->to_vector (force);
142+ vec.insert (vec.end (), std::make_move_iterator (parent_vec.begin ()),
143+ std::make_move_iterator (parent_vec.end ()));
116144 }
145+ return vec;
117146 }
118147
119148 static Value eval_iden_ast_node (const fe::ast::IdenAstNode &iden_ast_node, const std::shared_ptr<Env> &env) {
0 commit comments