ztsdb
env.hpp
1 // (C) 2016 Leonardo Silvestri
2 //
3 // This file is part of ztsdb.
4 //
5 // ztsdb is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // ztsdb is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with ztsdb. If not, see <http://www.gnu.org/licenses/>.
17 
18 
19 #ifndef ENV_HPP
20 #define ENV_HPP
21 
22 #include <vector>
23 #include <map>
24 #include <string>
25 #include <iterator>
26 #include <memory>
27 #include <tuple>
28 #include "valuevar.hpp"
29 #include "display.hpp"
30 
31 
32 // #define ENV_HPP_DEBUG
33 
34 using namespace Juice;
35 
36 namespace interp {
37  struct Kont;
38 
39  struct BaseFrame;
40  typedef std::shared_ptr<BaseFrame> shpfrm;
41 
42  struct BaseFrame : std::enable_shared_from_this<BaseFrame> {
43 
44  typedef map<string,val::Value> map_type;
45  typedef map<string,val::Value>::const_iterator const_map_iterator;
46 
47 
48  // BaseFrame(const string& name_p) : name(name_p), up(0), global(0), ec(nullptr), cc(nullptr) { }
49  BaseFrame(const string& name_p,
50  shpfrm g, // pointer to global
51  shpfrm u, // pointer to upper frame
52  shared_ptr<interp::Kont> bc_p = nullptr,
53  shared_ptr<interp::Kont> ec_p = shared_ptr<interp::Kont>(),
54  shared_ptr<interp::Kont> cc_p = nullptr) :
55  name(name_p), up(u), global(g), bc(bc_p), ec(ec_p), cc(cc_p), depth(u ? u->depth + 1 : 0) {
56 #ifdef ENV_HPP_DEBUG
57  cout << name << " FRAME CREATED: " << this << endl;
58 #endif
59 
60  }
61 
62  shared_ptr<interp::Kont> getec() { return ec; }
63  void resetec() { ec = nullptr; }
64  std::vector<BaseFrame*> getStack(std::vector<BaseFrame*> s = std::vector<BaseFrame*>()) {
65  s.push_back(this);
66  return up ? up->getStack(s) : s;
67  }
68 
69 
70  virtual val::Value find(const string& s) const = 0;
71  virtual val::Value findLocal(const string& s) const = 0;
72  virtual val::Value& findR(const string& s, bool funcall=false) = 0;
73 
74  virtual val::SpVAS getNames() = 0;
75 
76  virtual val::Value& add(string s, val::Value&& val) = 0;
77  virtual val::Value& addSpecial(string s, val::Value&& val) = 0;
78  virtual val::Value& addEllipsis(string s, val::Value&& val,
79  const yy::location& loc, bool isRef) = 0;
80  virtual val::Value& addArg(string s, val::Value&& val, const yy::location& loc, bool isRef) = 0;
81  virtual bool remove(const string& symb) = 0;
82  virtual bool removeSpecial(const string& symb) = 0;
83 
84  virtual shpfrm getTrueFrame() { return shared_from_this(); }
85 
86  virtual operator string() const = 0;
87  virtual void clearTmp() = 0;
88  virtual void clear() {
89 #ifdef ENV_HPP_DEBUG
90  cout << "clearing: " << this << endl;
91 #endif
92  m.clear();
93  mtmp.clear();
94  ec = bc = cc = nullptr;
95  }
96  virtual bool isFrame() { return false; }
97  virtual bool isShadow() { return false; }
98  virtual ~BaseFrame() {
99  clear();
100 #ifdef ENV_HPP_DEBUG
101  cout << name << " FRAME DELETED: " << this << endl;
102 #endif
103  }
104 
105  unsigned getDepth() const { return depth; }
106 
107  string name;
108  shpfrm up;
109  shpfrm global;
110  shared_ptr<interp::Kont> bc;
111  shared_ptr<interp::Kont> ec;
112  shared_ptr<interp::Kont> cc;
113 
114  protected:
115  map_type m;
116  map_type mtmp; // temporaries
117 
118  unsigned depth;
119  };
120 
121 
123  struct Frame : BaseFrame {
124  Frame(const string& name_p,
125  shpfrm g = nullptr,
126  shpfrm u = nullptr,
127  shared_ptr<interp::Kont> bc = nullptr,
128  shared_ptr<interp::Kont> ec = shared_ptr<interp::Kont>(),
129  shared_ptr<interp::Kont> cc = nullptr) :
130  BaseFrame(name_p, g, u, bc, ec, cc)
131  { }
132 
133  val::Value find(const string& s) const {
134  const map_type& ml = s[0] != '?' ? m : mtmp;
135  auto elt = ml.find(s);
136  if (elt != ml.end()) {
137  return elt->second;
138  } else {
139  if (up) {
140  return up->find(s);
141  } else {
142  throw std::out_of_range("object '" + s + "' not found");
143  }
144  }
145  }
146 
147  val::Value findLocal(const string& s) const {
148  const map_type& ml = s[0] != '?' ? m : mtmp;
149  auto elt = ml.find(s);
150  if (elt != ml.end()) {
151  return elt->second;
152  }
153  throw std::out_of_range("object '" + s + "' not found");
154  }
155 
156  val::Value& findR(const string& s, bool funcall=false) {
157  map_type& ml = s[0] != '?' ? m : mtmp;
158  auto elt = ml.find(s);
159  if (elt != ml.end() &&
160  (!funcall || ml[s].which() == val::vt_clos || ml[s].which() == val::vt_builting)) {
161  return ml[s];
162  } else {
163  if (up) {
164  return up->findR(s, funcall);
165  } else {
166  throw std::out_of_range("object '" + s + "' not found");
167  }
168  }
169  }
170 
171  val::SpVAS getNames() {
172  auto a = arr::make_cow<arr::Array<arr::zstring>>(false, arr::rsv, Vector<idx_type>{0});
173  for (auto elt=m.begin(); elt != m.end(); ++elt) {
174  a->concat(arr::zstring(elt->first));
175  }
176  return a;
177  }
178 
179  val::Value& add(string s, val::Value&& val) {
180 #ifdef ENV_HPP_DEBUG
181  cout << "add " << s << "=" << val::to_string(val) << " to " << this << endl;
182 #endif
183  map_type& ml = s[0] != '?' ? m : mtmp;
184  auto elt = ml.find(s);
185  if (elt != ml.end()) {
186  val::Value tmp = elt->second; // this is needed in the case where val is pointing to
187  // same array; otherwise it might get deleted before
188  // the insertion.
189  ml.erase(elt);
190  auto res = ml.emplace(s, val::gval(val));
191  return res.first->second;
192  }
193  else {
194  auto res = ml.emplace(s, val::gval(val));
195  return res.first->second;
196  }
197  }
198 
199  val::Value& addSpecial(string s, val::Value&& val) {
200 #ifdef ENV_HPP_DEBUG
201  cout << "add special " << s << " to " << this << endl;
202 #endif
203  auto elt = m.find(s);
204  if (elt != m.end()) {
205  val::Value tmp = elt->second; // this is needed in the case where val is pointing to
206  // same array; otherwise it might get deleted before
207  // the insertion.
208  m.erase(elt);
209  auto res = m.emplace(s, val::gval(val));
210  return res.first->second;
211  }
212  else if (name == "global") { // not found, so just add it if this is global
213  auto res = m.emplace(s, val::gval(val));
214  return res.first->second;
215  }
216  else {
217  return up->addSpecial(s, std::move(val));
218  }
219  }
220 
221 
222  val::Value& addArg(string s, val::Value&& val, const yy::location& loc, bool isRef) {
223  assert(false); // at least put a string, no? LLL
224  throw std::range_error("'addArg' no meaningful on base frame");
225  }
226 
227  val::Value& addEllipsis(string s, val::Value&& val, const yy::location& loc, bool isRef) {
228  assert(false);
229  throw std::range_error("'addEllipsis' no meaningful on base frame");
230  }
231 
232  virtual bool remove(const string& symb) {
233  if (!symb.size()) return false;
234 
235  map_type& ml = symb[0] != '?' ? m : mtmp;
236  return ml.erase(symb) == 1;
237  }
238 
239  virtual bool removeSpecial(const string& symb) {
240  if (!symb.size()) return false;
241 
242  map_type& ml = symb[0] != '?' ? m : mtmp;
243  if (ml.erase(symb) == 0) {
244  return up ? up->removeSpecial(symb) : false;
245  }
246  else {
247  return true;
248  }
249  }
250 
251  operator string() const {
252  stringstream ss;
253  ss << "frame(" << this->up << "<-" << this << ')' << endl;
254  for (auto p : m) {
255  ss << p.first << ":" << val::to_string(p.second) << " ";
256  }
257  for (auto p : mtmp) {
258  ss << p.first << ":" << val::to_string(p.second) << " ";
259  }
260  return ss.str();
261  }
262 
263  void clearTmp() {
264  // cout << "clearing: " << string(*this) << endl;
265  mtmp.clear();
266  }
267 
268  virtual bool isFrame() { return true; }
269 
270  ~Frame() { }
271  }; // Frame
272 
273 
275  struct ClosureFrame : Frame {
276  ClosureFrame(shpfrm u) : Frame("closure", u->global, u) { }
277 
278  val::Value& addArg(string s, val::Value&& val, const yy::location& loc, bool isRef) {
279 #ifdef ENV_HPP_DEBUG
280  cout << "addArg " << s << " to " << this << "; isRef: " << isRef << endl;
281 #endif
282  map_type& ml = s[0] != '?' ? m : mtmp;
283  auto elt = ml.find(s);
284  if (elt != ml.end()) {
285  ml.erase(elt);
286  }
287  auto res = ml.emplace(s, isRef ? std::move(val) : val::gval(val));
288  if (isRef)
289  setRef(res.first->second);
290  else
291  resetRef(res.first->second);
292  return res.first->second;
293  }
294 
295  val::Value& addEllipsis(string s, val::Value&& val, const yy::location& loc, bool isRef) {
296  mv.emplace_back(make_tuple(s, std::move(val), loc));
297  return get<1>(mv.back());
298  }
299 
300  std::vector<std::tuple<std::string, val::Value, yy::location>> mv;
301  };
302 
303 
305  struct BuiltinFrame : Frame {
306  static const size_t MAX_ARGS = 5096;
307  typedef std::tuple<string, val::Value, yy::location> arg_t;
308 
310  BuiltinFrame(shpfrm u, shared_ptr<interp::Kont> ec, int nargs) :
311  Frame("native", u->global, u, nullptr, ec, nullptr),
312  currentPos(0), mv(nargs)
313  {
314  mv.reserve(MAX_ARGS);
315  }
316 
317  val::Value& addArg(string s, val::Value&& val, const yy::location& loc, bool isRef) {
318  mv[currentPos] = make_tuple(s, isRef ? std::move(val) : val::Value(val::gval(val)), loc);
319  if (isRef)
320  setRef(get<1>(mv[currentPos]));
321  else
322  resetRef(get<1>(mv[currentPos]));
323  return get<1>(mv[currentPos++]);
324  }
325 
326  val::Value& addEllipsis(string s, val::Value&& val, const yy::location& loc, bool isRef) {
327  // std::cout << "addEllipsis: isRef: " << isRef << std::endl;
328  mv.emplace_back(make_tuple(s, isRef ? std::move(val) : val::Value(val::gval(val)), loc));
329  if (isRef)
330  setRef(get<1>(mv.back()));
331  else
332  resetRef(get<1>(mv.back()));
333  return get<1>(mv.back());
334  }
335 
336  val::Value find(const string& s) const {
337  // this is not very efficient, but it will work for now:
338  auto res = std::find_if(mv.begin(), mv.end(), [s](const arg_t& x) { return get<0>(x) == s; });
339  if (res != mv.end()) {
340  return get<1>(*res);
341  }
342  else {
343  return Frame::find(s);
344  }
345  }
346 
347  val::Value findLocal(const string& s) const {
348  // this is not very efficient, but it will work for now:
349  auto res = std::find_if(mv.begin(), mv.end(), [s](const arg_t& x) { return get<0>(x) == s; });
350  if (res != mv.end()) {
351  return get<1>(*res);
352  }
353  else {
354  return Frame::findLocal(s);
355  }
356  }
357 
358  val::Value& findR(const string& s, bool funcall=false) {
359  // this is not very efficient, but it will work for now:
360  auto res = std::find_if(mv.begin(), mv.end(), [s](const arg_t& x) { return get<0>(x) == s; });
361  const auto res_t = get<1>(*res).which();
362  if (res != mv.end() && (!funcall || res_t == val::vt_clos || res_t == val::vt_builting)) {
363  return get<1>(*res);
364  }
365  else {
366  return Frame::findR(s, funcall);
367  }
368  }
369 
370  operator string() const {
371  stringstream ss;
372  for (const auto& t : mv) {
373  const auto& v = get<1>(t);
374  if (v.which() != 0) { // test if the argument was ever initialized
375  ss << get<0>(t) << ":" << val::to_string(v) << " ";
376  }
377  }
378  return ss.str();
379  }
380 
381  void clearTmp() {
382  assert(false);
383  }
384 
385  void clear() {
386  mv.clear();
387  BaseFrame::clear();
388  }
389 
390  bool hasFutures() {
391  return std::any_of(mv.begin(), mv.end(),
392  [](const std::tuple<string, val::Value, yy::location>& x) {
393  return get<1>(x).which() == val::vt_future; });
394  }
395 
396  int currentPos;
397  vector<std::tuple<string, val::Value, yy::location>> mv;
398  };
399 
400 
401  // for cleanliness we could decide to do the temp allocs here and the
402  // global ones in the upper env... LLL
403  struct ShadowFrame : Frame {
404  ShadowFrame(shpfrm u,
405  shared_ptr<interp::Kont> bc,
406  shared_ptr<interp::Kont> ec,
407  shared_ptr<interp::Kont> cc) : Frame("shadow", u->global, u, bc, ec, cc) { }
408 
409  val::Value find(const string& s) const {
410  if (s[0] == '?') {
411  return Frame::find(s);
412  }
413  else {
414  return up->find(s);
415  }
416  }
417 
418  val::Value findLocal(const string& s) const {
419  if (s[0] == '?') {
420  return Frame::findLocal(s);
421  }
422  else {
423  return up->findLocal(s);
424  }
425  }
426 
427  val::Value& findR(const string& s, bool funcall=false) {
428  if (s[0] == '?') {
429  return Frame::findR(s, funcall);
430  }
431  else {
432  return up->findR(s, funcall);
433  }
434  }
435 
436  virtual val::SpVAS getNames() {
437  return up->getNames();
438  }
439 
440  val::Value& add(string s, val::Value&& val) {
441  if (s[0] == '?') {
442 #ifdef ENV_HPP_DEBUG
443  cout << "add " << s << " to " << this << endl;
444 #endif
445  return Frame::add(s, std::move(val));
446  }
447  else {
448  return up->add(s, std::move(val));
449  }
450  }
451 
452  val::Value& addSpecial(string s, val::Value&& val) {
453  return up->addSpecial(s, std::move(val));
454  }
455 
456  val::Value& addArg(string s, val::Value&& val, const yy::location& loc, bool isRef) {
457  return up->add(s, std::move(val));
458  }
459 
460  val::Value& addEllipsis(string s, val::Value&& val, const yy::location& loc, bool isRef) {
461  assert(false);
462  throw std::out_of_range("'addEllipsis' irrelevant for shadow frame");
463  }
464 
465  bool remove(const string& symb) {
466  return up->remove(symb);
467  }
468 
469  bool removeSpecial(const string& symb) {
470  return up->removeSpecial(symb);
471  }
472 
473  operator string() const {
474  stringstream ss;
475  if (up) {
476  ss << "shadow(" << string(*up) << "<-" << this << ")";
477  }
478  else {
479  ss << "shadow(null<-" << this << ")";
480  }
481  return ss.str();
482  }
483 
484  void clear() {
485  BaseFrame::clear();
486  }
487 
488  virtual shpfrm getTrueFrame() { return up->getTrueFrame(); }
489 
490  ~ShadowFrame() { }
491  };
492 
493 } // end namespace interp
494 
495 #endif
interp::BuiltinFrame::BuiltinFrame
BuiltinFrame(shpfrm u, shared_ptr< interp::Kont > ec, int nargs)
Construct a buitin frame. After construction, the vector of arguments has a size of n.
Definition: env.hpp:310
interp::BaseFrame::m
map_type m
current continuation
Definition: env.hpp:115
interp::BuiltinFrame
Type of frame used when invoking builtin functions (see 'val::BuiltinG').
Definition: env.hpp:305
arr::cow_ptr
Definition: cow_ptr.hpp:42
interp::BaseFrame::cc
shared_ptr< interp::Kont > cc
escape continuation
Definition: env.hpp:112
arr::Vector< idx_type >
arr::ZString
Definition: string.hpp:33
interp::BaseFrame::ec
shared_ptr< interp::Kont > ec
begin continuation
Definition: env.hpp:111
val
Contains the types that constitute the output of an evaluation by the interpreter.
Definition: display.hpp:31
yy::location
Abstract a location.
Definition: location.hpp:54
interp::ClosureFrame
Type of frame used when invoking functions defined in R (see 'val::VClos').
Definition: env.hpp:275
interp
Struct and functions implementing the interpreter.
Definition: env.hpp:36
interp::Kont
Definition: interp.hpp:49
interp::Frame
The default frame associated with an interpretation context.
Definition: env.hpp:123
interp::ShadowFrame
Definition: env.hpp:403
interp::BaseFrame
Definition: env.hpp:42