AERA
decompiler.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 <algorithm>
86 #include <regex>
87 #include "decompiler.h"
88 #include "../submodules/CoreLibrary/CoreLibrary/utils.h"
89 
90 using namespace std;
91 using namespace std::chrono;
92 using namespace r_code;
93 
94 namespace r_comp {
95 
96 // Get a string for the value such as "a", "b" ... "z", "aa", "ab" ....
97 static std::string make_suffix(uint32 value) {
98  string result;
99  do {
100  // Get the lowest digit as base 26 and prepend a char from 'a' to 'z'.
101  uint32 lowest = value % 26;
102  result = (char)('a' + lowest) + result;
103 
104  // Shift.
105  value /= 26;
106  } while (value != 0);
107 
108  return result;
109 }
110 
111 Decompiler::Decompiler() : out_stream_(NULL), current_object_(NULL), metadata_(NULL), image_(NULL), in_hlp_(false) {
112  // Make hlp_postfix_ true by default to put ':' after variables, unless it is set false for guards in cst and mdl.
113  hlp_postfix_ = true;
114 }
115 
116 Decompiler::~Decompiler() {
117 
118  if (out_stream_)
119  delete out_stream_;
120 }
121 
122 std::string Decompiler::get_variable_name(uint16 index, bool postfix) {
123 
124  unordered_map<uint16, std::string>::iterator it = variable_names_.find(index);
125  if (it == variable_names_.end()) {
126 
127  std::string s = "v" + std::to_string(last_variable_id_++);
128  variable_names_[index] = s;
129  if (postfix)
130  s += ':';
131  out_stream_->insert(index, s);
132  if (postfix)
133  return s.substr(0, s.length() - 1);
134  return s;
135  }
136  return it->second;
137 }
138 
139 std::string Decompiler::get_hlp_variable_name(uint16 index) {
140 
141  std::string s = "v" + std::to_string(index);
142  if (hlp_postfix_)
143  s += ':';
144  return s;
145 }
146 
147 std::string Decompiler::get_object_name(uint16 index) {
148 
149  std::string s;
150  unordered_map<uint16, std::string>::iterator it = object_names_.find(index);
151  if (it == object_names_.end()) {
152 
153  s = "unknown-object";
154  return s;
155  }
156  return it->second;
157 }
158 
159 void Decompiler::init(r_comp::Metadata *metadata) {
160 
161  metadata_ = metadata;
162  time_reference_ = Timestamp(seconds(0));
163 
164  partial_decompilation_ = false;
165  ignore_named_objects_ = false;
166 
167  // Load the renderers;
168  for (uint16 i = 0; i < metadata->classes_by_opcodes_.size(); ++i) {
169 
170  Class *c = metadata->get_class(i);
171  std::string class_name = c->str_opcode;
172  size_t p = class_name.find("mk.");
173  if (p != std::string::npos)
174  renderers_[i] = &Decompiler::write_marker;
175  else if (class_name == "pred")
176  renderers_[i] = &Decompiler::write_marker;
177  else if (class_name == "grp")
178  renderers_[i] = &Decompiler::write_group;
179  else if (class_name == "ipgm" || class_name == "icpp_pgm")
180  renderers_[i] = &Decompiler::write_ipgm;
181  else if (class_name == "pgm" || class_name == "|pgm")
182  renderers_[i] = &Decompiler::write_pgm;
183  else if (class_name == "icmd")
184  renderers_[i] = &Decompiler::write_icmd;
185  else if (class_name == "cmd")
186  renderers_[i] = &Decompiler::write_cmd;
187  else if (class_name == "fact" || class_name == "|fact")
188  renderers_[i] = &Decompiler::write_fact;
189  else if (class_name == "cst" || class_name == "mdl")
190  renderers_[i] = &Decompiler::write_hlp;
191  else if (class_name == "icst" || class_name == "imdl")
192  renderers_[i] = &Decompiler::write_ihlp;
193  else
194  renderers_[i] = &Decompiler::write_expression;
195  }
196 }
197 
198 uint32 Decompiler::decompile(r_comp::Image *image, std::ostringstream *stream, Timestamp time_reference, bool ignore_named_objects) {
199 
200  ignore_named_objects_ = ignore_named_objects;
201 
202  uint32 object_count = decompile_references(image);
203 
204  for (uint16 i = 0; i < image->code_segment_.objects_.size(); ++i)
205  decompile_object(i, stream, time_reference);
206 
207  return object_count;
208 }
209 
210 uint32 Decompiler::decompile(r_comp::Image *image, std::ostringstream *stream, Timestamp time_reference, vector<SysObject *> &imported_objects,
211  bool include_oid, bool include_label, bool include_views) {
212 
213  partial_decompilation_ = true;
214  ignore_named_objects_ = true;
215  imported_objects_ = imported_objects;
216 
217  uint32 object_count = decompile_references(image);
218 
219  for (uint16 i = 0; i < image->code_segment_.objects_.size(); ++i)
220  decompile_object(i, stream, time_reference, include_oid, include_label, include_views);
221 
222  return object_count;
223 }
224 
225 uint32 Decompiler::decompile_references(r_comp::Image *image, unordered_map<uint16, std::string>* object_names) {
226 
227  if (object_names) {
228  // Pre-populate object_names_ and object_indices_.
229  for (auto entry = object_names->begin(); entry != object_names->end(); ++entry) {
230  object_names_[entry->first] = entry->second;
231  object_indices_[entry->second] = entry->first;
232  }
233  }
234 
235  unordered_map<const Class *, uint16> object_ID_per_class;
236  unordered_map<std::string, Class>::const_iterator it;
237  for (it = metadata_->sys_classes_.begin(); it != metadata_->sys_classes_.end(); ++it)
238  object_ID_per_class[&(it->second)] = 0;
239 
240  std::string s;
241 
242  image_ = image;
243 
244  // populate object names first so they can be referenced in any order.
245  // First pass: Add the user-defined names to object_names_ and object_indices_.
246  for (uint16 i = 0; i < image->code_segment_.objects_.size(); ++i) {
247 
248  SysObject *sys_object = (SysObject *)image->code_segment_.objects_[i];
249  unordered_map<uint32, std::string>::const_iterator n = image->object_names_.symbols_.find(sys_object->oid_);
250  if (n != image->object_names_.symbols_.end()) {
251 
252  s = n->second;
253  named_objects_.insert(sys_object->oid_);
254 
255  if (object_names_[i] != "" && object_names_[i] != s)
256  // The image->object_names_.symbols_ for the OID is different than the name in the provided object_names.
257  // (We don't expect this to happen.)
258  return 0;
259 
260  object_names_[i] = s;
261  object_indices_[s] = i;
262  }
263  }
264 
265  regex verticalBarRegex("\\|");
266  // Second pass: Create names for the remaining objects, making sure they are unique.
267  for (uint16 i = 0; i < image->code_segment_.objects_.size(); ++i) {
268  SysObject *sys_object = (SysObject *)image->code_segment_.objects_[i];
269 
270  unordered_map<uint32, std::string>::const_iterator n = image->object_names_.symbols_.find(sys_object->oid_);
271  if (n != image->object_names_.symbols_.end())
272  // Already set the user-defined name in the first pass.
273  continue;
274  if (object_names_.find(i) != object_names_.end())
275  // Already assigned by the passed-in object_names.
276  continue;
277 
278  Class *c = metadata_->get_class(sys_object->code_[0].asOpcode());
279  string className = c->str_opcode;
280  // A class name like mk.val has a dot, but this isn't allowed as an identifier.
281  replace(className.begin(), className.end(), '.', '_');
282  // A class name like |fact has a bar, but this isn't allowed as an identifier.
283  // (Use regex_replace because it can handle multi-character strings.)
284  className = regex_replace(className, verticalBarRegex, "anti_");
285 
286  if (sys_object->oid_ != UNDEFINED_OID)
287  // Use the object's OID.
288  s = className + "_" + std::to_string(sys_object->oid_);
289  else {
290  // Create a name with a unique ID.
291  uint16 last_object_ID = object_ID_per_class[c];
292  object_ID_per_class[c] = last_object_ID + 1;
293  s = className + std::to_string(last_object_ID);
294  }
295 
296  if (object_indices_.find(s) != object_indices_.end()) {
297  // The created name matches an existing name. Keep trying an added
298  // suffix until it is unique.
299  for (uint32 value = 1; true; ++value) {
300  std::string new_s = s + make_suffix(value);
301  if (object_indices_.find(new_s) == object_indices_.end()) {
302  s = new_s;
303  break;
304  }
305  }
306  }
307 
308  object_names_[i] = s;
309  object_indices_[s] = i;
310  }
311 
312  closing_set_ = false;
313 
314  return image->code_segment_.objects_.size();
315 }
316 
317 void Decompiler::decompile_object(
318  uint16 object_index, std::ostringstream *stream, Timestamp time_reference, bool include_oid,
319  bool include_label, bool include_views) {
320 
321  if (!out_stream_)
322  out_stream_ = new OutStream(stream);
323  else if (out_stream_->stream_ != stream) {
324 
325  delete out_stream_;
326  out_stream_ = new OutStream(stream);
327  }
328 
329  time_reference_ = time_reference;
330 
331  variable_names_.clear();
332  last_variable_id_ = 0;
333 
334  current_object_ = image_->code_segment_.objects_[object_index];
335  SysObject *sys_object = (SysObject *)current_object_;
336  uint16 read_index = 0;
337  bool after_tail_wildcard = false;
338  indents_ = 0;
339 
340  if (!partial_decompilation_ && ignore_named_objects_) { // decompilation of the entire memory.
341 
342  if (named_objects_.find(sys_object->oid_) != named_objects_.end())
343  return;
344  }
345  else { // decompiling on-the-fly: ignore named objects only if imported.
346 
347  bool imported = false;
348  for (uint32 i = 0; i < imported_objects_.size(); ++i) {
349 
350  if (sys_object == imported_objects_[i]) {
351 
352  imported = true;
353  break;
354  }
355  }
356 
357  if (imported) {
358 
359  if (named_objects_.find(sys_object->oid_) != named_objects_.end())
360  return;
361  else
362  *out_stream_ << "imported";
363  }
364  else {
365  if (include_oid) {
366  if (sys_object->oid_ != UNDEFINED_OID)
367  *out_stream_ << sys_object->oid_;
368 #ifdef WITH_DETAIL_OID
369  *out_stream_ << "(" << sys_object->detail_oid_ << ") ";
370 #else
371  if (sys_object->oid_ != UNDEFINED_OID)
372  *out_stream_ << " ";
373 #endif
374  }
375  }
376  }
377 
378  if (include_label) {
379  std::string s = object_names_[object_index];
380  s += ":";
381  *out_stream_ << s;
382  }
383 
384  horizontal_set_ = false;
385 
386  (this->*renderers_[current_object_->code_[read_index].asOpcode()])(read_index);
387 
388  if (include_views) {
389  uint16 view_count = sys_object->views_.size();
390  if (view_count) { // write the set of views
391 
392  *out_stream_ << " []";
393  for (uint16 i = 0; i < view_count; ++i) {
394 
395  write_indent(3);
396  current_object_ = sys_object->views_[i];
397  write_view(0, current_object_->code_[0].getAtomCount());
398  }
399  }
400  else
401  *out_stream_ << " |[]";
402  }
403  write_indent(0);
404  write_indent(0);
405 }
406 
407 void Decompiler::decompile_object(const std::string object_name, std::ostringstream *stream, Timestamp time_reference) {
408 
409  decompile_object(object_indices_[object_name], stream, time_reference);
410 }
411 
412 void Decompiler::write_indent(uint16 i) {
413 
414  *out_stream_ << NEWLINE;
415  indents_ = i;
416  for (uint16 j = 0; j < indents_; j++)
417  *out_stream_ << ' ';
418 }
419 
420 void Decompiler::write_expression_head(uint16 read_index) {
421 
422  switch (current_object_->code_[read_index].getDescriptor()) {
423  case Atom::OPERATOR:
424  *out_stream_ << metadata_->operator_names_[current_object_->code_[read_index].asOpcode()];
425  break;
426  case Atom::OBJECT:
427  case Atom::MARKER:
428  *out_stream_ << metadata_->class_names_[current_object_->code_[read_index].asOpcode()];
429  break;
430  case Atom::INSTANTIATED_PROGRAM:
431  case Atom::INSTANTIATED_INPUT_LESS_PROGRAM:
432  case Atom::INSTANTIATED_ANTI_PROGRAM:
433  *out_stream_ << "ipgm";
434  break;
435  case Atom::INSTANTIATED_CPP_PROGRAM:
436  *out_stream_ << "icpp_pgm";
437  break;
438  case Atom::COMPOSITE_STATE:
439  *out_stream_ << "cst";
440  break;
441  case Atom::MODEL:
442  *out_stream_ << "mdl";
443  break;
444  case Atom::GROUP:
445  *out_stream_ << "grp";
446  break;
447  default:
448  *out_stream_ << "undefined-class";
449  break;
450  }
451 }
452 
453 void Decompiler::write_expression_tail(uint16 read_index) { // read_index points initially to the head.
454 
455  uint16 arity = current_object_->code_[read_index].getAtomCount();
456  bool after_tail_wildcard = false;
457 
458  for (uint16 i = 0; i < arity; ++i) {
459 
460  if (after_tail_wildcard)
461  write_any(++read_index, after_tail_wildcard);
462  else {
463 
464  if (closing_set_) {
465 
466  closing_set_ = false;
467  if (!horizontal_set_)
468  write_indent(indents_);
469  else
470  *out_stream_ << ' ';
471  } else
472  *out_stream_ << ' ';
473 
474  write_any(++read_index, after_tail_wildcard);
475  }
476  }
477 }
478 
479 void Decompiler::write_expression(uint16 read_index) {
480 
481  if (closing_set_) {
482 
483  closing_set_ = false;
484  write_indent(indents_);
485  }
486  out_stream_->push('(', read_index);
487  write_expression_head(read_index);
488  write_expression_tail(read_index);
489  if (closing_set_) {
490 
491  closing_set_ = false;
492  write_indent(indents_);
493  }
494  *out_stream_ << ')';
495 }
496 
497 void Decompiler::write_group(uint16 read_index) {
498 
499  if (closing_set_) {
500 
501  closing_set_ = false;
502  write_indent(indents_);
503  }
504  out_stream_->push('(', read_index);
505  write_expression_head(read_index);
506  write_expression_tail(read_index);
507  if (closing_set_) {
508 
509  closing_set_ = false;
510  write_indent(indents_);
511  }
512  *out_stream_ << ')';
513 }
514 
515 void Decompiler::write_marker(uint16 read_index) {
516 
517  if (!in_hlp_)
518  horizontal_set_ = true;
519  if (closing_set_) {
520 
521  closing_set_ = false;
522  write_indent(indents_);
523  }
524  out_stream_->push('(', read_index);
525  write_expression_head(read_index);
526  write_expression_tail(read_index);
527  if (closing_set_) {
528 
529  closing_set_ = false;
530  write_indent(indents_);
531  }
532  *out_stream_ << ')';
533  if (!in_hlp_)
534  horizontal_set_ = false;
535 }
536 
537 void Decompiler::write_pgm(uint16 read_index) {
538 
539  if (closing_set_) {
540 
541  closing_set_ = false;
542  write_indent(indents_);
543  }
544  out_stream_->push('(', read_index);
545  write_expression_head(read_index);
546  write_expression_tail(read_index);
547  if (closing_set_) {
548 
549  closing_set_ = false;
550  write_indent(indents_);
551  }
552  *out_stream_ << ')';
553 }
554 
555 
556 void Decompiler::write_ipgm(uint16 read_index) {
557 
558  if (closing_set_) {
559 
560  closing_set_ = false;
561  write_indent(indents_);
562  }
563  out_stream_->push('(', read_index);
564  write_expression_head(read_index);
565  write_expression_tail(read_index);
566  if (closing_set_) {
567 
568  closing_set_ = false;
569  write_indent(indents_);
570  }
571  *out_stream_ << ')';
572 }
573 
574 void Decompiler::write_hlp(uint16 read_index) {
575 
576  in_hlp_ = true;
577  if (closing_set_) {
578 
579  closing_set_ = false;
580  write_indent(indents_);
581  }
582  out_stream_->push('(', read_index);
583  write_expression_head(read_index);
584  *out_stream_ << " ";
585 
586  uint16 arity = current_object_->code_[read_index].getAtomCount();
587  bool after_tail_wildcard = false;
588 
589  for (uint16 i = 0; i < arity; ++i) {
590 
591  if (after_tail_wildcard)
592  write_any(++read_index, after_tail_wildcard);
593  else {
594 
595  if (closing_set_) {
596 
597  closing_set_ = false;
598  if (i == 1)
599  // Put the [] on the end of the same line.
600  *out_stream_ << ' ';
601  else
602  write_indent(indents_);
603  }
604 
605  if (!(i == 0 || i == 1))
606  // Put a colon after variables for template arguments and the facts, but not after further
607  // element such as guards.
608  hlp_postfix_ = false;
609  bool save_horizontal_set = horizontal_set_;
610  if (i == 0 || i == 4)
611  // Write the set of template arguments and set of output groups horizontally.
612  horizontal_set_ = true;
613  write_any(++read_index, after_tail_wildcard);
614  hlp_postfix_ = true;
615  horizontal_set_ = save_horizontal_set;
616 
617  if (!closing_set_)
618  *out_stream_ << (i == 0 || i >= 4 ? ' ' : NEWLINE);
619  }
620  }
621 
622  if (closing_set_) {
623 
624  closing_set_ = false;
625  write_indent(indents_);
626  }
627  *out_stream_ << ')';
628  in_hlp_ = false;
629 }
630 
631 void Decompiler::write_ihlp(uint16 read_index) {
632 
633  if (!in_hlp_)
634  horizontal_set_ = true;
635  if (closing_set_) {
636 
637  closing_set_ = false;
638  write_indent(indents_);
639  }
640  out_stream_->push('(', read_index);
641  write_expression_head(read_index);
642  write_expression_tail(read_index);
643  if (closing_set_) {
644 
645  closing_set_ = false;
646  write_indent(indents_);
647  }
648  *out_stream_ << ')';
649  if (!in_hlp_)
650  horizontal_set_ = false;
651 }
652 
653 void Decompiler::write_icmd(uint16 read_index) {
654 
655  if (closing_set_) {
656 
657  closing_set_ = false;
658  write_indent(indents_);
659  }
660  out_stream_->push('(', read_index);
661  write_expression_head(read_index);
662 
663  uint16 write_as_view_index = 0;
664  if (current_object_->code_[read_index + 1].asOpcode() == metadata_->classes_.find("_inj")->second.atom_.asOpcode()) {
665 
666  uint16 arg_set_index = current_object_->code_[read_index + 2].asIndex(); // 2 args for _inj; the view is the second.
667  write_as_view_index = current_object_->code_[arg_set_index + 2].asIndex();
668  }
669 
670  uint16 arity = current_object_->code_[read_index].getAtomCount();
671  bool after_tail_wildcard = false;
672 
673  for (uint16 i = 0; i < arity; ++i) {
674 
675  if (after_tail_wildcard)
676  write_any(++read_index, after_tail_wildcard);
677  else {
678 
679  if (closing_set_) {
680 
681  closing_set_ = false;
682  write_indent(indents_);
683  } else
684  *out_stream_ << ' ';
685 
686  write_any(++read_index, after_tail_wildcard, write_as_view_index);
687  }
688  }
689 
690  if (closing_set_) {
691 
692  closing_set_ = false;
693  write_indent(indents_);
694  }
695  *out_stream_ << ')';
696 }
697 
698 void Decompiler::write_cmd(uint16 read_index) {
699 
700  if (!in_hlp_)
701  horizontal_set_ = true;
702  if (closing_set_) {
703 
704  closing_set_ = false;
705  write_indent(indents_);
706  }
707  out_stream_->push('(', read_index);
708  write_expression_head(read_index);
709  write_expression_tail(read_index);
710  if (closing_set_) {
711 
712  closing_set_ = false;
713  write_indent(indents_);
714  }
715  *out_stream_ << ')';
716  if (!in_hlp_)
717  horizontal_set_ = false;
718 }
719 
720 void Decompiler::write_fact(uint16 read_index) {
721 
722  if (in_hlp_)
723  horizontal_set_ = true;
724  if (closing_set_) {
725 
726  closing_set_ = false;
727  write_indent(indents_);
728  }
729  out_stream_->push('(', read_index);
730  write_expression_head(read_index);
731  write_expression_tail(read_index);
732  if (closing_set_) {
733 
734  closing_set_ = false;
735  write_indent(indents_);
736  }
737  *out_stream_ << ')';
738  horizontal_set_ = false;
739 }
740 
741 void Decompiler::write_view(uint16 read_index, uint16 arity) {
742 
743  if (arity > VIEW_CODE_MAX_SIZE || arity <= 1) {
744 
745  *out_stream_ << "nil";
746  return;
747  }
748 
749  bool after_tail_wildcard = false;
750 
751  *out_stream_ << "[";
752  for (uint16 j = 1; j <= arity; ++j) {
753 
754  write_any(read_index + j, after_tail_wildcard);
755  if (j < arity)
756  *out_stream_ << " ";
757  }
758  *out_stream_ << "]";
759 }
760 
761 void Decompiler::write_set(uint16 read_index, uint16 write_as_view_index) { // read_index points to a set atom.
762 
763  uint16 arity = current_object_->code_[read_index].getAtomCount();
764  bool after_tail_wildcard = false;
765 
766  if (arity == 1) { // write [element]
767 
768  out_stream_->push('[', read_index);
769  write_any(++read_index, after_tail_wildcard);
770  *out_stream_ << ']';
771  } else if (write_as_view_index > 0 && write_as_view_index == read_index)
772  write_view(read_index, arity);
773  else if (horizontal_set_) { // write [elements].
774 
775  out_stream_->push('[', read_index);
776  for (uint16 i = 0; i < arity; ++i) {
777 
778  if (i > 0)
779  *out_stream_ << ' ';
780  if (after_tail_wildcard)
781  write_any(++read_index, after_tail_wildcard);
782  else
783  write_any(++read_index, after_tail_wildcard, write_as_view_index);
784  }
785  *out_stream_ << ']';
786  closing_set_ = true;
787  } else { // write []+indented elements.
788 
789  out_stream_->push("[]", read_index);
790  indents_ += 3;
791  for (uint16 i = 0; i < arity; ++i) {
792 
793  if (after_tail_wildcard)
794  write_any(++read_index, after_tail_wildcard);
795  else {
796 
797  write_indent(indents_);
798  write_any(++read_index, after_tail_wildcard, write_as_view_index);
799  }
800  }
801  closing_set_ = true;
802  indents_ -= 3; // don't call write_indents() here as the last set member can be a set.
803  }
804 }
805 
806 void Decompiler::write_any(uint16 read_index, bool &after_tail_wildcard, uint16 write_as_view_index) { // after_tail_wildcard meant to avoid printing ':' after "::".
807 
808  Atom a = current_object_->code_[read_index];
809 
810  if (a.isFloat()) {
811 
812  if (a.atom_ == 0x3FFFFFFF)
813  out_stream_->push("|nb", read_index);
814  else if (a == Atom::PlusInfinity())
815  out_stream_->push("forever", read_index);
816  else {
817 
818  *out_stream_ << std::dec;
819  out_stream_->push(a.asFloat(), read_index);
820  }
821  return;
822  }
823 
824  Atom atom;
825  uint16 index;
826  switch (a.getDescriptor()) {
827  case Atom::VL_PTR:
828  // JTNote: The opcode 0x0FFE doesn't seem to be used.
829  if (a.asCastOpcode() == 0x0FFE)
830  out_stream_->push(':', read_index);
831  else {
832 
833  std::string s = get_hlp_variable_name(a.asIndex());
834  out_stream_->push(s, read_index);
835  }
836  break;
837  case Atom::ASSIGN_PTR:
838  // Output the assignment index, then fall through to process like an I_PTR.
839  out_stream_->push(get_hlp_variable_name(a.asAssignmentIndex()), read_index);
840  *out_stream_ << ":";
841  case Atom::CODE_VL_PTR:
842  // Fall through to start processing like an I_PTR. Will print the get_variable_name() and break.
843  case Atom::I_PTR:
844  index = a.asIndex();
845  atom = current_object_->code_[index];
846  while (atom.getDescriptor() == Atom::I_PTR) {
847 
848  index = atom.asIndex();
849  atom = current_object_->code_[index];
850  }
851  if (index < read_index) { // reference to a label or variable, including CODE_VL_PTR.
852 
853  std::string s = get_variable_name(index, atom.getDescriptor() != Atom::WILDCARD); // post-fix labels with ':' (no need for variables since they are inserted just before wildcards).
854  out_stream_->push(s, read_index);
855  break;
856  }
857  switch (atom.getDescriptor()) { // structures.
858  case Atom::OBJECT:
859  case Atom::MARKER:
860  case Atom::GROUP:
861  case Atom::INSTANTIATED_PROGRAM:
862  case Atom::INSTANTIATED_INPUT_LESS_PROGRAM:
863  case Atom::INSTANTIATED_ANTI_PROGRAM:
864  case Atom::INSTANTIATED_CPP_PROGRAM:
865  case Atom::COMPOSITE_STATE:
866  case Atom::MODEL:
867  case Atom::OPERATOR:
868  (this->*renderers_[atom.asOpcode()])(index);
869  break;
870  case Atom::SET:
871  case Atom::S_SET:
872  if (atom.readsAsNil())
873  // In a horizontal set (where characters follow), we can write an empty set as [] .
874  out_stream_->push(horizontal_set_ ? "[]" : "|[]", read_index);
875  else
876  write_set(index, write_as_view_index);
877  break;
878  case Atom::STRING:
879  if (atom.readsAsNil())
880  out_stream_->push("|st", read_index);
881  else {
882 
883  std::string s = Utils::GetString(&current_object_->code_[index]);
884  *out_stream_ << '\"' << s << '\"';
885  }
886  break;
887  case Atom::TIMESTAMP:
888  if (atom.readsAsNil())
889  out_stream_->push("|ts", read_index);
890  else
891  out_stream_->push(Utils::ToString_s_ms_us(Utils::GetTimestamp(&current_object_->code_[index]), time_reference_), read_index);
892  break;
893  case Atom::DURATION:
894  out_stream_->push(Utils::ToString_us(Utils::GetDuration(&current_object_->code_[index])), read_index);
895  break;
896  case Atom::C_PTR: {
897 
898  uint16 opcode;
899  uint16 member_count = atom.getAtomCount();
900  atom = current_object_->code_[index + 1]; // current_object_->code[index] is the cptr; lead atom is at index+1; iptrs start at index+2.
901  switch (atom.getDescriptor()) {
902  case Atom::THIS: // this always refers to an instantiated reactive object.
903  out_stream_->push("this", read_index);
904  opcode = metadata_->sys_classes_["ipgm"].atom_.asOpcode();
905  break;
906  case Atom::CODE_VL_PTR: {
907 
908  uint8 cast_opcode = atom.asCastOpcode();
909  while (current_object_->code_[atom.asIndex()].getDescriptor() == Atom::I_PTR) // position to a structure or an atomic value_.
910  atom = current_object_->code_[atom.asIndex()];
911  out_stream_->push(get_variable_name(atom.asIndex(), current_object_->code_[atom.asIndex()].getDescriptor() != Atom::WILDCARD), read_index);
912  if (cast_opcode == 0xFF) {
913 
914  if (current_object_->code_[atom.asIndex()].getDescriptor() == Atom::WILDCARD)
915  opcode = current_object_->code_[atom.asIndex()].asOpcode();
916  else
917  opcode = current_object_->code_[atom.asIndex()].asOpcode();
918  } else
919  opcode = cast_opcode;
920  break;
921  }case Atom::R_PTR: {
922  uint32 object_index = current_object_->references_[atom.asIndex()];
923  out_stream_->push(get_object_name(object_index), read_index);
924  opcode = image_->code_segment_.objects_[object_index]->code_[0].asOpcode();
925  break;
926  }default:
927  out_stream_->push("unknown-cptr-lead-type", read_index);
928  break;
929  }
930 
931  Class embedding_class = metadata_->classes_by_opcodes_[opcode]; // class defining the members.
932  for (uint16 i = 2; i <= member_count; ++i) { // get the class of the pointed structure and retrieve the member name from i.
933 
934  std::string member_name;
935  atom = current_object_->code_[index + i]; // atom is an iptr appearing after the leading atom in the cptr.
936  switch (atom.getDescriptor()) {
937  case Atom::VIEW:
938  member_name = "vw";
939  break;
940  case Atom::MKS:
941  member_name = "mks";
942  break;
943  case Atom::VWS:
944  member_name = "vws";
945  break;
946  default:
947  member_name = embedding_class.get_member_name(atom.asIndex());
948  if (i < member_count) // not the last member, get the next class.
949  embedding_class = *embedding_class.get_member_class(metadata_, member_name);
950  break;
951  }
952  *out_stream_ << '.' << member_name;
953 
954  if (member_name == "vw") { // special case: no view structure in the code, vw is just a place holder; vw is the second to last member of the cptr: write the last member and exit.
955 
956  atom = current_object_->code_[index + member_count]; // atom is the last internal pointer.
957  Class view_class;
958  if (embedding_class.str_opcode == "grp")
959  view_class = metadata_->classes_.find("grp_view")->second;
960  else if (embedding_class.str_opcode == "ipgm" ||
961  embedding_class.str_opcode == "icpp_pgm" ||
962  embedding_class.str_opcode == "mdl" ||
963  embedding_class.str_opcode == "cst")
964  view_class = metadata_->classes_.find("pgm_view")->second;
965  else
966  view_class = metadata_->classes_.find("view")->second;
967  member_name = view_class.get_member_name(atom.asIndex());
968  *out_stream_ << '.' << member_name;
969  break;
970  }
971  }
972  break;
973  }default:
974  out_stream_->push("undefined-structural-atom-or-reference", read_index);
975  break;
976  }
977  break;
978  case Atom::R_PTR:
979  out_stream_->push(get_object_name(current_object_->references_[a.asIndex()]), read_index);
980  break;
981  case Atom::THIS:
982  out_stream_->push("this", read_index);
983  break;
984  case Atom::NIL:
985  out_stream_->push("nil", read_index);
986  break;
987  case Atom::BOOLEAN_:
988  if (a.readsAsNil())
989  out_stream_->push("|bl", read_index);
990  else {
991 
992  *out_stream_ << std::boolalpha;
993  out_stream_->push(a.asBoolean(), read_index);
994  }
995  break;
996  case Atom::WILDCARD:
997  if (after_tail_wildcard)
998  out_stream_->push();
999  else
1000  out_stream_->push(':', read_index);
1001  break;
1002  case Atom::T_WILDCARD:
1003  out_stream_->push("::", read_index);
1004  after_tail_wildcard = true;
1005  break;
1006  case Atom::NODE:
1007  if (a.readsAsNil())
1008  out_stream_->push("|sid", read_index);
1009  else {
1010 
1011  out_stream_->push("0x", read_index);
1012  *out_stream_ << std::hex;
1013  *out_stream_ << a.atom_;
1014  }
1015  break;
1016  case Atom::DEVICE:
1017  if (a.readsAsNil())
1018  out_stream_->push("|did", read_index);
1019  else {
1020 
1021  out_stream_->push("0x", read_index);
1022  *out_stream_ << std::hex;
1023  *out_stream_ << a.atom_;
1024  }
1025  break;
1026  case Atom::DEVICE_FUNCTION:
1027  if (a.readsAsNil())
1028  out_stream_->push("|fid", read_index);
1029  else
1030  out_stream_->push(metadata_->function_names_[a.asOpcode()], read_index);
1031  break;
1032  case Atom::VIEW:
1033  out_stream_->push("vw", read_index);
1034  break;
1035  case Atom::MKS:
1036  out_stream_->push("mks", read_index);
1037  break;
1038  case Atom::VWS:
1039  out_stream_->push("vws", read_index);
1040  break;
1041  default:
1042  // out_stream_->push("undefined-atom",read_index).
1043  out_stream_->push("0x", read_index);
1044  *out_stream_ << std::hex;
1045  *out_stream_ << a.atom_;
1046  break;
1047  }
1048 }
1049 }
r_code::Atom
Definition: atom.h:104
r_code::SysObject
Definition: r_code/object.h:136
r_comp::Image
Definition: segments.h:177
r_comp::OutStream
Definition: out_stream.h:97
r_comp::Metadata
Definition: segments.h:109
r_comp::Class
Definition: class.h:96