replicode
context.h
Go to the documentation of this file.
1 // ipgm_context.h
2 //
3 // Author: Eric Nivel
4 //
5 // BSD license:
6 // Copyright (c) 2010, Eric Nivel
7 // All rights reserved.
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are met:
10 //
11 // - Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // - Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions and the following disclaimer in the
15 // documentation and/or other materials provided with the distribution.
16 // - Neither the name of Eric Nivel nor the
17 // names of their contributors may be used to endorse or promote products
18 // derived from this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
21 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 // DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
24 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #ifndef ipgm_context_h
32 #define ipgm_context_h
33 
34 #include "r_code/atom.h"
35 #include "r_code/utils.h"
36 #include "object.h"
37 #include "_context.h"
38 #include "pgm_overlay.h"
39 #include "operator.h"
40 
41 
42 namespace r_exec {
43 
44 class InputLessPGMOverlay;
45 
46 // Evaluation context.
48  public _Context {
49 private:
50  Code *object; // the object the code belongs to; unchanged when the context is dereferenced to the overlay's value array.
51  View *view; // the object's view, can be NULL when the context is dereferenced to a reference_set or a marker_set.
52 
53  bool is_cmd_with_cptr() const;
54 
55  void addReference(Code *destination, uint16_t write_index, Code *referenced_object) const {
56 
57  for (uint16_t i = 0; i < destination->references_size(); ++i)
58  if (referenced_object == destination->get_reference(i)) {
59 
60  destination->code(write_index) = Atom::RPointer(i);
61  return;
62  }
63 
64  destination->add_reference(referenced_object);
65  destination->code(write_index) = Atom::RPointer(destination->references_size() - 1);
66  }
67 
68  void addReference(View *destination, uint16_t write_index, Code *referenced_object) const { // view references are set in order (index 0 then 1).
69 
70  uint16_t r_ptr_index;
71  if (destination->references[0]) // first ref already in place.
72  r_ptr_index = 1;
73  else
74  r_ptr_index = 0;
75  destination->references[r_ptr_index] = referenced_object;
76  destination->code(write_index) = Atom::RPointer(r_ptr_index);
77  }
78 
79  template<class C> void copy_structure(C *destination,
80  uint16_t write_index,
81  uint16_t &extent_index,
82  bool dereference_cptr,
83  int64_t pgm_index) const { // assumes the context is a structure; C: Object or View.
84 
85  if ((*this)[0].getDescriptor() == Atom::OPERATOR && Operator::Get((*this)[0].asOpcode()).is_syn()) { // (\ (expression ...)).
86 
87  IPGMContext c = getChild(1);
88  c.copy_member(destination, write_index, extent_index, dereference_cptr, pgm_index);
89  } else {
90 
91  destination->code(write_index++) = (*this)[0];
92 
93  uint16_t atom_count = getChildrenCount();
94  extent_index = write_index + atom_count;
95 
96  switch ((*this)[0].getDescriptor()) {
97  case Atom::C_PTR: // copy members as is (no dereference).
98  if ((*this)[1].getDescriptor() == Atom::VL_PTR) {
99 
100  Atom a = code[(*this)[1].asIndex()];
101  if (a.getDescriptor() == Atom::I_PTR)
102  a = code[a.asIndex()];
103  switch (a.getDescriptor()) {
104  case Atom::OUT_OBJ_PTR:
105  destination->code(write_index++) = Atom::VLPointer(code[(*this)[1].asIndex()].asIndex());
106  break;
107  case Atom::IN_OBJ_PTR: // TMP: assumes destination is a mk.rdx.
108  destination->code(write_index++) = Atom::RPointer(1 + a.asInputIndex());
109  break;
110  default:
111  destination->code(write_index++) = (*this)[1];
112  break;
113  }
114  } else
115  destination->code(write_index++) = (*this)[1];
116  for (uint16_t i = 2; i <= atom_count; ++i)
117  destination->code(write_index++) = (*this)[i];
118  break;
119  case Atom::TIMESTAMP: // copy members as is (no dereference).
120  for (uint16_t i = 1; i <= atom_count; ++i)
121  destination->code(write_index++) = (*this)[i];
122  break;
123  default:
124  if (is_cmd_with_cptr()) {
125 
126  for (uint16_t i = 1; i <= atom_count; ++i) {
127 
128  IPGMContext c = getChild(i);
129  c.copy_member(destination, write_index++, extent_index, i != 2, pgm_index);
130  }
131  } else { // if a pgm is being copied, indicate the starting index of the pgm so that we can turn on code patching and know if a cptr is referencing code inside the pgm (in that case it will not be dereferenced).
132 
133  int64_t _pgm_index;
134  if (pgm_index >= 0)
135  _pgm_index = pgm_index;
136  else if ((*this)[0].getDescriptor() == Atom::OBJECT && ((*this)[0].asOpcode() == Opcodes::Pgm || (*this)[0].asOpcode() == Opcodes::AntiPgm))
137  _pgm_index = index;
138  else
139  _pgm_index = -1;
140 
141  for (uint16_t i = 1; i <= atom_count; ++i) {
142 
143  IPGMContext c = getChild(i);
144  c.copy_member(destination, write_index++, extent_index, !(!dereference_cptr && i == 1), _pgm_index);
145  }
146  }
147  break;
148  }
149  }
150  }
151 
152  template<class C> void copy_member(C *destination,
153  uint16_t write_index,
154  uint16_t &extent_index,
155  bool dereference_cptr,
156  int64_t pgm_index) const {
157 
158  switch ((*this)[0].getDescriptor()) {
159  case Atom::I_PTR:
160  case Atom::VALUE_PTR:
161  case Atom::IPGM_PTR: {
162 
163  if (data == REFERENCE && index == 0) { // points to an object, not to one of its members.
164 
165  addReference(destination, write_index, object);
166  break;
167  }
168 
169  if (code[(*this)[0].asIndex()].getDescriptor() == Atom::C_PTR) {
170 
171  if (!dereference_cptr || (pgm_index > 0 && code[(*this)[0].asIndex() + 1].asIndex() > pgm_index)) { // the latter case occurs when a cptr references code inside a pgm being copied.
172 
173  IPGMContext c = IPGMContext(object, view, code, (*this)[0].asIndex(), (InputLessPGMOverlay *)overlay, data);
174  destination->code(write_index) = Atom::IPointer(extent_index);
175  c.copy_structure(destination, extent_index, extent_index, dereference_cptr, pgm_index);
176  break;
177  }
178  }
179 
180  IPGMContext c = **this;
181  if (c[0].isStructural()) {
182 
183  destination->code(write_index) = Atom::IPointer(extent_index);
184  if (pgm_index > 0 && index > pgm_index && data == STEM)
185  this->patch_code(index, Atom::OutObjPointer(write_index));
186  c.copy_structure(destination, extent_index, extent_index, dereference_cptr, pgm_index);
187  } else
188  destination->code(write_index) = c[0];
189  break;
190  }
191  case Atom::VL_PTR:
192  switch (code[(*this)[0].asIndex()].getDescriptor()) {
193  case Atom::PROD_PTR:
194  addReference(destination, write_index, ((InputLessPGMOverlay *)overlay)->productions[code[(*this)[0].asIndex()].asIndex()]);
195  break;
196  case Atom::I_PTR:
197  if (code[code[(*this)[0].asIndex()].asIndex()].getDescriptor() == Atom::IN_OBJ_PTR)
198  addReference(destination, write_index, ((PGMOverlay *)overlay)->getInputObject(code[code[(*this)[0].asIndex()].asIndex()].asInputIndex()));
199  else
200  (**this).copy_member(destination, write_index, extent_index, dereference_cptr, pgm_index);
201  break;
202  case Atom::OUT_OBJ_PTR:
203  destination->code(write_index) = Atom::VLPointer(code[(*this)[0].asIndex()].asIndex());
204  break;
205  case Atom::IN_OBJ_PTR:
206  case Atom::D_IN_OBJ_PTR: {
207 
208  IPGMContext c = **this;
209  if (c.index == 0)
210  addReference(destination, write_index, c.object);
211  else if (c[0].isStructural()) {
212 
213  destination->code(write_index++) = Atom::IPointer(extent_index);
214  c.copy_structure(destination, extent_index, extent_index, dereference_cptr, pgm_index);
215  } else
216  c.copy_member(destination, write_index, extent_index, dereference_cptr, pgm_index);
217  break;
218  } default:
219  (**this).copy_member(destination, write_index, extent_index, dereference_cptr, pgm_index);
220  break;
221  }
222  break;
223  case Atom::R_PTR:
224  addReference(destination, write_index, object->get_reference((*this)[0].asIndex()));
225  break;
226  case Atom::PROD_PTR:
227  addReference(destination, write_index, ((InputLessPGMOverlay *)overlay)->productions[(*this)[0].asIndex()]);
228  break;
229  case Atom::IN_OBJ_PTR:
230  addReference(destination, write_index, ((PGMOverlay *)overlay)->getInputObject((*this)[0].asIndex()));
231  break;
232  case Atom::D_IN_OBJ_PTR: {
233  IPGMContext c = **this;
234  addReference(destination, write_index, c.object);
235  break;
236  } case Atom::OPERATOR:
237  case Atom::OBJECT:
238  case Atom::MARKER:
239  case Atom::INSTANTIATED_PROGRAM:
240  case Atom::INSTANTIATED_CPP_PROGRAM:
241  case Atom::INSTANTIATED_INPUT_LESS_PROGRAM:
242  case Atom::INSTANTIATED_ANTI_PROGRAM:
243  case Atom::COMPOSITE_STATE:
244  case Atom::MODEL:
245  case Atom::GROUP:
246  case Atom::SET:
247  case Atom::S_SET:
248  case Atom::TIMESTAMP:
249  case Atom::STRING:
250  destination->code(write_index) = Atom::IPointer(extent_index);
251  if (pgm_index > 0 && index > pgm_index && data == STEM)
252  this->patch_code(index, Atom::OutObjPointer(write_index));
253  copy_structure(destination, extent_index, extent_index, dereference_cptr, pgm_index);
254  break;
255  case Atom::T_WILDCARD:
256  destination->code(write_index) = (*this)[0];
257  break;
258  default:
259  destination->code(write_index) = (*this)[0];
260  if (pgm_index > 0 && index > pgm_index && data == STEM)
261  this->patch_code(index, Atom::OutObjPointer(write_index));
262  break;
263  }
264  }
265 
266  void copy_structure_to_value_array(bool prefix, uint16_t write_index, uint16_t &extent_index, bool dereference_cptr);
267  void copy_member_to_value_array(uint16_t child_index, bool prefix, uint16_t write_index, uint16_t &extent_index, bool dereference_cptr);
268 public:
270  return IPGMContext(input->object, input, &input->object->code(0), 0, overlay, REFERENCE);
271  }
272 
273  IPGMContext(): _Context(NULL, 0, NULL, UNDEFINED), object(NULL), view(NULL) {} // undefined context (happens when accessing the view of an object when it has not been provided).
274  IPGMContext(Code *object, View *view, Atom *code, uint16_t index, InputLessPGMOverlay *const overlay, Data data = STEM): _Context(code, index, overlay, data), object(object), view(view) {}
275  IPGMContext(Code *object, uint16_t index): _Context(&object->code(0), index, NULL, REFERENCE), object(object), view(NULL) {}
276  IPGMContext(Code *object, Data data): _Context(&object->code(0), index, NULL, data), object(object), view(NULL) {}
277 
278 // _Context implementation.
279  _Context *assign(const _Context *c) {
280 
281  IPGMContext *_c = new IPGMContext(*(IPGMContext *)c);
282  return _c;
283  }
284 
285  bool equal(const _Context *c) const {
286  return *this == *(IPGMContext *)c;
287  }
288 
289  Atom &get_atom(uint16_t i) const {
290  return this->operator [](i);
291  }
292 
293  uint16_t get_object_code_size() const {
294  return object->code_size();
295  }
296 
297  uint16_t getChildrenCount() const {
298 
299  uint16_t c;
300  switch (data) {
301  case MKS:
302  object->acq_markers();
303  c = object->markers.size();
304  object->rel_markers();
305  return c;
306  case VWS:
307  object->acq_views();
308  c = object->views.size();
309  object->rel_views();
310  return c;
311  default:
312  return code[index].getAtomCount();
313  }
314  }
315  _Context *_getChild(uint16_t index) const {
316 
317  IPGMContext *_c = new IPGMContext(getChild(index));
318  return _c;
319  }
320 
322 
323  IPGMContext *_c = new IPGMContext(**this);
324  return _c;
325  }
326 
327 // IPGM specifics.
328  bool evaluate(uint16_t &result_index) const; // index is set to the index of the result, undefined in case of failure.
329  bool evaluate_no_dereference(uint16_t &result_index) const;
330 
331  IPGMContext &operator =(const IPGMContext &c) {
332 
333  object = c.object;
334  view = c.view;
335  code = c.code;
336  index = c.index;
337  data = c.data;
338  return *this;
339  }
340 
341  bool operator ==(const IPGMContext &c) const;
342  bool operator !=(const IPGMContext &c) const;
343 
344  IPGMContext getChild(uint16_t index) const {
345 
346  switch (data) {
347  case STEM:
348  return IPGMContext(object, view, code, this->index + index, (InputLessPGMOverlay *)overlay, STEM);
349  case REFERENCE:
350  return IPGMContext(object, view, code, this->index + index, (InputLessPGMOverlay *)overlay, REFERENCE);
351  case VIEW:
352  return IPGMContext(object, view, code, this->index + index, NULL, VIEW);
353  case MKS: {
354 
355  uint16_t i = 0;
357  object->acq_markers();
358  for (m = object->markers.begin(); i < index - 1; ++i, ++m) {
359 
360  if (m == object->markers.end()) { // happens when the list has changed after the call to getChildrenCount.
361 
362  object->rel_markers();
363  return IPGMContext();
364  }
365  }
366  object->rel_markers();
367  return IPGMContext(*m, 0);
368  } case VWS: {
369 
370  uint16_t i = 0;
371  std::unordered_set<r_code::View *, r_code::View::Hash, r_code::View::Equal>::const_iterator v;
372  object->acq_views();
373  for (v = object->views.begin(); i < index - 1; ++i, ++v) {
374 
375  if (v == object->views.end()) { // happens when the list has changed after the call to getChildrenCount.
376 
377  object->rel_views();
378  return IPGMContext();
379  }
380  }
381  object->rel_views();
382  return IPGMContext(object, (r_exec::View*)*v, &(*v)->code(0), this->index + index, NULL, VIEW);
383  } case VALUE_ARRAY:
384  return IPGMContext(object, view, code, this->index + index, (InputLessPGMOverlay *)overlay, VALUE_ARRAY);
385  default: // undefined context.
386  return IPGMContext();
387  }
388  }
389  Atom &operator [](uint16_t i) const {
390  return code[index + i];
391  }
392  Code *getObject() const {
393  return object;
394  }
395  uint16_t getIndex() const {
396  return index;
397  }
398 
399  IPGMContext operator *() const;
400  void dereference_once();
401 
402  bool is_reference() const {
403  return data == REFERENCE;
404  }
405  bool is_undefined() const {
406  return data == UNDEFINED;
407  }
408 
409  void patch_input_code(uint16_t pgm_code_index, uint16_t input_index) const {
410  ((InputLessPGMOverlay *)overlay)->patch_input_code(pgm_code_index, input_index, 0);
411  }
412 
413  uint16_t addProduction(Code *object, bool check_for_existence) const; // if check_for_existence==false, the object is assumed not to be new.
414 
415  template<class C> void copy(C *destination, uint16_t write_index) const {
416 
417  uint16_t extent_index = 0;
418  copy_structure(destination, write_index, extent_index, true, -1);
419  }
420 
421  template<class C> void copy(C *destination, uint16_t write_index, uint16_t &extent_index) const {
422 
423  copy_structure(destination, write_index, extent_index, true, -1);
424  }
425 
426  void copy_to_value_array(uint16_t &position);
427 
428  typedef enum {
429  TYPE_OBJECT = 0,
430  TYPE_VIEW = 1,
431  TYPE_GROUP = 2,
432  TYPE_UNDEFINED = 3
433  } ObjectType;
434 
435 // To retrieve objects, groups and views in mod/set expressions; views are copied.
436  void getMember(void *&object, uint64_t &view_oid, ObjectType &object_type, int16_t &member_index) const;
437 
438 // 'this' is a context on a pattern skeleton.
439  bool match(const IPGMContext &input) const;
440 
441 // called by operators.
443  return overlay->build_object(head);
444  }
445 
446 // Implementation of executive-dependent operators.
447  static bool Ins(const IPGMContext &context, uint16_t &index);
448  static bool Fvw(const IPGMContext &context, uint16_t &index);
449  static bool Red(const IPGMContext &context, uint16_t &index);
450 };
451 }
452 
453 
454 #endif
View * view
Definition: context.h:51
_Context * assign(const _Context *c)
Definition: context.h:279
r_code::Code * build_object(Atom head) const
Definition: context.h:442
static uint16_t AntiPgm
Definition: opcodes.h:60
static IPGMContext GetContextFromInput(View *input, InputLessPGMOverlay *overlay)
Definition: context.h:269
IPGMContext getChild(uint16_t index) const
Definition: context.h:344
void patch_input_code(uint16_t pgm_code_index, uint16_t input_index) const
Definition: context.h:409
Definition: pgm_overlay.h:73
virtual void add_reference(Code *object) const
Definition: object.h:248
Definition: _context.h:45
virtual Code * get_reference(uint16_t i) const =0
#define dll_export
Definition: dll.h:44
uint8_t asInputIndex() const
Definition: atom.cpp:359
void copy(C *destination, uint16_t write_index) const
Definition: context.h:415
Definition: pgm_overlay.h:45
Data data
Definition: _context.h:61
IPGMContext()
Definition: context.h:273
Definition: structure_member.h:51
Code * references[2]
Definition: object.h:107
static Operator Get(uint16_t opcode)
Definition: operator.h:114
Definition: _context.cpp:34
Definition: context.h:47
Atom * code
Definition: _context.h:48
void addReference(View *destination, uint16_t write_index, Code *referenced_object) const
Definition: context.h:68
IPGMContext(Code *object, Data data)
Definition: context.h:276
bool match(const IPGMContext &input, const IPGMContext &pattern)
Definition: context.cpp:452
Definition: view.h:47
bool is_undefined() const
Definition: context.h:405
P< Code > object
Definition: object.h:108
Code * object
Definition: context.h:50
uint16_t getIndex() const
Definition: context.h:395
bool equal(const _Context *c) const
Definition: context.h:285
IPGMContext(Code *object, View *view, Atom *code, uint16_t index, InputLessPGMOverlay *const overlay, Data data=STEM)
Definition: context.h:274
uint16_t asIndex() const
Definition: atom.cpp:354
bool is_reference() const
Definition: context.h:402
Data
Definition: _context.h:51
Definition: atom.h:45
static uint16_t Pgm
Definition: opcodes.h:59
void addReference(Code *destination, uint16_t write_index, Code *referenced_object) const
Definition: context.h:55
Code * getObject() const
Definition: context.h:392
Definition: list.h:216
virtual uint16_t references_size() const =0
uint16_t index
Definition: _context.h:49
void copy_structure(C *destination, uint16_t write_index, uint16_t &extent_index, bool dereference_cptr, int64_t pgm_index) const
Definition: context.h:79
Atom & code(uint16_t i)
Definition: object.h:125
_Context * _getChild(uint16_t index) const
Definition: context.h:315
Definition: structure_member.h:52
Definition: object.h:172
Atom & get_atom(uint16_t i) const
Definition: context.h:289
_Context * dereference() const
Definition: context.h:321
uint16_t getChildrenCount() const
Definition: context.h:297
std::unordered_set< View *, View::Hash, View::Equal > views
Definition: object.h:225
r_code::list< Code * > markers
Definition: object.h:224
uint16_t get_object_code_size() const
Definition: context.h:293
void copy_member(C *destination, uint16_t write_index, uint16_t &extent_index, bool dereference_cptr, int64_t pgm_index) const
Definition: context.h:152
virtual Atom & code(uint16_t i)=0
Definition: structure_member.h:54
uint8_t getDescriptor() const
Definition: atom.cpp:316
void copy(C *destination, uint16_t write_index, uint16_t &extent_index) const
Definition: context.h:421
IPGMContext(Code *object, uint16_t index)
Definition: context.h:275