AERA
context.cpp
1 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
2 //_/_/
3 //_/_/ AERA
4 //_/_/ Autocatalytic Endogenous Reflective Architecture
5 //_/_/
6 //_/_/ Copyright (c) 2018-2025 Jeff Thompson
7 //_/_/ Copyright (c) 2018-2025 Kristinn R. Thorisson
8 //_/_/ Copyright (c) 2018-2025 Icelandic Institute for Intelligent Machines
9 //_/_/ http://www.iiim.is
10 //_/_/
11 //_/_/ Copyright (c) 2010-2012 Eric Nivel
12 //_/_/ Center for Analysis and Design of Intelligent Agents
13 //_/_/ Reykjavik University, Menntavegur 1, 102 Reykjavik, Iceland
14 //_/_/ http://cadia.ru.is
15 //_/_/
16 //_/_/ Part of this software was developed by Eric Nivel
17 //_/_/ in the HUMANOBS EU research project, which included
18 //_/_/ the following parties:
19 //_/_/
20 //_/_/ Autonomous Systems Laboratory
21 //_/_/ Technical University of Madrid, Spain
22 //_/_/ http://www.aslab.org/
23 //_/_/
24 //_/_/ Communicative Machines
25 //_/_/ Edinburgh, United Kingdom
26 //_/_/ http://www.cmlabs.com/
27 //_/_/
28 //_/_/ Istituto Dalle Molle di Studi sull'Intelligenza Artificiale
29 //_/_/ University of Lugano and SUPSI, Switzerland
30 //_/_/ http://www.idsia.ch/
31 //_/_/
32 //_/_/ Institute of Cognitive Sciences and Technologies
33 //_/_/ Consiglio Nazionale delle Ricerche, Italy
34 //_/_/ http://www.istc.cnr.it/
35 //_/_/
36 //_/_/ Dipartimento di Ingegneria Informatica
37 //_/_/ University of Palermo, Italy
38 //_/_/ http://diid.unipa.it/roboticslab/
39 //_/_/
40 //_/_/
41 //_/_/ --- HUMANOBS Open-Source BSD License, with CADIA Clause v 1.0 ---
42 //_/_/
43 //_/_/ Redistribution and use in source and binary forms, with or without
44 //_/_/ modification, is permitted provided that the following conditions
45 //_/_/ are met:
46 //_/_/ - Redistributions of source code must retain the above copyright
47 //_/_/ and collaboration notice, this list of conditions and the
48 //_/_/ following disclaimer.
49 //_/_/ - Redistributions in binary form must reproduce the above copyright
50 //_/_/ notice, this list of conditions and the following disclaimer
51 //_/_/ in the documentation and/or other materials provided with
52 //_/_/ the distribution.
53 //_/_/
54 //_/_/ - Neither the name of its copyright holders nor the names of its
55 //_/_/ contributors may be used to endorse or promote products
56 //_/_/ derived from this software without specific prior
57 //_/_/ written permission.
58 //_/_/
59 //_/_/ - CADIA Clause: The license granted in and to the software
60 //_/_/ under this agreement is a limited-use license.
61 //_/_/ The software may not be used in furtherance of:
62 //_/_/ (i) intentionally causing bodily injury or severe emotional
63 //_/_/ distress to any person;
64 //_/_/ (ii) invading the personal privacy or violating the human
65 //_/_/ rights of any person; or
66 //_/_/ (iii) committing or preparing for any act of war.
67 //_/_/
68 //_/_/ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
69 //_/_/ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
70 //_/_/ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
71 //_/_/ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
72 //_/_/ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
73 //_/_/ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
74 //_/_/ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
75 //_/_/ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
76 //_/_/ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
77 //_/_/ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
78 //_/_/ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
79 //_/_/ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
80 //_/_/ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
81 //_/_/ OF SUCH DAMAGE.
82 //_/_/
83 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
84 
85 #include "context.h"
86 #include "pgm_overlay.h"
87 #include "operator.h"
88 #include "opcodes.h"
89 #include "mem.h"
90 
91 
92 using namespace std;
93 using namespace r_code;
94 
95 namespace r_exec {
96 
97 bool IPGMContext::operator ==(const IPGMContext &c) const {
98  IPGMContext lhs = dereference();
99  IPGMContext rhs = c.dereference();
100 
101  if (lhs.data_ == REFERENCE && lhs.index_ == 0 &&
102  rhs.data_ == REFERENCE && rhs.index_ == 0) // both point to an object's head, not one of its members.
103  return lhs.object_ == rhs.object_;
104 
105  // both contexts point to an atom which is not a pointer.
106  if (lhs[0] != rhs[0])
107  return false;
108 
109  if (lhs[0].isStructural()) { // both are structural.
110 
111  uint16 atom_count = lhs.get_children_count();
112  for (uint16 i = 1; i <= atom_count; ++i)
113  if (lhs.get_child_deref(i) != rhs.get_child_deref(i))
114  return false;
115  return true;
116  }
117  return true;
118 }
119 
120 inline bool IPGMContext::operator !=(const IPGMContext &c) const {
121 
122  return !(*this == c);
123 }
124 
125 bool IPGMContext::match(const IPGMContext &input) const {
126 
127  if (data_ == REFERENCE && index_ == 0 &&
128  input.data_ == REFERENCE && input.index_ == 0) { // both point to an object's head, not one of its members.
129 
130  if (object_ == input.object_)
131  return true;
132  return false;
133  }
134 
135  if (code_[index_].isStructural()) {
136 
137  uint16 atom_count = get_children_count();
138  if (input.get_children_count() != atom_count)
139  return false;
140 
141  if (((*this)[0].atom_ & 0xFFFFFFF8) != (input[0].atom_ & 0xFFFFFFF8)) // masking a possible tolerance embedded in timestamps; otherwise, the last 3 bits encode an arity.
142  return false;
143 
144  for (uint16 i = 1; i <= atom_count; ++i) {
145 
146  IPGMContext pc = get_child_deref(i);
147  IPGMContext ic = input.get_child_deref(i);
148  if (!pc.match(ic))
149  return false;
150  }
151  return true;
152  }
153 
154  switch ((*this)[0].getDescriptor()) {
155  case Atom::WILDCARD:
156  case Atom::T_WILDCARD:
157  return true;
158  case Atom::IPGM_PTR:
159  return dereference().match(input);
160  default:
161  return (*this)[0] == input[0];
162  }
163 }
164 
165 void IPGMContext::dereference_once() {
166 
167  switch ((*this)[0].getDescriptor()) {
168  case Atom::I_PTR:
169  index_ = (*this)[0].asIndex();
170  break;
171  default:
172  break;
173  }
174 }
175 
176 IPGMContext IPGMContext::dereference() const {
177 
178  switch ((*this)[0].getDescriptor()) {
179  case Atom::CODE_VL_PTR: { // evaluate the code if necessary.
180  // TODO: OPTIMIZATION: if not in a cptr and if this eventually points to an r-ptr or in-obj-ptr,
181  // patch the code at this->index, i.e. replace the vl ptr by the in-obj-ptr or rptr.
182  Atom a = code_[(*this)[0].asIndex()];
183  uint16 structure_index;
184  if (a.getDescriptor() == Atom::I_PTR) // dereference once.
185  a = code_[structure_index = a.asIndex()];
186  if (a.isStructural()) { // the target location is not evaluated yet.
187 
188  IPGMContext s(object_, view_, code_, structure_index, (InputLessPGMOverlay *)overlay_, data_);
189  if (s.evaluate_no_dereference())
190  return s; // patched code: atom at CODE_VL_PTR's index changed to VALUE_PTR or 32 bits result.
191  else // evaluation failed, return undefined context.
192  return IPGMContext();
193  } else
194  return IPGMContext(object_, view_, code_, (*this)[0].asIndex(), (InputLessPGMOverlay *)overlay_, data_).dereference();
195  }case Atom::I_PTR:
196  return IPGMContext(object_, view_, code_, (*this)[0].asIndex(), (InputLessPGMOverlay *)overlay_, data_).dereference();
197  case Atom::R_PTR: {
198  Code *o = object_->get_reference((*this)[0].asIndex());
199  return IPGMContext(o, NULL, &o->code(0), 0, NULL, REFERENCE);
200  }case Atom::C_PTR: {
201 
202  IPGMContext c = get_child_deref(1);
203  for (uint16 i = 2; i <= get_children_count(); ++i) {
204 
205  switch ((*this)[i].getDescriptor()) {
206  case Atom::VIEW: // accessible only for this and input objects.
207  if (c.view_)
208  c = IPGMContext(c.get_object(), c.view_, &c.view_->code(0), 0, NULL, VIEW);
209  else
210  return IPGMContext();
211  break;
212  case Atom::MKS:
213  return IPGMContext(c.get_object(), MKS);
214  break;
215  case Atom::VWS:
216  return IPGMContext(c.get_object(), VWS);
217  break;
218  default:
219  c = c.get_child_deref((*this)[i].asIndex());
220  }
221  }
222  return c;
223  }
224  case Atom::THIS: // refers to the ipgm; the pgm view is not available.
225  return IPGMContext(overlay_->get_object(), overlay_->get_view(), &overlay_->get_object()->code(0), 0, (InputLessPGMOverlay *)overlay_, REFERENCE);
226  case Atom::VIEW: // never a reference, always in a cptr.
227  if (overlay_ && object_ == overlay_->get_object())
228  return IPGMContext(object_, view_, &view_->code(0), 0, NULL, VIEW);
229  return *this;
230  case Atom::MKS:
231  return IPGMContext(object_, MKS);
232  case Atom::VWS:
233  return IPGMContext(object_, VWS);
234  case Atom::VALUE_PTR:
235  return IPGMContext(object_, view_, &overlay_->values_[0], (*this)[0].asIndex(), (InputLessPGMOverlay *)overlay_, VALUE_ARRAY);
236  case Atom::IPGM_PTR:
237  return IPGMContext(overlay_->get_object(), (*this)[0].asIndex()).dereference();
238  case Atom::IN_OBJ_PTR: {
239  Code *input_object = ((PGMOverlay *)overlay_)->getInputObject((*this)[0].asInputIndex());
240  View *input_view = (r_exec::View*)((PGMOverlay *)overlay_)->getInputView((*this)[0].asInputIndex());
241  return IPGMContext(input_object, input_view, &input_object->code(0), (*this)[0].asIndex(), NULL, REFERENCE).dereference();
242  }case Atom::D_IN_OBJ_PTR: {
243  IPGMContext parent = IPGMContext(object_, view_, code_, (*this)[0].asRelativeIndex(), (InputLessPGMOverlay *)overlay_, data_).dereference();
244  Code *parent_object = parent.object_;
245  return IPGMContext(parent_object, NULL, &parent_object->code(0), (*this)[0].asIndex(), NULL, REFERENCE).dereference();
246  }case Atom::PROD_PTR:
247  return IPGMContext(((InputLessPGMOverlay *)overlay_)->productions_[(*this)[0].asIndex()], 0);
248  default:
249  return *this;
250  }
251 }
252 
253 bool IPGMContext::evaluate_no_dereference() const {
254 
255  switch (data_) {
256  case REFERENCE:
257  case VALUE_ARRAY:
258  return true;
259  case UNDEFINED:
260  return false;
261  case VIEW:
262  case MKS:
263  case VWS:
264  return true;
265  }
266  switch (code_[index_].getDescriptor()) {
267  case Atom::OPERATOR: {
268 
269  Operator op = Operator::Get((*this)[0].asOpcode());
270  if (op.is_syn())
271  return true;
272  if (!op.is_red()) { // red will prevent the evaluation of its productions before reducting its input.
273 
274  uint16 atom_count = get_children_count();
275  for (uint16 i = 1; i <= atom_count; ++i) {
276 
277  if (!get_child_deref(i).evaluate_no_dereference())
278  return false;
279  }
280  }
281  IPGMContext *__c = new IPGMContext(*this);
282  Context _c(__c);
283  return op(_c);
284  }case Atom::OBJECT: // incl. cmd.
285  if ((*this)[0].asOpcode() == Opcodes::Ptn || (*this)[0].asOpcode() == Opcodes::AntiPtn) { // skip patterns.
286 
287  return true;
288  }
289  case Atom::MARKER:
290  case Atom::INSTANTIATED_PROGRAM:
291  case Atom::INSTANTIATED_CPP_PROGRAM:
292  case Atom::INSTANTIATED_INPUT_LESS_PROGRAM:
293  case Atom::INSTANTIATED_ANTI_PROGRAM:
294  case Atom::COMPOSITE_STATE:
295  case Atom::MODEL:
296  case Atom::GROUP:
297  case Atom::SET:
298  case Atom::S_SET: {
299 
300  uint16 atom_count = get_children_count();
301  for (uint16 i = 1; i <= atom_count; ++i) {
302 
303  if (!get_child_deref(i).evaluate_no_dereference())
304  return false;
305  }
306  return true;
307  }default:
308  return true;
309  }
310 }
311 
312 inline bool IPGMContext::evaluate() const {
313 
314  if (data_ == REFERENCE || data_ == VALUE_ARRAY)
315  return true;
316 
317  IPGMContext c = dereference();
318  return c.evaluate_no_dereference();
319 }
320 
321 void IPGMContext::copy_to_value_array(uint16 &position) {
322 
323  position = overlay_->values_.size();
324  uint16 extent_index;
325  if (code_[index_].isStructural())
326  copy_structure_to_value_array(false, overlay_->values_.size(), extent_index, true);
327  else
328  copy_member_to_value_array(0, false, overlay_->values_.size(), extent_index, true);
329 }
330 
331 void IPGMContext::copy_structure_to_value_array(bool prefix, uint16 write_index, uint16 &extent_index, bool dereference_cptr) { // prefix: by itpr or not.
332 
333  if (code_[index_].getDescriptor() == Atom::OPERATOR && Operator::Get(code_[index_].asOpcode()).is_syn())
334  copy_member_to_value_array(1, prefix, write_index, extent_index, dereference_cptr);
335  else {
336 
337  uint16 atom_count = get_children_count();
338  overlay_->values_[write_index++] = code_[index_];
339  extent_index = write_index + atom_count;
340  switch (code_[index_].getDescriptor()) {
341  case Atom::TIMESTAMP:
342  for (uint16 i = 1; i <= atom_count; ++i)
343  overlay_->values_[write_index++] = code_[index_ + i];
344  break;
345  case Atom::DURATION:
346  for (uint16 i = 1; i <= atom_count; ++i)
347  overlay_->values_[write_index++] = code_[index_ + i];
348  break;
349  case Atom::C_PTR:
350  if (!dereference_cptr) {
351 
352  copy_member_to_value_array(1, prefix, write_index++, extent_index, false);
353  for (uint16 i = 2; i <= atom_count; ++i)
354  overlay_->values_[write_index++] = code_[index_ + i];
355  break;
356  } // else, dereference the c_ptr.
357  default:
358  if (is_cmd_with_cptr()) {
359 
360  for (uint16 i = 1; i <= atom_count; ++i)
361  copy_member_to_value_array(i, prefix, write_index++, extent_index, i != 2);
362  } else {
363 
364  for (uint16 i = 1; i <= atom_count; ++i)
365  copy_member_to_value_array(i, prefix, write_index++, extent_index, !(!dereference_cptr && i == 1));
366  }
367  }
368  }
369 }
370 
371 void IPGMContext::copy_member_to_value_array(uint16 child_index, bool prefix, uint16 write_index, uint16 &extent_index, bool dereference_cptr) {
372 
373  uint16 _index = index_ + child_index;
374  Atom head;
375 dereference:
376  head = code_[_index];
377  switch (head.getDescriptor()) { // dereference until either we reach some non-pointer or a reference or a value pointer.
378  case Atom::I_PTR:
379  case Atom::CODE_VL_PTR:
380  _index = head.asIndex();
381  goto dereference;
382  case Atom::VALUE_PTR:
383  overlay_->values_[write_index] = Atom::IPointer(head.asIndex());
384  return;
385  case Atom::PROD_PTR:
386  case Atom::IN_OBJ_PTR:
387  case Atom::D_IN_OBJ_PTR:
388  case Atom::R_PTR:
389  overlay_->values_[write_index] = head;
390  return;
391  case Atom::C_PTR:
392  if (dereference_cptr) {
393 
394  uint16 saved_index = index_;
395  index_ = _index;
396  IPGMContext cptr = dereference();
397  overlay_->values_[write_index] = cptr[0];
398  index_ = saved_index;
399  return;
400  }
401  }
402 
403  if (head.isStructural()) {
404 
405  uint16 saved_index = index_;
406  index_ = _index;
407  if (prefix) {
408 
409  overlay_->values_[write_index] = Atom::IPointer(extent_index);
410  copy_structure_to_value_array(true, extent_index, extent_index, dereference_cptr);
411  } else
412  copy_structure_to_value_array(true, write_index, extent_index, dereference_cptr);
413  index_ = saved_index;
414  } else
415  overlay_->values_[write_index] = head;
416 }
417 
418 void IPGMContext::getMember(void *&object, uint32 &view_oid, ObjectType &object_type, int16 &member_index) const {
419 
420  if ((*this)[0].getDescriptor() != Atom::I_PTR) { // ill-formed mod/set expression.
421 
422  object = NULL;
423  object_type = TYPE_UNDEFINED;
424  member_index = 0;
425  return;
426  }
427 
428  IPGMContext cptr = IPGMContext(object_, view_, code_, (*this)[0].asIndex(), (InputLessPGMOverlay *)overlay_, data_); // dereference manually (1 offset) to retain the cptr as is.
429 
430  if (cptr[0].getDescriptor() != Atom::C_PTR) { // ill-formed mod/set expression.
431 
432  object = NULL;
433  object_type = TYPE_UNDEFINED;
434  member_index = 0;
435  return;
436  }
437 
438  IPGMContext c = cptr.get_child_deref(1); // this, vl_ptr, value_ptr or rptr.
439 
440  uint16 atom_count = cptr.get_children_count();
441  for (uint16 i = 2; i < atom_count; ++i) { // stop before the last iptr.
442 
443  if (cptr[i].getDescriptor() == Atom::VIEW)
444  c = IPGMContext(c.get_object(), c.view_, &c.view_->code(0), 0, NULL, VIEW);
445  else
446  c = c.get_child_deref(cptr[i].asIndex());
447  }
448 
449  // at this point, c is an iptr dereferenced to an object or a view; the next iptr holds the member index.
450  // c is pointing at the first atom of an object or a view.
451  switch (c[0].getDescriptor()) {
452  case Atom::OBJECT:
453  case Atom::MARKER:
454  case Atom::INSTANTIATED_PROGRAM:
455  case Atom::INSTANTIATED_CPP_PROGRAM:
456  case Atom::INSTANTIATED_INPUT_LESS_PROGRAM:
457  case Atom::INSTANTIATED_ANTI_PROGRAM:
458  case Atom::COMPOSITE_STATE:
459  case Atom::MODEL:
460  object_type = TYPE_OBJECT;
461  object = c.get_object();
462  break;
463  case Atom::GROUP:
464  case Atom::SET: // dynamically generated views can be sets.
465  case Atom::S_SET: // views are always copied; set the object to the view's group on which to perform an operation for the view's oid.
466  if (c.data_ == VALUE_ARRAY)
467  object = (Group *)c[VIEW_CODE_MAX_SIZE].atom_; // first reference of grp in a view stored in athe value array.
468  else
469  object = c.view_->get_host();
470  view_oid = c[VIEW_OID].atom_; // oid is hidden at the end of the view code; stored directly as a uint32.
471  object_type = TYPE_VIEW;
472  break;
473  default: // atomic value or ill-formed mod/set expression.
474  object = NULL;
475  object_type = TYPE_UNDEFINED;
476  return;
477  }
478 
479  // get the index held by the last iptr.
480  member_index = cptr[atom_count].asIndex();
481 }
482 
483 bool IPGMContext::is_cmd_with_cptr() const {
484 
485  if ((*this)[0].getDescriptor() != Atom::OBJECT)
486  return false;
487  if ((*this)[0].asOpcode() != Opcodes::ICmd)
488  return false;
489  return (*this)[1].asOpcode() == Opcodes::Mod ||
490  (*this)[1].asOpcode() == Opcodes::Set;
491 }
492 
493 uint16 IPGMContext::addProduction(Code *object, bool check_for_existence) const { // called by operators (ins and red).
494 
495  ((InputLessPGMOverlay *)overlay_)->productions_.push_back(_Mem::Get()->check_existence(object));
496  return ((InputLessPGMOverlay *)overlay_)->productions_.size() - 1;
497 }
498 
499 // Utilities for executive-dependent operators ////////////////////////////////////////////////////////////////////////////////
500 
501 bool match(const IPGMContext &input, const IPGMContext &pattern) { // in red, patterns like (ptn object: [guards]) are allowed.
502 
503  // patch the pattern with a ptr to the input.
504  if (input.is_reference()) {
505 
506  uint16 ptr = pattern.addProduction(input.get_object(), false); // the object obviously is not new.
507  pattern.patch_code(pattern.getIndex() + 1, Atom::ProductionPointer(ptr));
508  } else
509  pattern.patch_code(pattern.getIndex() + 1, Atom::IPointer(input.getIndex()));
510 
511  // evaluate the set of guards.
512  IPGMContext guard_set = pattern.get_child_deref(2);
513  uint16 guard_count = guard_set.get_children_count();
514  for (uint16 i = 1; i <= guard_count; ++i) {
515 
516  if (!guard_set.get_child_deref(i).evaluate_no_dereference()) // WARNING: no check for duplicates.
517  return false;
518  }
519 
520  return true;
521 }
522 
523 bool match(const IPGMContext &input, const IPGMContext &pattern, const IPGMContext &productions, vector<uint16> &production_indices) {
524 
525  uint16 last_patch_index;
526  if (pattern[0].asOpcode() == Opcodes::Ptn) {
527 
528  auto skeleton = pattern.get_child_deref(1);
529  if (!skeleton.match(input))
530  return false;
531  last_patch_index = pattern.get_last_patch_index();
532  if (!match(input, pattern))
533  return false;
534 
535  goto build_productions;
536  }
537 
538  if (pattern[0].asOpcode() == Opcodes::AntiPtn) {
539 
540  auto skeleton = pattern.get_child_deref(1);
541  if (skeleton.match(input))
542  return false;
543  last_patch_index = pattern.get_last_patch_index();
544  if (match(input, pattern))
545  return false;
546 
547  goto build_productions;
548  }
549 
550  return false;
551 
552 build_productions:
553  // compute all productions for this input.
554  uint16 production_count = productions.get_children_count();
555  uint16 production_index;
556  for (uint16 i = 1; i <= production_count; ++i) {
557 
558  IPGMContext prod = productions.get_child(i);
559  prod.evaluate();
560  prod.copy_to_value_array(production_index);
561  production_indices.push_back(production_index);
562  }
563 
564  pattern.unpatch_code(last_patch_index);
565  return true;
566 }
567 
568 void reduce(const IPGMContext &context, const IPGMContext &input_set, const IPGMContext &section, vector<uint16> &input_indices, vector<uint16> &production_indices) {
569 
570  IPGMContext pattern = section.get_child_deref(1);
571  if (pattern[0].asOpcode() != Opcodes::Ptn && pattern[0].asOpcode() != Opcodes::AntiPtn)
572  return;
573 
574  IPGMContext productions = section.get_child_deref(2);
575  if (productions[0].getDescriptor() != Atom::SET)
576  return;
577 
578  uint16 production_count = productions.get_children_count();
579  if (!production_count)
580  return;
581 
582  vector<uint16>::iterator i;
583  for (i = input_indices.begin(); i != input_indices.end();) { // to be successful, at least one input must match the pattern.
584 
585  IPGMContext c = input_set.get_child_deref(*i);
586  if (c.is_undefined()) {
587 
588  i = input_indices.erase(i);
589  continue;
590  }
591 
592  bool failure = false;
593  if (!match(c, pattern, productions, production_indices)) {
594 
595  failure = true;
596  break;
597  }
598 
599  if (failure)
600  ++i;
601  else // pattern matched: remove the input from the todo list.
602  i = input_indices.erase(i);
603  }
604 }
605 
606 bool IPGMContext::Red(const IPGMContext &context) {
607  IPGMContext input_set = context.get_child_deref(1);
608  if (!input_set.evaluate_no_dereference())
609  return false;
610 
611  // a section is a set of one pattern and a set of productions.
612  IPGMContext positive_section = context.get_child_deref(2);
613  if (!positive_section.get_child_deref(1).evaluate_no_dereference()) // evaluate the pattern only.
614  return false;
615 
616  IPGMContext negative_section = context.get_child_deref(3);
617  if (!negative_section.get_child_deref(1).evaluate_no_dereference()) // evaluate the pattern only.
618  return false;
619 
620  vector<uint16> input_indices; // todo list of inputs to match.
621  for (uint16 i = 1; i <= input_set.get_children_count(); ++i)
622  input_indices.push_back(i);
623 
624  vector<uint16> production_indices; // list of productions built upon successful matches.
625 
626  uint16 input_count = input_set.get_children_count();
627  if (input_set[0].getDescriptor() != Atom::SET &&
628  input_set[0].getDescriptor() != Atom::S_SET &&
629  positive_section[0].getDescriptor() != Atom::SET &&
630  negative_section[0].getDescriptor() != Atom::SET)
631  goto failure;
632 
633  if (!input_count)
634  goto failure;
635 
636  reduce(context, input_set, positive_section, input_indices, production_indices); // input_indices now filled only with the inputs that did not match the positive pattern.
637  reduce(context, input_set, negative_section, input_indices, production_indices); // input_indices now filled only with the inputs that did not match the positive nor the negative pattern.
638  if (production_indices.size()) {
639 
640  // build the set of all productions in the value array.
641  context.setCompoundResultHead(Atom::Set(production_indices.size()));
642  for (uint16 i = 0; i < production_indices.size(); ++i) // fill the set with iptrs to productions: the latter are copied in the value array.
643  context.addCompoundResultPart(Atom::IPointer(production_indices[i]));
644  return true;
645  }
646 failure:
647  context.setCompoundResultHead(Atom::Set(0));
648  return false;
649 }
650 
651 bool IPGMContext::Ins(const IPGMContext &context) {
652 
653  IPGMContext object = context.get_child_deref(1);
654  IPGMContext args = context.get_child_deref(2);
655  IPGMContext run = context.get_child_deref(3);
656  IPGMContext tsc = context.get_child_deref(4);
657  IPGMContext res = context.get_child_deref(5);
658  IPGMContext nfr = context.get_child_deref(6);
659 
660  Code *pgm = object.get_object();
661  uint16 pgm_opcode = pgm->code(0).asOpcode();
662  if (pgm_opcode != Opcodes::Pgm &&
663  pgm_opcode != Opcodes::AntiPgm) {
664 
665  context.setAtomicResult(Atom::Nil());
666  return false;
667  }
668 
669  if (pgm && args[0].getDescriptor() == Atom::SET) {
670 
671  uint16 pattern_set_index = pgm->code(PGM_TPL_ARGS).asIndex();
672  uint16 arg_count = args[0].getAtomCount();
673  if (pgm->code(pattern_set_index).getAtomCount() != arg_count) {
674 
675  context.setAtomicResult(Atom::Nil());
676  return false;
677  }
678 
679  // match args with the tpl patterns in _object.
680  IPGMContext pattern_set(pgm, pattern_set_index);
681  for (uint16 i = 1; i <= arg_count; ++i) {
682 
683  IPGMContext arg = args.get_child_deref(i);
684  IPGMContext skel = pattern_set.get_child_deref(i).get_child_deref(1);
685  if (!skel.match(arg)) {
686 
687  context.setAtomicResult(Atom::Nil());
688  return false;
689  }
690  }
691 
692  Code *ipgm; // created in the production array.
693  if (pgm_opcode == Opcodes::AntiPgm)
694  ipgm = context.build_object(Atom::InstantiatedAntiProgram(Opcodes::IPgm, IPGM_ARITY));
695  else {
696 
697  uint16 input_index = pgm->code(PGM_INPUTS).asIndex();
698  uint16 input_count = pgm->code(input_index).getAtomCount();
699  if (input_count == 0)
700  ipgm = context.build_object(Atom::InstantiatedInputLessProgram(Opcodes::IPgm, IPGM_ARITY));
701  else
702  ipgm = context.build_object(Atom::InstantiatedProgram(Opcodes::IPgm, IPGM_ARITY));
703  }
704 
705  ipgm->code(IPGM_PGM) = Atom::RPointer(0); // points to the pgm object.
706  ipgm->add_reference(pgm);
707 
708  uint16 extent_index = 0;
709  ipgm->code(IPGM_ARGS) = Atom::IPointer(IPGM_ARITY + 1); // points to the arg set.
710  args.copy(ipgm, IPGM_ARITY + 1, extent_index); // writes the args after psln_thr.
711 
712  ipgm->code(IPGM_RUN) = run[0];
713  ipgm->code(IPGM_TSC) = Atom::IPointer(extent_index); // points to the tsc.
714 
715  ipgm->code(extent_index++) = tsc[0]; // writes the tsc after the args.
716  ipgm->code(extent_index++) = tsc[1];
717  ipgm->code(extent_index++) = tsc[2];
718 
719  ipgm->code(IPGM_RES) = res[0]; // res.
720  ipgm->code(IPGM_NFR) = nfr[0]; // nfr.
721  ipgm->code(IPGM_ARITY) = Atom::Float(1); // psln_thr.
722 
723  context.setAtomicResult(Atom::ProductionPointer(context.addProduction(ipgm, true))); // object may be new: we don't know at this point, therefore check=true.
724  return true;
725  }
726 
727  context.setAtomicResult(Atom::Nil());
728  return false;
729 }
730 
731 bool IPGMContext::Fvw(const IPGMContext &context) {
732 
733  IPGMContext object = context.get_child_deref(1);
734  IPGMContext group = context.get_child_deref(2);
735 
736  Code *_object = object.get_object();
737  Group *_group = (Group *)group.get_object();
738  if (!_object || !_group) {
739 
740  context.setAtomicResult(Atom::Nil());
741  return false;
742  }
743 
744  View *v = (View *)_object->get_view(_group, true); // returns (a copy of: deprecated) of the view, if any.
745  if (v) { // copy the view in the value array: code on VIEW_CODE_MAX_SIZE followed by 2 atoms holding raw pointers to grp and org.
746 
747  context.setCompoundResultHead(v->code(0));
748  for (uint16 i = 1; i < VIEW_CODE_MAX_SIZE; ++i)
749  context.addCompoundResultPart(v->code(i));
750  context.addCompoundResultPart(Atom((uint32)v->references_[0]));
751  context.addCompoundResultPart(Atom((uint32)v->references_[1]));
752  delete v;
753  return true;
754  }
755 
756  context.setAtomicResult(Atom::Nil());
757  return false;
758 }
759 }
r_code::Atom
Definition: atom.h:104
r_code::Code
Definition: r_code/object.h:224
r_exec::View
Definition: view.h:102