]> git.tdb.fi Git - libs/game.git/blobdiff - tools/setupgen/setupgen.cpp
Add import functionality for setup modules
[libs/game.git] / tools / setupgen / setupgen.cpp
index 950667794e818082487348ca69bc16655e620710..571396ff0cfad6dfe80a26a6e760327aa8a7acf6 100644 (file)
@@ -1,6 +1,8 @@
 #include "setupgen.h"
+#include <algorithm>
 #include <msp/core/getopt.h>
 #include <msp/core/maputils.h>
+#include <msp/fs/stat.h>
 #include <msp/fs/utils.h>
 #include <msp/io/console.h>
 #include <msp/io/print.h>
@@ -11,23 +13,29 @@ using namespace Msp;
 
 SetupGen::SetupGen(int argc, char **argv)
 {
+       vector<string> import_dirs;
+
        GetOpt getopt;
+       getopt.add_option('I', "importdir", import_dirs, GetOpt::REQUIRED_ARG);
        getopt.add_option('o', "output", out_fn, GetOpt::REQUIRED_ARG);
        getopt.add_argument("input_file", in_fn, GetOpt::REQUIRED_ARG);
        getopt(argc, argv);
+
+       import_path.insert(import_path.end(), import_dirs.begin(), import_dirs.end());
 }
 
 int SetupGen::main()
 {
        create_standard_types();
-       load();
+       load(in_fn);
 
-       collect_headers();
+       const Module &main_mod = modules.front();
+       collect_headers(main_mod);
 
        if(out_fn.empty())
        {
-               generate_header(IO::cout);
-               generate_code(IO::cout);
+               generate_header(main_mod, IO::cout);
+               generate_code(main_mod, IO::cout);
        }
        else
        {
@@ -38,19 +46,19 @@ int SetupGen::main()
                        FS::Path out_dir = FS::dirname(out_fn);
                        out_base = FS::basepart(out_base);
                        IO::BufferedFile header_out((out_dir/(out_base+".h")).str(), IO::M_WRITE);
-                       generate_header(header_out);
+                       generate_header(main_mod, header_out);
                        IO::BufferedFile code_out((out_dir/(out_base+".cpp")).str(), IO::M_WRITE);
                        IO::print(code_out, "#include \"%s.h\"\n", out_base);
-                       if(!enums.empty())
+                       if(!main_mod.enums.empty())
                                IO::print(code_out, "#include <msp/strings/format.h>\n");
-                       generate_code(code_out);
+                       generate_code(main_mod, code_out);
                }
                else
                {
                        IO::BufferedFile out(out_fn, IO::M_WRITE);
-                       generate_header(out);
+                       generate_header(main_mod, out);
                        out.put('\n');
-                       generate_code(out);
+                       generate_code(main_mod, out);
                }
        }
 
@@ -85,30 +93,31 @@ const Type &SetupGen::get_type(const string &n) const
        return get_item(types, n);
 }
 
-void SetupGen::load()
+void SetupGen::load(const FS::Path &fn)
 {
-       IO::BufferedFile in_file(in_fn);
-       DataFile::Parser parser(in_file, in_fn);
-       Loader ldr(*this);
+       Module &mod = modules.emplace_back();
+       IO::BufferedFile in_file(fn.str());
+       DataFile::Parser parser(in_file, fn.str());
+       Loader ldr(*this, mod);
        ldr.load(parser);
 }
 
-void SetupGen::collect_headers()
+void SetupGen::collect_headers(const Module &mod)
 {
        headers.insert("msp/datafile/objectloader.h");
        headers.insert("msp/strings/lexicalcast.h");
-       for(const unique_ptr<Struct> &s: structs)
+       for(const unique_ptr<Struct> &s: mod.structs)
                for(const Struct::Field &f: s->get_fields())
                        if(const string &h = f.type->get_header(); !h.empty())
                                headers.insert(h);
 }
 
-void SetupGen::generate_header(IO::Base &out) const
+void SetupGen::generate_header(const Module &mod, IO::Base &out) const
 {
        string guard = toupper(FS::basepart(FS::basename(out_fn.empty() ? in_fn : out_fn)))+"_H_";
-       if(!name_space.empty())
+       if(!mod.name_space.empty())
        {
-               vector<string> parts = split(name_space, "::");
+               vector<string> parts = split(mod.name_space, "::");
                parts.emplace_back(move(guard));
                guard = join(parts.begin(), parts.end(), "_");
        }
@@ -122,63 +131,64 @@ void SetupGen::generate_header(IO::Base &out) const
                        IO::print(out, "#include <%s>\n", h);
        }
 
-       if(!name_space.empty())
-               IO::print(out, "\nnamespace %s {\n", name_space);
+       if(!mod.name_space.empty())
+               IO::print(out, "\nnamespace %s {\n", mod.name_space);
 
-       for(const unique_ptr<Enum> &e: enums)
+       for(const unique_ptr<Enum> &e: mod.enums)
        {
                out.put('\n');
                e->define_type(out);
        }
 
-       for(const unique_ptr<Struct> &s: structs)
+       for(const unique_ptr<Struct> &s: mod.structs)
        {
                out.put('\n');
                s->define_type(out);
        }
 
-       for(const unique_ptr<Struct> &s: structs)
+       for(const unique_ptr<Struct> &s: mod.structs)
        {
                out.put('\n');
                s->define_loader(out);
        }
 
-       for(const unique_ptr<Enum> &e: enums)
+       for(const unique_ptr<Enum> &e: mod.enums)
        {
                out.put('\n');
                e->declare_conversions(out);
        }
 
-       if(!name_space.empty())
-               IO::print(out, "\n}  // namespace %s\n", name_space);
+       if(!mod.name_space.empty())
+               IO::print(out, "\n}  // namespace %s\n", mod.name_space);
 
        IO::print(out, "\n#endif\n");
 }
 
-void SetupGen::generate_code(IO::Base &out) const
+void SetupGen::generate_code(const Module &mod, IO::Base &out) const
 {
-       if(!name_space.empty())
-               IO::print(out, "\nnamespace %s {\n", name_space);
+       if(!mod.name_space.empty())
+               IO::print(out, "\nnamespace %s {\n", mod.name_space);
 
-       for(const unique_ptr<Struct> &s: structs)
+       for(const unique_ptr<Struct> &s: mod.structs)
        {
                out.put('\n');
                s->define_functions(out);
        }
 
-       for(const unique_ptr<Enum> &e: enums)
+       for(const unique_ptr<Enum> &e: mod.enums)
        {
                out.put('\n');
                e->define_conversions(out);
        }
 
-       if(!name_space.empty())
-               IO::print(out, "\n}  // namespace %s\n", name_space);
+       if(!mod.name_space.empty())
+               IO::print(out, "\n}  // namespace %s\n", mod.name_space);
 }
 
 
-SetupGen::Loader::Loader(SetupGen &s):
-       ObjectLoader<SetupGen>(s)
+SetupGen::Loader::Loader(SetupGen &s, Module &m):
+       ObjectLoader<SetupGen>(s),
+       mod(m)
 {
        static ActionMap shared_actions;
        set_actions(shared_actions);
@@ -189,6 +199,7 @@ void SetupGen::Loader::init_actions()
        add("component", &Loader::struct_def, Struct::COMPONENT);
        add("entity", &Loader::struct_def, Struct::ENTITY);
        add("enum", &Loader::enum_def);
+       add("import", &Loader::import);
        add("namespace", &Loader::name_space);
 }
 
@@ -197,12 +208,26 @@ void SetupGen::Loader::enum_def(const DataFile::Symbol &n)
        Enum en(n.name);
        load_sub(en);
        Type &type = obj.add_type(n.name, Type::ENUM);
-       type.set_enum(*obj.enums.emplace_back(make_unique<Enum>(move(en))));
+       type.set_enum(*mod.enums.emplace_back(make_unique<Enum>(move(en))));
+}
+
+void SetupGen::Loader::import(const string &n)
+{
+       string fn = n+".mgs";
+       FS::Path full_path;
+       if(!ranges::any_of(obj.import_path, [&full_path, &fn](const FS::Path &p){
+                       full_path = p/fn;
+                       return FS::exists(full_path);
+               }))
+               throw IO::file_not_found(fn);
+
+       obj.load(full_path);
+       obj.headers.insert(n+".h");
 }
 
 void SetupGen::Loader::name_space(const string &ns)
 {
-       obj.name_space = ns;
+       mod.name_space = ns;
 }
 
 void SetupGen::Loader::struct_def(Struct::Kind kind, const DataFile::Symbol &n)
@@ -210,5 +235,5 @@ void SetupGen::Loader::struct_def(Struct::Kind kind, const DataFile::Symbol &n)
        Struct sct(n.name+"Setup", kind);
        load_sub(sct, obj);
        Type &type = obj.add_type(n.name, Type::STRUCT);
-       type.set_struct(*obj.structs.emplace_back(make_unique<Struct>(move(sct))));
+       type.set_struct(*mod.structs.emplace_back(make_unique<Struct>(move(sct))));
 }