3 #include <msp/core/getopt.h>
4 #include <msp/core/maputils.h>
5 #include <msp/fs/stat.h>
6 #include <msp/fs/utils.h>
7 #include <msp/io/console.h>
8 #include <msp/io/print.h>
9 #include <msp/strings/utils.h>
14 SetupGen::SetupGen(int argc, char **argv)
16 vector<string> import_dirs;
19 getopt.add_option('I', "importdir", import_dirs, GetOpt::REQUIRED_ARG);
20 getopt.add_option('o', "output", out_fn, GetOpt::REQUIRED_ARG);
21 getopt.add_argument("input_file", in_fn, GetOpt::REQUIRED_ARG);
24 import_path.insert(import_path.end(), import_dirs.begin(), import_dirs.end());
29 create_standard_types();
32 const Module &main_mod = modules.front();
33 collect_headers(main_mod);
37 generate_header(main_mod, IO::cout);
38 generate_code(main_mod, IO::cout);
42 string out_base = FS::basename(out_fn);
43 string out_ext = FS::extpart(out_base);
44 if(out_ext==".cpp" || out_ext==".h")
46 FS::Path out_dir = FS::dirname(out_fn);
47 out_base = FS::basepart(out_base);
48 IO::BufferedFile header_out((out_dir/(out_base+".h")).str(), IO::M_WRITE);
49 generate_header(main_mod, header_out);
50 IO::BufferedFile code_out((out_dir/(out_base+".cpp")).str(), IO::M_WRITE);
51 IO::print(code_out, "#include \"%s.h\"\n", out_base);
52 if(!main_mod.enums.empty())
53 IO::print(code_out, "#include <msp/strings/format.h>\n");
54 generate_code(main_mod, code_out);
58 IO::BufferedFile out(out_fn, IO::M_WRITE);
59 generate_header(main_mod, out);
61 generate_code(main_mod, out);
68 void SetupGen::create_standard_types()
70 add_type("bool", Type::VALUE);
71 add_type("int", Type::VALUE);
72 add_type("uint", Type::VALUE).set_cpp_type("unsigned");
73 const Type &float_type = add_type("float", Type::VALUE);
74 add_type("string", Type::VALUE).set_cpp_type("std::string", "string");
75 add_type("angle", Type::VALUE).set_cpp_type("Msp::Geometry::Angle<float>", "msp/geometry/angle.h")
76 .set_load("float", "Msp::Geometry::Angle<float>::from_degrees");
77 add_type("vector2", Type::AGGREGATE).set_cpp_type("Msp::LinAl::Vector<float, 2>", "msp/linal/vector.h")
78 .set_elements(float_type, 2);
79 add_type("vector3", Type::AGGREGATE).set_cpp_type("Msp::LinAl::Vector<float, 3>", "msp/linal/vector.h")
80 .set_elements(float_type, 3);
83 Type &SetupGen::add_type(const string &n, Type::Kind k)
85 auto result = types.try_emplace(n, n, k);
88 return result.first->second;
91 const Type &SetupGen::get_type(const string &n) const
93 return get_item(types, n);
96 void SetupGen::load(const FS::Path &fn)
98 Module &mod = modules.emplace_back();
99 IO::BufferedFile in_file(fn.str());
100 DataFile::Parser parser(in_file, fn.str());
101 Loader ldr(*this, mod);
105 void SetupGen::collect_headers(const Module &mod)
107 headers.insert("msp/datafile/objectloader.h");
108 headers.insert("msp/strings/lexicalcast.h");
109 for(const unique_ptr<Struct> &s: mod.structs)
110 for(const Struct::Field &f: s->get_fields())
111 if(const string &h = f.type->get_header(); !h.empty())
115 void SetupGen::generate_header(const Module &mod, IO::Base &out) const
117 string guard = toupper(FS::basepart(FS::basename(out_fn.empty() ? in_fn : out_fn)))+"_H_";
118 if(!mod.name_space.empty())
120 vector<string> parts = split(mod.name_space, "::");
121 parts.emplace_back(move(guard));
122 guard = join(parts.begin(), parts.end(), "_");
124 IO::print(out, "#ifndef %s\n", guard);
125 IO::print(out, "#define %s\n", guard);
130 for(const string &h: headers)
131 IO::print(out, "#include <%s>\n", h);
134 if(!mod.name_space.empty())
135 IO::print(out, "\nnamespace %s {\n", mod.name_space);
137 for(const unique_ptr<Enum> &e: mod.enums)
143 for(const unique_ptr<Struct> &s: mod.structs)
149 for(const unique_ptr<Struct> &s: mod.structs)
152 s->define_loader(out);
155 for(const unique_ptr<Enum> &e: mod.enums)
158 e->declare_conversions(out);
161 if(!mod.name_space.empty())
162 IO::print(out, "\n} // namespace %s\n", mod.name_space);
164 IO::print(out, "\n#endif\n");
167 void SetupGen::generate_code(const Module &mod, IO::Base &out) const
169 if(!mod.name_space.empty())
170 IO::print(out, "\nnamespace %s {\n", mod.name_space);
172 for(const unique_ptr<Struct> &s: mod.structs)
175 s->define_functions(out);
178 for(const unique_ptr<Enum> &e: mod.enums)
181 e->define_conversions(out);
184 if(!mod.name_space.empty())
185 IO::print(out, "\n} // namespace %s\n", mod.name_space);
189 SetupGen::Loader::Loader(SetupGen &s, Module &m):
190 ObjectLoader<SetupGen>(s),
193 static ActionMap shared_actions;
194 set_actions(shared_actions);
197 void SetupGen::Loader::init_actions()
199 add("component", &Loader::struct_def, Struct::COMPONENT);
200 add("entity", &Loader::struct_def, Struct::ENTITY);
201 add("enum", &Loader::enum_def);
202 add("import", &Loader::import);
203 add("namespace", &Loader::name_space);
206 void SetupGen::Loader::enum_def(const DataFile::Symbol &n)
210 Type &type = obj.add_type(n.name, Type::ENUM);
211 type.set_enum(*mod.enums.emplace_back(make_unique<Enum>(move(en))));
214 void SetupGen::Loader::import(const string &n)
216 string fn = n+".mgs";
218 if(!ranges::any_of(obj.import_path, [&full_path, &fn](const FS::Path &p){
220 return FS::exists(full_path);
222 throw IO::file_not_found(fn);
225 obj.headers.insert(n+".h");
228 void SetupGen::Loader::name_space(const string &ns)
233 void SetupGen::Loader::struct_def(Struct::Kind kind, const DataFile::Symbol &n)
235 Struct sct(n.name+"Setup", kind);
237 Type &type = obj.add_type(n.name, Type::STRUCT);
238 type.set_struct(*mod.structs.emplace_back(make_unique<Struct>(move(sct))));