semantics_node.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_NODE_H_
  5. #define CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_NODE_H_
  6. #include <cstdint>
  7. #include "common/check.h"
  8. #include "common/ostream.h"
  9. #include "toolchain/parser/parse_tree.h"
  10. #include "toolchain/semantics/semantics_builtin_kind.h"
  11. #include "toolchain/semantics/semantics_node_kind.h"
  12. namespace Carbon {
  13. // The ID of a node.
  14. struct SemanticsNodeId : public IndexBase {
  15. // An explicitly invalid node ID.
  16. static const SemanticsNodeId Invalid;
  17. // Builtin node IDs.
  18. #define CARBON_SEMANTICS_BUILTIN_KIND_NAME(Name) \
  19. static const SemanticsNodeId Builtin##Name;
  20. #include "toolchain/semantics/semantics_builtin_kind.def"
  21. using IndexBase::IndexBase;
  22. auto Print(llvm::raw_ostream& out) const -> void {
  23. out << "node";
  24. if (!is_valid()) {
  25. IndexBase::Print(out);
  26. } else if (index < SemanticsBuiltinKind::ValidCount) {
  27. out << SemanticsBuiltinKind::FromInt(index);
  28. } else {
  29. // Use the `+` as a small reminder that this is a delta, rather than an
  30. // absolute index.
  31. out << "+" << index - SemanticsBuiltinKind::ValidCount;
  32. }
  33. }
  34. };
  35. constexpr SemanticsNodeId SemanticsNodeId::Invalid =
  36. SemanticsNodeId(SemanticsNodeId::InvalidIndex);
  37. // Uses the cross-reference node ID for a builtin. This relies on SemanticsIR
  38. // guarantees for builtin cross-reference placement.
  39. #define CARBON_SEMANTICS_BUILTIN_KIND_NAME(Name) \
  40. constexpr SemanticsNodeId SemanticsNodeId::Builtin##Name = \
  41. SemanticsNodeId(SemanticsBuiltinKind::Name.AsInt());
  42. #include "toolchain/semantics/semantics_builtin_kind.def"
  43. // The ID of a call.
  44. struct SemanticsCallId : public IndexBase {
  45. using IndexBase::IndexBase;
  46. auto Print(llvm::raw_ostream& out) const -> void {
  47. out << "call";
  48. IndexBase::Print(out);
  49. }
  50. };
  51. // The ID of a callable, such as a function.
  52. struct SemanticsCallableId : public IndexBase {
  53. using IndexBase::IndexBase;
  54. auto Print(llvm::raw_ostream& out) const -> void {
  55. out << "callable";
  56. IndexBase::Print(out);
  57. }
  58. };
  59. // The ID of a cross-referenced IR.
  60. struct SemanticsCrossReferenceIRId : public IndexBase {
  61. using IndexBase::IndexBase;
  62. auto Print(llvm::raw_ostream& out) const -> void {
  63. out << "ir";
  64. IndexBase::Print(out);
  65. }
  66. };
  67. // The ID of an integer literal.
  68. struct SemanticsIntegerLiteralId : public IndexBase {
  69. using IndexBase::IndexBase;
  70. auto Print(llvm::raw_ostream& out) const -> void {
  71. out << "int";
  72. IndexBase::Print(out);
  73. }
  74. };
  75. // The ID of a node block.
  76. struct SemanticsNodeBlockId : public IndexBase {
  77. // All SemanticsIR instances must provide the 0th node block as empty.
  78. static const SemanticsNodeBlockId Empty;
  79. // An explicitly invalid ID.
  80. static const SemanticsNodeBlockId Invalid;
  81. using IndexBase::IndexBase;
  82. auto Print(llvm::raw_ostream& out) const -> void {
  83. out << "block";
  84. IndexBase::Print(out);
  85. }
  86. };
  87. constexpr SemanticsNodeBlockId SemanticsNodeBlockId::Empty =
  88. SemanticsNodeBlockId(0);
  89. constexpr SemanticsNodeBlockId SemanticsNodeBlockId::Invalid =
  90. SemanticsNodeBlockId(SemanticsNodeBlockId::InvalidIndex);
  91. // The ID of a real literal.
  92. struct SemanticsRealLiteralId : public IndexBase {
  93. using IndexBase::IndexBase;
  94. auto Print(llvm::raw_ostream& out) const -> void {
  95. out << "real";
  96. IndexBase::Print(out);
  97. }
  98. };
  99. // The ID of a string.
  100. struct SemanticsStringId : public IndexBase {
  101. using IndexBase::IndexBase;
  102. auto Print(llvm::raw_ostream& out) const -> void {
  103. out << "str";
  104. IndexBase::Print(out);
  105. }
  106. };
  107. // An index for member access.
  108. struct SemanticsMemberIndex : public IndexBase {
  109. using IndexBase::IndexBase;
  110. auto Print(llvm::raw_ostream& out) const -> void {
  111. out << "member";
  112. IndexBase::Print(out);
  113. }
  114. };
  115. // The standard structure for SemanticsNode. This is trying to provide a minimal
  116. // amount of information for a node:
  117. //
  118. // - parse_node for error placement.
  119. // - kind for run-time logic when the input Kind is unknown.
  120. // - type_id for quick type checking.
  121. // - Up to two Kind-specific members.
  122. //
  123. // For each Kind in SemanticsNodeKind, a typical flow looks like:
  124. //
  125. // - Create a `SemanticsNode` using `SemanticsNode::Kind::Make()`
  126. // - Access cross-Kind members using `node.type_id()` and similar.
  127. // - Access Kind-specific members using `node.GetAsKind()`, which depending on
  128. // the number of members will return one of NoArgs, a single value, or a
  129. // `std::pair` of values.
  130. // - Using the wrong `node.GetAsKind()` is a programming error, and should
  131. // CHECK-fail in debug modes (opt may too, but it's not an API guarantee).
  132. //
  133. // Internally, each Kind uses the `Factory*` types to provide a boilerplate
  134. // `Make` and `Get` methods.
  135. class SemanticsNode {
  136. public:
  137. struct NoArgs {};
  138. // Factory base classes are private, then used for public classes. This class
  139. // has two public and two private sections to prevent accidents.
  140. private:
  141. // Factory templates need to use the raw enum instead of the class wrapper.
  142. using KindTemplateEnum = Internal::SemanticsNodeKindRawEnum;
  143. // Provides Make and Get to support 0, 1, or 2 arguments for a SemanticsNode.
  144. // These are protected so that child factories can opt in to what pieces they
  145. // want to use.
  146. template <KindTemplateEnum Kind, typename... ArgTypes>
  147. class FactoryBase {
  148. protected:
  149. static auto Make(ParseTree::Node parse_node, SemanticsNodeId type_id,
  150. ArgTypes... arg_ids) -> SemanticsNode {
  151. return SemanticsNode(parse_node, SemanticsNodeKind::Create(Kind), type_id,
  152. arg_ids.index...);
  153. }
  154. static auto Get(SemanticsNode node) {
  155. struct Unused {};
  156. return GetImpl<ArgTypes..., Unused>(node);
  157. }
  158. private:
  159. // GetImpl handles the different return types based on ArgTypes.
  160. template <typename Arg0Type, typename Arg1Type, typename>
  161. static auto GetImpl(SemanticsNode node) -> std::pair<Arg0Type, Arg1Type> {
  162. CARBON_CHECK(node.kind() == Kind);
  163. return {Arg0Type(node.arg0_), Arg1Type(node.arg1_)};
  164. }
  165. template <typename Arg0Type, typename>
  166. static auto GetImpl(SemanticsNode node) -> Arg0Type {
  167. CARBON_CHECK(node.kind() == Kind);
  168. return Arg0Type(node.arg0_);
  169. }
  170. template <typename>
  171. static auto GetImpl(SemanticsNode node) -> NoArgs {
  172. CARBON_CHECK(node.kind() == Kind);
  173. return NoArgs();
  174. }
  175. };
  176. // Provide Get along with a Make that requires a type.
  177. template <KindTemplateEnum Kind, typename... ArgTypes>
  178. class Factory : public FactoryBase<Kind, ArgTypes...> {
  179. public:
  180. using FactoryBase<Kind, ArgTypes...>::Make;
  181. using FactoryBase<Kind, ArgTypes...>::Get;
  182. };
  183. // Provides Get along with a Make that assumes a non-changing type.
  184. template <KindTemplateEnum Kind, int32_t TypeIndex, typename... ArgTypes>
  185. class FactoryPreTyped : public FactoryBase<Kind, ArgTypes...> {
  186. public:
  187. static auto Make(ParseTree::Node parse_node, ArgTypes... args) {
  188. SemanticsNodeId type_id(TypeIndex);
  189. return FactoryBase<Kind, ArgTypes...>::Make(parse_node, type_id, args...);
  190. }
  191. using FactoryBase<Kind, ArgTypes...>::Get;
  192. };
  193. public:
  194. // Invalid is in the SemanticsNodeKind enum, but should never be used.
  195. class Invalid {
  196. public:
  197. static auto Get(SemanticsNode /*node*/) -> SemanticsNode::NoArgs {
  198. CARBON_FATAL() << "Invalid access";
  199. }
  200. };
  201. using Assign = SemanticsNode::Factory<SemanticsNodeKind::Assign,
  202. SemanticsNodeId /*lhs_id*/,
  203. SemanticsNodeId /*rhs_id*/>;
  204. using BinaryOperatorAdd =
  205. SemanticsNode::Factory<SemanticsNodeKind::BinaryOperatorAdd,
  206. SemanticsNodeId /*lhs_id*/,
  207. SemanticsNodeId /*rhs_id*/>;
  208. using BindName = SemanticsNode::Factory<SemanticsNodeKind::BindName,
  209. SemanticsStringId /*name_id*/,
  210. SemanticsNodeId /*node_id*/>;
  211. class Builtin {
  212. public:
  213. static auto Make(SemanticsBuiltinKind builtin_kind, SemanticsNodeId type_id)
  214. -> SemanticsNode {
  215. // Builtins won't have a ParseTree node associated, so we provide the
  216. // default invalid one.
  217. // This can't use the standard Make function because of the `AsInt()` cast
  218. // instead of `.index`.
  219. return SemanticsNode(ParseTree::Node::Invalid, SemanticsNodeKind::Builtin,
  220. type_id, builtin_kind.AsInt());
  221. }
  222. static auto Get(SemanticsNode node) -> SemanticsBuiltinKind {
  223. return SemanticsBuiltinKind::FromInt(node.arg0_);
  224. }
  225. };
  226. using Call = Factory<SemanticsNodeKind::Call, SemanticsCallId /*call_id*/,
  227. SemanticsCallableId /*callable_id*/>;
  228. using CodeBlock = FactoryPreTyped<SemanticsNodeKind::CodeBlock,
  229. SemanticsNodeId::InvalidIndex,
  230. SemanticsNodeBlockId /*node_block_id*/>;
  231. class CrossReference
  232. : public FactoryBase<SemanticsNodeKind::CrossReference,
  233. SemanticsCrossReferenceIRId /*ir_id*/,
  234. SemanticsNodeId /*node_id*/> {
  235. public:
  236. static auto Make(SemanticsNodeId type_id, SemanticsCrossReferenceIRId ir_id,
  237. SemanticsNodeId node_id) -> SemanticsNode {
  238. // A node's parse tree node must refer to a node in the current parse
  239. // tree. This cannot use the cross-referenced node's parse tree node
  240. // because it will be in a different parse tree.
  241. return FactoryBase::Make(ParseTree::Node::Invalid, type_id, ir_id,
  242. node_id);
  243. }
  244. using FactoryBase::Get;
  245. };
  246. using FunctionDeclaration = FactoryPreTyped<
  247. SemanticsNodeKind::FunctionDeclaration, SemanticsNodeId::InvalidIndex,
  248. SemanticsStringId /*name_id*/, SemanticsCallableId /*signature_id*/>;
  249. using FunctionDefinition = FactoryPreTyped<
  250. SemanticsNodeKind::FunctionDefinition, SemanticsNodeId::InvalidIndex,
  251. SemanticsNodeId /*decl_id*/, SemanticsNodeBlockId /*node_block_id*/>;
  252. using IntegerLiteral =
  253. FactoryPreTyped<SemanticsNodeKind::IntegerLiteral,
  254. SemanticsBuiltinKind::IntegerType.AsInt(),
  255. SemanticsIntegerLiteralId /*integer_id*/>;
  256. using RealLiteral =
  257. FactoryPreTyped<SemanticsNodeKind::RealLiteral,
  258. SemanticsBuiltinKind::FloatingPointType.AsInt(),
  259. SemanticsRealLiteralId /*real_id*/>;
  260. using Return =
  261. FactoryPreTyped<SemanticsNodeKind::Return, SemanticsNodeId::InvalidIndex>;
  262. using ReturnExpression =
  263. Factory<SemanticsNodeKind::ReturnExpression, SemanticsNodeId /*expr_id*/>;
  264. using StringLiteral =
  265. FactoryPreTyped<SemanticsNodeKind::StringLiteral,
  266. SemanticsBuiltinKind::StringType.AsInt(),
  267. SemanticsStringId /*string_id*/>;
  268. using StructMemberAccess = Factory<SemanticsNodeKind::StructMemberAccess,
  269. SemanticsNodeId /*struct_id*/,
  270. SemanticsMemberIndex /*ref_index*/>;
  271. using StructType = FactoryPreTyped<
  272. SemanticsNodeKind::StructType, SemanticsBuiltinKind::TypeType.AsInt(),
  273. SemanticsNodeBlockId /*ir_id*/, SemanticsNodeBlockId /*refs_id*/>;
  274. using StructTypeField = Factory<SemanticsNodeKind::StructTypeField,
  275. SemanticsStringId /*name_id*/>;
  276. using StructValue =
  277. Factory<SemanticsNodeKind::StructValue, SemanticsNodeBlockId /*ir_id*/,
  278. SemanticsNodeBlockId /*refs_id*/>;
  279. using StubReference =
  280. Factory<SemanticsNodeKind::StubReference, SemanticsNodeId /*node_id*/>;
  281. using VarStorage = Factory<SemanticsNodeKind::VarStorage>;
  282. SemanticsNode()
  283. : SemanticsNode(ParseTree::Node::Invalid, SemanticsNodeKind::Invalid,
  284. SemanticsNodeId::Invalid) {}
  285. // Provide `node.GetAsKind()` as an instance method for all kinds, essentially
  286. // an alias for`SemanticsNode::Kind::Get(node)`.
  287. #define CARBON_SEMANTICS_NODE_KIND(Name) \
  288. auto GetAs##Name() const { return Name::Get(*this); }
  289. #include "toolchain/semantics/semantics_node_kind.def"
  290. auto parse_node() const -> ParseTree::Node { return parse_node_; }
  291. auto kind() const -> SemanticsNodeKind { return kind_; }
  292. auto type_id() const -> SemanticsNodeId { return type_id_; }
  293. auto Print(llvm::raw_ostream& out) const -> void;
  294. private:
  295. // Builtins have peculiar construction, so they are a friend rather than using
  296. // a factory base class.
  297. friend struct SemanticsNodeForBuiltin;
  298. explicit SemanticsNode(ParseTree::Node parse_node, SemanticsNodeKind kind,
  299. SemanticsNodeId type_id,
  300. int32_t arg0 = SemanticsNodeId::InvalidIndex,
  301. int32_t arg1 = SemanticsNodeId::InvalidIndex)
  302. : parse_node_(parse_node),
  303. kind_(kind),
  304. type_id_(type_id),
  305. arg0_(arg0),
  306. arg1_(arg1) {}
  307. ParseTree::Node parse_node_;
  308. SemanticsNodeKind kind_;
  309. SemanticsNodeId type_id_;
  310. // Use GetAsKind to access arg0 and arg1.
  311. int32_t arg0_;
  312. int32_t arg1_;
  313. };
  314. // TODO: This is currently 20 bytes because we sometimes have 2 arguments for a
  315. // pair of SemanticsNodes. However, SemanticsNodeKind is 1 byte; if args
  316. // were 3.5 bytes, we could potentially shrink SemanticsNode by 4 bytes. This
  317. // may be worth investigating further.
  318. static_assert(sizeof(SemanticsNode) == 20, "Unexpected SemanticsNode size");
  319. } // namespace Carbon
  320. #endif // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_NODE_H_