From: Daniel Karbach Date: Wed, 13 Mar 2013 18:07:19 +0000 (+0100) Subject: new object file format in compiler X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=8c8061a4f8b88410d6d93c039afe6affc4b69cf2;p=l2e.git new object file format in compiler --- diff --git a/src/loader/Compiler.cpp b/src/loader/Compiler.cpp index 5575838..d122643 100644 --- a/src/loader/Compiler.cpp +++ b/src/loader/Compiler.cpp @@ -1,26 +1,27 @@ -/* - * Compiler.cpp - * - * Created on: Sep 11, 2012 - * Author: holy - */ - #include "Compiler.h" #include "Interpreter.h" +#include "TypeDescription.h" #include #include +#include #include #include #include +#include #include +#include #include +using std::iostream; +using std::make_pair; using std::map; using std::ostream; +using std::runtime_error; using std::set; using std::string; +using std::strlen; using std::vector; namespace loader { @@ -28,151 +29,254 @@ namespace loader { Compiler::Compiler(const Interpreter &intp) : intp(intp) , cursor(0) { - int headerSize(sizeof(ObjectFileHeader) + (intp.Values().size() * sizeof(TypeOffset))); - - fileHeader.exportsBegin = headerSize + Remaining(headerSize, 16); - fileHeader.exportsEnd = fileHeader.exportsBegin + (intp.ExportedIdentifiers().size() * sizeof(Export)); + int headerSize(sizeof(ObjectFileHeader)); - fileHeader.externalsBegin = fileHeader.exportsEnd + Remaining(fileHeader.exportsEnd, 16); - fileHeader.externalsEnd = fileHeader.externalsBegin + (intp.PostponedDefinitions().size() * sizeof(External)); - - fileHeader.exportStringsBegin = fileHeader.externalsEnd + Remaining(fileHeader.externalsEnd, 16); - fileHeader.exportStringsEnd = fileHeader.exportStringsBegin; - for (set::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) { - fileHeader.exportStringsEnd += i->size() + 1; - } + fileHeader.exportsBegin = headerSize; + fileHeader.exportsEnd = fileHeader.exportsBegin + + (intp.ExportedIdentifiers().size() * sizeof(Export)); - fileHeader.externalStringsBegin = fileHeader.exportStringsEnd + Remaining(fileHeader.exportStringsEnd, 16); - fileHeader.externalStringsEnd = fileHeader.externalStringsBegin; - for(vector::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) { - fileHeader.externalStringsEnd += std::strlen(i->identifier) + 1; - } - - fileHeader.imagesBegin = fileHeader.externalStringsEnd + Remaining(fileHeader.externalStringsEnd, 16); - fileHeader.imagesEnd = fileHeader.imagesBegin + (intp.Images().size() * sizeof(ImageProperties)); - for (map::const_iterator i(intp.Images().begin()), end(intp.Images().end()); i != end; ++i) { - fileHeader.imagesEnd += i->second->w * i->second->h * i->second->format->BytesPerPixel; - } + fileHeader.externalsBegin = fileHeader.exportsEnd; + fileHeader.externalsEnd = fileHeader.externalsBegin + + (intp.PostponedDefinitions().size() * sizeof(External)); - fileHeader.objectsBegin = fileHeader.imagesEnd + Remaining(fileHeader.imagesEnd, 16); - fileHeader.objectsEnd = fileHeader.objectsBegin; - for (map >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) { - const TypeDescription &td(TypeDescription::Get(i->first)); - objectOffsets[i->first] = fileHeader.objectsEnd; - fileHeader.objectsEnd += td.Size() * i->second.size(); - fileHeader.objectsEnd += Remaining(fileHeader.objectsEnd, 16); - } + fileHeader.objectsBegin = fileHeader.externalsEnd + + Remaining(fileHeader.externalsEnd, 16); } -void Compiler::Write(ostream &out) { - WriteHeader(out); +void Compiler::Write(iostream &out) { + ReserveHeader(out); + WriteObjects(out); + WriteOwnStrings(out); + fileHeader.objectsEnd = cursor; Pad(out, 16); + fileHeader.arraysBegin = cursor; + WriteArrays(out); + fileHeader.arraysEnd = cursor; + out.seekp(0); + cursor = 0; + WriteHeader(out); WriteExports(out); - Pad(out, 16); WriteExternals(out); - Pad(out, 16); - WriteExportStrings(out); - Pad(out, 16); - WriteExternalStrings(out); - Pad(out, 16); - WriteImages(out); - Pad(out, 16); - WriteObjects(out); + out.seekg(fileHeader.objectsBegin); + out.clear(); + Relocate(out); } +void Compiler::ReserveHeader(ostream &out) { + Fill(out, fileHeader.objectsBegin); +} void Compiler::WriteHeader(ostream &out) { - Write(out, reinterpret_cast(&fileHeader), sizeof(ObjectFileHeader)); - for(map >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) { - TypeOffset to; - to.typeId = i->first; - to.begin = GetTypeOffset(i->first); - to.end = to.begin + (i->second.size() * TypeDescription::Get(i->first).Size()); - Write(out, reinterpret_cast(&to), sizeof(TypeOffset)); + Write(out, &fileHeader, sizeof(ObjectFileHeader)); +} + +void Compiler::WriteOwnStrings(ostream &out) { + for (set::const_iterator + i(intp.ExportedIdentifiers().begin()), + end(intp.ExportedIdentifiers().end()); + i != end; ++i) { + addressMap.insert(make_pair(i->c_str(), cursor)); + Object object; + object.typeId = Interpreter::STRING_ID; + object.size = i->size() + 1; + Write(out, &object, sizeof(Object)); + Write(out, i->c_str(), object.size); + } + for(vector::const_iterator + i(intp.PostponedDefinitions().begin()), + end(intp.PostponedDefinitions().end()); + i != end; ++i) { + addressMap.insert(make_pair( + i->identifier.c_str(), cursor)); + Object object; + object.typeId = Interpreter::STRING_ID; + object.size = i->identifier.size() + 1; + Write(out, &object, sizeof(Object)); + Write(out, i->identifier.c_str(), object.size); } - TypeOffset to; - to.typeId = 0; - to.begin = 0; - to.end = 0; - Write(out, reinterpret_cast(&to), sizeof(TypeOffset)); } void Compiler::WriteExports(ostream &out) { - int nameOffset(fileHeader.externalStringsBegin); - for (set::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) { - const Interpreter::ParsedDefinition &dfn(intp.GetDefinition(*i)); + for (set::const_iterator + i(intp.ExportedIdentifiers().begin()), + end(intp.ExportedIdentifiers().end()); + i != end; ++i) { Export exp; - exp.nameOffset = nameOffset; - exp.typeId = dfn.type; - exp.dataOffset = ObjectOffset(dfn.type, dfn.id); - Write(out, reinterpret_cast(&exp), sizeof(Export)); - nameOffset += i->size() + 1; + PrepareExport(exp, *i); + Write(out, &exp, sizeof(Export)); } } void Compiler::WriteExternals(ostream &out) { - int nameOffset(fileHeader.exportStringsBegin); - for(vector::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) { + for(vector::const_iterator + i(intp.PostponedDefinitions().begin()), + end(intp.PostponedDefinitions().end()); + i != end; ++i) { External ext; - ext.nameOffset = nameOffset; - ext.referenceOffset = ReferenceOffset(i->type, i->id, i->offset); - ext.inlined = i->inlined ? 1 : 0; - Write(out, reinterpret_cast(&ext), sizeof(External)); - nameOffset += std::strlen(i->identifier) + 1; + PrepareExternal(ext, *i); + Write(out, &ext, sizeof(External)); } } -void Compiler::WriteExportStrings(ostream &out) { - for (set::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) { - Write(out, i->c_str(), i->size() + 1); +void Compiler::WriteObjects(ostream &out) { + Pad(out, 16); + for (map >::const_iterator + i(intp.Values().begin()), end(intp.Values().end()); + i != end; ++i) { + const TypeDescription &td(TypeDescription::Get(i->first)); + for (vector::const_iterator + j(i->second.begin()), jend(i->second.end()); + j != jend; ++j) { + Object object; + PrepareObject(object, td, *j); + Write(out, &object, sizeof(Object)); + Write(out, *j, object.size); + } } } -void Compiler::WriteExternalStrings(ostream &out) { - for(vector::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) { - Write(out, i->identifier, std::strlen(i->identifier) + 1); +void Compiler::WriteArrays(ostream &out) { + Pad(out, 16); + for (vector::const_iterator + i(intp.Arrays().begin()), end(intp.Arrays().end()); + i != end; ++i) { + Array array; + array.size = i->size; + array.ref = i->ref; + Write(out, &array, sizeof(Array)); + addressMap.insert(make_pair(i->data, cursor)); + Write(out, i->data, array.size); } } -void Compiler::WriteImages(ostream &out) { - for (map::const_iterator i(intp.Images().begin()), end(intp.Images().end()); i != end; ++i) { - ImageProperties ip; - ip.flags = i->second->flags; - ip.width = i->second->w; - ip.height = i->second->h; - ip.depth = i->second->format->BitsPerPixel; - ip.pitch = i->second->pitch; - ip.rmask = i->second->format->Rmask; - ip.gmask = i->second->format->Gmask; - ip.bmask = i->second->format->Bmask; - ip.amask = i->second->format->Amask; - Write(out, reinterpret_cast(&ip), sizeof(ImageProperties)); - SDL_LockSurface(i->second); - Write(out, reinterpret_cast(i->second->pixels), ip.width * ip.height * (ip.depth / CHAR_BIT + (ip.depth % CHAR_BIT ? 1 : 0))); - // TODO: store palette too? - SDL_UnlockSurface(i->second); + +void Compiler::PrepareExport(Export &exp, const string &str) { + const Interpreter::ParsedDefinition &dfn + = intp.GetDefinition(str); + exp.nameOffset = addressMap[str.c_str()]; + exp.typeId = dfn.type; + exp.dataOffset = addressMap[intp.GetObject(dfn.type, str)]; +} + +void Compiler::PrepareExternal( + External &ext, + const Interpreter::PostponedDefinition &def) { + ext.nameOffset = addressMap[def.identifier.c_str()]; + ext.referenceOffset = addressMap[def.object] + (def.dest - def.object); + ext.inlined = 0; + if (def.inlined) ext.inlined |= 1; + if (def.aggregate) ext.inlined |= 2; +} + +void Compiler::PrepareObject( + Object &object, + const TypeDescription &td, + void *data) { + addressMap.insert(make_pair(data, cursor + sizeof(Object))); + object.typeId = td.TypeId(); + switch (td.TypeId()) { + case Interpreter::STRING_ID: + object.size = strlen( + reinterpret_cast(data)) + 1; + break; + default: + object.size = td.Size(); + break; } } -void Compiler::WriteObjects(ostream &out) { - for (map >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) { - const TypeDescription &td(TypeDescription::Get(i->first)); - for (vector::const_iterator j(i->second.begin()), jend(i->second.end()); j != jend; ++j) { - Write(out, reinterpret_cast(*j), td.Size()); +void Compiler::Relocate(iostream &out) { + int bufferSize = TypeDescription::GetMaxSize(); + char *buffer = new char[bufferSize]; + for (;out && out.tellg() < fileHeader.objectsEnd;) { + // 20785 + Object object; + out.read(reinterpret_cast(&object), sizeof(Object)); + const TypeDescription &td = TypeDescription::Get(object.typeId); + if (td.NeedsLinking()) { + out.seekg(object.size, iostream::cur); + continue; + } + unsigned int pos = out.tellg(); + out.seekg(pos); + out.read(buffer, object.size); + Relocate(buffer, td); + out.seekp(pos); + out.write(buffer, object.size); + out.seekg(out.tellp()); + } + delete[] buffer; + out.seekg(fileHeader.arraysBegin); + Array array; + for (; out && out.tellg() < fileHeader.arraysEnd;) { + out.read(reinterpret_cast(&array), sizeof(Array)); + if (!array.ref) { + out.seekg(array.size); + continue; } - Pad(out, 16); + buffer = new char[array.size]; + unsigned int pos = out.tellg(); + out.seekg(pos); + out.read(buffer, array.size); + RelocateArray(buffer, array.size); + out.seekp(pos); + out.write(buffer, array.size); + out.seekg(out.tellp()); + delete[] buffer; } } +void Compiler::RelocateArray(char *array, int size) { + for (char *i = array, *end = array + size; + i < end; i += sizeof(void *)) { + char **dest = reinterpret_cast(i); + map::const_iterator + entry(addressMap.find(*dest)); + if (entry == addressMap.end()) { + throw runtime_error("unable to relocate array member"); + } + unsigned int destOffset = entry->second; + *dest = reinterpret_cast(destOffset); + } +} -void Compiler::Write(ostream &out, const char *data, int amount) { - out.write(data, amount); +void Compiler::Relocate(char *object, const TypeDescription &td) { + for (TypeDescription::FieldIterator + i(td.FieldsBegin()), end(td.FieldsEnd()); + i != end; ++i) { + const FieldDescription &fd = i->second; + if (!fd.IsAggregate() && !fd.IsReferenced()) { + continue; + } + char **dest = reinterpret_cast( + object + fd.Offset()); + if (!(*dest)) { + continue; + } + map::const_iterator + entry(addressMap.find(*dest)); + if (entry == addressMap.end()) { + throw runtime_error(string("unable to relocate field ") + + i->first + " in object of type " + td.TypeName()); + } + unsigned int destOffset = entry->second; + *dest = reinterpret_cast(destOffset); + } +} + + +void Compiler::Write(ostream &out, const void *data, int amount) { + out.write(reinterpret_cast(data), amount); cursor += amount; } void Compiler::Pad(ostream &out, int to) { - for (int remaining(Remaining(cursor, to)); remaining > 0; --remaining) { - out.put(0); + Fill(out, Remaining(cursor, to)); +} + +void Compiler::Fill(ostream &out, int count, char c) { + for (int remaining(count); remaining > 0; --remaining) { + out.put(c); ++cursor; } } @@ -182,18 +286,4 @@ int Compiler::Remaining(int value, int alignment) { return (have > 0) ? (16 - have) : 0; } - -int Compiler::ReferenceOffset(int typeId, int objectId, std::ptrdiff_t fieldOffset) const { - return ObjectOffset(typeId, objectId) + fieldOffset; -} - -int Compiler::ObjectOffset(int typeId, int objectId) const { - const TypeDescription &td(TypeDescription::Get(typeId)); - return GetTypeOffset(typeId) + (td.Size() * objectId); -} - -int Compiler::GetTypeOffset(int typeId) const { - return objectOffsets.at(typeId); -} - } diff --git a/src/loader/Compiler.h b/src/loader/Compiler.h index ab26cea..7afe633 100644 --- a/src/loader/Compiler.h +++ b/src/loader/Compiler.h @@ -1,14 +1,9 @@ -/* - * Compiler.h - * - * Created on: Sep 11, 2012 - * Author: holy - */ - #ifndef LOADER_COMPILER_H_ #define LOADER_COMPILER_H_ +#include "Interpreter.h" #include "ObjectFile.h" +#include "TypeDescription.h" #include #include @@ -17,8 +12,6 @@ namespace loader { -class Interpreter; - class Compiler { public: @@ -29,36 +22,41 @@ private: Compiler &operator =(const Compiler &); public: - void Write(std::ostream &); + void Write(std::iostream &); private: + void ReserveHeader(std::ostream &); + void WriteObjects(std::ostream &); + void WriteOwnStrings(std::ostream &); + void WriteArrays(std::ostream &); void WriteHeader(std::ostream &); void WriteExports(std::ostream &); void WriteExternals(std::ostream &); - void WriteExportStrings(std::ostream &); - void WriteExternalStrings(std::ostream &); - void WriteImages(std::ostream &); - void WriteObjects(std::ostream &); - void Write(std::ostream &, const char *data, int amount); + void Relocate(std::iostream &); + void RelocateArray(char *, int size); + void Relocate(char *, const TypeDescription &); + + void PrepareExport(Export &, const std::string &); + void PrepareExternal(External &, const Interpreter::PostponedDefinition &); + void PrepareObject(Object &, const TypeDescription &, void *); + + void Write(std::ostream &, const void *data, int amount); void Pad(std::ostream &, int to); + void Fill(std::ostream &, int count, char c = '\0'); static int Remaining(int value, int alignment); - int ReferenceOffset(int typeId, int objectId, std::ptrdiff_t fieldOffset) const; - int ObjectOffset(int typeId, int objectId) const; - int GetTypeOffset(int typeId) const; - private: const Interpreter &intp; - int cursor; + unsigned int cursor; ObjectFileHeader fileHeader; - std::map objectOffsets; + std::map addressMap; }; } -#endif /* LOADER_COMPILER_H_ */ +#endif diff --git a/src/loader/Interpreter.cpp b/src/loader/Interpreter.cpp index 8b54fc1..fc428cd 100644 --- a/src/loader/Interpreter.cpp +++ b/src/loader/Interpreter.cpp @@ -68,20 +68,64 @@ const Interpreter::ParsedDefinition &Interpreter::GetDefinition(const string &id } } +const Interpreter::ParsedDefinition &Interpreter::GetDefinition(const string &identifier) const { + std::map::const_iterator i(parsedDefinitions.find(identifier)); + if (i != parsedDefinitions.end()) { + return i->second; + } else { + throw Error("access to undefined object " + identifier); + } +} + -void *Interpreter::GetObject(int typeId, const std::string &name) { - std::map::const_iterator i(parsedDefinitions.find(name)); +void *Interpreter::GetObject( + int typeId, + const std::string &name) { + std::map::const_iterator + i(parsedDefinitions.find(name)); if (i != parsedDefinitions.end()) { - const TypeDescription &requested(TypeDescription::Get(typeId)); - const TypeDescription &actual(TypeDescription::Get(i->second.type)); + const TypeDescription &requested = + TypeDescription::Get(typeId); + const TypeDescription &actual = + TypeDescription::Get(i->second.type); if (requested.TypeId() == actual.TypeId()) { return values[actual.TypeId()][i->second.id]; } else if (actual.IsSubtypeOf(requested)) { - char *sub(reinterpret_cast(values[actual.TypeId()][i->second.id])); - std::ptrdiff_t offset(actual.SupertypeOffset(requested)); + char *sub = reinterpret_cast( + values[actual.TypeId()][i->second.id]); + std::ptrdiff_t offset = + actual.SupertypeOffset(requested); + return sub - offset; + } else { + throw Error("cannot cast " + actual.TypeName() + + " to " + requested.TypeName()); + } + } else { + throw Error("access to undefined object " + name); + } +} + +const void *Interpreter::GetObject( + int typeId, + const std::string &name) const { + std::map::const_iterator + i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + const TypeDescription &requested = + TypeDescription::Get(typeId); + const TypeDescription &actual = + TypeDescription::Get(i->second.type); + if (requested.TypeId() == actual.TypeId()) { + return values.at(actual.TypeId()).at(i->second.id); + } else if (actual.IsSubtypeOf(requested)) { + char *sub = reinterpret_cast( + values.at(actual.TypeId()).at(i->second.id)); + std::ptrdiff_t offset = + actual.SupertypeOffset(requested); return sub - offset; } else { - throw Error("cannot cast " + actual.TypeName() + " to " + requested.TypeName()); + throw Error("cannot cast " + actual.TypeName() + + " to " + requested.TypeName()); } } else { throw Error("access to undefined object " + name); @@ -287,11 +331,16 @@ void Interpreter::ReadObject(int typeId, int id, char *object, const PropertyLis if (fd.IsAggregate()) { int arraySize(i->second->GetLiteral().ArraySize()); size_t memberSize = fd.IsReferenced() ? sizeof(char *) : fieldType.Size(); - char *aggregate = alloc.Alloc(arraySize * memberSize); - char *iter = aggregate; + Array array; + array.size = arraySize * memberSize; + array.data = alloc.Alloc(array.size); + array.ref = fd.IsReferenced(); + arrays.push_back(array); + char *iter = reinterpret_cast(array.data); if (i->second->GetLiteral().GetType() == Literal::ARRAY_PROPS) { const vector &list(i->second->GetLiteral().GetPropertyLists()); - for (vector::const_iterator j(list.begin()), end(list.end()); + for (vector::const_iterator + j(list.begin()), end(list.end()); j != end; ++j, iter += memberSize) { char *member; if (fd.IsReferenced()) { @@ -329,11 +378,12 @@ void Interpreter::ReadObject(int typeId, int id, char *object, const PropertyLis *reinterpret_cast(iter) = GetObject(fd.TypeId(), *j); } else { - Postpone(iter, *j, fd.TypeId(), false); + Postpone(reinterpret_cast(array.data), + iter, *j, fd.TypeId(), false); } } } - std::memcpy(dest, &aggregate, sizeof(char *)); + std::memcpy(dest, &array.data, sizeof(char *)); dest += sizeof(char *); std::memcpy(dest, &arraySize, sizeof(int)); } else if (i->second->IsLiteral() && !fd.IsReferenced()) { @@ -355,7 +405,7 @@ void Interpreter::ReadObject(int typeId, int id, char *object, const PropertyLis } } } else { - Postpone(object, i->second->GetIdentifier(), fd.TypeId(), !fd.IsReferenced(), fd.IsAggregate()); + Postpone(object, object + fd.Offset(), i->second->GetIdentifier(), fd.TypeId(), !fd.IsReferenced(), fd.IsAggregate()); } } td.Load(object); @@ -861,16 +911,14 @@ bool Interpreter::CanLink(const Value &v) const { } void Interpreter::Postpone( + char *object, char *dest, const std::string &identifier, int type, bool inlined, bool aggregate) { - char *str(alloc.Alloc(identifier.size() + 1)); - std::memcpy(str, identifier.c_str(), identifier.size()); - str[identifier.size()] = '\0'; postponedDefinitions.push_back( - PostponedDefinition(dest, str, type, inlined, aggregate)); + PostponedDefinition(object, dest, identifier, type, inlined, aggregate)); } diff --git a/src/loader/Interpreter.h b/src/loader/Interpreter.h index 1a73d2d..3e9f661 100644 --- a/src/loader/Interpreter.h +++ b/src/loader/Interpreter.h @@ -59,6 +59,7 @@ public: /// Error is thrown if the object is undefined or a cast /// was unsuccessful. void *GetObject(int typeId, const std::string &name); + const void *GetObject(int typeId, const std::string &name) const; /// Register the type descriptions of builtin types. /// This should be called before any interpretation (like @@ -80,18 +81,21 @@ public: /// linked by its identifier. struct PostponedDefinition { PostponedDefinition( + char *object, char *dest, - const char *identifier, + const std::string &identifier, int type, bool inlined, bool aggregate) - : dest(dest) + : object(object) + , dest(dest) , identifier(identifier) , type(type) , inlined(inlined) , aggregate(aggregate) { } + char *object; char *dest; - const char *identifier; + std::string identifier; int type; bool inlined; bool aggregate; @@ -104,6 +108,7 @@ public: } /// Get the object definition for given identifier. const ParsedDefinition &GetDefinition(const std::string &identifier); + const ParsedDefinition &GetDefinition(const std::string &identifier) const; /// Get all images reference by he source. /// The returned map is indexed by filenames relative to /// the source file and contains ready-to-blit surfaces. @@ -119,6 +124,14 @@ public: const std::map > &Values() const { return values; } + struct Array { + void *data; + unsigned int size; + bool ref; + }; + const std::vector &Arrays() const { + return arrays; + } private: /// Interpret given definition. @@ -169,6 +182,7 @@ private: bool CanLink(const Value &) const; /// Defer linking of given object reference. void Postpone( + char *object, char *dest, const std::string &identifier, int type, @@ -184,6 +198,7 @@ private: std::vector postponedDefinitions; std::map imageCache; std::map > values; + std::vector arrays; }; diff --git a/src/loader/Loader.cpp b/src/loader/Loader.cpp index a1183f7..2403044 100644 --- a/src/loader/Loader.cpp +++ b/src/loader/Loader.cpp @@ -1,10 +1,3 @@ -/* - * Loader.cpp - * - * Created on: Sep 13, 2012 - * Author: holy - */ - #include "Loader.h" #include @@ -19,14 +12,10 @@ using std::vector; namespace loader { Loader::~Loader() { - for(map::const_iterator i(objectFiles.begin()), end(objectFiles.end()); i != end; ++i) { - if (i->second.surfaceCount) { - for (int j(0); j < i->second.surfaceCount; ++j) { - SDL_FreeSurface(i->second.surfaces[j]); - } - delete[] i->second.surfaces; - } - delete[] i->second.allocPtr; + for(map::const_iterator + i(objectFiles.begin()), end(objectFiles.end()); + i != end; ++i) { + delete[] i->second; } } @@ -37,73 +26,59 @@ void Loader::Load(const std::string &filePath) { int fileLength(file.tellg()); int length(fileLength + 15); - LoadedObjectFile &object(objectFiles[filePath]); - object.allocPtr = new char[length]; + char *block = new char[length]; + ObjectFileHeader *header = + reinterpret_cast(block); - if (reinterpret_cast(object.allocPtr) % 16) { - object.fileHeader = reinterpret_cast(object.allocPtr + (16 - (reinterpret_cast(object.allocPtr) % 16))); - } else { - object.fileHeader = reinterpret_cast(object.allocPtr); + unsigned long padding = + reinterpret_cast(block) % 16; + if (padding) { + header = reinterpret_cast( + block + (16 - padding)); } file.seekg(0, std::ios::beg); - file.read(reinterpret_cast(object.fileHeader), fileLength); - - if (object.fileHeader->versionId != FORMAT_ID) { - throw std::runtime_error("mismatched version id of file " + filePath); + file.read(reinterpret_cast(header), fileLength); + + try { + header->IntegrityCheck(fileLength); + + LoadExports(header->ident, + header->ExportsBegin(), + header->ExportsEnd()); + LoadExternals(header->ident, + header->ExternalsBegin(), + header->ExternalsEnd()); + LoadObjects(header->ident, + header->ObjectsBegin(), + header->ObjectsEnd()); + } catch (...) { + delete[] block; + throw; } - - LoadHeader(object); - LoadExports(object); - LoadImages(object); - LinkObjects(object); - LinkExternals(object); + objectFiles.insert(make_pair(filePath, block)); } -void Loader::LoadHeader(LoadedObjectFile &object) { - ObjectFileHeader *header(object.fileHeader); - char *charHeader(reinterpret_cast(header)); - - object.typeOffsetsBegin = reinterpret_cast(charHeader + sizeof(ObjectFileHeader)); - for (object.typeOffsetsEnd = object.typeOffsetsBegin; object.typeOffsetsEnd->begin != 0 && object.typeOffsetsEnd->end != 0; ++object.typeOffsetsEnd); - - object.exportsBegin = reinterpret_cast(charHeader + header->exportsBegin); - object.exportsEnd = reinterpret_cast(charHeader + header->exportsEnd); - - object.externalsBegin = reinterpret_cast(charHeader + header->externalsBegin); - object.externalsEnd = reinterpret_cast(charHeader + header->externalsEnd); - - object.exportStringsBegin = charHeader + header->exportStringsBegin; - object.exportStringsEnd = charHeader + header->exportStringsEnd; - - object.externalStringsBegin = charHeader + header->externalStringsBegin; - object.externalStringsEnd = charHeader + header->externalStringsEnd; - - object.imagesBegin = charHeader + header->imagesBegin; - object.imagesEnd = charHeader + header->imagesEnd; - - object.objectsBegin = charHeader + header->objectsBegin; - object.objectsEnd = charHeader + header->objectsEnd; -} - -void Loader::LoadExports(LoadedObjectFile &object) { - for (Export *i(object.exportsBegin); i != object.exportsEnd; ++i) { - string identifier(object.At(i->nameOffset)); +void Loader::LoadExports(char *src, Export *begin, Export *end) { + for (Export *i = begin; i < end; ++i) { + string identifier(src + i->nameOffset); LoadedExport &exp(exports[identifier]); exp.typeId = i->typeId; - exp.location = object.At(i->dataOffset); + exp.location = src + i->dataOffset; } } -void Loader::LinkExternals(LoadedObjectFile &object) { - for (External *i(object.externalsBegin); i != object.externalsEnd; ++i) { - string identifier(object.At(i->nameOffset)); - map::const_iterator exp(exports.find(identifier)); +void Loader::LoadExternals(char *src, External *begin, External *end) { + for (External *i = begin; i < end; ++i) { + string identifier(src + i->nameOffset); + map::const_iterator + exp(exports.find(identifier)); if (exp == exports.end()) { - throw std::runtime_error("undefined reference to " + identifier); + throw std::runtime_error("undefined reference to " + + identifier); } const TypeDescription &td(TypeDescription::Get(exp->second.typeId)); - char *dest(object.At(i->referenceOffset)); + char *dest = src + i->referenceOffset; if (i->inlined) { std::memcpy(dest, exp->second.location, td.Size()); } else { @@ -112,50 +87,28 @@ void Loader::LinkExternals(LoadedObjectFile &object) { } } -void Loader::LoadImages(LoadedObjectFile &object) { - for (char *i(object.imagesBegin); i != object.imagesEnd;) { - ImageProperties *props(reinterpret_cast(i)); - i += sizeof(ImageProperties) + props->width * props->height * (props->depth / CHAR_BIT + (props->depth % CHAR_BIT ? 1 : 0)); - ++object.surfaceCount; - } - if (object.surfaceCount == 0) return; - - object.surfaces = new SDL_Surface *[object.surfaceCount]; - int index(0); - for (char *i(object.imagesBegin); i != object.imagesEnd;) { - ImageProperties *props(reinterpret_cast(i)); - i += sizeof(ImageProperties); - SDL_Surface *image(SDL_CreateRGBSurfaceFrom( - i, - props->width, - props->height, - props->depth, - props->pitch, - props->rmask, - props->gmask, - props->bmask, - props->amask)); - i += props->width * props->height * (props->depth / CHAR_BIT + (props->depth % CHAR_BIT ? 1 : 0)); - object.surfaces[index] = image; - ++index; - } -} - -void Loader::LinkObjects(LoadedObjectFile &object) { - for (TypeOffset *type(object.typeOffsetsBegin); type != object.typeOffsetsEnd; ++type) { - const TypeDescription &td(TypeDescription::Get(type->typeId)); - for (int offset(type->begin); offset != type->end; offset += td.Size()) { - LinkObject(object, td, object.At(offset)); +void Loader::LoadObjects(char *src, Object *begin, Object *end) { + for (Object *i = begin; i < end; i = i->Next()) { + const TypeDescription &td = + TypeDescription::Get(i->typeId); + if (td.NeedsLinking()) { + LoadObject(src, i->RawObject(), td); } } } -void Loader::LinkObject(LoadedObjectFile &file, const TypeDescription &td, char *object) { - for (TypeDescription::FieldIterator i(td.FieldsBegin()), end(td.FieldsEnd()); i != end; ++i) { - const FieldDescription &field(i->second); - if (!field.IsReferenced()) continue; +void Loader::LoadObject(char *src, char *object, const TypeDescription &td) { + for (TypeDescription::FieldIterator + i(td.FieldsBegin()), end(td.FieldsEnd()); + i != end; ++i) { + const FieldDescription &field = i->second; + if (!field.IsReferenced() && !field.IsAggregate()) { + continue; + } char **dest(reinterpret_cast(object + field.Offset())); - *dest = file.At(*reinterpret_cast(*dest)); + if (*dest) { + *dest = src + *reinterpret_cast(dest); + } } } diff --git a/src/loader/Loader.h b/src/loader/Loader.h index 7717167..cf7dd13 100644 --- a/src/loader/Loader.h +++ b/src/loader/Loader.h @@ -1,21 +1,14 @@ -/* - * Loader.h - * - * Created on: Sep 13, 2012 - * Author: holy - */ - #ifndef LOADER_LOADER_H_ #define LOADER_LOADER_H_ #include "ObjectFile.h" #include "TypeDescription.h" -namespace loader { - #include #include -#include +#include + +namespace loader { class Loader { @@ -27,18 +20,16 @@ public: void Load(const std::string &file); private: - void LoadHeader(LoadedObjectFile &); - void LoadExports(LoadedObjectFile &); - void LinkExternals(LoadedObjectFile &); - void LoadImages(LoadedObjectFile &); - void LinkObjects(LoadedObjectFile &); - void LinkObject(LoadedObjectFile &, const TypeDescription &, char *object); + void LoadExports(char *src, Export *begin, Export *end); + void LoadExternals(char *src, External *begin, External *end); + void LoadObjects(char *src, Object *begin, Object *end); + void LoadObject(char *src, char *dest, const TypeDescription &); private: - std::map objectFiles; + std::map objectFiles; std::map exports; }; } -#endif /* LOADER_LOADER_H_ */ +#endif diff --git a/src/loader/ObjectFile.cpp b/src/loader/ObjectFile.cpp index 4cb8862..929b54a 100644 --- a/src/loader/ObjectFile.cpp +++ b/src/loader/ObjectFile.cpp @@ -1,12 +1,10 @@ -/* - * ObjectFile.cpp - * - * Created on: Sep 15, 2012 - * Author: holy - */ - #include "ObjectFile.h" +#include + +using std::runtime_error; + + namespace loader { ObjectFileHeader::ObjectFileHeader() @@ -15,40 +13,114 @@ ObjectFileHeader::ObjectFileHeader() , exportsEnd(0) , externalsBegin(0) , externalsEnd(0) -, exportStringsBegin(0) -, exportStringsEnd(0) -, externalStringsBegin(0) -, externalStringsEnd(0) -, imagesBegin(0) -, imagesEnd(0) , objectsBegin(0) -, objectsEnd(0) { +, objectsEnd(0) +, arraysBegin(0) +, arraysEnd(0) { ident[0] = 'L'; ident[1] = '2'; ident[2] = 'E'; ident[3] = '\n'; } -LoadedObjectFile::LoadedObjectFile() -: allocPtr(0) -, fileHeader(0) -, typeOffsetsBegin(0) -, typeOffsetsEnd(0) -, exportsBegin(0) -, exportsEnd(0) -, externalsBegin(0) -, externalsEnd(0) -, exportStringsBegin(0) -, exportStringsEnd(0) -, externalStringsBegin(0) -, externalStringsEnd(0) -, imagesBegin(0) -, imagesEnd(0) -, objectsBegin(0) -, objectsEnd(0) -, surfaces(0) -, surfaceCount(0) { +void ObjectFileHeader::IntegrityCheck(unsigned int fsize) const { + if (ident[0] != 'L' + || ident[1] != '2' + || ident[2] != 'E' + || ident[3] != '\n') { + throw runtime_error("magic bytes mismatch"); + } + if (versionId != FORMAT_ID) { + throw runtime_error("format ID mismatch"); + } + if (exportsBegin < sizeof(ObjectFileHeader) + || exportsBegin > fsize) { + throw runtime_error("exports section out of bounds"); + } + if (exportsEnd < exportsBegin + || exportsEnd > fsize + || (exportsEnd - exportsBegin) % sizeof(Export) != 0) { + throw runtime_error("bogus exports section end"); + } + if (externalsBegin < sizeof(ObjectFileHeader) + || externalsBegin >= fsize) { + throw runtime_error("externals section out of bounds"); + } + if (externalsEnd < externalsBegin + || externalsEnd > fsize + || (externalsEnd - externalsBegin) % sizeof(External) != 0) { + throw runtime_error("bogus externals section end"); + } + if (objectsBegin < sizeof(ObjectFileHeader) + || objectsBegin >= fsize + || objectsEnd < objectsBegin + || objectsEnd > fsize) { + throw runtime_error("objects section out of bounds"); + } + if (arraysBegin < sizeof(ObjectFileHeader) + || arraysBegin >= fsize + || arraysEnd < arraysBegin + || arraysEnd > fsize) { + throw runtime_error("arrays section out of bounds"); + } +} + +Export *ObjectFileHeader::ExportsBegin() { + char *data = reinterpret_cast(this); + return reinterpret_cast(data + exportsBegin); +} + +Export *ObjectFileHeader::ExportsEnd() { + char *data = reinterpret_cast(this); + return reinterpret_cast(data + exportsEnd); +} + +External *ObjectFileHeader::ExternalsBegin() { + char *data = reinterpret_cast(this); + return reinterpret_cast(data + externalsBegin); +} + +External *ObjectFileHeader::ExternalsEnd() { + char *data = reinterpret_cast(this); + return reinterpret_cast(data + externalsEnd); +} + +Object *ObjectFileHeader::ObjectsBegin() { + char *data = reinterpret_cast(this); + return reinterpret_cast(data + objectsBegin); +} + +Object *ObjectFileHeader::ObjectsEnd() { + char *data = reinterpret_cast(this); + return reinterpret_cast(data + objectsEnd); +} + +Array *ObjectFileHeader::ArraysBegin() { + char *data = reinterpret_cast(this); + return reinterpret_cast(data + arraysBegin); +} + +Array *ObjectFileHeader::ArraysEnd() { + char *data = reinterpret_cast(this); + return reinterpret_cast(data + arraysEnd); +} + + +char *Object::RawObject() { + return reinterpret_cast(this) + sizeof(Object); +} + +Object *Object::Next() { + return reinterpret_cast(RawObject() + size); +} + + +char *Array::Data() { + return reinterpret_cast(this) + sizeof(Array); +} +Array *Array::Next() { + return reinterpret_cast(Data() + size); } } diff --git a/src/loader/ObjectFile.h b/src/loader/ObjectFile.h index 6a7d677..178180a 100644 --- a/src/loader/ObjectFile.h +++ b/src/loader/ObjectFile.h @@ -1,10 +1,3 @@ -/* - * ObjectFile.h - * - * Created on: Sep 15, 2012 - * Author: holy - */ - #ifndef LOADER_OBJECTFILE_H_ #define LOADER_OBJECTFILE_H_ @@ -12,95 +5,104 @@ namespace loader { -const int FORMAT_ID(1); - -struct ObjectFileHeader { - char ident[4]; - - int versionId; - - int exportsBegin; - int exportsEnd; - - int externalsBegin; - int externalsEnd; - - int exportStringsBegin; - int exportStringsEnd; - - int externalStringsBegin; - int externalStringsEnd; - - int imagesBegin; - int imagesEnd; - - int objectsBegin; - int objectsEnd; - - ObjectFileHeader(); -}; - -struct TypeOffset { - int typeId; - int begin; - int end; -}; +const unsigned int FORMAT_ID = 2; struct Export { - int nameOffset; - int typeId; - int dataOffset; + /// Offset of the identifier in the file. + unsigned int nameOffset; + /// Type ID of referenced object. + unsigned int typeId; + /// File-offset of the object's actual data. + unsigned int dataOffset; }; struct External { - int nameOffset; - int referenceOffset; - int inlined; + /// File-relative offset of the referenced object's + /// identifier. + unsigned int nameOffset; + /// Target position for linking/inlining. + unsigned int referenceOffset; + /// Nonzero if the object should be copied rather that + /// just writing a reference. + unsigned int inlined; }; -struct ImageProperties { - Uint32 flags; - int width; - int height; - int depth; - int pitch; - Uint32 rmask; - Uint32 gmask; - Uint32 bmask; - Uint32 amask; +struct Object { + unsigned int typeId; + unsigned int size; + char *RawObject(); + Object *Next(); }; -struct LoadedObjectFile { - char *allocPtr; - ObjectFileHeader *fileHeader; - - TypeOffset *typeOffsetsBegin; - TypeOffset *typeOffsetsEnd; - - Export *exportsBegin; - Export *exportsEnd; - - External *externalsBegin; - External *externalsEnd; - - char *exportStringsBegin; - char *exportStringsEnd; - - char *externalStringsBegin; - char *externalStringsEnd; - - char *imagesBegin; - char *imagesEnd; +struct Array { + unsigned int size; + bool ref; + char *Data(); + Array *Next(); +}; - char *objectsBegin; - char *objectsEnd; +struct ObjectFileHeader { + /// Has to be "L2E\n" + char ident[4]; - SDL_Surface **surfaces; - int surfaceCount; + /// Version ID of the object file format + /// For now it must match FORMAT_ID for the loader to be + /// able to read it. + /// Backwards compatibility might be implemented at some + /// point in the future, but don't bet on that ever + /// happening. + unsigned int versionId; + + /// File-relative offsets of the export section's begin + /// and end respectively. + /// Exports are named and typed addresses within the + /// file. This is essentially an array of Export structs. + unsigned int exportsBegin; + unsigned int exportsEnd; + + /// File-relative offsets of the externals section's + /// begin and end respectively. + /// Each external names an entity which must be linked in + /// for this object file to function properly. This is + /// essentially an array of External structs. + unsigned int externalsBegin; + unsigned int externalsEnd; + + /// File-relative offsets of the objet section's begin + /// and end respectively. + /// Each object begins with its type ID followed by its + /// size and finally the raw object data. + /// All referecte type fields should contain either a + /// file-relative offset or zero to indicate a null + /// reference. + /// This can be sen as a linked list where the next + /// object for a node can be obtained by adding the size + /// of to int and the object to the current node's + /// address. + unsigned int objectsBegin; + unsigned int objectsEnd; + + /// File-relative offsets of the array section's begin + /// and end respectively. + /// Each array consists of an unsigned integer indicating + /// its size followed by a boolean flag which is true if + /// the arrays consists of pointers followed by the data. + unsigned int arraysBegin; + unsigned int arraysEnd; - LoadedObjectFile(); + ObjectFileHeader(); - char *At(int offset) { return reinterpret_cast(fileHeader) + offset; } + /// Check if there are any problems with the file header. + /// Throws a std::runtime_error on failure. + void IntegrityCheck(unsigned int fileSize) const; + Export *ExportsBegin(); + Export *ExportsEnd(); + External *ExternalsBegin(); + External *ExternalsEnd(); + Object *ObjectsBegin(); + Object *ObjectsEnd(); + Array *ArraysBegin(); + Array *ArraysEnd(); }; struct LoadedExport { @@ -110,4 +112,4 @@ struct LoadedExport { } -#endif /* LOADER_OBJECTFILE_H_ */ +#endif diff --git a/src/loader/PagedAllocator.cpp b/src/loader/PagedAllocator.cpp index 77af8ad..464d9d1 100644 --- a/src/loader/PagedAllocator.cpp +++ b/src/loader/PagedAllocator.cpp @@ -1,6 +1,10 @@ #include "PagedAllocator.h" +#include + using std::deque; +using std::runtime_error; + namespace loader { @@ -32,6 +36,25 @@ char *PagedAllocator::Alloc(unsigned int size) { return chunk; } +unsigned int PagedAllocator::PageOf(void *ptrIn) const { + char *ptr = reinterpret_cast(ptrIn); + unsigned int counter = 0; + for (deque::const_iterator i(pages.begin()), end(pages.end()); i != end; ++i, ++counter) { + if (ptr < *i) continue; + if (*i < ptr) return counter; + } + throw runtime_error("PagedAllocator::PageOf"); +} + +unsigned int PagedAllocator::PageOffsetOf(void *ptrIn) const { + char *ptr = reinterpret_cast(ptrIn); + for (deque::const_iterator i(pages.begin()), end(pages.end()); i != end; ++i) { + if (ptr < *i) continue; + if (*i < ptr) return ptr - *i; + } + throw runtime_error("PagedAllocator::PageOffsetOf"); +} + unsigned int PagedAllocator::Free() const { return pageSize - (head - CurrentPage()); } diff --git a/src/loader/PagedAllocator.h b/src/loader/PagedAllocator.h index 13b79a4..b9922c4 100644 --- a/src/loader/PagedAllocator.h +++ b/src/loader/PagedAllocator.h @@ -17,6 +17,9 @@ private: public: char *Alloc(unsigned int size); + unsigned int PageOf(void *) const; + unsigned int PageOffsetOf(void *) const; + private: unsigned int Free() const; void NewPage(); diff --git a/src/loader/TypeDescription.cpp b/src/loader/TypeDescription.cpp index c6e5d7e..1bb6c65 100644 --- a/src/loader/TypeDescription.cpp +++ b/src/loader/TypeDescription.cpp @@ -23,6 +23,9 @@ void TypeDescription::AddField(const std::string &n, const FieldDescription &f) } else { fields.insert(std::make_pair(n, f)); } + if (f.IsReferenced() || f.IsAggregate()) { + link = true; + } } bool TypeDescription::HasField(const std::string &name) const { @@ -107,6 +110,20 @@ const TypeDescription &TypeDescription::Get(int id) { } +int TypeDescription::GetMaxSize() { + int max = 0; + for (map::const_iterator + i(typeDescriptions.begin()), + end(typeDescriptions.end()); + i != end; ++i) { + if (i->second.Size() > max) { + max = i->second.Size(); + } + } + return max; +} + + void TypeDescription::WriteSourceWiki(std::ostream &out) { vector types; for (map::const_iterator i(typeDescriptions.begin()), end(typeDescriptions.end()); i != end; ++i) { diff --git a/src/loader/TypeDescription.h b/src/loader/TypeDescription.h index 262f76b..fb1b078 100644 --- a/src/loader/TypeDescription.h +++ b/src/loader/TypeDescription.h @@ -41,6 +41,7 @@ public: const FieldDescription &GetField(const std::string &name) const; void Construct(void *) const; void Load(void *) const; + bool NeedsLinking() const { return link; } void SetConstructor(void (*ctor)(void *)) { constructor = ctor; } void SetLoader(void (*ld)(void *)) { loader = ld; } @@ -67,10 +68,12 @@ public: static int GetTypeId(const std::string &); static const TypeDescription &Get(int id); + static int GetMaxSize(); + static void WriteSourceWiki(std::ostream &); private: - TypeDescription(int id, const std::string &name) : constructor(0), loader(0), description(0), name(name), id(id), size(0) { } + TypeDescription(int id, const std::string &name) : constructor(0), loader(0), description(0), name(name), id(id), size(0), link(false) { } private: void (*constructor)(void *); @@ -81,6 +84,7 @@ private: std::map supertypes; int id; int size; + bool link; static std::map typeDescriptions; static std::map typeName2ID; diff --git a/src/main.cpp b/src/main.cpp index bdde265..73a9f16 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,8 +19,6 @@ #include "common/Script.h" #include "common/Spell.h" #include "common/Stats.h" -#include "math/Fixed.h" -#include "math/Vector.h" #include "graphics/CharSelect.h" #include "graphics/ComplexAnimation.h" #include "graphics/Font.h" @@ -31,6 +29,7 @@ #include "graphics/Sprite.h" #include "graphics/Texture.h" #include "loader/Caster.h" +#include "loader/Compiler.h" #include "loader/Interpreter.h" #include "loader/Loader.h" #include "loader/ParsedSource.h" @@ -42,6 +41,8 @@ #include "map/MapState.h" #include "map/Tile.h" #include "map/Trigger.h" +#include "math/Fixed.h" +#include "math/Vector.h" #include "menu/Resources.h" #include "sdl/InitImage.h" #include "sdl/InitScreen.h" @@ -67,10 +68,9 @@ using common::GameConfig; using common::GameState; using common::Hero; using common::Spell; -using math::Fixed; -using math::Vector; using graphics::Texture; using loader::Caster; +using loader::Compiler; using loader::Interpreter; using loader::Loader; using loader::ParsedSource; @@ -78,6 +78,8 @@ using loader::Parser; using loader::TypeDescription; using map::Entity; using map::MapState; +using math::Fixed; +using math::Vector; using sdl::InitImage; using sdl::InitScreen; using sdl::InitSDL; @@ -158,6 +160,9 @@ int main(int argc, char **argv) { } } + Interpreter intp(source); + intp.ReadSource(); + switch (args.GetRunLevel()) { case Arguments::WRITE: { @@ -169,9 +174,14 @@ int main(int argc, char **argv) { break; } case 'o': { - std::ofstream outstream(args.OutfilePath()); + std::fstream outstream(args.OutfilePath(), std::ios_base::out|std::ios_base::trunc); + outstream.flush(); + outstream.close(); + outstream.open(args.OutfilePath()); + outstream.exceptions(std::ios_base::badbit|std::ios_base::failbit); Compiler(intp).Write(outstream); break; + } default: { throw std::runtime_error(string("don't know how to write file ") + args.OutfilePath()); } @@ -194,9 +204,6 @@ int main(int argc, char **argv) { break; } - Interpreter intp(source); - intp.ReadSource(); - if (intp.PostponedDefinitions().size() > 0) { for (vector::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) { std::cerr << "missing definition of " << TypeDescription::Get(i->type).TypeName() << " " << i->identifier << std::endl;