--- /dev/null
+#include "type.h"
+#include <msp/core/except.h>
+#include <msp/strings/format.h>
+#include <msp/strings/utils.h>
+
+using namespace std;
+using namespace Msp;
+
+Type::Type(const string &n, Kind k):
+ name(n),
+ kind(k)
+{
+ if(kind==VALUE || kind==ENUM)
+ cpp_type = name;
+ if(kind==STRUCT)
+ cpp_type = name+"Setup";
+}
+
+Type &Type::set_cpp_type(const string &t, const string &h)
+{
+ cpp_type = t;
+ header = h;
+ return *this;
+}
+
+Type &Type::set_elements(const Type &t, unsigned c)
+{
+ if(kind!=AGGREGATE && kind!=POINTER && kind!=DYN_ARRAY)
+ throw invalid_state("wrong kind");
+ if((kind==POINTER && c>1) || (kind==DYN_ARRAY && c>0))
+ throw invalid_argument("Type::set_elements");
+
+ element_type = &t;
+ element_count = (kind==POINTER ? 1 : c);
+ if(cpp_type.empty())
+ {
+ if(kind==POINTER)
+ cpp_type = format("%s *", t.get_cpp_type());
+ else if(kind==DYN_ARRAY)
+ cpp_type = format("std::vector<%s>", t.get_cpp_type());
+ }
+
+ return *this;
+}
+
+Type &Type::set_struct(const Struct &s)
+{
+ if(kind!=STRUCT)
+ throw invalid_state("wrong kind");
+ struct_def = &s;
+ return *this;
+}
+
+Type &Type::set_enum(const Enum &e)
+{
+ if(kind!=ENUM)
+ throw invalid_state("wrong kind");
+ enum_def = &e;
+ return *this;
+}
+
+Type &Type::set_load(const string &l, const string &c)
+{
+ if(kind!=VALUE)
+ throw invalid_state("wrong kind");
+ load_type = l;
+ conversion = c;
+ return *this;
+}
+
+const Type &Type::get_element_type() const
+{
+ if(kind!=AGGREGATE && kind!=POINTER && kind!=DYN_ARRAY)
+ throw invalid_state("wrong kind");
+ if(!element_type)
+ throw invalid_state("no element type");
+ return *element_type;
+}
+
+const Struct &Type::get_struct() const
+{
+ if(kind!=STRUCT)
+ throw invalid_state("wrong kind");
+ if(!struct_def)
+ throw invalid_state("no struct");
+ return *struct_def;
+}
+
+const Enum &Type::get_enum() const
+{
+ if(kind!=ENUM)
+ throw invalid_state("wrong kind");
+ if(!enum_def)
+ throw invalid_state("no enum");
+ return *enum_def;
+}
+
+bool Type::needs_loader_function() const
+{
+ switch(kind)
+ {
+ case VALUE: return !load_type.empty();
+ case POINTER:
+ case ENUM: return false;
+ case AGGREGATE:
+ case DYN_ARRAY:
+ case STRUCT: return true;
+ default: throw invalid_state("bad kind");
+ }
+}
+
+string Type::create_loader_params(bool with_names) const
+{
+ if(kind==AGGREGATE)
+ {
+ string result;
+ for(unsigned i=0; i<element_count; ++i)
+ {
+ if(with_names)
+ append(result, ", ", format("%s _a%d", element_type->get_cpp_type(), i));
+ else
+ append(result, ", ", element_type->get_cpp_type());
+ }
+ return result;
+ }
+ else if(kind==VALUE)
+ {
+ const string &type = (load_type.empty() ? cpp_type : load_type);
+ return (with_names ? format("%s _a", type) : type);
+ }
+ else if(kind==DYN_ARRAY)
+ {
+ Kind elem_kind = element_type->get_kind();
+ if(elem_kind==VALUE || elem_kind==ENUM)
+ {
+ string type = format("std::vector<%s>", element_type->get_cpp_type());
+ return (with_names ? format("%s _a", type) : type);
+ }
+ else
+ return string();
+ }
+ else if(kind==STRUCT)
+ return string();
+ else
+ throw invalid_state("wrong kind");
+}
+
+string Type::create_loader_statement() const
+{
+ if(kind==AGGREGATE)
+ {
+ string init;
+ for(unsigned i=0; i<element_count; ++i)
+ append(init, ", ", format("_a%d", i));
+ return format("_v = { %s };", init);
+ }
+ else if(kind==VALUE)
+ return format("_v = %s(_a);", (conversion.empty() ? cpp_type : conversion));
+ else if(kind==STRUCT)
+ return "load_sub(_v);";
+ else if(kind==DYN_ARRAY)
+ {
+ Kind elem_kind = element_type->get_kind();
+ if(elem_kind==VALUE || elem_kind==ENUM)
+ return "_v.insert(_v.end(), _a.begin(), _a.end());";
+ else
+ return format("%s _e; load_sub(_e); _v.emplace_back(move(_e));", cpp_type);
+ }
+ else
+ throw invalid_state("wrong kind");
+}