Leviathan  0.8.0.0
Leviathan game engine
ObjectFileProcessor.cpp
Go to the documentation of this file.
1 #include "Include.h"
2 // ------------------------------------ //
3 #include "ObjectFileProcessor.h"
4 
5 #include "FileSystem.h"
7 #ifndef NO_DEFAULT_DATAINDEX
8 #include "../Common/DataStoring/DataStore.h"
9 #endif
12 #include "utf8/core.h"
13 #include "utf8/checked.h"
14 
15 #include "ObjectFile.h"
16 
17 #ifdef ALLOW_INTERNAL_EXCEPTIONS
18 #include "Exceptions.h"
19 #endif // ALLOW_INTERNAL_EXCEPTIONS
20 
21 #ifdef LEVIATHAN_USING_ANGELSCRIPT
22 #include "../Script/ScriptModule.h"
23 #include "Script/ScriptExecutor.h"
24 #include "Script/ScriptScript.h"
25 #endif // LEVIATHAN_USING_ANGELSCRIPT
26 using namespace Leviathan;
27 // ------------------------------------ //
28 #ifndef NO_DEFAULT_DATAINDEX
29 // quick macro to make this shorter //
30 #define ADDDATANAMEINTDEFINITION(x) {#x, std::shared_ptr<VariableBlock>(new VariableBlock(\
31  new IntBlock(x)))}
32 
33 
34 std::map<std::string, std::shared_ptr<VariableBlock>>
35  Leviathan::ObjectFileProcessor::RegisteredValues = {
48 
49 };
50 #else
51 std::map<std::string, std::shared_ptr<VariableBlock>>
52  Leviathan::ObjectFileProcessor::RegisteredValues;
53 #endif
54 // ------------------------------------ //
56 #if defined(_DEBUG) && !defined(NO_DEFAULT_DATAINDEX)
57  // Just out of curiosity check this //
58  auto iter = RegisteredValues.find("DATAINDEX_TICKTIME");
59 
60  if(iter == RegisteredValues.end()){
61 
62  LOG_FATAL("ObjectFileProcessor: RegisteredValues are messed up, "
63  "DATAINDEX_TICKTIME is not defined, check the macros!");
64 
65  return;
66  }
67 #endif // _DEBUG
68 }
70  // Release our allocated memory //
71  RegisteredValues.clear();
72 }
73 // ------------------------------------ //
75  VariableBlock* valuetokeep)
76 {
77  RegisteredValues[name] = std::shared_ptr<VariableBlock>(valuetokeep);
78 }
79 
80 template<class TStr, class TLineType>
81  void LogError(const TStr &msgStart, const std::string &file, TLineType line,
82  LErrorReporter* reporterror)
83 {
84  std::stringstream sstream;
85  sstream << "ObjectFileProcessor: " << msgStart << ", file: " << file << ":" << line;
86 
87  reporterror->Error(sstream.str());
88 }
89 // ------------------ Processing function ------------------ //
91  const std::string &file, LErrorReporter* reporterror)
92 {
93  // First read the file entirely //
94  std::string filecontents;
95 
96  if (!FileSystem::ReadFileEntirely(file, filecontents)) {
97 
98  reporterror->Error("ObjectFileProcessor: ProcessObjectFile: file could not be read: " +
99  file);
100  return nullptr;
101  }
102 
103  // Skip empty files //
104  if(filecontents.size() == 0){
105 
106  return nullptr;
107  }
108 
109  // Skip the BOM if there is one //
110  if(utf8::starts_with_bom(filecontents.begin(), filecontents.end())){
111 
112  // Pop the first 3 bytes //
113  filecontents = filecontents.substr(3, filecontents.size()-3);
114  }
115 
116  return ProcessObjectFileFromString(filecontents, file, reporterror);
117 }
118 
119 DLLEXPORT std::unique_ptr<Leviathan::ObjectFile>
121  const std::string &filecontents, const std::string &filenameforerrors,
122  LErrorReporter* reporterror)
123 {
124  // Create the target object //
125  auto ofile = std::make_unique<ObjectFile>();
126 
127  bool succeeded = true;
128 
129  // Create an UTF8 supporting iterator //
130  StringIterator itr(std::make_unique<UTF8PointerDataIterator>(filecontents));
131 
132  while(!itr.IsOutOfBounds()){
133 
134  // First get the first thing defining what the following object/thing will be //
135  auto thingtype = itr.GetNextCharacterSequence<std::string>(
138 
139  // Empty line
140  if(!thingtype)
141  continue;
142 
143  // Store the starting line for error reporting purposes //
144  size_t thisstart = itr.GetCurrentLine();
145 
146  if(*thingtype == "template") {
147  // Either a template definition or a template instantiation //
148 
149  if(!TryToHandleTemplate(filenameforerrors, itr, *ofile, *thingtype, reporterror)){
150 
151  LogError("processing a template definitions or instantiation has failed",
152  filenameforerrors, thisstart, reporterror);
153 
154  succeeded = false;
155  break;
156  }
157 
158  continue;
159 
160  } else if(*thingtype == "o"){
161 
162  // Process an object //
163  auto tmpobj = TryToLoadObject(filenameforerrors, itr, *ofile, *thingtype,
164  reporterror);
165 
166  if(!tmpobj){
167 
168  LogError("processing an object has failed",
169  filenameforerrors, thisstart, reporterror);
170 
171  succeeded = false;
172  break;
173  }
174 
175  if(!ofile->AddObject(tmpobj)){
176 
177  LogError("object has a conflicting name, name: \"" + tmpobj->GetName() +
178  "\"",
179  filenameforerrors, thisstart, reporterror);
180 
181  succeeded = false;
182  break;
183  }
184 
185 
186  continue;
187 
188  } else{
189  // It should be a named variable //
190 
191  auto ptr = TryToLoadNamedVariables(filenameforerrors, itr, *thingtype, reporterror);
192  if(!ptr){
193 
194  LogError("processing a NamedVariableList has failed",
195  filenameforerrors, thisstart, reporterror);
196 
197  succeeded = false;
198  break;
199  }
200 
201  // Add to the object //
202  if(!ofile->AddNamedVariable(ptr)){
203 
204  LogError("variable name (\"" + ptr->GetName() + "\") already in use",
205  filenameforerrors, thisstart, reporterror);
206 
207  succeeded = false;
208  break;
209  }
210 
211  continue;
212  }
213 
214  // It is something that cannot be handled //
215  LogError("ObjectFile has an invalid/unknown block (" + *thingtype + ")",
216  filenameforerrors, thisstart, reporterror);
217 
218  // The file is clearly malformed //
219  succeeded = false;
220  break;
221  }
222 
223 
224  if(!succeeded || !itr.IsOutOfBounds()){
225 
226  // It failed //
227  LogError("parsing file failed. Parsing ended",
228  filenameforerrors, itr.GetCurrentLine(), reporterror);
229 
230  // Notify about unended strings and comments //
231 
232  if(itr.IsInsideString()){
233  LogError("parsing ended inside unclosed quotes",
234  filenameforerrors, itr.GetCurrentLine(), reporterror);
235  }
236 
237  if(itr.IsInsideComment()){
238  LogError("parsing ended inside unclosed comment",
239  filenameforerrors, itr.GetCurrentLine(), reporterror);
240  }
241 
242  return nullptr;
243  }
244 
245  // Generate the template instantiations and it's done //
246  if(!ofile->GenerateTemplatedObjects(reporterror)){
247 
248  LogError("file has invalid templates (either bad names, "
249  "or instances without definitions)",
250  filenameforerrors, itr.GetCurrentLine(), reporterror);
251 
252  return nullptr;
253  }
254 
255  return ofile;
256 }
257 
258 // ------------------------------------ //
259 std::shared_ptr<NamedVariableList>
260  Leviathan::ObjectFileProcessor::TryToLoadNamedVariables(const std::string &file,
261  StringIterator &itr, const std::string &preceeding, LErrorReporter* reporterror)
262 {
263  // Try to load a named variable of format: "Variable = myvalue;" //
264 
265  // Store the beginning line //
266  size_t startline = itr.GetCurrentLine();
267 
268  // Next thing after the preceeding is rest of the name until the '=' character //
269 
270  // This is often empty //
271  auto restofname = itr.GetUntilEqualityAssignment<std::string>(
273 
274  if(!restofname && preceeding.size() == 0){
275  // No name //
276  LogError("ObjectFile named variable is malformed, unknown block?",
277  file, Convert::ToString(startline)+"-"+
278  Convert::ToString(itr.GetCurrentLine()), reporterror);
279 
280  return nullptr;
281  }
282 
283  // There needs to be a separator, the last character should be it //
284  int lastchar = itr.GetPreviousCharacter();
285 
286  if(lastchar != '=' && lastchar != ':'){
287 
288  // Invalid format //
289  LogError("ObjectFile block isn't a named variable, unknown block?",
290  file, itr.GetCurrentLine(), reporterror);
291 
292  return nullptr;
293  }
294 
295  // We need to skip whitespace //
297 
298  // Get the value //
299  auto valuestr = itr.GetUntilNextCharacterOrAll<std::string>(';',
301 
302  if(!valuestr){
303  // No ';' or nothing after the equals sign //
304 
305  LogError("ObjectFile named variable is empty or missing an (optional) ending ';' "
306  "(should be like: \"MyVar = 42;\")",
307  file, startline, reporterror);
308 
309  return nullptr;
310  }
311 
312  // Skip the ';' //
313  itr.MoveToNext();
314 
315  // Try to construct a named variable //
316 
317  // Put the name together //
318  std::string varname = preceeding+ (restofname ? *restofname: std::string());
319 
320  // Try to use the name and the variable string to try to create one named variable //
321 
322  try{
323 
324  // NamedVariableList now uses UTF8 so conversion is no longer required //
325 
326  // This was a valid definition //
327  return std::make_shared<NamedVariableList>(varname, *valuestr,
328  reporterror, &RegisteredValues);
329 
330  } catch(const InvalidArgument &e){
331 
332  LogError("named variable parse failed (see following exception)",
333  file, startline, reporterror);
334  e.Print(reporterror);
335  return nullptr;
336  }
337 }
338 // ------------------------------------ //
339 bool Leviathan::ObjectFileProcessor::TryToHandleTemplate(const std::string &file,
340  StringIterator &itr, ObjectFile &obj, const std::string &preceeding,
341  LErrorReporter* reporterror)
342 {
343  // Skip potential space between 'template' and '<' //
345 
346  // Get to the first character //
347  if(itr.GetCharacter(0) != '<'){
348 
349  LogError("ObjectFile template has a missing '<' after 'template'",
350  file, itr.GetCurrentLine(), reporterror);
351 
352  return false;
353  }
354 
355  size_t startline = itr.GetCurrentLine();
356 
357  // Move from the '<' to the actual content //
358  itr.MoveToNext();
359 
360  std::vector<std::unique_ptr<std::string>> templateargs;
361 
362  // Skip ifthere is nothing //
363  if(itr.GetCharacter() != '>'){
364 
365  // Now process the template arguments //
366  auto tmpldata = itr.GetUntilNextCharacterOrNothing<std::string>('>',
368 
369  if(!tmpldata){
370 
371  LogError("ObjectFile template has an invalid argument list (missing "
372  "the ending '>')",
373  file, startline, reporterror);
374 
375  return false;
376  }
377 
378  StringIterator itr2(tmpldata.get());
379 
380  auto tmplarg = itr2.GetNextCharacterSequence<std::string>(
384 
385  // Go somewhere proper //
386  itr2.SkipWhiteSpace(SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING);
387 
388  if(tmplarg && tmplarg->size()){
389  templateargs.push_back(move(tmplarg));
390  }
391 
392  while(itr2.GetCharacter() == ',' && !itr2.IsOutOfBounds()){
393 
394  // More arguments //
395  tmplarg = itr2.GetNextCharacterSequence<std::string>(
399 
400  if(tmplarg && tmplarg->size()){
401  templateargs.push_back(move(tmplarg));
402  }
403 
404  // Potentially more //
405  itr2.SkipWhiteSpace(SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING);
406  }
407  }
408 
409  StringIterator quoteremover;
410 
411  // Remove any quotes from the arguments //
412  for(size_t i = 0; i < templateargs.size(); i++){
413 
414  auto chartype = templateargs[i]->at(0);
415 
416  if(chartype == '"' || chartype == '\''){
417 
418  // Remove the quotes //
419  quoteremover.ReInit(std::make_unique<UTF8DataIterator>(*templateargs[i]));
420  auto newstr = quoteremover.GetStringInQuotes<std::string>(QUOTETYPE_BOTH);
421 
422  if(!newstr || newstr->empty()){
423 
424  LogError("Template: failed to remove quotes from template argument, " +
425  *templateargs[i],
426  file, startline, reporterror);
427 
428  continue;
429  }
430 
431  templateargs[i] = move(newstr);
432  }
433  }
434 
435 
436  // We should now be at the '>' character //
437 
438  // Move over it //
439  itr.MoveToNext();
440 
442 
443  // Now should be the name //
444  auto name = itr.GetNextCharacterSequence<std::string>(
447 
448  if(!name || name->size() < 3){
449 
450  LogError("ObjectFile template has too short name (has to be a minimum of 3 "
451  "characters), file",
452  file, itr.GetCurrentLine(), reporterror);
453 
454  return false;
455  }
456 
457  if(!templateargs.size()){
458  // This is a template instantiation //
459 
460  // Next should be the argument list //
462 
463  // We should now be at the '<' character //
464  if(itr.GetCharacter() != '<'){
465 
466  LogError("ObjectFile template instance has an invalid argument list "
467  "(missing starting '<' after name)",
468  file, startline, reporterror);
469 
470  return false;
471  }
472 
473  itr.MoveToNext();
474 
475  auto tmpldata = itr.GetUntilNextCharacterOrNothing<std::string>('>',
477 
478  if(!tmpldata){
479 
480  LogError("ObjectFile template has an invalid argument list "
481  "(missing the ending '>' or the instantiation is missing its parameters)",
482  file, startline, reporterror);
483 
484  return false;
485  }
486 
487  StringIterator itr3(tmpldata.get());
488 
489  // Load all the arguments //
490  auto instarg = itr3.GetNextCharacterSequence<std::string>(
493 
495 
496  std::vector<std::unique_ptr<std::string>> instanceargs;
497 
498  if(instarg && instarg->size()){
499  instanceargs.push_back(move(instarg));
500  }
501 
502  while(itr3.GetCharacter() == ',' && !itr3.IsOutOfBounds()){
503 
504  // More arguments //
505  instarg = itr3.GetNextCharacterSequence<std::string>(
508 
509  if(instarg && instarg->size()){
510  instanceargs.push_back(move(instarg));
511  }
512 
513  // Potentially more //
514  itr3.SkipWhiteSpace(SPECIAL_ITERATOR_HANDLECOMMENTS_ASSTRING);
515  }
516 
517  // Remove any quotes from the arguments //
518  for(size_t i = 0; i < instanceargs.size(); i++){
519 
520  auto chartype = instanceargs[i]->at(0);
521 
522  if(chartype == '"' || chartype == '\''){
523  // Remove the quotes //
524  quoteremover.ReInit(std::make_unique<UTF8DataIterator>(*instanceargs[i]));
525  auto newstr = quoteremover.GetStringInQuotes<std::string>(QUOTETYPE_BOTH);
526 
527  if(!newstr || newstr->empty()){
528 
529  if(instanceargs[i]->size() > 2){
530  reporterror->Warning("ObjectFileProcessor: Template: failed to "
531  "remove quotes from template argument, "+*instanceargs[i]);
532  }
533 
534  continue;
535  }
536 
537  instanceargs[i] = move(newstr);
538  }
539  }
540 
541 
542  // We should now be at the '>' character //
543  itr.MoveToNext();
544 
545  // Create a template instantiation and add it to the file //
546  auto ourval = std::make_shared<ObjectFileTemplateInstance>(*name, instanceargs);
547 
548  // Add it //
549  obj.AddTemplateInstance(ourval);
550 
551 
552  return true;
553  }
554 
555  // Handle the template definition //
556  if(itr.GetCharacter() != ':'){
557 
558  LogError("ObjectFile template definition has no ':' after name "
559  "(template and following object must be separated)",
560  file, startline, reporterror);
561 
562  return false;
563  }
564 
565  // Skip the o //
566  auto justchecking = itr.GetUntilNextCharacterOrNothing<std::string>('o',
568 
569  if(!justchecking){
570 
571  LogError("ObjectFile template definition is missing 'o' after ':' "
572  "(or maybe there is a missing space?)",
573  file, startline, reporterror);
574 
575  return false;
576  }
577 
578  // Move over it and the object should start there //
579  itr.MoveToNext();
580 
581  const auto templateObjStartLine = itr.GetCurrentLine();
582 
583  // Now there should be an object definition //
584  auto templatesobject = TryToLoadObject(file, itr, obj, "", reporterror);
585 
586  if(!templatesobject){
587 
588  LogError("ObjectFile template definition has an invalid object",
589  file, templateObjStartLine, reporterror);
590  return false;
591  }
592 
593  // Create a template definition from the object //
594  auto createdtemplate = ObjectFileTemplateDefinition::CreateFromObject(*name,
595  templatesobject, templateargs);
596 
597  if(!createdtemplate){
598 
599  LogError("ObjectFile template failed to create from an object",
600  file, startline, reporterror);
601  return false;
602  }
603 
604  // Now add it //
605  if(!obj.AddTemplate(createdtemplate)){
606 
607  LogError("ObjectFile template has a conflicting name, name: \"" + *name + "\"",
608  file, startline, reporterror);
609 
610  return false;
611  }
612 
613  return true;
614 }
615 // ------------------------------------ //
616 std::shared_ptr<ObjectFileObject> Leviathan::ObjectFileProcessor::TryToLoadObject(
617  const std::string &file, StringIterator &itr, ObjectFile &obj,
618  const std::string &preceeding, LErrorReporter* reporterror)
619 {
621 
622  size_t startline = itr.GetCurrentLine();
623 
624  std::vector<std::unique_ptr<std::string>> prefixesvec;
625  std::unique_ptr<std::string> typesname;
626 
627  // Now there should be variable number of prefixes followed by a name //
628  while(itr.GetCharacter() != '"'){
629 
630  auto oprefix = itr.GetNextCharacterSequence<std::string>(
633 
634  if(oprefix && oprefix->size()){
635 
636  if(!typesname){
637 
638  // First prefix is the type //
639  typesname = std::move(oprefix);
640 
641  } else{
642 
643  prefixesvec.push_back(move(oprefix));
644  }
645  }
646 
648 
649  if(itr.IsOutOfBounds()){
650  // Failed //
651  LogError("ObjectFile object doesn't have a name, because prefixes are messed up"
652  "(expected quoted std::string like this: \"o Type Prefix \'MyName\'\")",
653  file, startline, reporterror);
654 
655  return nullptr;
656  }
657  }
658 
659  // Now try to get the name //
660  auto oname = itr.GetStringInQuotes<std::string>(QUOTETYPE_BOTH,
662 
663  if(!oname || !oname->size()){
664 
665  LogError("ObjectFile object doesn't have a name (expected quoted std::string "
666  "like this: \"o Type Prefix \'MyName\'\")",
667  file, startline, reporterror);
668 
669  return nullptr;
670  }
671 
672  // There should now be a{ //
674 
675  if(itr.GetCharacter() != '{'){
676  // There is a missing brace //
677  LogError("ObjectFile object is missing a '{' after its name",
678  file, itr.GetCurrentLine(), reporterror);
679  return nullptr;
680  }
681 
682  // No need to convert the loaded utf8 std::strings //
683 
684  // Create a new ObjectFileObject to hold our contents //
685  std::shared_ptr<ObjectFileObject> ourobj = std::make_shared<ObjectFileObjectProper>(
686  *oname, typesname ? *typesname : "", std::move(prefixesvec));
687 
688  // Now there should be the object contents //
689  itr.MoveToNext();
690 
691  while(!itr.IsOutOfBounds()){
692  // First skip whitespace //
694 
695  // Then check the character //
696  int curcharacter = itr.GetCharacter();
697  size_t ourline = itr.GetCurrentLine();
698 
699  // We want to be on the next character to continue processing //
700  itr.MoveToNext();
701 
702  switch(curcharacter){
703  case 'l':
704  {
705  if(!TryToLoadVariableList(file, itr, *ourobj, startline, reporterror)){
706 
707  LogError("ObjectFile object contains an invalid variable list",
708  file, ourline, reporterror);
709 
710  return nullptr;
711  }
712  }
713  break;
714  case 't':
715  {
716  if(!TryToLoadTextBlock(file, itr, *ourobj, startline, reporterror)){
717 
718  LogError("ObjectFile object contains an invalid text block",
719  file, ourline, reporterror);
720 
721  return nullptr;
722  }
723  }
724  break;
725  case 's':
726  {
727  if(!TryToLoadScriptBlock(file, itr, *ourobj, startline, reporterror)){
728 
729  LogError("ObjectFile object contains an invalid script block",
730  file, ourline, reporterror);
731 
732  return nullptr;
733  }
734  }
735  break;
736  case '}':
737  {
738  // The object ended properly //
739  // Add the object to the file's object //
740  return ourobj;
741  }
742  break;
743  }
744 
745  }
746 
747  // It didn't end properly //
748  LogError("ObjectFile object \"" + *oname + "\" is missing a closing '}' "
749  "after its contents",
750  file, startline, reporterror);
751 
752  return nullptr;
753 }
754 // ------------------------------------ //
755 bool Leviathan::ObjectFileProcessor::TryToLoadVariableList(const std::string &file,
756  StringIterator &itr, ObjectFileObject &obj, size_t startline, LErrorReporter* reporterror)
757 {
758  // First thing is the name //
759  itr.SkipWhiteSpace();
760  auto ourname = itr.GetNextCharacterSequence<std::string>(
763 
764  if(ourname){
766  }
767 
768  // Check is it valid //
769  if(!ourname || ourname->size() == 0){
770 
771  LogError("ObjectFile variable list has an invalid name",
772  file, itr.GetCurrentLine(), reporterror);
773 
774  return false;
775  }
776 
778 
779  // There should be a '{' character here //
780  if(itr.GetCharacter() != '{'){
781  // There is a missing brace //
782  LogError("ObjectFile variable list is missing '{' after its name",
783  file, itr.GetCurrentLine(), reporterror);
784 
785  return false;
786  }
787 
788  // Still on the first line //
789  size_t ourstartline = itr.GetCurrentLine();
790 
791  itr.MoveToNext();
792 
794 
795  // Create us //
796  std::unique_ptr<ObjectFileList> ourobj = std::make_unique<ObjectFileListProper>(*ourname);
797 
798  // Now we should get named variables until a } //
799  while(!itr.IsOutOfBounds()){
800  // First skip whitespace //
802 
803  if(itr.GetCharacter() == '}'){
804  // Valid //
805  // Skip it so the object doesn't end here //
806  itr.MoveToNext();
807 
808  // Add us to the object //
809  if(!obj.AddVariableList(std::move(ourobj))){
810 
811  LogError("ObjectFile variable list has conflicting name inside "
812  "its object",
813  file, ourstartline, reporterror);
814 
815  return false;
816  }
817 
818  return true;
819  }
820 
821  size_t varsline = itr.GetCurrentLine();
822 
823  // Try to load a named variable //
824  auto loadvar = TryToLoadNamedVariables(file, itr, "", reporterror);
825 
826  if(!loadvar){
827 
828  LogError("ObjectFile variable list has an invalid variable",
829  file, varsline, reporterror);
830 
831  return false;
832  }
833 
834  // Add a variable to us //
835  if(!ourobj->AddVariable(loadvar)){
836 
837  LogError("ObjectFile variable list has conflicting name inside its "
838  "object, name: \""+loadvar->GetName()+"\"",
839  file, varsline, reporterror);
840 
841  return false;
842  }
843  }
844 
845  LogError("ObjectFile variable list is missing the closing '}'",
846  file, ourstartline, reporterror);
847 
848  // It failed //
849  return false;
850 }
851 
852 bool Leviathan::ObjectFileProcessor::TryToLoadTextBlock(const std::string &file,
853  StringIterator &itr, ObjectFileObject &obj, size_t startline, LErrorReporter* reporterror)
854 {
855  // First thing is the name //
856  itr.SkipWhiteSpace();
857  auto ourname = itr.GetNextCharacterSequence<std::string>(
860 
861  if(ourname){
862 
864  }
865 
866  // Check is it valid //
867  if(!ourname || ourname->size() == 0){
868 
869  LogError("ObjectFile variable text block has an invalid name",
870  file, itr.GetCurrentLine(), reporterror);
871 
872  return false;
873  }
874 
876 
877  // There should be a '{' character here //
878  if(itr.GetCharacter() != '{'){
879  // There is a missing brace //
880  LogError("ObjectFile variable list is missing '{' after its name",
881  file, startline, reporterror);
882 
883  return false;
884  }
885 
886  // Still on the first line //
887  size_t ourstartline = itr.GetCurrentLine();
888 
889  itr.MoveToNext();
890 
892 
893  // Create us //
894  std::unique_ptr<ObjectFileTextBlock> ourobj =std::make_unique<ObjectFileTextBlockProper>(
895  *ourname);
896 
897  // Now we should get text lines until a } //
898  while(!itr.IsOutOfBounds()){
899  // First skip whitespace //
901 
902  if(itr.GetCharacter() == '}'){
903  // Valid //
904 
905  // Skip it so the object doesn't end here //
906  itr.MoveToNext();
907 
908  // Add us to the object //
909  if(!obj.AddTextBlock(std::move(ourobj))){
910 
911  LogError("ObjectFile text block has a conflicting name",
912  file, ourstartline, reporterror);
913 
914  return false;
915  }
916 
917  return true;
918  }
919 
920  // If there was an empty line we will be at whitespace right now
922 
923  // Empty line
924  ourobj->AddTextLine("");
925 
926  } else {
927 
928  // Read a single line //
929  auto linething = itr.GetUntilLineEnd<std::string>();
930 
931  // Add it to us //
932  // But make sure we strip also trailing spaces
934  ourobj->AddTextLine(*linething);
935  }
936  }
937 
938  LogError("ObjectFile text block is missing the closing '}'",
939  file, ourstartline, reporterror);
940 
941  // It failed //
942  return false;
943 }
944 
945 bool Leviathan::ObjectFileProcessor::TryToLoadScriptBlock(const std::string &file,
946  StringIterator &itr, ObjectFileObject &obj, size_t startline, LErrorReporter* reporterror)
947 {
948  // The line that contains the 's' //
949  size_t lineforname = itr.GetCurrentLine();
950 
951  // First thing is the name //
952  auto ourname = itr.GetNextCharacterSequence<std::string>(
955 
956  std::string modname;
957 
958  // Check is it valid //
959  if(!ourname || ourname->size() == 0){
960  // Auto generate our name //
961  modname = obj.GetName()+"'s_script";
962  } else{
963 
964  modname = *ourname;
965  }
966 
968 
969  // There should be a '{' character here, or the line must have changed //
970  bool linechanged = (lineforname != itr.GetCurrentLine());
971  if(itr.GetCharacter() != '{' && !linechanged){
972 
973  // There is a missing brace //
974  LogError("ObjectFile script block is missing '{' after its name",
975  file, itr.GetCurrentLine(), reporterror);
976 
977  return false;
978  }
979 
980  // Move to the next line //
981  if(!linechanged)
982  itr.GetUntilLineEnd<std::string>();
983 
984  // This is the line the script block starts //
985  // TODO: verify that this is correct
986  //size_t ourstartline = itr.GetCurrentLine()-1;
987  size_t ourstartline = itr.GetCurrentLine();
988 
989  // Get until the ending sequence //
990  auto scriptdata = itr.GetUntilCharacterSequence<std::string>("@%};",
992 
993  if(!scriptdata){
994 
995  LogError("ObjectFile script block is missing the source code",
996  file, ourstartline, reporterror);
997 
998  return false;
999  }
1000 
1001  // Check was it terminated properly, the last character processed should be ';' //
1002  if(itr.GetCharacter() != ';'){
1003 
1004  LogError("ObjectFile script block is missing the ending sequence "
1005  "(\"@%};\")",
1006  file, ourstartline, reporterror);
1007 
1008  return false;
1009  }
1010 
1011  // Create us //
1012 #ifdef LEVIATHAN_USING_ANGELSCRIPT
1013  auto ourobj = std::make_shared<ScriptScript>((ScriptExecutor::Get()->CreateNewModule(
1014  modname, file + "(" + Convert::ToString(ourstartline) + ")")));
1015 
1016  // Add the source to the script //
1017  auto ourmod = ourobj->GetModule();
1018 
1019  ourmod->AddScriptSegment(file, static_cast<int>(ourstartline), *scriptdata);
1020  ourmod->SetBuildState(SCRIPTBUILDSTATE_READYTOBUILD);
1021 
1022  // Add to the object //
1023  obj.AddScriptScript(ourobj);
1024 
1025 #else
1026  LogError("ObjectFile has a ScriptBlock but there is no script "
1027  "support compiled in",
1028  file, ourstartline, reporterror);
1029 #endif// LEVIATHAN_USING_ANGELSCRIPT
1030 
1031  return true;
1032 }
1033 // ------------------------------------ //
1035  const std::string &file, LErrorReporter* reporterror)
1036 {
1037  std::string datatowrite;
1038 
1039  if(!SerializeObjectFile(data, datatowrite)){
1040 
1041  reporterror->Error("WriteObjectFile: failed to serialize data into a std::string");
1042  return false;
1043  }
1044 
1045  FileSystem::WriteToFile(datatowrite, file);
1046 
1047  return true;
1048 }
1049 
1051  std::string &receiver)
1052 {
1053 
1054  // Header variables //
1055  for (size_t i = 0; i < data.GetVariables()->GetVariableCount(); ++i){
1056 
1057  const auto* variable = data.GetVariables()->GetValueDirectRaw(i);
1058 
1059  receiver += variable->ToText() + "\n";
1060  }
1061 
1062  receiver += "\n";
1063 
1064  // Template definitions //
1065  for (size_t i = 0; i < data.GetTemplateDefinitionCount(); ++i){
1066 
1067  std::shared_ptr<ObjectFileTemplateDefinition> object = data.GetTemplateDefinition(i);
1068 
1069  LEVIATHAN_ASSERT(object, "GetTemplateDefinition iteration invalid");
1070 
1071  receiver += object->Serialize();
1072  }
1073 
1074  // Objects //
1075  for (size_t i = 0; i < data.GetTotalObjectCount(); ++i){
1076 
1077  std::shared_ptr<ObjectFileObject> object = data.GetObject(i);
1078 
1079  LEVIATHAN_ASSERT(object, "GetObject iteration invalid");
1080 
1081  if(object->IsThisTemplated())
1082  continue;
1083 
1084  receiver += object->Serialize();
1085  }
1086 
1087  // Template instantiations //
1088  for (size_t i = 0; i < data.GetTemplateInstanceCount(); ++i){
1089 
1090  std::shared_ptr<ObjectFileTemplateInstance> object = data.GetTemplateInstance(i);
1091 
1092  LEVIATHAN_ASSERT(object, "GetTemplateInstance iteration invalid");
1093 
1094  receiver += object->Serialize();
1095  }
1096 
1097  receiver += "\n";
1098  return true;
1099 }
1100 
std::unique_ptr< RStrType > GetUntilCharacterSequence(const RStrType &findstr, int specialflags=0)
Gets all characters until a sequence is matched.
#define DATAINDEX_FRAMETIME
Definition: DataStore.h:13
#define DATAINDEX_FRAMETIME_MIN
Definition: DataStore.h:19
#define DATAINDEX_TICKTIME
Definition: DataStore.h:11
static DLLEXPORT std::unique_ptr< ObjectFile > ProcessObjectFileFromString(const std::string &filecontents, const std::string &filenameforerrors, LErrorReporter *reporterror)
static DLLEXPORT void RegisterValue(const std::string &name, VariableBlock *valuetokeep)
Registers a new value alias for the processor.
DLLEXPORT size_t GetTemplateInstanceCount() const
Definition: ObjectFile.h:473
virtual DLLEXPORT bool AddVariableList(std::unique_ptr< ObjectFileList > &&list)=0
Add a variable list to this object.
Non-template class for working with all types of DataBlocks.
Definition: DataBlock.h:425
#define DATAINDEX_TICKCOUNT
Definition: DataStore.h:12
#define LOG_FATAL(x)
Definition: Define.h:98
void SkipWhiteSpace(int specialflags=0)
Skips until characters that are not whitespace are found.
bool IsOutOfBounds()
Returns true when the read position is valid.
virtual void Warning(const std::string &Text)=0
DLLEXPORT void ReInit(std::unique_ptr< StringDataIterator > &&iterator)
Changes the current iterator to the new iterator and goes to the beginning.
static DLLEXPORT std::unique_ptr< ObjectFile > ProcessObjectFile(const std::string &file, LErrorReporter *reporterror)
Reads an ObjectFile to an in-memory data structure.
bool MoveToNext()
Skips the current character and moves to the next.
std::unique_ptr< RStrType > GetStringInQuotes(QUOTETYPE quotes, int specialflags=0)
Gets the next string in quotes.
virtual DLLEXPORT bool AddVariable(std::shared_ptr< NamedVariableList > var)=0
Adds a new variable.
static DLLEXPORT bool SerializeObjectFile(ObjectFile &data, std::string &receiver)
Serializes an ObjectFile object into a string.
#define DATAINDEX_FRAMETIME_AVERAGE
Definition: DataStore.h:20
#define DATAINDEX_FPS_AVERAGE
Definition: DataStore.h:24
DLLEXPORT int GetPreviousCharacter()
Gets the previous character.
static DLLEXPORT std::shared_ptr< ObjectFileTemplateDefinition > CreateFromObject(const std::string &name, std::shared_ptr< ObjectFileObject > obj, std::vector< std::unique_ptr< std::string >> &templateargs)
Creates a ObjectFileTemplateDefinition from an ObjectFileObject and a parameter list.
Definition: ObjectFile.cpp:523
#define DATAINDEX_FPS
Definition: DataStore.h:14
DLLEXPORT size_t GetVariableCount() const
Returns the size of the internal variable vector.
Definition: NamedVars.cpp:1304
static DLLEXPORT ScriptExecutor * Get()
size_t GetCurrentLine()
Returns the current line the processing is happening.
DLLEXPORT std::shared_ptr< ObjectFileObject > GetObject(size_t index)
Definition: ObjectFile.h:464
static DLLEXPORT bool WriteObjectFile(ObjectFile &data, const std::string &file, LErrorReporter *reporterror)
Writes an ObjectFile's data structure to a file.
int GetCharacter(size_t forward=0)
Gets the character in the position current + forward.
DLLEXPORT std::string ToText(int WhichSeparator=0, bool AddAllBrackets=false) const
Definition: NamedVars.cpp:490
std::unique_ptr< RStrType > GetUntilEqualityAssignment(EQUALITYCHARACTER stopcase, int specialflags=0)
Gets the string that is before the equality assignment.
#define DATAINDEX_HEIGHT
Definition: DataStore.h:16
DLLEXPORT std::shared_ptr< ObjectFileTemplateInstance > GetTemplateInstance(size_t index)
Definition: ObjectFile.h:479
std::unique_ptr< RStrType > GetUntilNextCharacterOrAll(int charactertolookfor, int specialflags=0)
Gets characters until a character or all remaining characters.
virtual DLLEXPORT void Print(LErrorReporter *errorreport) const noexcept
Definition: Exceptions.cpp:41
#define DATAINDEX_FPS_MIN
Definition: DataStore.h:22
DLLEXPORT size_t GetTotalObjectCount() const
Gets the total number of objects (objects + template instances)
Definition: ObjectFile.h:414
Iterator class for getting parts of a string.
bool starts_with_bom(octet_iterator it, octet_iterator end)
Definition: core.h:306
DLLEXPORT bool AddTemplate(std::shared_ptr< ObjectFileTemplateDefinition > templatedef)
Adds a ObjectFileTemplateInstance to this file.
Definition: ObjectFile.cpp:165
static DLLEXPORT void Initialize()
#define LEVIATHAN_ASSERT(x, msg)
Definition: Define.h:104
#define SPECIAL_ITERATOR_FILEHANDLING
Common flag for file handling.
static std::string ToString(const T &val)
Definition: Convert.h:72
virtual DLLEXPORT const std::string & GetName() const =0
Gets the name of this object.
static bool IsCharacterWhitespace(CharType character)
std::unique_ptr< RStrType > GetUntilNextCharacterOrNothing(int charactertolookfor, int specialflags=0)
Gets characters until a character or nothing if the specified character is not found.
Interface for object file objects to implement.
Definition: ObjectFile.h:122
static void RemovePreceedingTrailingSpaces(StringTypeN &str)
std::unique_ptr< RStrType > GetUntilLineEnd()
Gets all characters until a line end.
virtual void Error(const std::string &Text)=0
#define DATAINDEX_FPS_MAX
Definition: DataStore.h:23
#define DATAINDEX_FRAMETIME_MAX
Definition: DataStore.h:18
Causes comments to be handled as whitespace/delimiting.
virtual DLLEXPORT void AddTextLine(const std::string &line)=0
Adds an UTF8 encoded line.
DLLEXPORT std::shared_ptr< ObjectFileTemplateDefinition > GetTemplateDefinition(size_t index)
Definition: ObjectFile.h:455
static DLLEXPORT bool ReadFileEntirely(const std::string &file, std::string &resultreceiver)
Definition: FileSystem.cpp:538
void LogError(const TStr &msgStart, const std::string &file, TLineType line, LErrorReporter *reporterror)
DLLEXPORT NamedVariableList * GetValueDirectRaw(const std::string &name) const
Definition: NamedVars.cpp:1096
#define DLLEXPORT
Definition: Include.h:84
#define ADDDATANAMEINTDEFINITION(x)
DLLEXPORT NamedVars * GetVariables()
Returns a raw pointer to HeaderVars.
Definition: ObjectFile.cpp:70
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
virtual DLLEXPORT bool IsThisTemplated() const =0
Returns true when this is a templated object.
DLLEXPORT void AddTemplateInstance(std::shared_ptr< ObjectFileTemplateInstance > tiobj)
Adds a ObjectFileTemplateInstance to this file.
Definition: ObjectFile.cpp:158
#define DATAINDEX_WIDTH
Definition: DataStore.h:15
static DLLEXPORT bool WriteToFile(const std::string &data, const std::string &filename)
Definition: FileSystem.cpp:456
virtual DLLEXPORT void AddScriptScript(std::shared_ptr< ScriptScript > script)=0
Add a script block to this object.
std::unique_ptr< RStrType > GetNextCharacterSequence(int stopcaseflags, int specialflags=0)
Gets the next sequence of characters according to stopcaseflags.
DLLEXPORT size_t GetTemplateDefinitionCount() const
Definition: ObjectFile.h:449
virtual DLLEXPORT bool AddTextBlock(std::unique_ptr< ObjectFileTextBlock > &&tblock)=0
Add a text block to this object.