X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=tools%2Fsetupgen%2Fsetupgen.cpp;fp=tools%2Fsetupgen%2Fsetupgen.cpp;h=950667794e818082487348ca69bc16655e620710;hb=3b551a2caabdfebaac592b5fcbbeb6cbfe2fd43f;hp=0000000000000000000000000000000000000000;hpb=8420959665d2a2cfeed3e50dc0d706b9b7570414;p=libs%2Fgame.git diff --git a/tools/setupgen/setupgen.cpp b/tools/setupgen/setupgen.cpp new file mode 100644 index 0000000..9506677 --- /dev/null +++ b/tools/setupgen/setupgen.cpp @@ -0,0 +1,214 @@ +#include "setupgen.h" +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace Msp; + +SetupGen::SetupGen(int argc, char **argv) +{ + GetOpt getopt; + getopt.add_option('o', "output", out_fn, GetOpt::REQUIRED_ARG); + getopt.add_argument("input_file", in_fn, GetOpt::REQUIRED_ARG); + getopt(argc, argv); +} + +int SetupGen::main() +{ + create_standard_types(); + load(); + + collect_headers(); + + if(out_fn.empty()) + { + generate_header(IO::cout); + generate_code(IO::cout); + } + else + { + string out_base = FS::basename(out_fn); + string out_ext = FS::extpart(out_base); + if(out_ext==".cpp" || out_ext==".h") + { + 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); + 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()) + IO::print(code_out, "#include \n"); + generate_code(code_out); + } + else + { + IO::BufferedFile out(out_fn, IO::M_WRITE); + generate_header(out); + out.put('\n'); + generate_code(out); + } + } + + return 0; +} + +void SetupGen::create_standard_types() +{ + add_type("bool", Type::VALUE); + add_type("int", Type::VALUE); + add_type("uint", Type::VALUE).set_cpp_type("unsigned"); + const Type &float_type = add_type("float", Type::VALUE); + add_type("string", Type::VALUE).set_cpp_type("std::string", "string"); + add_type("angle", Type::VALUE).set_cpp_type("Msp::Geometry::Angle", "msp/geometry/angle.h") + .set_load("float", "Msp::Geometry::Angle::from_degrees"); + add_type("vector2", Type::AGGREGATE).set_cpp_type("Msp::LinAl::Vector", "msp/linal/vector.h") + .set_elements(float_type, 2); + add_type("vector3", Type::AGGREGATE).set_cpp_type("Msp::LinAl::Vector", "msp/linal/vector.h") + .set_elements(float_type, 3); +} + +Type &SetupGen::add_type(const string &n, Type::Kind k) +{ + auto result = types.try_emplace(n, n, k); + if(!result.second) + throw key_error(n); + return result.first->second; +} + +const Type &SetupGen::get_type(const string &n) const +{ + return get_item(types, n); +} + +void SetupGen::load() +{ + IO::BufferedFile in_file(in_fn); + DataFile::Parser parser(in_file, in_fn); + Loader ldr(*this); + ldr.load(parser); +} + +void SetupGen::collect_headers() +{ + headers.insert("msp/datafile/objectloader.h"); + headers.insert("msp/strings/lexicalcast.h"); + for(const unique_ptr &s: 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 +{ + string guard = toupper(FS::basepart(FS::basename(out_fn.empty() ? in_fn : out_fn)))+"_H_"; + if(!name_space.empty()) + { + vector parts = split(name_space, "::"); + parts.emplace_back(move(guard)); + guard = join(parts.begin(), parts.end(), "_"); + } + IO::print(out, "#ifndef %s\n", guard); + IO::print(out, "#define %s\n", guard); + + if(!headers.empty()) + { + out.put('\n'); + for(const string &h: headers) + IO::print(out, "#include <%s>\n", h); + } + + if(!name_space.empty()) + IO::print(out, "\nnamespace %s {\n", name_space); + + for(const unique_ptr &e: enums) + { + out.put('\n'); + e->define_type(out); + } + + for(const unique_ptr &s: structs) + { + out.put('\n'); + s->define_type(out); + } + + for(const unique_ptr &s: structs) + { + out.put('\n'); + s->define_loader(out); + } + + for(const unique_ptr &e: enums) + { + out.put('\n'); + e->declare_conversions(out); + } + + if(!name_space.empty()) + IO::print(out, "\n} // namespace %s\n", name_space); + + IO::print(out, "\n#endif\n"); +} + +void SetupGen::generate_code(IO::Base &out) const +{ + if(!name_space.empty()) + IO::print(out, "\nnamespace %s {\n", name_space); + + for(const unique_ptr &s: structs) + { + out.put('\n'); + s->define_functions(out); + } + + for(const unique_ptr &e: enums) + { + out.put('\n'); + e->define_conversions(out); + } + + if(!name_space.empty()) + IO::print(out, "\n} // namespace %s\n", name_space); +} + + +SetupGen::Loader::Loader(SetupGen &s): + ObjectLoader(s) +{ + static ActionMap shared_actions; + set_actions(shared_actions); +} + +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("namespace", &Loader::name_space); +} + +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(move(en)))); +} + +void SetupGen::Loader::name_space(const string &ns) +{ + obj.name_space = ns; +} + +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(move(sct)))); +}