diff --git a/include/sirEdit/main.hpp b/include/sirEdit/main.hpp index 5abd6ee..31ecbf7 100644 --- a/include/sirEdit/main.hpp +++ b/include/sirEdit/main.hpp @@ -11,6 +11,8 @@ namespace sirEdit { extern void doSave(bool blocking=false); extern std::string getSavePath(); + extern std::string getSirPath(); + extern std::string getSpec(const sirEdit::data::Tool* tool); extern void loadFile(Gtk::Window* window, Gtk::FileChooserNative* chooser); extern void runInGui(std::function func); diff --git a/meson.build b/meson.build index 0d5cd21..d7aa0c3 100644 --- a/meson.build +++ b/meson.build @@ -15,33 +15,42 @@ gtkmm = dependency('gtkmm-3.0', version: '>= 3.18') # Sources of sir src_sir = [ + 'sir/BuildInformationFieldDeclarations.cpp', 'sir/CommentFieldDeclarations.cpp', 'sir/CommentTagFieldDeclarations.cpp', 'sir/CustomFieldOptionFieldDeclarations.cpp', 'sir/FieldLikeFieldDeclarations.cpp', + 'sir/FilePathFieldDeclarations.cpp', 'sir/HintFieldDeclarations.cpp', 'sir/IdentifierFieldDeclarations.cpp', 'sir/RestrictionFieldDeclarations.cpp', 'sir/ToolFieldDeclarations.cpp', + 'sir/ToolTypeCustomizationFieldDeclarations.cpp', 'sir/TypeFieldDeclarations.cpp', 'sir/File.cpp', + 'sir/BuildInformationPools.cpp', 'sir/CommentPools.cpp', 'sir/CommentTagPools.cpp', 'sir/CustomFieldOptionPools.cpp', 'sir/FieldLikePools.cpp', + 'sir/FilePathPools.cpp', 'sir/HintPools.cpp', 'sir/IdentifierPools.cpp', 'sir/RestrictionPools.cpp', 'sir/ToolPools.cpp', + 'sir/ToolTypeCustomizationPools.cpp', 'sir/TypePools.cpp', + 'sir/TypesOfBuildInformation.cpp', 'sir/TypesOfComment.cpp', 'sir/TypesOfCommentTag.cpp', 'sir/TypesOfCustomFieldOption.cpp', 'sir/TypesOfFieldLike.cpp', + 'sir/TypesOfFilePath.cpp', 'sir/TypesOfHint.cpp', 'sir/TypesOfIdentifier.cpp', 'sir/TypesOfRestriction.cpp', 'sir/TypesOfTool.cpp', + 'sir/TypesOfToolTypeCustomization.cpp', 'sir/TypesOfType.cpp' ] inc_sir = include_directories('sir') diff --git a/sirSpec/tools.skill b/sirSpec/tools.skill index e221baf..913b830 100644 --- a/sirSpec/tools.skill +++ b/sirSpec/tools.skill @@ -7,15 +7,79 @@ Tool { string description; string command; + /** + * build targets associated with this tool + */ + BuildInformation[] buildTargets; + /** * the map of user types selected by this tool. * The string can get "u", "r", "w", "d". */ - map selectedUserTypes; + map selTypes; /** * The set of fields selected by this tool. * The string can get "u", "r", "w", "c". */ - map selectedFields; + map selFields; + + /** + * the set of user types selected by this tool + */ + set selectedUserTypes; + + /** + * The set of fields selected by this tool. + * The string argument is used to ensure, that selected fields have unique names. + */ + map selectedFields; + + /* overrides existing annotations */ + map customTypeAnnotations; + + /* overrides existing annotations */ + map customFieldAnnotations; +} + +/** + * this type is used to allow tools to define their own non-standard set of hints and restrictions + */ +ToolTypeCustomization extends Annotations {} + +BuildInformation { + + /** + * the output directory passed to the target generator + */ + FilePath output; + + /** + * the name of the language to be used. It is explicitly discouraged to use all languages. + * Create different build informations for every language instead, as the output directory should be changed. + */ + string language; + + /** + * options are processed as if they were entered in the command line interface + * + * @note options consisting of multiple strings will be stored in multiple strings in this form + */ + string[] options; +} + +/** + * a path that can be used in the description of a build process + */ +FilePath { + + /** + * true, iff starting from file system root + */ + bool isAbsolut; + + /** + * parts of the path that will be assembled into a usable path + */ + string[] parts; } diff --git a/src/data/serializeSIR.cpp b/src/data/serializeSIR.cpp index 719c0b4..8b88bde 100644 --- a/src/data/serializeSIR.cpp +++ b/src/data/serializeSIR.cpp @@ -11,6 +11,8 @@ #include #include +#include + using namespace sir::api; using namespace sirEdit::data; using namespace std; @@ -671,9 +673,10 @@ namespace { // Update types auto types = new ::skill::api::Map<::sir::UserdefinedType*, ::skill::api::String>(); - if(sTool->getSelectedUserTypes() != nullptr) - delete sTool->getSelectedUserTypes(); - sTool->setSelectedUserTypes(types); + if(sTool->getSelTypes() != nullptr) + delete sTool->getSelTypes(); + sTool->setSelTypes(types); + for(auto& j : i.second.getStatesTypes()) { switch(get<1>(j.second)) { case TYPE_STATE::READ: @@ -696,9 +699,9 @@ namespace { // Update fields { auto fields = new ::skill::api::Map<::sir::UserdefinedType*, ::skill::api::Map<::sir::FieldLike*, ::skill::api::String>*>(); - if(sTool->getSelectedFields() != nullptr) - delete sTool->getSelectedFields(); - sTool->setSelectedFields(fields); + if(sTool->getSelFields() != nullptr) + delete sTool->getSelFields(); + sTool->setSelFields(fields); // Copy field data for(auto& j : i.second.getStatesFields()) { @@ -736,10 +739,49 @@ namespace { tmp = fields->find(static_cast(this->types[const_cast(k.first)])); } - (*(tmp->second))[this->field[const_cast(j.first)]] = s; + auto& tmp2 = (*fields)[static_cast(this->types[const_cast(k.first)])]; + (*tmp2)[this->field[const_cast(j.first)]] = s; } } } + + // Update codegen data + { + if(sTool->getSelectedUserTypes() == nullptr) + sTool->setSelectedUserTypes(new skill::api::Set(0)); + if(sTool->getSelectedFields() == nullptr) + sTool->setSelectedFields(new skill::api::Map*>()); + auto& forCMDType = *(sTool->getSelectedUserTypes()); + forCMDType.clear(); + auto& forCMDField = *(sTool->getSelectedFields()); + forCMDField.clear(); + + // Bugfix for interfaces + for(auto& j : this->types) { + if(i.second.getTypeTransitiveState(*j.first) < TYPE_STATE::READ) + continue; + auto nothing = []() -> void {}; + doBaseType(j.first, nothing, [&i, j]() -> void { + for(auto& k : getFields(*j.first)) + i.second.setFieldState(*j.first, k, FIELD_STATE::READ); + }, nothing, nothing, nothing); + } + + // Set data + for(auto j : this->types) + if(dynamic_cast(j.second) != nullptr) + if(i.second.getTypeTransitiveState(*j.first) >= TYPE_STATE::READ) { + forCMDType.insert(dynamic_cast(j.second)); + auto fieldsRef = new skill::api::Map(); + forCMDField[dynamic_cast(j.second)] = fieldsRef; + for(auto& k : listAllFields(*(j.first))) + if(i.second.getFieldTransitiveState(*k) >= FIELD_STATE::READ) { + auto tmp = this->field.find(const_cast(k)); + if(tmp != this->field.end()) + (*fieldsRef)[this->newSirString(j.first->getName())] = tmp->second; + } + } + } } this->saveToolData.clear(); this->saveTools.clear(); diff --git a/src/gui/loadFile.cpp b/src/gui/loadFile.cpp index ac7b1b8..4d4ab2a 100644 --- a/src/gui/loadFile.cpp +++ b/src/gui/loadFile.cpp @@ -1,9 +1,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -21,12 +23,53 @@ static thread& loader_thread = *_loader_thread; static Glib::RefPtr outputFile; static std::string filePath; static sirEdit::data::Serializer* ser; +static mutex saveMutex; -std::string sirEdit::getSavePath() { +extern std::string sirEdit::getSavePath() { return outputFile->get_parent()->get_path(); } +extern std::string sirEdit::getSirPath() { + return filePath; +} +extern std::string sirEdit::getSpec(const sirEdit::data::Tool* tool) { + // Global spec? + bool wasGlobal = false; + if(tool == nullptr) { + wasGlobal = true; + auto* t = new sirEdit::data::Tool("@@ALL@@", "", ""); + tool = t; + for(auto& i : ser->getTypes()) + for(auto& j : sirEdit::data::getFields(*i)) + t->setFieldState(*i, j, sirEdit::data::FIELD_STATE::READ); + ser->addTool(t); + } + // Save + sirEdit::doSave(); -void sirEdit::doSave(bool blocking) { + // Call codegen + std::string path = filePath.substr(0, filePath.rfind("/")); + sirEdit::runCodegen({filePath, "-t", tool->getName(), "-b"}, path); + + // Read data + string result; + { + auto fileSize = ifstream(path + "/specification.skill", ios::ate | ios::binary).tellg(); + result.resize(fileSize); + ifstream in(path + "/specification.skill", ios::binary); + in.read(const_cast(&(result[0])), fileSize); + } + + // Was global spec? + if(wasGlobal) { + ser->removeTool(const_cast(tool)); + sirEdit::doSave(); + } + + // Return + return result; +} + +extern void sirEdit::doSave(bool blocking) { // Save function auto toRunFunc = []() -> void { char buffer[256]; @@ -41,16 +84,19 @@ void sirEdit::doSave(bool blocking) { }; // TODO: Asyc - ser->prepareSave(); - ser->save(); - toRunFunc(); + { + lock_guard __lock__(saveMutex); + ser->prepareSave(); + ser->save(); + toRunFunc(); + } } inline void loadFileThread(Gtk::Window* mainWindow, Gtk::Window* popup, Glib::RefPtr file) { outputFile = file; // Create tmpfile - string fileName = tmpnam(nullptr); // TODO: replace tmpnam + string fileName = string(tmpnam(nullptr)) + ".sir"; filePath = fileName; FILE* output = fopen(fileName.c_str(), "w"); @@ -90,19 +136,19 @@ inline void loadFileThread(Gtk::Window* mainWindow, Gtk::Window* popup, Glib::Re } }); cv.wait(lock); -} -extern void sirEdit::loadFile(Gtk::Window* window, Gtk::FileChooserNative* chooser) { // Autosave new thread([]() -> void { if(ended) return; - runInGui([]() -> void { - doSave(false); + sirEdit::runInGui([]() -> void { + sirEdit::doSave(false); }); sleep(30); }); +} +extern void sirEdit::loadFile(Gtk::Window* window, Gtk::FileChooserNative* chooser) { // Start loader auto files = chooser->get_files(); if(files.size() != 1)