cppEnumType.cxx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file cppEnumType.cxx
  10. * @author drose
  11. * @date 1999-10-25
  12. */
  13. #include "cppEnumType.h"
  14. #include "cppTypedefType.h"
  15. #include "cppExpression.h"
  16. #include "cppSimpleType.h"
  17. #include "cppConstType.h"
  18. #include "cppScope.h"
  19. #include "cppParser.h"
  20. #include "cppIdentifier.h"
  21. #include "indent.h"
  22. /**
  23. * Creates an untyped enum.
  24. */
  25. CPPEnumType::
  26. CPPEnumType(Type type, CPPIdentifier *ident, CPPScope *current_scope,
  27. CPPScope *scope, const CPPFile &file) :
  28. CPPExtensionType(type, ident, current_scope, file),
  29. _scope(scope),
  30. _element_type(NULL),
  31. _last_value(NULL)
  32. {
  33. _parent_scope = (type == T_enum) ? current_scope : scope;
  34. if (ident != NULL) {
  35. ident->_native_scope = current_scope;
  36. }
  37. }
  38. /**
  39. * Creates a typed enum.
  40. */
  41. CPPEnumType::
  42. CPPEnumType(Type type, CPPIdentifier *ident, CPPType *element_type,
  43. CPPScope *current_scope, CPPScope *scope, const CPPFile &file) :
  44. CPPExtensionType(type, ident, current_scope, file),
  45. _scope(scope),
  46. _element_type(element_type),
  47. _last_value(NULL)
  48. {
  49. _parent_scope = (type == T_enum) ? current_scope : scope;
  50. if (ident != NULL) {
  51. ident->_native_scope = current_scope;
  52. }
  53. }
  54. /**
  55. * Returns true if this is a scoped enum.
  56. */
  57. bool CPPEnumType::
  58. is_scoped() const {
  59. return (_type != T_enum);
  60. }
  61. /**
  62. * Returns the integral type used to store enum values.
  63. */
  64. CPPType *CPPEnumType::
  65. get_underlying_type() {
  66. if (_element_type == NULL) {
  67. // This enum is untyped. Use a suitable default, ie. 'int'. In the
  68. // future, we might want to check whether it fits in an int.
  69. static CPPType *default_element_type = NULL;
  70. if (default_element_type == NULL) {
  71. default_element_type =
  72. CPPType::new_type(new CPPConstType(new CPPSimpleType(CPPSimpleType::T_int, 0)));
  73. }
  74. return default_element_type;
  75. } else {
  76. // This enum has an explicit type, so use that.
  77. return CPPType::new_type(new CPPConstType(_element_type));
  78. }
  79. }
  80. /**
  81. *
  82. */
  83. CPPInstance *CPPEnumType::
  84. add_element(const string &name, CPPExpression *value, CPPPreprocessor *preprocessor, const cppyyltype &pos) {
  85. CPPIdentifier *ident = new CPPIdentifier(name);
  86. ident->_native_scope = _parent_scope;
  87. CPPInstance *inst;
  88. if (_type == T_enum) {
  89. // Weakly typed enum.
  90. inst = new CPPInstance(get_underlying_type(), ident);
  91. } else {
  92. // C++11-style strongly typed enum.
  93. inst = new CPPInstance(this, ident);
  94. }
  95. inst->_storage_class |= CPPInstance::SC_constexpr;
  96. _elements.push_back(inst);
  97. if (value == (CPPExpression *)NULL) {
  98. if (_last_value == (CPPExpression *)NULL) {
  99. // This is the first value, and should therefore be 0.
  100. static CPPExpression *const zero = new CPPExpression(0);
  101. value = zero;
  102. } else if (_last_value->_type == CPPExpression::T_integer) {
  103. value = new CPPExpression(_last_value->_u._integer + 1);
  104. } else {
  105. // We may not be able to determine the value just yet. No problem;
  106. // we'll just define it as another expression.
  107. static CPPExpression *const one = new CPPExpression(1);
  108. value = new CPPExpression('+', _last_value, one);
  109. }
  110. }
  111. inst->_initializer = value;
  112. _last_value = value;
  113. if (preprocessor != (CPPPreprocessor *)NULL) {
  114. // Same-line comment?
  115. CPPCommentBlock *comment =
  116. preprocessor->get_comment_on(pos.first_line, pos.file);
  117. if (comment == (CPPCommentBlock *)NULL) {
  118. // Nope. Check for a comment before this line.
  119. comment =
  120. preprocessor->get_comment_before(pos.first_line, pos.file);
  121. if (comment != NULL) {
  122. // This is a bit of a hack, but it prevents us from picking up a same-
  123. // line comment from the previous line.
  124. if (comment->_line_number != pos.first_line - 1 ||
  125. comment->_col_number <= pos.first_column) {
  126. inst->_leading_comment = comment;
  127. }
  128. }
  129. } else {
  130. inst->_leading_comment = comment;
  131. }
  132. }
  133. // Add the value to the enum scope (as per C++11), assuming it's not anonymous.
  134. if (_scope != NULL) {
  135. _scope->add_enum_value(inst);
  136. }
  137. // Now add it to the containing scope as well if it's not an "enum class".
  138. if (!is_scoped() && _parent_scope != NULL) {
  139. _parent_scope->add_enum_value(inst);
  140. }
  141. return inst;
  142. }
  143. /**
  144. * Returns true if the type has not yet been fully specified, false if it has.
  145. */
  146. bool CPPEnumType::
  147. is_incomplete() const {
  148. return false;
  149. }
  150. /**
  151. * Returns true if this declaration is an actual, factual declaration, or
  152. * false if some part of the declaration depends on a template parameter which
  153. * has not yet been instantiated.
  154. */
  155. bool CPPEnumType::
  156. is_fully_specified() const {
  157. if (!CPPDeclaration::is_fully_specified()) {
  158. return false;
  159. }
  160. if (_ident != NULL && !_ident->is_fully_specified()) {
  161. return false;
  162. }
  163. if (_element_type != NULL && !_element_type->is_fully_specified()) {
  164. return false;
  165. }
  166. Elements::const_iterator ei;
  167. for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
  168. if (!(*ei)->is_fully_specified()) {
  169. return false;
  170. }
  171. }
  172. return true;
  173. }
  174. /**
  175. *
  176. */
  177. CPPDeclaration *CPPEnumType::
  178. substitute_decl(CPPDeclaration::SubstDecl &subst,
  179. CPPScope *current_scope, CPPScope *global_scope) {
  180. SubstDecl::const_iterator si = subst.find(this);
  181. if (si != subst.end()) {
  182. return (*si).second;
  183. }
  184. CPPEnumType *rep = new CPPEnumType(*this);
  185. if (_ident != NULL) {
  186. rep->_ident =
  187. _ident->substitute_decl(subst, current_scope, global_scope);
  188. }
  189. if (_element_type != NULL) {
  190. rep->_element_type =
  191. _element_type->substitute_decl(subst, current_scope, global_scope)
  192. ->as_type();
  193. }
  194. bool any_changed = false;
  195. for (size_t i = 0; i < _elements.size(); ++i) {
  196. // We don't just do substitute_decl on the instance, which could lead to
  197. // an infinite recursion.
  198. CPPInstance *element = _elements[i];
  199. CPPExpression *value = element->_initializer->
  200. substitute_decl(subst, current_scope, global_scope)->as_expression();
  201. if (is_scoped()) {
  202. // For a strong enum, we consider the elements to be of this type.
  203. if (value != element->_initializer) {
  204. rep->_elements[i] = new CPPInstance(rep, element->_ident);
  205. rep->_elements[i]->_initializer = value;
  206. any_changed = true;
  207. }
  208. } else if (value != element->_initializer ||
  209. rep->get_underlying_type() != get_underlying_type()) {
  210. // In an unscoped enum, the elements are integers.
  211. rep->_elements[i] = new CPPInstance(rep->get_underlying_type(), element->_ident);
  212. rep->_elements[i]->_initializer = value;
  213. any_changed = true;
  214. }
  215. }
  216. if (rep->_ident == _ident &&
  217. rep->_element_type == _element_type &&
  218. !any_changed) {
  219. delete rep;
  220. rep = this;
  221. }
  222. rep = CPPType::new_type(rep)->as_enum_type();
  223. subst.insert(SubstDecl::value_type(this, rep));
  224. return rep;
  225. }
  226. /**
  227. *
  228. */
  229. void CPPEnumType::
  230. output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
  231. if (!complete && _ident != NULL) {
  232. // If we have a name, use it.
  233. if (cppparser_output_class_keyword) {
  234. out << _type << " ";
  235. }
  236. out << _ident->get_local_name(scope);
  237. } else {
  238. out << _type;
  239. if (_ident != NULL) {
  240. out << " " << _ident->get_local_name(scope);
  241. }
  242. if (_element_type != NULL) {
  243. out << " : " << _element_type->get_local_name(scope);
  244. }
  245. out << " {\n";
  246. Elements::const_iterator ei;
  247. for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
  248. indent(out, indent_level + 2) << (*ei)->get_local_name();
  249. if ((*ei)->_initializer != NULL) {
  250. out << " = " << *(*ei)->_initializer;
  251. }
  252. out << ",\n";
  253. }
  254. indent(out, indent_level) << "}";
  255. }
  256. }
  257. /**
  258. *
  259. */
  260. CPPDeclaration::SubType CPPEnumType::
  261. get_subtype() const {
  262. return ST_enum;
  263. }
  264. /**
  265. *
  266. */
  267. CPPEnumType *CPPEnumType::
  268. as_enum_type() {
  269. return this;
  270. }