44
55namespace intp ::interp {
66 std::ostream &operator <<(std::ostream &os, const Closure &closure) {
7- return os << " <closure " << closure.param << " >" ;
7+ return os << " <closure: " << closure.param << " >" ;
88 }
99
1010 std::ostream &operator <<(std::ostream &os, const NativeFunction &native_fn) {
11- return os << " <native_fn " << native_fn.name << " " << native_fn.arity << " >" ;
11+ return os << " <native_fn: " << native_fn.name << " " << native_fn.arity << " >" ;
12+ }
13+
14+ static std::ostream &print_loc_prefix (std::ostream &os, const std::optional<fe::loc::Loc> &loc) {
15+ if (loc.has_value ()) {
16+ return os << loc.value () << " : " ;
17+ }
18+ return os;
1219 }
1320
1421 std::ostream &operator <<(std::ostream &os, const Value &value) {
@@ -36,10 +43,8 @@ namespace intp::interp {
3643 }
3744 // Expression is not initialized
3845 if (!expr) {
39- if (origin) {
40- std::cerr << *origin << " : " ;
41- }
42- std::cerr << " runtime error: forcing empty thunk" ;
46+ print_loc_prefix (std::cerr, origin)
47+ << " runtime error: forcing empty thunk" ;
4348 exit (EXIT_FAILURE );
4449 }
4550 cached = eval_expr (*expr, env);
@@ -49,9 +54,21 @@ namespace intp::interp {
4954 void Thunk::set (const fe::ast::Expression *expr_, std::shared_ptr<Env> env_,
5055 std::optional<fe::loc::Loc> origin_) {
5156 expr = expr_;
57+ owned.reset ();
5258 env = std::move (env_);
53- if (origin_) {
54- origin = std::move (origin_);
59+ if (origin_.has_value ()) {
60+ origin = std::move (origin_.value ());
61+ }
62+ cached.reset ();
63+ }
64+
65+ void Thunk::set_owned (fe::ast::Expression expr_, std::shared_ptr<Env> env_,
66+ std::optional<fe::loc::Loc> origin_) {
67+ owned = std::make_unique<fe::ast::Expression>(std::move (expr_));
68+ expr = owned.get ();
69+ env = std::move (env_);
70+ if (origin_.has_value ()) {
71+ origin = std::move (origin_.value ());
5572 }
5673 cached.reset ();
5774 }
@@ -74,11 +91,36 @@ namespace intp::interp {
7491 table[name] = std::move (thunk);
7592 }
7693
94+ void Env::dump (std::ostream &os, const bool force) const {
95+ for (const auto &[name, thunk]: table) {
96+ os << " " << name << " = " ;
97+ try {
98+ if (force) {
99+ 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+ }
107+ }
108+ } catch (const std::exception &ex) {
109+ os << " <thunk: unevaluated>" ;
110+ }
111+ os << std::endl;
112+ }
113+ if (parent) {
114+ os << " info: parent environment" << std::endl;
115+ parent->dump (os, force);
116+ }
117+ }
118+
77119 static Value eval_iden_ast_node (const fe::ast::IdenAstNode &iden_ast_node, const std::shared_ptr<Env> &env) {
78120 const auto thunk = env->lookup (iden_ast_node.value );
79121 if (!thunk) {
80- std::cerr << iden_ast_node.loc << " : runtime error: "
81- << " undefined identifier "
122+ print_loc_prefix ( std::cerr, iden_ast_node.loc )
123+ << " runtime error: undefined identifier "
82124 << iden_ast_node.value
83125 << std::endl;
84126 exit (EXIT_FAILURE );
@@ -94,8 +136,8 @@ namespace intp::interp {
94136 // Lookup the callee lazily
95137 const auto callee_thunk = env->lookup (fn_apl.fn_name .value );
96138 if (!callee_thunk) {
97- std::cerr << fn_apl.loc << " : runtime error: "
98- << " undefined function "
139+ print_loc_prefix ( std::cerr, fn_apl.loc )
140+ << " runtime error: undefined function "
99141 << fn_apl.fn_name .value
100142 << std::endl;
101143 exit (EXIT_FAILURE );
@@ -133,13 +175,6 @@ namespace intp::interp {
133175 return t;
134176 }
135177
136- static std::ostream &print_loc_prefix (std::ostream &os, const std::optional<fe::loc::Loc> &loc) {
137- if (loc) {
138- return os << *loc << " : " ;
139- }
140- return os;
141- }
142-
143178 Value apply_fn_apl (Value fn_value, const std::vector<std::shared_ptr<Thunk> > &args,
144179 const std::shared_ptr<Env> &call_site_env, const std::optional<fe::loc::Loc> &call_loc) {
145180 // Local mutable copy of the args, for inserting evaluated values as Thunks when needed.
@@ -237,25 +272,33 @@ namespace intp::interp {
237272 }
238273
239274 // Creates placeholder Thunk then set body so recursion can refer to it during lazy evaluation
240- static void bind_def_ast_node_lazy (const fe::ast::DefAstNode &def_ast_node, const std::shared_ptr<Env> &env) {
275+ static void bind_def_ast_node_lazy (fe::ast::DefAstNode &def_ast_node, const std::shared_ptr<Env> &env,
276+ Options options) {
241277 const auto thunk = std::make_shared<Thunk>();
242278 env->bind (def_ast_node.def_name .value , thunk);
243- thunk->set (&def_ast_node.expr , env, def_ast_node.expr .get_loc ());
279+ if (options.own_expr ) {
280+ thunk->set_owned (std::move (def_ast_node.expr ), env, def_ast_node.expr .get_loc ());
281+ } else {
282+ thunk->set (&def_ast_node.expr , env, def_ast_node.expr .get_loc ());
283+ }
244284 }
245285
246- Result interpret (const fe::ast::Program &program, std::optional<std::shared_ptr<Env> > global_env) {
286+ Result interpret (fe::ast::Program &program, std::optional<std::shared_ptr<Env> > global_env,
287+ Options options) {
247288 if (!global_env) {
248289 global_env = std::make_shared<Env>();
290+ install_builtins (*global_env);
249291 }
250292 Value result_value;
251- install_builtins (*global_env);
252- for (const auto &[value]: program.nodes ) {
293+ for (auto &[value]: program.nodes ) {
253294 std::visit ([&]<typename T0 >(T0 &&arg) {
254295 using T = std::decay_t <T0 >;
255296 if constexpr (std::is_same_v<T, fe::ast::Expression>) {
256297 result_value = eval_expr (arg, *global_env);
257298 } else if constexpr (std::is_same_v<T, fe::ast::DefAstNode>) {
258- bind_def_ast_node_lazy (arg, *global_env);
299+ bind_def_ast_node_lazy (arg, *global_env, options);
300+ const fe::ast::DefAstNode &def_ast_node = arg;
301+ result_value = def_ast_node.def_name .value ;
259302 } else {
260303 STATIC_ASSERT_UNREACHABLE_T (T, " unhandled program node" );
261304 }
0 commit comments