semantics_node.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. // Type-safe storage of Node IDs.
  14. struct SemanticsNodeId : public IndexBase {
  15. static constexpr int32_t CrossReferenceBit = 0x8000'0000;
  16. // Constructs a cross-reference node ID.
  17. static auto MakeCrossReference(int32_t index) -> SemanticsNodeId {
  18. return SemanticsNodeId(index | CrossReferenceBit);
  19. }
  20. // Constructs a cross-reference node ID for a builtin. This relies on
  21. // SemanticsIR guarantees for builtin cross-reference placement.
  22. static auto MakeBuiltinReference(SemanticsBuiltinKind kind)
  23. -> SemanticsNodeId {
  24. return MakeCrossReference(kind.AsInt());
  25. }
  26. // Constructs an explicitly invalid instance.
  27. static auto MakeInvalid() -> SemanticsNodeId { return SemanticsNodeId(); }
  28. using IndexBase::IndexBase;
  29. auto is_cross_reference() const -> bool { return index & CrossReferenceBit; }
  30. // Returns the ID for a cross-reference, just handling removal of the marker
  31. // bit.
  32. auto GetAsCrossReference() const -> int32_t {
  33. return index & ~CrossReferenceBit;
  34. }
  35. auto Print(llvm::raw_ostream& out) const -> void {
  36. if (is_cross_reference()) {
  37. out << "node_xref" << GetAsCrossReference();
  38. } else {
  39. out << "node" << index;
  40. }
  41. }
  42. };
  43. // Type-safe storage of identifiers.
  44. struct SemanticsIdentifierId : public IndexBase {
  45. using IndexBase::IndexBase;
  46. auto Print(llvm::raw_ostream& out) const -> void { out << "ident" << index; }
  47. };
  48. // Type-safe storage of integer literals.
  49. struct SemanticsIntegerLiteralId : public IndexBase {
  50. using IndexBase::IndexBase;
  51. auto Print(llvm::raw_ostream& out) const -> void { out << "int" << index; }
  52. };
  53. // Type-safe storage of node blocks.
  54. struct SemanticsNodeBlockId : public IndexBase {
  55. using IndexBase::IndexBase;
  56. auto Print(llvm::raw_ostream& out) const -> void { out << "block" << index; }
  57. };
  58. // The standard structure for nodes.
  59. class SemanticsNode {
  60. public:
  61. struct NoArgs {};
  62. auto GetAsInvalid() const -> NoArgs { CARBON_FATAL() << "Invalid access"; }
  63. static auto MakeBinaryOperatorAdd(ParseTree::Node parse_node,
  64. SemanticsNodeId type, SemanticsNodeId lhs,
  65. SemanticsNodeId rhs) -> SemanticsNode {
  66. return SemanticsNode(parse_node, SemanticsNodeKind::BinaryOperatorAdd(),
  67. type, lhs.index, rhs.index);
  68. }
  69. auto GetAsBinaryOperatorAdd() const
  70. -> std::pair<SemanticsNodeId, SemanticsNodeId> {
  71. CARBON_CHECK(kind_ == SemanticsNodeKind::BinaryOperatorAdd());
  72. return {SemanticsNodeId(arg0_), SemanticsNodeId(arg1_)};
  73. }
  74. static auto MakeBindName(ParseTree::Node parse_node,
  75. SemanticsIdentifierId name, SemanticsNodeId node)
  76. -> SemanticsNode {
  77. return SemanticsNode(parse_node, SemanticsNodeKind::BindName(),
  78. SemanticsNodeId(), name.index, node.index);
  79. }
  80. auto GetAsBindName() const
  81. -> std::pair<SemanticsIdentifierId, SemanticsNodeId> {
  82. CARBON_CHECK(kind_ == SemanticsNodeKind::BindName());
  83. return {SemanticsIdentifierId(arg0_), SemanticsNodeId(arg1_)};
  84. }
  85. static auto MakeBuiltin(SemanticsBuiltinKind builtin_kind,
  86. SemanticsNodeId type) -> SemanticsNode {
  87. // Builtins won't have a ParseTree node associated, so we provide the
  88. // default invalid one.
  89. return SemanticsNode(ParseTree::Node(), SemanticsNodeKind::Builtin(), type,
  90. builtin_kind.AsInt());
  91. }
  92. auto GetAsBuiltin() const -> SemanticsBuiltinKind {
  93. CARBON_CHECK(kind_ == SemanticsNodeKind::Builtin());
  94. return SemanticsBuiltinKind::FromInt(arg0_);
  95. }
  96. static auto MakeCodeBlock(ParseTree::Node parse_node,
  97. SemanticsNodeBlockId node_block) -> SemanticsNode {
  98. return SemanticsNode(parse_node, SemanticsNodeKind::CodeBlock(),
  99. SemanticsNodeId(), node_block.index);
  100. }
  101. auto GetAsCodeBlock() const -> SemanticsNodeBlockId {
  102. CARBON_CHECK(kind_ == SemanticsNodeKind::CodeBlock());
  103. return SemanticsNodeBlockId(arg0_);
  104. }
  105. // TODO: The signature should be added as a parameter.
  106. static auto MakeFunctionDeclaration(ParseTree::Node parse_node)
  107. -> SemanticsNode {
  108. return SemanticsNode(parse_node, SemanticsNodeKind::FunctionDeclaration(),
  109. SemanticsNodeId());
  110. }
  111. auto GetAsFunctionDeclaration() const -> NoArgs {
  112. CARBON_CHECK(kind_ == SemanticsNodeKind::FunctionDeclaration());
  113. return {};
  114. }
  115. static auto MakeFunctionDefinition(ParseTree::Node parse_node,
  116. SemanticsNodeId decl,
  117. SemanticsNodeBlockId node_block)
  118. -> SemanticsNode {
  119. return SemanticsNode(parse_node, SemanticsNodeKind::FunctionDefinition(),
  120. SemanticsNodeId(), decl.index, node_block.index);
  121. }
  122. auto GetAsFunctionDefinition() const
  123. -> std::pair<SemanticsNodeId, SemanticsNodeBlockId> {
  124. CARBON_CHECK(kind_ == SemanticsNodeKind::FunctionDefinition());
  125. return {SemanticsNodeId(arg0_), SemanticsNodeBlockId(arg1_)};
  126. }
  127. static auto MakeIntegerLiteral(ParseTree::Node parse_node,
  128. SemanticsIntegerLiteralId integer)
  129. -> SemanticsNode {
  130. return SemanticsNode(parse_node, SemanticsNodeKind::IntegerLiteral(),
  131. SemanticsNodeId::MakeBuiltinReference(
  132. SemanticsBuiltinKind::IntegerType()),
  133. integer.index);
  134. }
  135. auto GetAsIntegerLiteral() const -> SemanticsIntegerLiteralId {
  136. CARBON_CHECK(kind_ == SemanticsNodeKind::IntegerLiteral());
  137. return SemanticsIntegerLiteralId(arg0_);
  138. }
  139. static auto MakeRealLiteral(ParseTree::Node parse_node) -> SemanticsNode {
  140. return SemanticsNode(parse_node, SemanticsNodeKind::RealLiteral(),
  141. SemanticsNodeId::MakeBuiltinReference(
  142. SemanticsBuiltinKind::RealType()));
  143. }
  144. auto GetAsRealLiteral() const -> NoArgs {
  145. CARBON_CHECK(kind_ == SemanticsNodeKind::RealLiteral());
  146. return {};
  147. }
  148. static auto MakeReturn(ParseTree::Node parse_node) -> SemanticsNode {
  149. // The actual type is `()`. However, code dealing with `return;` should
  150. // understand the type without checking, so it's not necessary but could be
  151. // specified if needed.
  152. return SemanticsNode(parse_node, SemanticsNodeKind::Return(),
  153. SemanticsNodeId());
  154. }
  155. auto GetAsReturn() const -> NoArgs {
  156. CARBON_CHECK(kind_ == SemanticsNodeKind::Return());
  157. return {};
  158. }
  159. static auto MakeReturnExpression(ParseTree::Node parse_node,
  160. SemanticsNodeId type, SemanticsNodeId expr)
  161. -> SemanticsNode {
  162. return SemanticsNode(parse_node, SemanticsNodeKind::ReturnExpression(),
  163. type, expr.index);
  164. }
  165. auto GetAsReturnExpression() const -> SemanticsNodeId {
  166. CARBON_CHECK(kind_ == SemanticsNodeKind::ReturnExpression());
  167. return SemanticsNodeId(arg0_);
  168. }
  169. SemanticsNode()
  170. : SemanticsNode(ParseTree::Node(), SemanticsNodeKind::Invalid(),
  171. SemanticsNodeId()) {}
  172. auto parse_node() const -> ParseTree::Node { return parse_node_; }
  173. auto kind() const -> SemanticsNodeKind { return kind_; }
  174. auto type() const -> SemanticsNodeId { return type_; }
  175. auto Print(llvm::raw_ostream& out) const -> void;
  176. private:
  177. explicit SemanticsNode(ParseTree::Node parse_node, SemanticsNodeKind kind,
  178. SemanticsNodeId type, int32_t arg0 = -1,
  179. int32_t arg1 = -1)
  180. : parse_node_(parse_node),
  181. kind_(kind),
  182. type_(type),
  183. arg0_(arg0),
  184. arg1_(arg1) {}
  185. ParseTree::Node parse_node_;
  186. SemanticsNodeKind kind_;
  187. SemanticsNodeId type_;
  188. int32_t arg0_;
  189. int32_t arg1_;
  190. };
  191. // TODO: This is currently 20 bytes because we sometimes have 2 arguments for a
  192. // pair of SemanticsNodes. However, SemanticsNodeKind is 1 byte; if args
  193. // were 3.5 bytes, we could potentially shrink SemanticsNode by 4 bytes. This
  194. // may be worth investigating further.
  195. static_assert(sizeof(SemanticsNode) == 20, "Unexpected SemanticsNode size");
  196. } // namespace Carbon
  197. #endif // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_NODE_H_