@@ -14,51 +14,59 @@ namespace intp::interp {
1414 return os << closure.to_string ();
1515 }
1616
17- [[nodiscard]] std::string NativeFunction ::to_string () const {
17+ [[nodiscard]] std::string List ::to_string () const {
1818 std::ostringstream oss;
19- oss << " <native_fn: " << name << " " << arity << " >" ;
20- return oss.str ();
21- }
22-
23- std::ostream &operator <<(std::ostream &os, const NativeFunction &native_fn) {
24- return os << native_fn.to_string ();
25- }
26-
27- static std::ostream &print_loc_prefix (std::ostream &os, const std::optional<fe::loc::Loc> &loc) {
28- if (loc.has_value ()) {
29- return os << loc.value () << " : " ;
19+ oss << " [" ;
20+ for (size_t i = 0 ; i < elements.size (); ++i) {
21+ oss << elements[i].to_string ();
22+ if (i + 1 != elements.size ()) {
23+ oss << " , " ;
24+ }
3025 }
31- return os;
26+ oss << " ]" ;
27+ return oss.str ();
3228 }
3329
34- std::string val_to_string ( const Value &value) {
30+ [[nodiscard]] std::string Value::to_string () const {
3531 return std::visit ([&]<typename T0 >(T0 &&arg) {
3632 using T = std::decay_t <T0 >;
3733 if constexpr (std::is_same_v<T, double >) {
3834 return std::to_string (arg);
3935 } else if constexpr (std::is_same_v<T, std::string>) {
4036 return arg;
41- } else if constexpr (std::is_same_v<T, Closure> ||
42- std::is_same_v<T, NativeFunction>) {
37+ } else if constexpr (std::is_same_v<T, Closure>) {
4338 return arg.to_string ();
39+ } else if constexpr (std::is_same_v<T, std::shared_ptr<NativeFunction> > ||
40+ std::is_same_v<T, std::shared_ptr<List> >) {
41+ return arg->to_string ();
4442 } else {
4543 STATIC_ASSERT_UNREACHABLE_T (T, " unhandled runtime value" );
4644 }
47- }, value );
45+ }, * this );
4846 }
4947
5048 std::ostream &operator <<(std::ostream &os, const Value &value) {
51- std::visit ([&]<typename T0 >(T0 &&arg) {
52- using T = std::decay_t <T0 >;
53- if constexpr (std::is_same_v<T, std::string> ||
54- std::is_same_v<T, double > ||
55- std::is_same_v<T, Closure> ||
56- std::is_same_v<T, NativeFunction>) {
57- os << arg;
58- } else {
59- STATIC_ASSERT_UNREACHABLE_T (T, " unhandled runtime value" );
60- }
61- }, value);
49+ return os << value.to_string ();
50+ }
51+
52+ std::ostream &operator <<(std::ostream &os, const List &list) {
53+ return os << list.to_string ();
54+ }
55+
56+ [[nodiscard]] std::string NativeFunction::to_string () const {
57+ std::ostringstream oss;
58+ oss << " <native_fn: " << name << " " << arity << " >" ;
59+ return oss.str ();
60+ }
61+
62+ std::ostream &operator <<(std::ostream &os, const NativeFunction &native_fn) {
63+ return os << native_fn.to_string ();
64+ }
65+
66+ static std::ostream &print_loc_prefix (std::ostream &os, const std::optional<fe::loc::Loc> &loc) {
67+ if (loc.has_value ()) {
68+ return os << loc.value () << " : " ;
69+ }
6270 return os;
6371 }
6472
@@ -128,12 +136,11 @@ namespace intp::interp {
128136 try {
129137 if (force) {
130138 const Value &val = thunk->force ();
131- val_str = val_to_string ( val);
139+ val_str = val. to_string ( );
132140 } else if (thunk->cached ) {
133- val_str = val_to_string (* thunk->cached ); // already computed
141+ val_str = thunk->cached -> to_string ( ); // already computed
134142 }
135143 } catch (const std::exception &) {
136- val_str = " <thunk: error>" ;
137144 }
138145 vec.push_back ({name, val_str});
139146 }
@@ -239,8 +246,8 @@ namespace intp::interp {
239246 resultant_value = eval_expr (*body, child_env);
240247 }
241248 // Native Function case: Consumes its arity-many Argument Thunks
242- else if (std::holds_alternative<NativeFunction>(current_fn)) {
243- const auto &[arity, name, impl] = std::get<NativeFunction>(current_fn);
249+ else if (std::holds_alternative<std::shared_ptr< NativeFunction> >(current_fn)) {
250+ const auto &[arity, name, impl] = * std::get<std::shared_ptr< NativeFunction> >(current_fn);
244251 if (work_args.size () - idx < arity) {
245252 print_loc_prefix (std::cerr, call_loc)
246253 << " runtime error: native function " << name
@@ -268,7 +275,7 @@ namespace intp::interp {
268275 std::exit (EXIT_FAILURE );
269276 }
270277 if (std::holds_alternative<Closure>(*resultant_value) ||
271- std::holds_alternative<NativeFunction>(*resultant_value)) {
278+ std::holds_alternative<std::shared_ptr< NativeFunction> >(*resultant_value)) {
272279 // Replace the top Frame with the returned Function (curry)
273280 frames.back () = std::move (*resultant_value);
274281 continue ;
@@ -302,7 +309,7 @@ namespace intp::interp {
302309
303310 // Creates placeholder Thunk then set body so recursion can refer to it during lazy evaluation
304311 static void bind_def_ast_node_lazy (fe::ast::DefAstNode &def_ast_node, const std::shared_ptr<Env> &env,
305- Options options) {
312+ const Options options) {
306313 const auto thunk = std::make_shared<Thunk>();
307314 env->bind (def_ast_node.def_name .value , thunk);
308315 if (options.own_expr ) {
@@ -339,7 +346,7 @@ namespace intp::interp {
339346 void install_builtins (const std::shared_ptr<Env> &env) {
340347 for (auto &native_fn: get_builtins ()) {
341348 const auto thunk = std::make_shared<Thunk>();
342- thunk->cached = Value{native_fn};
349+ thunk->cached = Value{std::make_shared<NativeFunction>( native_fn) };
343350 env->bind (native_fn.name , thunk);
344351 }
345352 }
0 commit comments