AERA
preprocessor.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 //_/_/ Copyright (c) 2018 Throstur Thorarensen
10 //_/_/ http://www.iiim.is
11 //_/_/
12 //_/_/ Copyright (c) 2010-2012 Eric Nivel
13 //_/_/ Copyright (c) 2010 Thor List
14 //_/_/ Center for Analysis and Design of Intelligent Agents
15 //_/_/ Reykjavik University, Menntavegur 1, 102 Reykjavik, Iceland
16 //_/_/ http://cadia.ru.is
17 //_/_/
18 //_/_/ Part of this software was developed by Eric Nivel
19 //_/_/ in the HUMANOBS EU research project, which included
20 //_/_/ the following parties:
21 //_/_/
22 //_/_/ Autonomous Systems Laboratory
23 //_/_/ Technical University of Madrid, Spain
24 //_/_/ http://www.aslab.org/
25 //_/_/
26 //_/_/ Communicative Machines
27 //_/_/ Edinburgh, United Kingdom
28 //_/_/ http://www.cmlabs.com/
29 //_/_/
30 //_/_/ Istituto Dalle Molle di Studi sull'Intelligenza Artificiale
31 //_/_/ University of Lugano and SUPSI, Switzerland
32 //_/_/ http://www.idsia.ch/
33 //_/_/
34 //_/_/ Institute of Cognitive Sciences and Technologies
35 //_/_/ Consiglio Nazionale delle Ricerche, Italy
36 //_/_/ http://www.istc.cnr.it/
37 //_/_/
38 //_/_/ Dipartimento di Ingegneria Informatica
39 //_/_/ University of Palermo, Italy
40 //_/_/ http://diid.unipa.it/roboticslab/
41 //_/_/
42 //_/_/
43 //_/_/ --- HUMANOBS Open-Source BSD License, with CADIA Clause v 1.0 ---
44 //_/_/
45 //_/_/ Redistribution and use in source and binary forms, with or without
46 //_/_/ modification, is permitted provided that the following conditions
47 //_/_/ are met:
48 //_/_/ - Redistributions of source code must retain the above copyright
49 //_/_/ and collaboration notice, this list of conditions and the
50 //_/_/ following disclaimer.
51 //_/_/ - Redistributions in binary form must reproduce the above copyright
52 //_/_/ notice, this list of conditions and the following disclaimer
53 //_/_/ in the documentation and/or other materials provided with
54 //_/_/ the distribution.
55 //_/_/
56 //_/_/ - Neither the name of its copyright holders nor the names of its
57 //_/_/ contributors may be used to endorse or promote products
58 //_/_/ derived from this software without specific prior
59 //_/_/ written permission.
60 //_/_/
61 //_/_/ - CADIA Clause: The license granted in and to the software
62 //_/_/ under this agreement is a limited-use license.
63 //_/_/ The software may not be used in furtherance of:
64 //_/_/ (i) intentionally causing bodily injury or severe emotional
65 //_/_/ distress to any person;
66 //_/_/ (ii) invading the personal privacy or violating the human
67 //_/_/ rights of any person; or
68 //_/_/ (iii) committing or preparing for any act of war.
69 //_/_/
70 //_/_/ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
71 //_/_/ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
72 //_/_/ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
73 //_/_/ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
74 //_/_/ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
75 //_/_/ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
76 //_/_/ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
77 //_/_/ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
78 //_/_/ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
79 //_/_/ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
80 //_/_/ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
81 //_/_/ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
82 //_/_/ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
83 //_/_/ OF SUCH DAMAGE.
84 //_/_/
85 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
86 
87 #include <experimental/filesystem>
88 #include "preprocessor.h"
89 #include "compiler.h"
90 #include "../submodules/CoreLibrary/CoreLibrary/utils.h"
91 namespace fs = std::experimental::filesystem;
92 
93 using namespace std;
94 using namespace r_code;
95 
96 namespace r_comp {
97 
98 unordered_map<std::string, RepliMacro *> RepliStruct::RepliMacros_;
99 unordered_map<std::string, int32> RepliStruct::Counters_;
100 std::list<RepliCondition *> RepliStruct::Conditions_;
101 uint32 RepliStruct::GlobalLine_ = 1;
102 vector<std::string> RepliStruct::LoadedFilePaths_;
103 
104 RepliStruct::RepliStruct(RepliStruct::Type type) {
105  type_ = type;
106  line_ = GlobalLine_;
107  parent_ = NULL;
108 }
109 
110 RepliStruct::~RepliStruct() {
111  parent_ = NULL;
112 }
113 
114 void RepliStruct::reset() {
115 
116  std::list<RepliStruct*>::const_iterator arg;
117  for (arg = args_.begin(); arg != args_.end();) {
118 
119  switch ((*arg)->type_) {
120  case RepliStruct::Atom:
121  case RepliStruct::Structure:
122  case RepliStruct::Development:
123  case RepliStruct::Set:
124  arg = args_.erase(arg);
125  break;
126  default:
127  ++arg;
128  }
129  }
130 }
131 
132 uint32 RepliStruct::getIndent(std::istream *stream) {
133 
134  uint32 count = 0;
135  while (!stream->eof()) {
136  switch (stream->get()) {
137  case 10:
138  GlobalLine_++;
139  case 13:
140  stream->seekg(-1, std::ios_base::cur);
141  return count / 3;
142  case ' ':
143  count++;
144  break;
145  default:
146  stream->seekg(-1, std::ios_base::cur);
147  return count / 3;
148  }
149  }
150  return count / 3;
151 }
152 
153 int32 RepliStruct::parse(std::istream *stream, const std::string& file_path, uint32 &cur_indent, uint32 &prev_indent, int32 param_expect) {
154 
155  char c = 0, lastc = 0, lastcc, tc;
156  std::string str, label;
157  RepliStruct* sub_struct;
158 
159  int32 param_count = 0;
160  int32 return_indent = 0;
161 
162  bool in_comment = false;
163  bool expect_set = false;
164 
165  while (!stream->eof()) {
166  lastcc = lastc;
167  lastc = c;
168  c = stream->get();
169  // printf("%c", c);
170 
171  if (!in_comment && c == '\"') {
172  // Special case: Read until the end of the string.
173  while (true) {
174  str += c;
175  lastcc = lastc;
176  lastc = c;
177  c = stream->get();
178 
179  if (c == '\"')
180  // End of the string. Continue below to append to str.
181  break;
182  if (c == 10 || c == 13) {
183  line_ = GlobalLine_;
184  error_ += "Newline is not permitted in a string. ";
185  return -1;
186  }
187  }
188  }
189 
190  switch (c) {
191  case '\t':
192  if (in_comment) continue; // allow tabs in comments, does not matter anyway
193  line_ = GlobalLine_;
194  error_ += "Tabs chars are not permitted. ";
195  return -1;
196  case '!':
197  if (in_comment) continue;
198  if (type_ == Root) {
199  sub_struct = new RepliStruct(Directive);
200  sub_struct->parent_ = this;
201  args_.push_back(sub_struct);
202  if (!sub_struct->parseDirective(stream, file_path, cur_indent, prev_indent))
203  return -1;
204  if (sub_struct->cmd_.compare("!load") == 0)
205  // Save the filePath of the containing file for later.
206  sub_struct->filePath_ = file_path;
207  }
208  else {
209  error_ += "Directive not allowed inside a structure. ";
210  return -1;
211  }
212  break;
213  case 10:
214  GlobalLine_++;
215  case 13:
216  // remain inComment?
217  if (in_comment) {
218  if ((lastc == '.') && (lastcc == '.'))
219  continue; // continue comment on next line
220  else
221  in_comment = false; // end comment
222  }
223  // skip all CR and LF
224  while ((!stream->eof()) && (stream->peek() < 32))
225  if (stream->get() == 10)
226  GlobalLine_++;
227  // get indents
228  prev_indent = cur_indent;
229  cur_indent = getIndent(stream);
230  // Are we in a parenthesis or set
231  if (cur_indent > prev_indent) {
232  // Are we in a set
233  if (expect_set) {
234  // Add new sub structure
235  sub_struct = new RepliStruct(Set);
236  sub_struct->parent_ = this;
237  sub_struct->label_ = label;
238  label = "";
239  args_.push_back(sub_struct);
240  return_indent = sub_struct->parse(stream, file_path, cur_indent, prev_indent);
241  expect_set = false;
242  if (return_indent < 0)
243  return -1;
244  if ((param_expect > 0) && (++param_count == param_expect))
245  return 0;
246  if (return_indent > 0)
247  return (return_indent - 1);
248  }
249  // or a parenthesis
250  else {
251  sub_struct = new RepliStruct(Structure);
252  args_.push_back(sub_struct);
253  return_indent = sub_struct->parse(stream, file_path, cur_indent, prev_indent);
254  expect_set = false;
255  if (return_indent < 0)
256  return -1;
257  if ((param_expect > 0) && (++param_count == param_expect))
258  return 0;
259  if (return_indent > 0)
260  return (return_indent - 1);
261  }
262  }
263  else if (cur_indent < prev_indent) {
264  if (str.size() > 0) {
265  if ((cmd_.size() > 0) || (type_ == Set)) {
266  sub_struct = new RepliStruct(Atom);
267  sub_struct->parent_ = this;
268  args_.push_back(sub_struct);
269  sub_struct->cmd_ = str;
270  str = "";
271  if ((param_expect > 0) && (++param_count == param_expect))
272  return 0;
273  }
274  else {
275  cmd_ = str;
276  str = "";
277  }
278  }
279  // current structure or set is complete
280  return prev_indent - cur_indent - 1;
281  }
282  else {
283  // act as if we met a space
284  if (str.size() > 0) {
285  if ((cmd_.size() > 0) || (type_ == Set) || (type_ == Root)) {
286  sub_struct = new RepliStruct(Atom);
287  sub_struct->parent_ = this;
288  args_.push_back(sub_struct);
289  sub_struct->cmd_ = str;
290  str = "";
291  if ((param_expect > 0) && (++param_count == param_expect))
292  return 0;
293  }
294  else {
295  cmd_ = str;
296  str = "";
297  }
298  }
299  }
300  break;
301  case ';':
302  in_comment = true;
303  break;
304  case ' ':
305  if (in_comment) continue;
306  // next string is ready
307  if (str.size() > 0) {
308  if ((cmd_.size() > 0) || (type_ == Set) || (type_ == Development)) { // Modification from Eric to have the Development treat tpl vars as atoms instead of a Development.cmd
309  sub_struct = new RepliStruct(Atom);
310  sub_struct->parent_ = this;
311  args_.push_back(sub_struct);
312  sub_struct->cmd_ = str;
313  str = "";
314  if ((param_expect > 0) && (++param_count == param_expect))
315  return 0;
316  }
317  else {
318  cmd_ = str;
319  str = "";
320  }
321  }
322  break;
323  case '(':
324  if (in_comment) continue;
325  // Check for scenario 'xxx('
326  if (str.size() > 0) {
327  if (lastc == ':') { // label:(xxx)
328  label = str;
329  str = "";
330  }
331  else if ((cmd_.size() > 0) || (type_ == Set)) {
332  sub_struct = new RepliStruct(Atom);
333  sub_struct->parent_ = this;
334  args_.push_back(sub_struct);
335  sub_struct->cmd_ = str;
336  str = "";
337  if ((param_expect > 0) && (++param_count == param_expect))
338  return 0;
339  }
340  else {
341  cmd_ = str;
342  str = "";
343  }
344  }
345  sub_struct = new RepliStruct(Structure);
346  sub_struct->label_ = label;
347  label = "";
348  sub_struct->parent_ = this;
349  args_.push_back(sub_struct);
350  return_indent = sub_struct->parse(stream, file_path, cur_indent, prev_indent);
351  if (return_indent < 0)
352  return -1;
353  if ((param_expect > 0) && (++param_count == param_expect))
354  return 0;
355  if (return_indent > 0)
356  return (return_indent - 1);
357  break;
358  case ')':
359  if (in_comment) continue;
360  // Check for directive use of xxx):xxx or xxx):
361  if (stream->peek() == ':') {
362  // expect ':' or ':xxx'
363  while ((!stream->eof()) && ((c = stream->get()) > 32))
364  tail_ += c;
365  }
366  // We met a boundary, act as ' '
367  if (str.size() > 0) {
368  if ((cmd_.size() > 0) || (type_ == Set)) {
369  sub_struct = new RepliStruct(Atom);
370  sub_struct->parent_ = this;
371  args_.push_back(sub_struct);
372  sub_struct->cmd_ = str;
373  str = "";
374  if ((param_expect > 0) && (++param_count == param_expect))
375  return 0;
376  }
377  else {
378  cmd_ = str;
379  str = "";
380  }
381  }
382  return 0;
383  case '{':
384  if (in_comment) continue;
385  // Check for scenario 'xxx{'
386  if (str.size() > 0) {
387  if (lastc == ':') { // label:{xxx}
388  label = str;
389  str = "";
390  }
391  else if ((cmd_.size() > 0) || (type_ == Set)) {
392  sub_struct = new RepliStruct(Atom);
393  sub_struct->parent_ = this;
394  args_.push_back(sub_struct);
395  sub_struct->cmd_ = str;
396  str = "";
397  if ((param_expect > 0) && (++param_count == param_expect))
398  return 0;
399  }
400  else {
401  cmd_ = str;
402  str = "";
403  }
404  }
405  sub_struct = new RepliStruct(Development);
406  sub_struct->label_ = label;
407  label = "";
408  sub_struct->parent_ = this;
409  args_.push_back(sub_struct);
410  return_indent = sub_struct->parse(stream, file_path, cur_indent, prev_indent);
411  if (return_indent < 0)
412  return -1;
413  if ((param_expect > 0) && (++param_count == param_expect))
414  return 0;
415  if (return_indent > 0)
416  return (return_indent - 1);
417  break;
418  case '}':
419  if (in_comment) continue;
420  // Check for directive use of xxx):xxx or xxx):
421  if (stream->peek() == ':') {
422  // expect ':' or ':xxx'
423  while ((!stream->eof()) && ((c = stream->get()) > 32))
424  tail_ += c;
425  }
426  // We met a boundary, act as ' '
427  if (str.size() > 0) {
428  if ((cmd_.size() > 0) || (type_ == Set) || (type_ == Development)) { // Modification from Eric to have the Development treat tpl vars as atoms instead of a Development.cmd
429  sub_struct = new RepliStruct(Atom);
430  sub_struct->parent_ = this;
431  args_.push_back(sub_struct);
432  sub_struct->cmd_ = str;
433  str = "";
434  if ((param_expect > 0) && (++param_count == param_expect))
435  return 0;
436  }
437  else {
438  cmd_ = str;
439  str = "";
440  }
441  }
442  return 0;
443  case '|':
444  if (in_comment) continue;
445  if (stream->peek() == '[') {
446  stream->get(); // read the [
447  stream->get(); // read the ]
448  str += "|[]";
449  }
450  else
451  str += c;
452  break;
453  case '[': // set start
454  if (in_comment) continue;
455  if (lastc == ':') { // label:[xxx]
456  label = str;
457  str = "";
458  }
459  if (stream->peek() == ']') {
460  stream->get(); // read the ]
461  // if we have a <CR> or <LF> next we may have a line indent set
462  if (((tc = stream->peek()) < 32) || (tc == ';'))
463  expect_set = true;
464  else {
465  // this could be a xxx:[] or xxx[]
466  if ((lastc != ':') && (lastc > 32)) { // label[]
467  // act as if [] is part of the string and continue
468  str += "[]";
469  continue;
470  }
471  // create empty set
472  sub_struct = new RepliStruct(Set);
473  sub_struct->parent_ = this;
474  sub_struct->label_ = label;
475  args_.push_back(sub_struct);
476  }
477  }
478  else {
479  // Check for scenario 'xxx['
480  if (str.size() > 0) {
481  if ((cmd_.size() > 0) || (type_ == Set)) {
482  sub_struct = new RepliStruct(Atom);
483  sub_struct->parent_ = this;
484  args_.push_back(sub_struct);
485  sub_struct->cmd_ = str;
486  str = "";
487  if ((param_expect > 0) && (++param_count == param_expect))
488  return 0;
489  }
490  else {
491  cmd_ = str;
492  str = "";
493  }
494  }
495  sub_struct = new RepliStruct(Set);
496  sub_struct->parent_ = this;
497  sub_struct->label_ = label;
498  label = "";
499  args_.push_back(sub_struct);
500  return_indent = sub_struct->parse(stream, file_path, cur_indent, prev_indent);
501  if (return_indent < 0)
502  return -1;
503  if ((param_expect > 0) && (++param_count == param_expect))
504  return 0;
505  if (return_indent > 0)
506  return (return_indent - 1);
507  }
508  break;
509  case ']':
510  if (in_comment) continue;
511  // We met a boundary, act as ' '
512  if (str.size() > 0) {
513  if ((cmd_.size() > 0) || (type_ == Set)) {
514  sub_struct = new RepliStruct(Atom);
515  sub_struct->parent_ = this;
516  args_.push_back(sub_struct);
517  sub_struct->cmd_ = str;
518  str = "";
519  if ((param_expect > 0) && (++param_count == param_expect))
520  return 0;
521  }
522  else {
523  cmd_ = str;
524  str = "";
525  }
526  }
527  return 0;
528  default:
529  if (in_comment) continue;
530  str += c;
531  break;
532  }
533  }
534  return 0;
535 }
536 
537 
538 bool RepliStruct::parseDirective(std::istream *stream, const std::string& file_path, uint32 &cur_indent, uint32 &prev_indent) {
539 
540  std::string str = "!";
541  // RepliStruct* subStruct;
542  char c;
543 
544  // We know that parent read a '!', so first find out which directive
545  while ((!stream->eof()) && ((c = stream->peek()) > 32))
546  str += stream->get();
547  if (stream->eof()) {
548  error_ += "Error in directive formatting, end of file reached unexpectedly. ";
549  return false;
550  }
551 
552  unsigned int param_count = 0;
553 
554  if (str.compare("!def") == 0) // () ()
555  param_count = 2;
556  else if (str.compare("!counter") == 0) // xxx val
557  param_count = 2;
558  else if (str.compare("!undef") == 0) // xxx
559  param_count = 1;
560  else if (str.compare("!ifdef") == 0) { // name
561  type_ = Condition;
562  param_count = 1;
563  }
564  else if (str.compare("!ifundef") == 0) { // name
565  type_ = Condition;
566  param_count = 1;
567  }
568  else if (str.compare("!else") == 0) { //
569  type_ = Condition;
570  param_count = 0;
571  }
572  else if (str.compare("!endif") == 0) { //
573  type_ = Condition;
574  param_count = 0;
575  }
576  else if (str.compare("!class") == 0) // ()
577  param_count = 1;
578  else if (str.compare("!op") == 0) // ():xxx
579  param_count = 1;
580  else if (str.compare("!dfn") == 0) // ()
581  param_count = 1;
582  else if (str.compare("!load") == 0) // xxx
583  param_count = 1;
584  else {
585  error_ += "Unknown directive: '" + str + "'. ";
586  return false;
587  }
588  cmd_ = str;
589 
590  if (param_count == 0) {
591  // read until end of line, including any comments
592  while ((!stream->eof()) && (stream->peek() > 13))
593  stream->get();
594  // read the end of line too
595  while ((!stream->eof()) && (stream->peek() < 32))
596  if (stream->get() == 10)
597  GlobalLine_++;
598  return true;
599  }
600 
601  if (parse(stream, file_path, cur_indent, prev_indent, param_count) != 0) {
602  error_ += "Error parsing the arguments for directive '" + cmd_ + "'. ";
603  return false;
604  }
605  else
606  return true;
607 }
608 
609 
610 int32 RepliStruct::process() {
611 
612  int32 changes = 0, count;
613  RepliStruct *structure, *new_struct, *temp_struct;
614  RepliMacro* macro;
615  RepliCondition* cond;
616  std::string load_error;
617 
618  // expand Counters_ in all structures
619  if (Counters_.find(cmd_) != Counters_.end()) {
620  // expand the counter
621  cmd_ = std::to_string(Counters_[cmd_]++);
622  changes++;
623  }
624  // expand Macros in all structures
625  if (RepliMacros_.find(cmd_) != RepliMacros_.end()) {
626  // expand the macro
627  macro = RepliMacros_[cmd_];
628  new_struct = macro->expandMacro(this);
629  if (new_struct != NULL) {
630  *this = *new_struct;
631  delete(new_struct);
632  changes++;
633  }
634  else {
635  error_ = macro->error_;
636  macro->error_ = "";
637  return -1;
638  }
639  }
640 
641  if (args_.size() == 0)
642  return changes;
643 
644  for (std::list<RepliStruct*>::iterator iter(args_.begin()), iterEnd(args_.end()); iter != iterEnd; ++iter) {
645  structure = (*iter);
646 
647  // printf("Processing %s with %d args...\n", structure->cmd.c_str(), structure->args.size());
648  if (structure->type_ == Condition) {
649  if (structure->cmd_.compare("!ifdef") == 0) {
650  cond = new RepliCondition(structure->args_.front()->cmd_, false);
651  Conditions_.push_back(cond);
652  }
653  else if (structure->cmd_.compare("!ifundef") == 0) {
654  cond = new RepliCondition(structure->args_.front()->cmd_, true);
655  Conditions_.push_back(cond);
656  }
657  else if (structure->cmd_.compare("!else") == 0) {
658  // reverse the current condition
659  Conditions_.back()->reverse();
660  }
661  else if (structure->cmd_.compare("!endif") == 0) {
662  Conditions_.pop_back();
663  }
664  return 0;
665  }
666 
667  // Check Conditions_ to see if we are active at the moment
668  for (std::list<RepliCondition*>::const_iterator iCon(Conditions_.begin()), iConEnd(Conditions_.end()); iCon != iConEnd; ++iCon) {
669  // if just one active condition is not active we will ignore the current line
670  // until we get an !else or !endif
671  if (!((*iCon)->isActive(RepliMacros_, Counters_)))
672  return 0;
673  }
674 
675  if (structure->type_ == Directive) {
676  if (structure->cmd_.compare("!counter") == 0) {
677  // register the counter
678  if (structure->args_.size() > 1)
679  Counters_[structure->args_.front()->cmd_] = atoi(structure->args_.back()->cmd_.c_str());
680  else
681  Counters_[structure->args_.front()->cmd_] = 0;
682  }
683  else if (structure->cmd_.compare("!def") == 0) {
684  // check second sub structure only containing macros
685  while ((count = structure->args_.back()->process()) > 0)
686  changes += count;
687  if (count < 0)
688  return -1;
689  // register the macro
690  macro = new RepliMacro(structure->args_.front()->cmd_, structure->args_.front(), structure->args_.back());
691  RepliMacros_[macro->name_] = macro;
692  }
693  else if (structure->cmd_.compare("!undef") == 0) {
694  // remove the counter or macro
695  RepliMacros_.erase(RepliMacros_.find(structure->args_.front()->cmd_));
696  Counters_.erase(Counters_.find(structure->args_.front()->cmd_));
697  }
698  else if (structure->cmd_.compare("!load") == 0) {
699  // Check for a load directive...
700  fs::path loadPath = fs::path(structure->args_.front()->cmd_);
701  if (loadPath.is_relative()) {
702  // Combine the relative path with the directory of the containing file.
703  fs::path containingDirectory = fs::path(structure->filePath_).parent_path();
704  loadPath = containingDirectory / loadPath;
705  }
706 
707  new_struct = loadReplicodeFile(loadPath.string());
708  if (new_struct == NULL) {
709  structure->error_ += "Load: File '" + loadPath.string() + "' cannot be read! ";
710  return -1;
711  }
712  else if ((load_error = new_struct->printError()).size() > 0) {
713  structure->error_ = load_error;
714  delete(new_struct);
715  return -1;
716  }
717  // Insert new data into current args
718  // save location
719  temp_struct = (*iter);
720  // insert new structures
721  args_.insert(++iter, new_struct->args_.begin(), new_struct->args_.end());
722  // The args have been copied out of newStruct. We are finished with it.
723  delete new_struct;
724  // reinit iterator and find location again
725  iter = args_.begin();
726  iterEnd = args_.end();
727  while ((*iter) != temp_struct) iter++;
728  // we want to remove the !load line, so get the next line
729  iter++;
730  args_.remove(temp_struct);
731  if (iter != iterEnd) {
732  // and because we changed the list, repeat
733  temp_struct = (*iter);
734  iter = args_.begin();
735  iterEnd = args_.end();
736  while ((*iter) != temp_struct) iter++;
737  }
738  // now we have replaced the !load line with the loaded lines
739  changes++;
740  }
741  }
742  else { // a Structure, Set, Atom or Development
743  if (RepliMacros_.find(structure->cmd_) != RepliMacros_.end()) {
744  // expand the macro
745  macro = RepliMacros_[structure->cmd_];
746  new_struct = macro->expandMacro(structure);
747  if (new_struct != NULL) {
748  *structure = *new_struct;
749  delete(new_struct);
750  changes++;
751  }
752  else {
753  structure->error_ = macro->error_;
754  macro->error_ = "";
755  return -1;
756  }
757  }
758 
759  // check for sub structures containing macros
760  for (std::list<RepliStruct*>::iterator iter2(structure->args_.begin()), iter2End(structure->args_.end()); iter2 != iter2End; ++iter2) {
761  if ((count = (*iter2)->process()) > 0)
762  changes += count;
763  else if (count < 0)
764  return -1;
765  }
766  }
767 
768  // expand Counters_ in all structures
769  if (Counters_.find(structure->cmd_) != Counters_.end()) {
770  // expand the counter
771  structure->cmd_ = std::to_string(Counters_[structure->cmd_]++);
772  changes++;
773  }
774 
775  // The iter may already be moved to the end, so check here before the for loop increments it.
776  if (iter == iterEnd)
777  break;
778  }
779 
780  return changes;
781 }
782 
783 RepliStruct *RepliStruct::loadReplicodeFile(const std::string &filename) {
784 
785  RepliStruct* new_root = new RepliStruct(Root);
786  if (isFileLoaded(filename)) {
787  // This file was already loaded. Skip it by returning an empty newRoot.
788  return new_root;
789  }
790 
791  // Mark this file as loaded.
792  LoadedFilePaths_.push_back(filename);
793 
794  std::ifstream load_stream(filename.c_str(), std::ios::binary | ios::in);
795  if (load_stream.bad() || load_stream.fail() || load_stream.eof()) {
796  new_root->error_ += "Load: File '" + filename + "' cannot be read! ";
797  load_stream.close();
798  return new_root;
799  }
800  // create new Root structure
801  uint32 a = 0, b = 0;
802  if (new_root->parse(&load_stream, filename, a, b) < 0) {
803  // error is already recorded in newRoot
804  }
805  if (!load_stream.eof())
806  new_root->error_ = "Code structure error: Unmatched ) or ].\n";
807  load_stream.close();
808  return new_root;
809 }
810 
811 bool RepliStruct::isFileLoaded(const std::string& file_path) {
812  for (auto loaded_file_path = LoadedFilePaths_.begin();
813  loaded_file_path != LoadedFilePaths_.end();
814  ++loaded_file_path) {
815  if (fs::equivalent(file_path, *loaded_file_path))
816  return true;
817  }
818 
819  return false;
820 }
821 
822 std::string RepliStruct::print() const {
823 
824 #if 1 // Just use a stringstream.
825  ostringstream out;
826  out << *this;
827  return out.str();
828 #else
829  std::string str;
830  switch (type_) {
831  case Atom:
832  return cmd_;
833  case Structure:
834  case Development:
835  case Directive:
836  case Condition:
837  str = cmd_;
838  for (std::list<RepliStruct*>::const_iterator iter(args_.begin()), iterEnd(args_.end()); iter != iterEnd; ++iter)
839  str += " " + (*iter)->print();
840  if (type_ == Structure)
841  return label_ + "(" + str + ")" + tail_;
842  else if (type_ == Development)
843  return label_ + "{" + str + "}" + tail_;
844  else
845  return str;
846  case Set:
847  for (std::list<RepliStruct*>::const_iterator iter(args_.begin()), last(args_.end()), iterEnd(last--); iter != iterEnd; ++iter) {
848  str += (*iter)->print();
849  if (iter != last)
850  str += " ";
851  }
852  return label_ + "[" + str + "]" + tail_;
853  case Root:
854  for (std::list<RepliStruct*>::const_iterator iter(args_.begin()), iterEnd(args_.end()); iter != iterEnd; ++iter)
855  str += (*iter)->print() + "\n";
856  return str;
857  default:
858  break;
859  }
860  return str;
861 #endif
862 }
863 
864 std::ostream &operator<<(std::ostream &os, RepliStruct *structure) {
865 
866  return operator<<(os, *structure);
867 }
868 
869 std::ostream &operator<<(std::ostream &os, const RepliStruct &structure) {
870 
871  switch (structure.type_) {
872  case RepliStruct::Atom:
873  return os << structure.cmd_;
874  case RepliStruct::Directive:
875  case RepliStruct::Condition:
876  return os;
877  case RepliStruct::Structure:
878  case RepliStruct::Development:
879  if (structure.type_ == RepliStruct::Structure)
880  os << structure.label_ << "(";
881  else if (structure.type_ == RepliStruct::Development)
882  os << structure.label_ << "{";
883  os << structure.cmd_;
884  for (std::list<RepliStruct*>::const_iterator iter(structure.args_.begin()), iterEnd(structure.args_.end()); iter != iterEnd; ++iter)
885  os << " " << (*iter);
886  if (structure.type_ == RepliStruct::Structure)
887  os << ")" << structure.tail_;
888  else if (structure.type_ == RepliStruct::Development)
889  os << "}" << structure.tail_;
890  break;
891  case RepliStruct::Set:
892  os << structure.label_ << "[";
893  if (structure.args_.size() > 0) {
894  for (std::list<RepliStruct*>::const_iterator iter(structure.args_.begin()), last(structure.args_.end()), iterEnd(last--); iter != iterEnd; ++iter) {
895  os << (*iter);
896  if (iter != last)
897  os << " ";
898  }
899  }
900  os << "]" << structure.tail_;
901  break;
902  case RepliStruct::Root:
903  for (std::list<RepliStruct*>::const_iterator iter(structure.args_.begin()), iterEnd(structure.args_.end()); iter != iterEnd; ++iter)
904  os << (*iter) << std::endl;
905  break;
906  default:
907  break;
908  }
909  return os;
910 }
911 
912 RepliStruct *RepliStruct::clone() const {
913 
914  RepliStruct* new_struct = new RepliStruct(type_);
915  new_struct->cmd_ = cmd_;
916  new_struct->label_ = label_;
917  new_struct->tail_ = tail_;
918  new_struct->parent_ = parent_;
919  new_struct->error_ = error_;
920  new_struct->line_ = line_;
921  for (std::list<RepliStruct*>::const_iterator iter(args_.begin()), iterEnd(args_.end()); iter != iterEnd; ++iter)
922  new_struct->args_.push_back((*iter)->clone());
923  return new_struct;
924 }
925 
926 std::string RepliStruct::printError() const {
927 
928  std::stringstream str_error;
929  if (error_.size() > 0) {
930  std::string com = cmd_;
931  RepliStruct* structure = parent_;
932  while ((cmd_.size() == 0) && (structure != NULL)) {
933  com = structure->cmd_;
934  structure = structure->parent_;
935  }
936  if (com.size() == 0)
937  str_error << "Error";
938  else
939  str_error << "Error in structure '" << com << "'";
940  if (line_ > 0)
941  str_error << " line " << line_;
942  str_error << ": " << error_ << std::endl;
943  }
944  for (std::list<RepliStruct*>::const_iterator iter(args_.begin()), iterEnd(args_.end()); iter != iterEnd; ++iter)
945  str_error << (*iter)->printError();
946  return str_error.str();
947 }
948 
949 RepliMacro::RepliMacro(const std::string &name, RepliStruct *src, RepliStruct *dest) {
950 
951  name_ = name;
952  src_ = src;
953  dest_ = dest;
954 }
955 
956 RepliMacro::~RepliMacro() {
957 
958  name_ = "";
959  src_ = NULL;
960  dest_ = NULL;
961 }
962 
963 uint32 RepliMacro::argCount() {
964 
965  if (src_ == NULL)
966  return 0;
967  return src_->args_.size();
968 }
969 
970 RepliStruct *RepliMacro::expandMacro(RepliStruct *old_struct) {
971 
972  if (src_ == NULL) {
973  error_ += "Macro '" + name_ + "' source not defined. ";
974  return NULL;
975  }
976  if (dest_ == NULL) {
977  error_ += "Macro '" + name_ + "' destination not defined. ";
978  return NULL;
979  }
980  if (old_struct == NULL) {
981  error_ += "Macro '" + name_ + "' cannot expand empty structure. ";
982  return NULL;
983  }
984  if (old_struct->cmd_.compare(name_) != 0) {
985  error_ += "Macro '" + name_ + "' cannot expand structure with different name '" + old_struct->cmd_ + "'. ";
986  return NULL;
987  }
988 
989  if ((src_->args_.size() > 0) && (src_->args_.size() != old_struct->args_.size())) {
990  error_ += "Macro '" + name_ + "' requires " + std::to_string(src_->args_.size()) + " arguments, cannot expand structure with " + std::to_string(old_struct->args_.size()) + " arguments. ";
991  return NULL;
992  }
993 
994  RepliStruct* new_struct;
995 
996  // Special case of macros without args, just copy in the args from oldStruct
997  if ((src_->args_.size() == 0) && (old_struct->args_.size() > 0)) {
998  new_struct = old_struct->clone();
999  new_struct->cmd_ = dest_->cmd_;
1000  new_struct->label_ = old_struct->label_;
1001  return new_struct;
1002  } else {
1003 
1004  new_struct = dest_->clone();
1005  new_struct->label_ = old_struct->label_;
1006  }
1007 
1008  RepliStruct *find_struct;
1009 
1010  std::list<RepliStruct*>::const_iterator i_old(old_struct->args_.begin());
1011  for (std::list<RepliStruct*>::const_iterator i_src(src_->args_.begin()), i_src_end(src_->args_.end()); i_src != i_src_end; ++i_src, ++i_old) {
1012  // printf("looking for '%s'\n", (*iSrc)->cmd.c_str());
1013  // find the Atom inside newStruct with the name of iSrc->cmd
1014  find_struct = new_struct->findAtom((*i_src)->cmd_);
1015  if (find_struct != NULL) {
1016  // overwrite data in findStruct with the matching one from old
1017  *find_struct = *(*i_old);
1018  }
1019  }
1020 
1021  return new_struct;
1022 }
1023 
1024 RepliStruct *RepliStruct::findAtom(const std::string &name) {
1025 
1026  RepliStruct* structure;
1027  for (std::list<RepliStruct*>::iterator iter(args_.begin()), iterEnd(args_.end()); iter != iterEnd; ++iter) {
1028  switch ((*iter)->type_) {
1029  case Atom:
1030  if ((*iter)->cmd_.compare(name) == 0)
1031  return (*iter);
1032  break;
1033  case Structure:
1034  case Set:
1035  case Development:
1036  structure = (*iter)->findAtom(name);
1037  if (structure != NULL)
1038  return structure;
1039  break;
1040  default:
1041  break;
1042  }
1043  }
1044  return NULL;
1045 }
1046 
1048 
1049 RepliCondition::RepliCondition(const std::string &name, bool reversed) {
1050 
1051  name_ = name;
1052  reversed_ = reversed;
1053 }
1054 
1055 RepliCondition::~RepliCondition() {
1056 }
1057 
1058 void RepliCondition::reverse() {
1059 
1060  reversed_ = !reversed_;
1061 }
1062 
1063 bool RepliCondition::isActive(unordered_map<std::string, RepliMacro *> &repli_macros, unordered_map<std::string, int32> &counters) {
1064 
1065  bool found_it = (repli_macros.find(name_) != repli_macros.end());
1066 
1067  if (!found_it)
1068  found_it = (counters.find(name_) != counters.end());
1069 
1070  if (reversed_)
1071  return (!found_it);
1072  else
1073  return found_it;
1074 }
1075 
1077 
1078 Preprocessor::Preprocessor() {
1079 
1080  root_ = new RepliStruct(RepliStruct::Root);
1081 }
1082 
1083 Preprocessor::~Preprocessor() {
1084 
1085  delete root_;
1086 }
1087 
1088 bool Preprocessor::process(std::istream *stream,
1089  const std::string& file_path,
1090  std::ostringstream *out_stream,
1091  std::string &error,
1092  Metadata *metadata) {
1093 
1094  // Mark this file as loaded. We don't check if it is already loaded because
1095  // this is called from the top level Init (not from a !load directive) and we
1096  // assume that it won't call this twice for the same file.
1097  RepliStruct::LoadedFilePaths_.push_back(file_path);
1098 
1099  root_->reset(); // trims root from previously preprocessed objects.
1100 
1101  uint32 a = 0, b = 0;
1102  if (root_->parse(stream, file_path, a, b) < 0) {
1103 
1104  error = root_->printError();
1105  return false;
1106  }
1107  if (!stream->eof()) {
1108 
1109  error = "Code structure error: Unmatched ) or ].\n";
1110  return false;
1111  }
1112 
1113  // printf("Replicode:\n\n%s\n",root->print().c_str());
1114 
1115  int32 pass = 0, total = 0, count;
1116  while ((count = root_->process()) > 0) {
1117 
1118  total += count;
1119  pass++;
1120  // printf("Pass %d, %d changes, %d total\n", pass, count, total);
1121  }
1122  if (count < 0) {
1123 
1124  error = root_->printError();
1125  return false;
1126  }
1127  // printf("Replicode:\n\n%s\n",root->print().c_str());
1128 
1129  *out_stream << root_;
1130 
1131  if (metadata)
1132  initialize(metadata);
1133 
1134  error = root_->printError();
1135  return (error.size() == 0);
1136 }
1137 
1138 bool Preprocessor::isTemplateClass(RepliStruct *s) {
1139 
1140  for (std::list<RepliStruct *>::iterator j(s->args_.begin()); j != s->args_.end(); ++j) {
1141 
1142  std::string name;
1143  std::string type;
1144  switch ((*j)->type_) {
1145  case RepliStruct::Atom:
1146  if ((*j)->cmd_ == ":~")
1147  return true;
1148  break;
1149  case RepliStruct::Structure: // template instantiation; args are the actual parameters.
1150  case RepliStruct::Development: // actual template arg as a list of args.
1151  case RepliStruct::Set: // sets can contain tpl args.
1152  if (isTemplateClass(*j))
1153  return true;
1154  break;
1155  default:
1156  break;
1157  }
1158  }
1159  return false;
1160 }
1161 
1162 bool Preprocessor::isSet(std::string class_name) {
1163 
1164  for (std::list<RepliStruct *>::iterator i(root_->args_.begin()); i != root_->args_.end(); ++i) {
1165 
1166  if ((*i)->type_ != RepliStruct::Directive || (*i)->cmd_ != "!class")
1167  continue;
1168  RepliStruct *s = *(*i)->args_.begin();
1169  if (s->cmd_ == class_name) // set classes are written class_name[].
1170  return false;
1171  if (s->cmd_ == class_name + "[]")
1172  return true;
1173  }
1174  return false;
1175 }
1176 
1177 void Preprocessor::instantiateClass(RepliStruct *tpl_class, std::list<RepliStruct *> &tpl_args, std::string &instantiated_class_name) {
1178 
1179  static uint32 LastClassID = 0;
1180  // remove the trailing [].
1181  std::string sset = "[]";
1182  instantiated_class_name = tpl_class->cmd_;
1183  instantiated_class_name = instantiated_class_name.substr(0, instantiated_class_name.length() - sset.length());
1184  // append an ID to the tpl class name.
1185  instantiated_class_name += std::to_string(LastClassID++);
1186 
1187  vector<StructureMember> members;
1188  std::list<RepliStruct *> _tpl_args;
1189  for (std::list<RepliStruct *>::reverse_iterator i = tpl_args.rbegin(); i != tpl_args.rend(); ++i)
1190  _tpl_args.push_back(*i);
1191  getMembers(tpl_class, members, _tpl_args, true);
1192 
1193  metadata_->class_names_[class_opcode_] = instantiated_class_name;
1194  metadata_->classes_by_opcodes_[class_opcode_] = metadata_->classes_[instantiated_class_name] = Class(Atom::SSet(class_opcode_, members.size()), instantiated_class_name, members);
1195  ++class_opcode_;
1196 }
1197 
1198 void Preprocessor::getMember(vector<StructureMember> &members, RepliStruct *m, std::list<RepliStruct *> &tpl_args, bool instantiate) {
1199 
1200  size_t p;
1201  std::string name;
1202  std::string type;
1203  switch (m->type_) {
1204  case RepliStruct::Set:
1205  name = m->label_.substr(0, m->label_.length() - 1);
1206  if (m->args_.size() == 0) // anonymous set of anything.
1207  members.push_back(StructureMember(&Compiler::read_set, name));
1208  else { // structured set, arg[0].cmd is ::type.
1209 
1210  type = (*m->args_.begin())->cmd_.substr(2, m->cmd_.length() - 1);
1211  if (isSet(type))
1212  members.push_back(StructureMember(&Compiler::read_set, name, type, StructureMember::I_SET));
1213  else if (type == Class::Type)
1214  members.push_back(StructureMember(&Compiler::read_set, name, type, StructureMember::I_DCLASS));
1215  else
1216  members.push_back(StructureMember(&Compiler::read_set, name, type, StructureMember::I_EXPRESSION));
1217  }
1218  break;
1219  case RepliStruct::Atom:
1220  if (m->cmd_ == "nil")
1221  break;
1222  p = m->cmd_.find(':');
1223  name = m->cmd_.substr(0, p);
1224  type = m->cmd_.substr(p + 1, m->cmd_.length());
1225  if (type == "")
1226  members.push_back(StructureMember(&Compiler::read_any, name));
1227  else if (type == "nb")
1228  members.push_back(StructureMember(&Compiler::read_number, name));
1229  else if (type == "ts")
1230  members.push_back(StructureMember(&Compiler::read_timestamp, name));
1231  else if (type == "us")
1232  members.push_back(StructureMember(&Compiler::read_duration, name));
1233  else if (type == "bl")
1234  members.push_back(StructureMember(&Compiler::read_boolean, name));
1235  else if (type == "st")
1236  members.push_back(StructureMember(&Compiler::read_string, name));
1237  else if (type == "did")
1238  members.push_back(StructureMember(&Compiler::read_device, name));
1239  else if (type == "fid")
1240  members.push_back(StructureMember(&Compiler::read_function, name));
1241  else if (type == "nid")
1242  members.push_back(StructureMember(&Compiler::read_node, name));
1243  else if (type == Class::Expression)
1244  members.push_back(StructureMember(&Compiler::read_expression, name));
1245  else if (type == "~") {
1246 
1247  RepliStruct *_m = tpl_args.back();
1248  tpl_args.pop_back();
1249  switch (_m->type_) {
1250  case RepliStruct::Structure: { // the tpl arg is an instantiated tpl set class.
1251  std::string instantiated_class_name;
1252  instantiateClass(template_classes_.find(_m->cmd_)->second, _m->args_, instantiated_class_name);
1253  members.push_back(StructureMember(&Compiler::read_set, _m->label_.substr(0, _m->label_.length() - 1), instantiated_class_name, StructureMember::I_CLASS));
1254  break;
1255  }default:
1256  getMember(members, _m, tpl_args, true);
1257  break;
1258  }
1259  } else if (type == Class::Type)
1260  members.push_back(StructureMember(&Compiler::read_class, name));
1261  else // type is a class name.
1262  members.push_back(StructureMember(&Compiler::read_expression, name, type));
1263  break;
1264  case RepliStruct::Structure: { // template instantiation; (*m)->cmd is the template class, (*m)->args are the actual parameters.
1265  RepliStruct *template_class = template_classes_.find(m->cmd_)->second;
1266  if (instantiate) {
1267 
1268  std::string instantiated_class_name;
1269  instantiateClass(template_class, m->args_, instantiated_class_name);
1270  members.push_back(StructureMember(&Compiler::read_set, m->label_.substr(0, m->label_.length() - 1), instantiated_class_name, StructureMember::I_CLASS));
1271  } else {
1272 
1273  for (std::list<RepliStruct *>::reverse_iterator i = m->args_.rbegin(); i != m->args_.rend(); ++i) // append the passed args to the ones held by m.
1274  tpl_args.push_back(*i);
1275  getMembers(template_class, members, tpl_args, false);
1276  }
1277  break;
1278  }case RepliStruct::Development:
1279  getMembers(m, members, tpl_args, instantiate);
1280  break;
1281  default:
1282  break;
1283  }
1284 }
1285 
1286 void Preprocessor::getMembers(RepliStruct *s, vector<StructureMember> &members, std::list<RepliStruct *> &tpl_args, bool instantiate) {
1287 
1288  for (std::list<RepliStruct *>::iterator j(s->args_.begin()); j != s->args_.end(); ++j)
1289  getMember(members, *j, tpl_args, instantiate);
1290 }
1291 
1292 ReturnType Preprocessor::getReturnType(RepliStruct *s) {
1293 
1294  if (s->tail_ == ":nb")
1295  return NUMBER;
1296  else if (s->tail_ == ":ts")
1297  return TIMESTAMP;
1298  else if (s->tail_ == ":us")
1299  return DURATION;
1300  else if (s->tail_ == ":bl")
1301  return BOOLEAN;
1302  else if (s->tail_ == ":st")
1303  return STRING;
1304  else if (s->tail_ == ":nid")
1305  return NODE_ID;
1306  else if (s->tail_ == ":did")
1307  return DEVICE_ID;
1308  else if (s->tail_ == ":fid")
1309  return FUNCTION_ID;
1310  else if (s->tail_ == ":[]")
1311  return SET;
1312  return ANY;
1313 }
1314 
1315 void Preprocessor::initialize(Metadata *metadata) {
1316 
1317  metadata_ = metadata;
1318 
1319  class_opcode_ = 0;
1320  uint16 function_opcode = 0;
1321  uint16 operator_opcode = 0;
1322 
1323  vector<StructureMember> r_xpr;
1324  metadata->classes_[std::string(Class::Expression)] = Class(Atom::Object(class_opcode_, 0), Class::Expression, r_xpr); // to read unspecified expressions in classes and sets.
1325  ++class_opcode_;
1326  vector<StructureMember> r_type;
1327  metadata->classes_[std::string(Class::Type)] = Class(Atom::Object(class_opcode_, 0), Class::Type, r_type); // to read object types in expressions and sets.
1328  ++class_opcode_;
1329 
1330  for (std::list<RepliStruct *>::iterator i(root_->args_.begin()); i != root_->args_.end(); ++i) {
1331 
1332  if ((*i)->type_ != RepliStruct::Directive)
1333  continue;
1334 
1335  RepliStruct *s = *(*i)->args_.begin();
1336  vector<StructureMember> members;
1337  if ((*i)->cmd_ == "!class") {
1338 
1339  std::string sset = "[]";
1340  std::string class_name = s->cmd_;
1341  size_t p = class_name.find(sset);
1342  ClassType class_type = (p == std::string::npos ? T_CLASS : T_SET);
1343  if (class_type == T_SET) // remove the trailing [] since the RepliStructs for instantiated classes do so.
1344  class_name = class_name.substr(0, class_name.length() - sset.length());
1345 
1346  if (isTemplateClass(s)) {
1347 
1348  template_classes_[class_name] = s;
1349  continue;
1350  }
1351 
1352  std::list<RepliStruct *> tpl_args;
1353  getMembers(s, members, tpl_args, false);
1354 
1355  Atom atom;
1356  if (class_name == "grp")
1357  atom = Atom::Group(class_opcode_, members.size());
1358  else if (class_name == "ipgm")
1359  atom = Atom::InstantiatedProgram(class_opcode_, members.size());
1360  else if (class_name == "icpp_pgm")
1361  atom = Atom::InstantiatedCPPProgram(class_opcode_, members.size());
1362  else if (class_name == "cst")
1363  atom = Atom::CompositeState(class_opcode_, members.size());
1364  else if (class_name == "mdl")
1365  atom = Atom::Model(class_opcode_, members.size());
1366  else if (class_name.find("mk.") != string::npos)
1367  atom = Atom::Marker(class_opcode_, members.size());
1368  else
1369  atom = Atom::Object(class_opcode_, members.size());
1370 
1371  if (class_type == T_CLASS) { // find out if the class is a sys class, i.e. is an instantiation of _obj, _grp or _fact.
1372 
1373  std::string base_class = s->args_.front()->cmd_;
1374  if (base_class == "_obj" || base_class == "_grp" || base_class == "_fact")
1375  class_type = T_SYS_CLASS;
1376  }
1377 
1378  metadata->class_names_[class_opcode_] = class_name;
1379  switch (class_type) {
1380  case T_SYS_CLASS:
1381  metadata->classes_by_opcodes_[class_opcode_] = metadata->classes_[class_name] = metadata->sys_classes_[class_name] = Class(atom, class_name, members);
1382  break;
1383  case T_CLASS:
1384  metadata->classes_by_opcodes_[class_opcode_] = metadata->classes_[class_name] = Class(atom, class_name, members);
1385  break;
1386  case T_SET:
1387  metadata->classes_by_opcodes_[class_opcode_] = metadata->classes_[class_name] = Class(Atom::SSet(class_opcode_, members.size()), class_name, members);
1388  break;
1389  default:
1390  break;
1391  }
1392  ++class_opcode_;
1393  } else if ((*i)->cmd_ == "!op") {
1394 
1395  std::list<RepliStruct *> tpl_args;
1396  getMembers(s, members, tpl_args, false);
1397  ReturnType return_type = getReturnType(s);
1398 
1399  std::string operator_name = s->cmd_;
1400  metadata->operator_names_.push_back(operator_name);
1401  metadata->classes_[operator_name] = Class(Atom::Operator(operator_opcode, s->args_.size()), operator_name, members, return_type);
1402  ++operator_opcode;
1403  } else if ((*i)->cmd_ == "!dfn") { // don't bother to read the members, it's always a set.
1404 
1405  vector<StructureMember> r_set;
1406  r_set.push_back(StructureMember(&Compiler::read_set, ""));
1407 
1408  std::string function_name = s->cmd_;
1409  metadata->function_names_.push_back(function_name);
1410  metadata->classes_[function_name] = Class(Atom::DeviceFunction(function_opcode), function_name, r_set);
1411  ++function_opcode;
1412  }
1413  }
1414 }
1415 }
r_code::Atom
Definition: atom.h:104
r_comp::RepliStruct
Definition: preprocessor.h:98