00001 #include "CPPParser.hpp"
00002 #include "CPPLexer.hpp"
00003 #include "typesolver.hh"
00004 #include <typelib/registry.hh>
00005 #include <utilmm/stringtools.hh>
00006 #include "packing.hh"
00007 #include <typelib/typevisitor.hh>
00008
00009 #include <iostream>
00010 #include <numeric>
00011 #include <sstream>
00012 #include <cassert>
00013
00014 using namespace std;
00015 using namespace Typelib;
00016 using utilmm::join;
00017
00018 ostream& operator << (ostream& io, TypeSolver::CurrentTypeDefinition const& def)
00019 {
00020 return io << " " << join(def.name, " ") << " [" << join(def.array, ", ") << "] " << def.pointer_level;
00021 }
00022
00023 TypeSolver::TypeSolver(const antlr::ParserSharedInputState& state, Registry& registry, bool cxx_mode)
00024 : CPPParser(state), m_class_object(0), m_registry(registry), m_cxx_mode(cxx_mode)
00025 , m_opaques_forced_alignment(true), m_opaques_ignore(false) {}
00026
00027 TypeSolver::TypeSolver(antlr::TokenStream& lexer, Registry& registry, bool cxx_mode)
00028 : CPPParser(lexer), m_class_object(0), m_registry(registry), m_cxx_mode(cxx_mode)
00029 , m_opaques_forced_alignment(true), m_opaques_ignore(false) {}
00030
00031 void TypeSolver::setupOpaqueHandling(bool forced_alignment, bool ignore)
00032 {
00033 m_opaques_forced_alignment = forced_alignment;
00034 m_opaques_ignore = ignore;
00035 }
00036 void TypeSolver::defineOpaqueAlignment(std::string const& type_name, size_t value)
00037 {
00038 cerr << type_name << " is aligned on " << value << endl;
00039 m_opaques_alignment[type_name] = value;
00040 }
00041
00042 void TypeSolver::setTypename(std::string const& name)
00043 {
00044 std::string type_name = name, alias_name = name;
00045
00046
00047 { std::string* prefixed_name;
00048 if (m_cxx_mode) prefixed_name = &alias_name;
00049 else prefixed_name = &type_name;
00050
00051 if (m_class_type == tsENUM)
00052 *prefixed_name = "enum " + *prefixed_name;
00053 else if (m_class_type == tsUNION)
00054 *prefixed_name = "union " + *prefixed_name;
00055 else if (m_class_type == tsSTRUCT)
00056 *prefixed_name = "struct " + *prefixed_name;
00057 }
00058
00059 m_class_object->setName(m_registry.getFullName(type_name));
00060 m_registry.add(m_class_object);
00061 if (m_cxx_mode)
00062 m_registry.alias(m_class_object->getName(), m_registry.getFullName(alias_name));
00063 }
00064
00065 void TypeSolver::beginTypeDefinition(TypeSpecifier class_type, const std::string& name)
00066 {
00067 if (m_class_object)
00068 throw NestedTypeDefinition(name, m_class_object->getName());
00069
00070 m_class_type = class_type;
00071 if (m_class_type == tsENUM)
00072 m_class_object = new Enum("");
00073 else
00074 m_class_object = new Compound("");
00075
00076 if (name != "" && name != "anonymous")
00077 setTypename(name);
00078 }
00079
00080 void TypeSolver::beginClassDefinition(TypeSpecifier class_type, const std::string& name)
00081 {
00082 beginTypeDefinition(class_type, name);
00083 CPPParser::beginClassDefinition(class_type, name);
00084 }
00085
00086 void TypeSolver::endClassDefinition()
00087 {
00088 if (!m_class_object->getName().empty())
00089 buildClassObject();
00090
00091 CPPParser::endClassDefinition();
00092 }
00093
00094 void TypeSolver::enterNamespace(std::string const& name)
00095 {
00096 m_namespace.push_back(name);
00097 m_registry.setDefaultNamespace( "/" + utilmm::join(m_namespace, "/") );
00098 }
00099
00100 void TypeSolver::exitNamespace()
00101 {
00102 m_namespace.pop_back();
00103 m_registry.setDefaultNamespace( "/" + utilmm::join(m_namespace, "/") );
00104 }
00105
00106 void TypeSolver::beginEnumDefinition(const std::string& name)
00107 {
00108 if (m_class_object)
00109 {
00110 CurrentTypeDefinition& def = pushNewType();
00111 def.name.push_back("enum");
00112 def.name.push_back(name);
00113 }
00114 else
00115 beginTypeDefinition(tsENUM, name);
00116 CPPParser::beginEnumDefinition(name);
00117 }
00118
00119 void TypeSolver::enumElement(const std::string& name, bool has_value, int value)
00120 {
00121 if (m_class_type != tsENUM)
00122 throw NestedTypeDefinition(m_current.front().name.back(), m_class_object->getName());
00123
00124 Enum& enum_type = dynamic_cast<Enum&>(*m_class_object);
00125 if (!has_value)
00126 value = enum_type.getNextValue();
00127
00128 enum_type.add(name, value);
00129 m_constants[name] = value;
00130 CPPParser::enumElement(name, has_value, value);
00131 }
00132
00133 void TypeSolver::endEnumDefinition()
00134 {
00135 CPPParser::endEnumDefinition();
00136
00137 if (m_class_type != tsENUM)
00138 return;
00139
00140 if (! m_class_object->getName().empty())
00141 buildClassObject();
00142 }
00143
00144 void TypeSolver::beginTypedef()
00145 {
00146 pushNewType();
00147 CPPParser::beginTypedef();
00148 }
00149
00150 int TypeSolver::getIntConstant(std::string const& name)
00151 {
00152 map<string, int>::iterator it = m_constants.find(name);
00153 if (it != m_constants.end())
00154 return it->second;
00155 else
00156 throw InvalidConstantName(name);
00157 }
00158
00159 int TypeSolver::getTypeSize(CurrentTypeDefinition const& def)
00160 {
00161 string def_name = join(def.name, " ");
00162 Type const* t = m_registry.build(def_name);
00163 if (t)
00164 return t->getSize();
00165 else
00166 throw InvalidTypeName(def_name);
00167 }
00168
00169 Type& TypeSolver::buildClassObject()
00170 {
00171 CurrentTypeDefinition& def = pushNewType();
00172 def.name.push_back(m_class_object->getName());
00173
00174 if (m_class_type == tsSTRUCT)
00175 {
00176 size_t size = 0;
00177 Compound& compound(dynamic_cast<Compound&>(*m_class_object));
00178 try {
00179 size = Packing::getSizeOfCompound(compound);
00180 compound.setSize(size);
00181 }
00182 catch(Typelib::UnsupportedType)
00183 {
00184
00185 if (!m_opaques_ignore)
00186 throw;
00187 }
00188 }
00189
00190 Type* object = m_class_object;
00191 m_class_object = 0;
00192 m_class_type = 0;
00193 return *object;
00194 }
00195
00196 void TypeSolver::beginFieldDeclaration()
00197 {
00198 pushNewType();
00199 CPPParser::beginFieldDeclaration();
00200 }
00201 void TypeSolver::endFieldDeclaration()
00202 { CPPParser::endFieldDeclaration(); }
00203
00204
00205 void TypeSolver::foundSimpleType(const std::list<std::string>& full_type)
00206 {
00207 if (!m_current.empty() && m_current.front().name.empty())
00208 {
00209 m_current.front().name = full_type;
00210 }
00211
00212 CPPParser::foundSimpleType(full_type);
00213 }
00214
00215 void TypeSolver::classForwardDeclaration(TypeSpecifier ts, DeclSpecifier ds, const std::string& name)
00216 {
00217 CurrentTypeDefinition& def = pushNewType();
00218 if (ts == tsSTRUCT)
00219 def.name.push_back("struct");
00220 else if (ts == tsUNION)
00221 def.name.push_back("union");
00222
00223 def.name.push_back(name);
00224
00225 CPPParser::classForwardDeclaration(ts, ds, name);
00226 }
00227
00228 BOOST_STATIC_ASSERT( sizeof(vector<int8_t>) == sizeof(vector<double>) );
00229 BOOST_STATIC_ASSERT( sizeof(set<int8_t>) == sizeof(set<double>) );
00230 BOOST_STATIC_ASSERT( sizeof(map<int8_t,int16_t>) == sizeof(map<double,float>) );
00231 struct TemplateDef {
00232 char const* name;
00233 size_t size;
00234 };
00235 TemplateDef const ALLOWED_TEMPLATES[] = {
00236 { "std/vector", sizeof(vector<int>) },
00237 { "std/set", sizeof(set<int>) },
00238 { "std/map", sizeof(map<int, int>) },
00239 { 0, 0 }
00240 };
00241
00242 Typelib::Type const& TypeSolver::buildCurrentType()
00243 {
00244 if (m_current.empty())
00245 throw TypeStackEmpty("buildCurrentType");
00246
00247 CurrentTypeDefinition type_def = popType();
00248 std::auto_ptr<TypeBuilder> builder;
00249
00250
00251
00252 if (!type_def.template_args.empty())
00253 {
00254 typedef Container::AvailableContainers Containers;
00255 typedef std::list<std::string> stringlist;
00256
00257 string fullname = join(type_def.name, "/");
00258 if (fullname[0] != '/')
00259 fullname = "/" + fullname;
00260
00261 Containers containers = Container::availableContainers();
00262 Containers::const_iterator factory = containers.find(fullname);
00263 if (factory == containers.end())
00264 throw Undefined(fullname);
00265
00266 std::list<Type const*> template_args;
00267 for (stringlist::const_iterator it = type_def.template_args.begin();
00268 it != type_def.template_args.end(); ++it)
00269 {
00270 template_args.push_back( m_registry.build( *it ) );
00271 }
00272
00273 Type const* container_t =
00274 &(*factory->second)(m_registry, template_args);
00275 builder.reset(new TypeBuilder(m_registry, container_t));
00276 }
00277 else
00278 {
00279 builder.reset(new TypeBuilder(m_registry, type_def.name));
00280 }
00281
00282 if (type_def.pointer_level)
00283 builder->addPointer(type_def.pointer_level);
00284
00285 while (!type_def.array.empty())
00286 {
00287 builder->addArrayMinor(type_def.array.front());
00288 type_def.array.pop_front();
00289 }
00290
00291 Type const& type = builder->getType();
00292 return type;
00293 }
00294
00295 void TypeSolver::resetPointerLevel()
00296 {
00297 if (!m_current.empty())
00298 m_current.front().pointer_level = 0;
00299 }
00300
00301 void TypeSolver::incrementPointerLevel()
00302 {
00303 if (!m_current.empty())
00304 m_current.front().pointer_level++;
00305 }
00306
00307 TypeSolver::CurrentTypeDefinition TypeSolver::popType()
00308 {
00309 if (m_current.empty())
00310 throw TypeStackEmpty("popType");
00311
00312 CurrentTypeDefinition def = m_current.front();
00313 m_current.pop_front();
00314 return def;
00315 }
00316 TypeSolver::CurrentTypeDefinition& TypeSolver::pushNewType()
00317 {
00318 m_current.push_front( CurrentTypeDefinition() );
00319 return m_current.front();
00320 }
00321 int TypeSolver::getStackSize() const { return m_current.size(); }
00322
00323 void TypeSolver::declaratorID(const std::string& name, QualifiedItem qi)
00324 {
00325 if (m_class_object && m_class_object->getName().empty() && qi == qiType)
00326 {
00327 setTypename(name);
00328 Type& new_type = buildClassObject();
00329 if (! m_cxx_mode)
00330 m_registry.alias(new_type.getName(), m_registry.getFullName(name), "");
00331 }
00332 else if (m_class_object)
00333 {
00334 if (m_class_type != tsENUM)
00335 {
00336
00337
00338
00339
00340 CurrentTypeDefinition def = m_current.front();
00341
00342 Compound& compound = dynamic_cast<Compound&>(*m_class_object);
00343 Type const& field_type = buildCurrentType();
00344 if (m_class_type == tsUNION)
00345 compound.addField(name, field_type, 0);
00346 else if (m_class_type == tsSTRUCT)
00347 {
00348 size_t offset = 0;
00349 if (field_type.getCategory() != Type::Opaque)
00350 offset = Packing::getOffsetOf( compound, field_type );
00351 else
00352 {
00353 size_t explicit_alignment = 0;
00354 AlignmentMap::const_iterator it = m_opaques_alignment.find(field_type.getName());
00355 if (it != m_opaques_alignment.end())
00356 explicit_alignment = it->second;
00357
00358 size_t natural_offset = 0;
00359 Compound::FieldList const& fields(compound.getFields());
00360 if (!fields.empty())
00361 {
00362 Field const& last_field = fields.back();
00363 natural_offset = last_field.getOffset() + last_field.getType().getSize();
00364 }
00365
00366 if (explicit_alignment)
00367 offset = Packing::getOffsetOf( compound, field_type, explicit_alignment );
00368 else if (m_opaques_ignore)
00369 offset = Packing::getOffsetOf( compound, field_type, natural_offset );
00370 else
00371 throw std::runtime_error("do not know how to compute alignment of the opaque field " + name + ": no explicit alignment value provided");
00372
00373 if (m_opaques_forced_alignment && natural_offset != offset)
00374 {
00375 ostringstream msg;
00376 msg << name << " needs to be explicitely aligned on " << explicit_alignment << " bytes, but "
00377 << offset - natural_offset << " padding bytes are missing";
00378
00379 throw std::runtime_error(msg.str());
00380 }
00381 }
00382
00383 compound.addField( name, field_type, offset );
00384 }
00385 else
00386 throw UnsupportedClassType(m_class_type);
00387
00388 def.pointer_level = 0;
00389 def.array.clear();
00390 m_current.push_front(def);
00391 }
00392 }
00393 else if (qi == qiType)
00394 {
00395 Type const& type = buildCurrentType();
00396 string base_name = m_registry.getFullName(type.getName());
00397 string new_name = m_registry.getFullName(name);
00398
00399 Type const* base_type = m_registry.get(base_name);
00400 if (! base_type)
00401 throw Undefined(base_name);
00402
00403
00404
00405 Type const* aliased_type = m_registry.get(new_name);
00406 if (aliased_type)
00407 {
00408 if (!aliased_type->isSame(*base_type))
00409 throw AlreadyDefined(new_name);
00410 }
00411 else
00412 m_registry.alias( base_name, new_name );
00413
00414 }
00415
00416 CPPParser::declaratorID(name, qi);
00417 }
00418
00419 void TypeSolver::declaratorArray(int size)
00420 {
00421 if (!m_current.empty())
00422 m_current.front().array.push_back(size);
00423
00424 CPPParser::declaratorArray(size);
00425 }
00426
00427 void TypeSolver::end_of_stmt()
00428 {
00429 while (! m_current.empty())
00430 popType();
00431 CPPParser::end_of_stmt();
00432 }
00433
00434 void TypeSolver::setTemplateArguments(int count)
00435 {
00436 if (m_current.empty())
00437 throw TypeStackEmpty("setTemplateArguments");
00438
00439 std::list<std::string> template_args;
00440 while (count)
00441 {
00442 Type const& arg_type = buildCurrentType();
00443 template_args.push_front(arg_type.getName());
00444 --count;
00445 }
00446
00447 m_current.front().template_args = template_args;
00448 }
00449