Procházet zdrojové kódy

Refactoring Semantics towards a more instruction-like model (#1349)

This is how I'm interpreting discussion:

- Basic elements are getting set to an ID.
- SetName exists to assign a name (which can then be referred to later with an identifier expression) to an ID.
- Expressions are broken down into a series of operations which operate on IDs.

So with something like the last test:

```
fn Main() { return 12 + 34; }
```

This becomes:

```
Function(%0,
  {IntegerLiteral(%3, 12),
   IntegerLiteral(%2, 34),
   BinaryOperator(%1, +, %3, %2),
   Return(%1),
  })
SetName(`Main`, %0)
```

Note I'm treating blocks as fairly equal to the top of a file now, and basically eliminating boundaries between things. That's because we have discussed also supporting code like:

```
fn Foo() {
  fn Bar() {}
  Bar();
}
```

Here a declaration of a function is occurring inside a code block, so it felt like eliminating the difference was the best choice.

I know you'd commented on the separation of nodes to individual files before; I still think we're going to have a lot of different types of nodes, and so separating them out into individual files makes them easier to browse.
Jon Ross-Perkins před 3 roky
rodič
revize
a23f15e901
33 změnil soubory, kde provedl 688 přidání a 937 odebrání
  1. 13 12
      toolchain/semantics/BUILD
  2. 0 115
      toolchain/semantics/meta_node.h
  3. 0 38
      toolchain/semantics/meta_node_block.h
  4. 24 0
      toolchain/semantics/node_kind.h
  5. 40 0
      toolchain/semantics/node_ref.h
  6. 59 0
      toolchain/semantics/node_store.h
  7. 53 0
      toolchain/semantics/nodes/binary_operator.h
  8. 39 0
      toolchain/semantics/nodes/binary_operator_test_matchers.h
  9. 0 26
      toolchain/semantics/nodes/declared_name.h
  10. 0 28
      toolchain/semantics/nodes/declared_name_test_matchers.h
  11. 0 31
      toolchain/semantics/nodes/expression_statement.h
  12. 32 29
      toolchain/semantics/nodes/function.h
  13. 10 38
      toolchain/semantics/nodes/function_test_matchers.h
  14. 0 34
      toolchain/semantics/nodes/infix_operator.h
  15. 0 39
      toolchain/semantics/nodes/infix_operator_test_matchers.h
  16. 39 0
      toolchain/semantics/nodes/integer_literal.h
  17. 34 0
      toolchain/semantics/nodes/integer_literal_test_matchers.h
  18. 0 29
      toolchain/semantics/nodes/literal.h
  19. 0 33
      toolchain/semantics/nodes/literal_test_matchers.h
  20. 0 33
      toolchain/semantics/nodes/pattern_binding.h
  21. 0 30
      toolchain/semantics/nodes/pattern_binding_test_matchers.h
  22. 21 6
      toolchain/semantics/nodes/return.h
  23. 10 10
      toolchain/semantics/nodes/return_test_matchers.h
  24. 44 0
      toolchain/semantics/nodes/set_name.h
  25. 34 0
      toolchain/semantics/nodes/set_name_test_matchers.h
  26. 12 0
      toolchain/semantics/nodes_test_matchers.h
  27. 15 104
      toolchain/semantics/semantics_ir.cpp
  28. 7 35
      toolchain/semantics/semantics_ir.h
  29. 108 74
      toolchain/semantics/semantics_ir_factory.cpp
  30. 41 17
      toolchain/semantics/semantics_ir_factory.h
  31. 43 58
      toolchain/semantics/semantics_ir_factory_test.cpp
  32. 7 89
      toolchain/semantics/semantics_ir_for_test.h
  33. 3 29
      toolchain/semantics/semantics_ir_test_helpers.h

+ 13 - 12
toolchain/semantics/BUILD

@@ -7,15 +7,13 @@ package(default_visibility = ["//visibility:public"])
 cc_library(
     name = "nodes",
     hdrs = [
-        "nodes/declared_name.h",
-        "nodes/expression_statement.h",
+        "node_kind.h",
+        "node_ref.h",
+        "nodes/binary_operator.h",
         "nodes/function.h",
-        "nodes/infix_operator.h",
-        "nodes/literal.h",
-        "meta_node.h",
-        "meta_node_block.h",
-        "nodes/pattern_binding.h",
+        "nodes/integer_literal.h",
         "nodes/return.h",
+        "nodes/set_name.h",
     ],
     deps = [
         "//common:check",
@@ -38,7 +36,10 @@ cc_library(
 cc_library(
     name = "semantics_ir",
     srcs = ["semantics_ir.cpp"],
-    hdrs = ["semantics_ir.h"],
+    hdrs = [
+        "node_store.h",
+        "semantics_ir.h",
+    ],
     deps = [
         ":nodes",
         "//common:check",
@@ -57,6 +58,7 @@ cc_library(
         ":parse_subtree_consumer",
         ":semantics_ir",
         "//common:check",
+        "//toolchain/lexer:token_kind",
         "//toolchain/lexer:tokenized_buffer",
         "//toolchain/parser:parse_node_kind",
         "//toolchain/parser:parse_tree",
@@ -69,12 +71,11 @@ cc_library(
     testonly = 1,
     srcs = ["semantics_ir_for_test.cpp"],
     hdrs = [
-        "nodes/declared_name_test_matchers.h",
+        "nodes/binary_operator_test_matchers.h",
         "nodes/function_test_matchers.h",
-        "nodes/infix_operator_test_matchers.h",
-        "nodes/literal_test_matchers.h",
-        "nodes/pattern_binding_test_matchers.h",
+        "nodes/integer_literal_test_matchers.h",
         "nodes/return_test_matchers.h",
+        "nodes/set_name_test_matchers.h",
         "semantics_ir_for_test.h",
         "semantics_ir_test_helpers.h",
     ],

+ 0 - 115
toolchain/semantics/meta_node.h

@@ -1,115 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#ifndef CARBON_TOOLCHAIN_SEMANTICS_META_NODE_H_
-#define CARBON_TOOLCHAIN_SEMANTICS_META_NODE_H_
-
-#include <cstdint>
-#include <tuple>
-
-#include "common/check.h"
-#include "llvm/ADT/SmallVector.h"
-
-namespace Carbon {
-class SemanticsIR;
-}  // namespace Carbon
-
-namespace Carbon::Testing {
-class SemanticsIRForTest;
-}  // namespace Carbon::Testing
-
-namespace Carbon::Semantics {
-
-// The standard structure for nodes which have multiple subtypes.
-//
-// This flyweight pattern is used so that each subtype can be stored in its own
-// vector, minimizing memory consumption and heap fragmentation when large
-// quantities are being created.
-template <typename KindT, typename MetaNodeStoreT>
-class MetaNode {
- public:
-  MetaNode() : MetaNode(KindT::Invalid, -1) {}
-
-  auto kind() -> KindT { return kind_; }
-
- private:
-  friend MetaNodeStoreT;
-
-  MetaNode(KindT kind, int32_t index) : kind_(kind), index_(index) {}
-
-  KindT kind_;
-
-  // The index of the named entity within its list.
-  int32_t index_;
-};
-
-// Provides storage for nodes, indexed by MetaNodes.
-template <typename KindT, typename... StoredNodeT>
-class MetaNodeStore {
- public:
-  using MetaNodeT = MetaNode<KindT, MetaNodeStore<KindT, StoredNodeT...>>;
-
-  // Stores the provided node, returning a pointer to it.
-  template <typename NodeT>
-  auto Store(NodeT node) -> MetaNodeT {
-    auto& node_store =
-        std::get<static_cast<size_t>(NodeT::MetaNodeKind)>(node_stores_);
-    int32_t index = node_store.size();
-    node_store.push_back(node);
-    return MetaNodeT(NodeT::MetaNodeKind, index);
-  }
-
-  // Returns the requested node. Requires that the pointer is valid for this
-  // store.
-  template <typename NodeT>
-  auto Get(MetaNodeT meta_node) const -> const NodeT& {
-    CARBON_CHECK(meta_node.index_ >= 0);
-    CARBON_CHECK(meta_node.kind_ == NodeT::MetaNodeKind)
-        << "Kind mismatch: " << static_cast<int>(meta_node.kind_) << " vs "
-        << static_cast<int>(NodeT::MetaNodeKind);
-    auto& node_store =
-        std::get<static_cast<size_t>(NodeT::MetaNodeKind)>(node_stores_);
-    CARBON_CHECK(static_cast<size_t>(meta_node.index_) < node_store.size());
-    return node_store[meta_node.index_];
-  }
-
- private:
-  std::tuple<llvm::SmallVector<StoredNodeT, 0>...> node_stores_;
-};
-
-// Meta node information for declarations.
-enum class DeclarationKind {
-  Function,
-  Invalid,
-};
-class Function;
-using DeclarationStore = MetaNodeStore<DeclarationKind, Function>;
-using Declaration = MetaNode<DeclarationKind, DeclarationStore>;
-
-// Meta node information for statements.
-enum class StatementKind {
-  ExpressionStatement,
-  Return,
-  Invalid,
-};
-class ExpressionStatement;
-class Return;
-using StatementStore =
-    MetaNodeStore<StatementKind, ExpressionStatement, Return>;
-using Statement = MetaNode<StatementKind, StatementStore>;
-
-// Meta node information for declarations.
-enum class ExpressionKind {
-  InfixOperator,
-  Literal,
-  Invalid,
-};
-class InfixOperator;
-class Literal;
-using ExpressionStore = MetaNodeStore<ExpressionKind, InfixOperator, Literal>;
-using Expression = MetaNode<ExpressionKind, ExpressionStore>;
-
-}  // namespace Carbon::Semantics
-
-#endif  // CARBON_TOOLCHAIN_SEMANTICS_META_NODE_H_

+ 0 - 38
toolchain/semantics/meta_node_block.h

@@ -1,38 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#ifndef CARBON_TOOLCHAIN_SEMANTICS_META_NODE_BLOCK_H_
-#define CARBON_TOOLCHAIN_SEMANTICS_META_NODE_BLOCK_H_
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringMap.h"
-#include "toolchain/semantics/meta_node.h"
-
-namespace Carbon::Semantics {
-
-// The standard structure for declaration and statement blocks.
-template <typename MetaNodeT>
-struct MetaNodeBlock {
- public:
-  MetaNodeBlock(llvm::SmallVector<MetaNodeT, 0> nodes,
-                llvm::StringMap<MetaNodeT> name_lookup)
-      : nodes_(std::move(nodes)), name_lookup_(std::move(name_lookup)) {}
-
-  auto nodes() const -> llvm::ArrayRef<MetaNodeT> { return nodes_; }
-  auto name_lookup() const -> const llvm::StringMap<MetaNodeT>& {
-    return name_lookup_;
-  }
-
- protected:
-  llvm::SmallVector<MetaNodeT, 0> nodes_;
-  llvm::StringMap<MetaNodeT> name_lookup_;
-};
-
-using DeclarationBlock = MetaNodeBlock<Declaration>;
-using StatementBlock = MetaNodeBlock<Statement>;
-
-}  // namespace Carbon::Semantics
-
-#endif  // CARBON_TOOLCHAIN_SEMANTICS_META_NODE_BLOCK_H_

+ 24 - 0
toolchain/semantics/node_kind.h

@@ -0,0 +1,24 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODE_KIND_H_
+#define CARBON_TOOLCHAIN_SEMANTICS_NODE_KIND_H_
+
+#include <cstdint>
+
+namespace Carbon::Semantics {
+
+// Meta node information for declarations.
+enum class NodeKind {
+  BinaryOperator,
+  Function,
+  IntegerLiteral,
+  Return,
+  SetName,
+  Invalid,
+};
+
+}  // namespace Carbon::Semantics
+
+#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODE_KIND_H_

+ 40 - 0
toolchain/semantics/node_ref.h

@@ -0,0 +1,40 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODE_REF_H_
+#define CARBON_TOOLCHAIN_SEMANTICS_NODE_REF_H_
+
+#include <cstdint>
+
+#include "common/ostream.h"
+#include "toolchain/semantics/node_kind.h"
+
+namespace Carbon::Semantics {
+
+// The standard structure for nodes.
+//
+// This flyweight pattern is used so that each subtype can be stored in its own
+// vector, minimizing memory consumption and heap fragmentation when large
+// quantities are being created.
+class NodeRef {
+ public:
+  NodeRef() : NodeRef(NodeKind::Invalid, -1) {}
+
+  auto kind() -> NodeKind { return kind_; }
+
+ private:
+  template <typename... StoredNodeT>
+  friend class NodeStoreBase;
+
+  NodeRef(NodeKind kind, int32_t index) : kind_(kind), index_(index) {}
+
+  NodeKind kind_;
+
+  // The index of the named entity within its list.
+  int32_t index_;
+};
+
+}  // namespace Carbon::Semantics
+
+#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODE_REF_H_

+ 59 - 0
toolchain/semantics/node_store.h

@@ -0,0 +1,59 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODE_STORE_H_
+#define CARBON_TOOLCHAIN_SEMANTICS_NODE_STORE_H_
+
+#include <tuple>
+
+#include "common/check.h"
+#include "llvm/ADT/SmallVector.h"
+#include "toolchain/semantics/node_ref.h"
+#include "toolchain/semantics/nodes/binary_operator.h"
+#include "toolchain/semantics/nodes/function.h"
+#include "toolchain/semantics/nodes/integer_literal.h"
+#include "toolchain/semantics/nodes/return.h"
+#include "toolchain/semantics/nodes/set_name.h"
+
+namespace Carbon::Semantics {
+
+// Provides storage for nodes, indexed by Nodes.
+//
+// This uses templating versus either a macro or repeated functions to provide
+// per-type storage.
+template <typename... StoredNodeT>
+class NodeStoreBase {
+ public:
+  // Stores the provided node, returning a pointer to it.
+  template <typename NodeT>
+  auto Store(NodeT node) -> NodeRef {
+    auto& node_store = std::get<static_cast<size_t>(NodeT::Kind)>(node_stores_);
+    int32_t index = node_store.size();
+    node_store.push_back(node);
+    return NodeRef(NodeT::Kind, index);
+  }
+
+  // Returns the requested node. Requires that the pointer is valid for this
+  // store.
+  template <typename NodeT>
+  auto Get(NodeRef node_ref) const -> const NodeT& {
+    CARBON_CHECK(node_ref.index_ >= 0);
+    CARBON_CHECK(node_ref.kind_ == NodeT::Kind)
+        << "Kind mismatch: " << static_cast<int>(node_ref.kind_) << " vs "
+        << static_cast<int>(NodeT::Kind);
+    auto& node_store = std::get<static_cast<size_t>(NodeT::Kind)>(node_stores_);
+    CARBON_CHECK(static_cast<size_t>(node_ref.index_) < node_store.size());
+    return node_store[node_ref.index_];
+  }
+
+ private:
+  std::tuple<llvm::SmallVector<StoredNodeT, 0>...> node_stores_;
+};
+
+using NodeStore =
+    NodeStoreBase<BinaryOperator, Function, IntegerLiteral, Return, SetName>;
+
+}  // namespace Carbon::Semantics
+
+#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODE_STORE_H_

+ 53 - 0
toolchain/semantics/nodes/binary_operator.h

@@ -0,0 +1,53 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_BINARY_OPERATOR_H_
+#define CARBON_TOOLCHAIN_SEMANTICS_NODES_BINARY_OPERATOR_H_
+
+#include "common/ostream.h"
+#include "toolchain/parser/parse_tree.h"
+#include "toolchain/semantics/node_kind.h"
+
+namespace Carbon::Semantics {
+
+// Represents a binary operator, such as `+` in `1 + 2`.
+class BinaryOperator {
+ public:
+  enum class Op {
+    Add,
+  };
+
+  static constexpr NodeKind Kind = NodeKind::BinaryOperator;
+
+  explicit BinaryOperator(ParseTree::Node node, int32_t id, Op op,
+                          int32_t lhs_id, int32_t rhs_id)
+      : node_(node), id_(id), op_(op), lhs_id_(lhs_id), rhs_id_(rhs_id) {}
+
+  void Print(llvm::raw_ostream& out) const {
+    out << "BinaryOperator(%" << id_ << ", ";
+    switch (op_) {
+      case Op::Add:
+        out << "+";
+        break;
+    }
+    out << ", %" << lhs_id_ << ", %" << rhs_id_ << ")";
+  }
+
+  auto node() const -> ParseTree::Node { return node_; }
+  auto id() const -> int32_t { return id_; }
+  auto op() const -> Op { return op_; }
+  auto lhs_id() const -> int32_t { return lhs_id_; }
+  auto rhs_id() const -> int32_t { return rhs_id_; }
+
+ private:
+  ParseTree::Node node_;
+  int32_t id_;
+  Op op_;
+  int32_t lhs_id_;
+  int32_t rhs_id_;
+};
+
+}  // namespace Carbon::Semantics
+
+#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_BINARY_OPERATOR_H_

+ 39 - 0
toolchain/semantics/nodes/binary_operator_test_matchers.h

@@ -0,0 +1,39 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_BINARY_OPERATOR_TEST_MATCHERS_H_
+#define CARBON_TOOLCHAIN_SEMANTICS_NODES_BINARY_OPERATOR_TEST_MATCHERS_H_
+
+#include <gmock/gmock.h>
+
+#include "llvm/ADT/StringExtras.h"
+#include "toolchain/semantics/nodes/binary_operator.h"
+#include "toolchain/semantics/semantics_ir_for_test.h"
+
+namespace Carbon::Testing {
+
+MATCHER_P4(
+    BinaryOperator, id_matcher, op_matcher, lhs_id_matcher, rhs_id_matcher,
+    llvm::formatv(
+        "BinaryOperator(%{0}, {1}, %{2}, %{3})",
+        ::testing::DescribeMatcher<int32_t>(id_matcher),
+        ::testing::DescribeMatcher<Semantics::BinaryOperator::Op>(op_matcher),
+        ::testing::DescribeMatcher<int32_t>(lhs_id_matcher),
+        ::testing::DescribeMatcher<int32_t>(rhs_id_matcher))) {
+  const Semantics::NodeRef& node_ref = arg;
+  if (auto op =
+          SemanticsIRForTest::GetNode<Semantics::BinaryOperator>(node_ref)) {
+    return ExplainMatchResult(id_matcher, op->id(), result_listener) &&
+           ExplainMatchResult(op_matcher, op->op(), result_listener) &&
+           ExplainMatchResult(lhs_id_matcher, op->lhs_id(), result_listener) &&
+           ExplainMatchResult(rhs_id_matcher, op->rhs_id(), result_listener);
+  } else {
+    *result_listener << "node is not a BinaryOperator";
+    return result_listener;
+  }
+}
+
+}  // namespace Carbon::Testing
+
+#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_BINARY_OPERATOR_TEST_MATCHERS_H_

+ 0 - 26
toolchain/semantics/nodes/declared_name.h

@@ -1,26 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_DECLARED_NAME_H_
-#define CARBON_TOOLCHAIN_SEMANTICS_NODES_DECLARED_NAME_H_
-
-#include "common/ostream.h"
-#include "toolchain/parser/parse_tree.h"
-
-namespace Carbon::Semantics {
-
-// Represents a name.
-class DeclaredName {
- public:
-  explicit DeclaredName(ParseTree::Node node) : node_(node) {}
-
-  auto node() const -> ParseTree::Node { return node_; }
-
- private:
-  ParseTree::Node node_;
-};
-
-}  // namespace Carbon::Semantics
-
-#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_DECLARED_NAME_H_

+ 0 - 28
toolchain/semantics/nodes/declared_name_test_matchers.h

@@ -1,28 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_DECLARED_NAME_TEST_MATCHERS_H_
-#define CARBON_TOOLCHAIN_SEMANTICS_NODES_DECLARED_NAME_TEST_MATCHERS_H_
-
-#include <gtest/gtest.h>
-
-#include "llvm/ADT/StringExtras.h"
-#include "toolchain/semantics/nodes/declared_name.h"
-#include "toolchain/semantics/semantics_ir_for_test.h"
-
-namespace Carbon::Testing {
-
-MATCHER_P(
-    DeclaredName, name_matcher,
-    llvm::formatv("DeclaredName {0}",
-                  ::testing::DescribeMatcher<llvm::StringRef>(name_matcher))) {
-  const Semantics::DeclaredName& name = arg;
-  return ExplainMatchResult(name_matcher,
-                            SemanticsIRForTest::GetNodeText(name.node()),
-                            result_listener);
-}
-
-}  // namespace Carbon::Testing
-
-#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_DECLARED_NAME_TEST_MATCHERS_H_

+ 0 - 31
toolchain/semantics/nodes/expression_statement.h

@@ -1,31 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_EXPRESSION_STATEMENT_H_
-#define CARBON_TOOLCHAIN_SEMANTICS_NODES_EXPRESSION_STATEMENT_H_
-
-#include "common/ostream.h"
-#include "toolchain/parser/parse_tree.h"
-#include "toolchain/semantics/meta_node.h"
-
-namespace Carbon::Semantics {
-
-// Represents a statement that is only an expression, such as `Call()`.
-class ExpressionStatement {
- public:
-  static constexpr StatementKind MetaNodeKind =
-      StatementKind::ExpressionStatement;
-
-  explicit ExpressionStatement(Expression expression)
-      : expression_(expression) {}
-
-  auto expression() const -> Expression { return expression_; }
-
- private:
-  Expression expression_;
-};
-
-}  // namespace Carbon::Semantics
-
-#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_EXPRESSION_STATEMENT_H_

+ 32 - 29
toolchain/semantics/nodes/function.h

@@ -7,57 +7,60 @@
 
 #include "common/ostream.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
 #include "toolchain/parser/parse_tree.h"
-#include "toolchain/semantics/meta_node.h"
-#include "toolchain/semantics/meta_node_block.h"
-#include "toolchain/semantics/nodes/declared_name.h"
-#include "toolchain/semantics/nodes/pattern_binding.h"
-
-// TODO: StatementBlock has some circularity in its forward declarations that
-// needs to be fixed. These includes are a workaround.
-#include "toolchain/semantics/nodes/expression_statement.h"
-#include "toolchain/semantics/nodes/return.h"
+#include "toolchain/semantics/node_kind.h"
+#include "toolchain/semantics/node_ref.h"
 
 namespace Carbon::Semantics {
 
 // Represents `fn name(params...) [-> return_expr] body`.
 class Function {
  public:
-  static constexpr DeclarationKind MetaNodeKind = DeclarationKind::Function;
+  static constexpr NodeKind Kind = NodeKind::Function;
 
-  Function(ParseTree::Node node, DeclaredName name,
-           llvm::SmallVector<PatternBinding, 0> params,
-           llvm::Optional<Semantics::Expression> return_expr,
-           StatementBlock body)
+  Function(ParseTree::Node node, int32_t id,
+           // llvm::SmallVector<PatternBinding, 0> params,
+           // llvm::SmallVector<NodeRef, 0> return_type,
+           llvm::SmallVector<NodeRef, 0> body)
       : node_(node),
-        name_(name),
-        params_(std::move(params)),
-        return_expr_(return_expr),
+        id_(id),
+        // params_(std::move(params)),
+        // return_expr_(return_expr),
         body_(std::move(body)) {}
 
-  auto node() const -> ParseTree::Node { return node_; }
-  auto name() const -> const DeclaredName& { return name_; }
-  auto params() const -> llvm::ArrayRef<PatternBinding> { return params_; }
-  auto return_expr() const -> llvm::Optional<Semantics::Expression> {
-    return return_expr_;
+  void Print(llvm::raw_ostream& out,
+             std::function<void(NodeRef)> print_node_ref) const {
+    out << "Function(%" << id_ << ", {";
+    llvm::ListSeparator sep(", ");
+    for (auto& node_ref : body_) {
+      out << sep;
+      print_node_ref(node_ref);
+    }
+    out << "})";
   }
 
-  auto body() const -> const StatementBlock& { return body_; }
+  auto node() const -> ParseTree::Node { return node_; }
+  auto id() const -> int32_t { return id_; }
+  // auto params() const -> llvm::ArrayRef<PatternBinding> { return params_; }
+  // auto return_expr() const -> llvm::Optional<Statement> { return
+  // return_expr_; }
+  auto body() const -> llvm::ArrayRef<NodeRef> { return body_; }
 
  private:
   // The FunctionDeclaration node.
   ParseTree::Node node_;
 
-  // The function's name.
-  DeclaredName name_;
+  // The function's ID.
+  int32_t id_;
 
   // Regular function parameters.
-  llvm::SmallVector<PatternBinding, 0> params_;
+  // llvm::SmallVector<PatternBinding, 0> params_;
 
-  // The return expression.
-  llvm::Optional<Semantics::Expression> return_expr_;
+  // The return type expression.
+  llvm::SmallVector<NodeRef, 0> return_type_;
 
-  StatementBlock body_;
+  llvm::SmallVector<NodeRef, 0> body_;
 };
 
 }  // namespace Carbon::Semantics

+ 10 - 38
toolchain/semantics/nodes/function_test_matchers.h

@@ -6,54 +6,26 @@
 #define CARBON_TOOLCHAIN_SEMANTICS_NODES_FUNCTION_TEST_MATCHERS_H_
 
 #include <gmock/gmock.h>
-#include <gtest/gtest.h>
 
 #include "llvm/ADT/StringExtras.h"
 #include "toolchain/semantics/nodes/function.h"
-#include "toolchain/semantics/nodes/pattern_binding.h"
 #include "toolchain/semantics/semantics_ir_for_test.h"
 
 namespace Carbon::Testing {
 
-MATCHER_P(FunctionName, name_matcher,
-          llvm::formatv("fn `{0}`", ::testing::DescribeMatcher<llvm::StringRef>(
-                                        name_matcher))) {
-  const Semantics::Declaration& decl = arg;
+MATCHER_P2(Function, id_matcher, body_matcher,
+           llvm::formatv(
+               "Function(%{0}, {1})",
+               ::testing::DescribeMatcher<int32_t>(id_matcher),
+               ::testing::DescribeMatcher<llvm::ArrayRef<Semantics::NodeRef>>(
+                   body_matcher))) {
+  const Semantics::NodeRef& node_ref = arg;
   if (auto function =
-          SemanticsIRForTest::GetDeclaration<Semantics::Function>(decl)) {
-    return ExplainMatchResult(
-        name_matcher, SemanticsIRForTest::GetNodeText(function->name().node()),
-        result_listener);
-  } else {
-    *result_listener << "node is not a function";
-    return result_listener;
-  }
-}
-
-MATCHER_P4(
-    Function, name_matcher, param_matcher, return_matcher, body_matcher,
-    llvm::formatv(
-        "fn `{0}` params `{1}` returns `{2}` body `{3}`",
-        ::testing::DescribeMatcher<llvm::StringRef>(name_matcher),
-        ::testing::DescribeMatcher<llvm::ArrayRef<Semantics::PatternBinding>>(
-            param_matcher),
-        ::testing::DescribeMatcher<llvm::Optional<Semantics::Expression>>(
-            return_matcher),
-        ::testing::DescribeMatcher<Semantics::StatementBlock>(body_matcher))) {
-  const Semantics::Declaration& decl = arg;
-  if (auto function =
-          SemanticsIRForTest::GetDeclaration<Semantics::Function>(decl)) {
-    return ExplainMatchResult(
-               name_matcher,
-               SemanticsIRForTest::GetNodeText(function->name().node()),
-               result_listener) &&
-           ExplainMatchResult(param_matcher, function->params(),
-                              result_listener) &&
-           ExplainMatchResult(return_matcher, function->return_expr(),
-                              result_listener) &&
+          SemanticsIRForTest::GetNode<Semantics::Function>(node_ref)) {
+    return ExplainMatchResult(id_matcher, function->id(), result_listener) &&
            ExplainMatchResult(body_matcher, function->body(), result_listener);
   } else {
-    *result_listener << "node is not a function";
+    *result_listener << "node is not a Function";
     return result_listener;
   }
 }

+ 0 - 34
toolchain/semantics/nodes/infix_operator.h

@@ -1,34 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_INFIX_OPERATOR_H_
-#define CARBON_TOOLCHAIN_SEMANTICS_NODES_INFIX_OPERATOR_H_
-
-#include "common/ostream.h"
-#include "toolchain/parser/parse_tree.h"
-#include "toolchain/semantics/meta_node.h"
-
-namespace Carbon::Semantics {
-
-// Represents an infix operator, such as `+` in `1 + 2`.
-class InfixOperator {
- public:
-  static constexpr ExpressionKind MetaNodeKind = ExpressionKind::InfixOperator;
-
-  explicit InfixOperator(ParseTree::Node node, Expression lhs, Expression rhs)
-      : node_(node), lhs_(lhs), rhs_(rhs) {}
-
-  auto node() const -> ParseTree::Node { return node_; }
-  auto lhs() const -> Expression { return lhs_; }
-  auto rhs() const -> Expression { return rhs_; }
-
- private:
-  ParseTree::Node node_;
-  Expression lhs_;
-  Expression rhs_;
-};
-
-}  // namespace Carbon::Semantics
-
-#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_INFIX_OPERATOR_H_

+ 0 - 39
toolchain/semantics/nodes/infix_operator_test_matchers.h

@@ -1,39 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_INFIX_OPERATOR_TEST_MATCHERS_H_
-#define CARBON_TOOLCHAIN_SEMANTICS_NODES_INFIX_OPERATOR_TEST_MATCHERS_H_
-
-#include <gtest/gtest.h>
-
-#include "llvm/ADT/StringExtras.h"
-#include "toolchain/semantics/nodes/infix_operator.h"
-#include "toolchain/semantics/semantics_ir_for_test.h"
-
-namespace Carbon::Testing {
-
-MATCHER_P3(
-    InfixOperator, lhs_matcher, op_matcher, rhs_matcher,
-    llvm::formatv(
-        "InfixOperator {0} {1} {2}",
-        ::testing::DescribeMatcher<Semantics::Expression>(lhs_matcher),
-        ::testing::DescribeMatcher<llvm::StringRef>(op_matcher),
-        ::testing::DescribeMatcher<Semantics::Expression>(rhs_matcher))) {
-  const Semantics::Expression& expr = arg;
-  if (auto infix =
-          SemanticsIRForTest::GetExpression<Semantics::InfixOperator>(expr)) {
-    return ExplainMatchResult(op_matcher,
-                              SemanticsIRForTest::GetNodeText(infix->node()),
-                              result_listener) &&
-           ExplainMatchResult(lhs_matcher, infix->lhs(), result_listener) &&
-           ExplainMatchResult(rhs_matcher, infix->rhs(), result_listener);
-  } else {
-    *result_listener << "node is not a literal";
-    return result_listener;
-  }
-}
-
-}  // namespace Carbon::Testing
-
-#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_INFIX_OPERATOR_TEST_MATCHERS_H_

+ 39 - 0
toolchain/semantics/nodes/integer_literal.h

@@ -0,0 +1,39 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_INTEGER_LITERAL_H_
+#define CARBON_TOOLCHAIN_SEMANTICS_NODES_INTEGER_LITERAL_H_
+
+#include "common/ostream.h"
+#include "toolchain/parser/parse_tree.h"
+#include "toolchain/semantics/node_kind.h"
+
+namespace Carbon::Semantics {
+
+// Represents all kinds of literals: `1`, `i32`, etc.
+class IntegerLiteral {
+ public:
+  static constexpr NodeKind Kind = NodeKind::IntegerLiteral;
+
+  explicit IntegerLiteral(ParseTree::Node node, int32_t id,
+                          const llvm::APInt& value)
+      : node_(node), id_(id), value_(&value) {}
+
+  void Print(llvm::raw_ostream& out) const {
+    out << "IntegerLiteral(%" << id_ << ", " << *value_ << ")";
+  }
+
+  auto node() const -> ParseTree::Node { return node_; }
+  auto id() const -> int32_t { return id_; }
+  auto value() const -> const llvm::APInt& { return *value_; }
+
+ private:
+  ParseTree::Node node_;
+  int32_t id_;
+  const llvm::APInt* value_;
+};
+
+}  // namespace Carbon::Semantics
+
+#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_INTEGER_LITERAL_H_

+ 34 - 0
toolchain/semantics/nodes/integer_literal_test_matchers.h

@@ -0,0 +1,34 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_INTEGER_LITERAL_TEST_MATCHERS_H_
+#define CARBON_TOOLCHAIN_SEMANTICS_NODES_INTEGER_LITERAL_TEST_MATCHERS_H_
+
+#include <gmock/gmock.h>
+
+#include "llvm/ADT/StringExtras.h"
+#include "toolchain/semantics/nodes/integer_literal.h"
+#include "toolchain/semantics/semantics_ir_for_test.h"
+
+namespace Carbon::Testing {
+
+MATCHER_P2(
+    IntegerLiteral, id_matcher, value_matcher,
+    llvm::formatv("IntegerLiteral(%{0}, {1})",
+                  ::testing::DescribeMatcher<int32_t>(id_matcher),
+                  ::testing::DescribeMatcher<llvm::APInt>(value_matcher))) {
+  const Semantics::NodeRef& node_ref = arg;
+  if (auto lit =
+          SemanticsIRForTest::GetNode<Semantics::IntegerLiteral>(node_ref)) {
+    return ExplainMatchResult(id_matcher, lit->id(), result_listener) &&
+           ExplainMatchResult(value_matcher, lit->value(), result_listener);
+  } else {
+    *result_listener << "node is not a IntegerLiteral";
+    return result_listener;
+  }
+}
+
+}  // namespace Carbon::Testing
+
+#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_INTEGER_LITERAL_TEST_MATCHERS_H_

+ 0 - 29
toolchain/semantics/nodes/literal.h

@@ -1,29 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_LITERAL_H_
-#define CARBON_TOOLCHAIN_SEMANTICS_NODES_LITERAL_H_
-
-#include "common/ostream.h"
-#include "toolchain/parser/parse_tree.h"
-#include "toolchain/semantics/meta_node.h"
-
-namespace Carbon::Semantics {
-
-// Represents all kinds of literals: `1`, `i32`, etc.
-class Literal {
- public:
-  static constexpr ExpressionKind MetaNodeKind = ExpressionKind::Literal;
-
-  explicit Literal(ParseTree::Node node) : node_(node) {}
-
-  auto node() const -> ParseTree::Node { return node_; }
-
- private:
-  ParseTree::Node node_;
-};
-
-}  // namespace Carbon::Semantics
-
-#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_LITERAL_H_

+ 0 - 33
toolchain/semantics/nodes/literal_test_matchers.h

@@ -1,33 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_LITERAL_TEST_MATCHERS_H_
-#define CARBON_TOOLCHAIN_SEMANTICS_NODES_LITERAL_TEST_MATCHERS_H_
-
-#include <gtest/gtest.h>
-
-#include "llvm/ADT/StringExtras.h"
-#include "toolchain/semantics/nodes/literal.h"
-#include "toolchain/semantics/semantics_ir_for_test.h"
-
-namespace Carbon::Testing {
-
-MATCHER_P(
-    Literal, text_matcher,
-    llvm::formatv("Literal {0}",
-                  ::testing::DescribeMatcher<llvm::StringRef>(text_matcher))) {
-  const Semantics::Expression& expr = arg;
-  if (auto lit = SemanticsIRForTest::GetExpression<Semantics::Literal>(expr)) {
-    return ExplainMatchResult(text_matcher,
-                              SemanticsIRForTest::GetNodeText(lit->node()),
-                              result_listener);
-  } else {
-    *result_listener << "node is not a literal";
-    return result_listener;
-  }
-}
-
-}  // namespace Carbon::Testing
-
-#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_LITERAL_TEST_MATCHERS_H_

+ 0 - 33
toolchain/semantics/nodes/pattern_binding.h

@@ -1,33 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_PATTERN_BINDING_H_
-#define CARBON_TOOLCHAIN_SEMANTICS_NODES_PATTERN_BINDING_H_
-
-#include "common/ostream.h"
-#include "toolchain/parser/parse_tree.h"
-#include "toolchain/semantics/meta_node.h"
-#include "toolchain/semantics/nodes/declared_name.h"
-
-namespace Carbon::Semantics {
-
-// Represents `name: type`.
-class PatternBinding {
- public:
-  PatternBinding(ParseTree::Node node, DeclaredName name, Expression type)
-      : node_(node), name_(name), type_(type) {}
-
-  auto node() const -> ParseTree::Node { return node_; }
-  auto name() const -> const DeclaredName& { return name_; }
-  auto type() const -> const Expression& { return type_; }
-
- private:
-  ParseTree::Node node_;
-  DeclaredName name_;
-  Expression type_;
-};
-
-}  // namespace Carbon::Semantics
-
-#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_PATTERN_BINDING_H_

+ 0 - 30
toolchain/semantics/nodes/pattern_binding_test_matchers.h

@@ -1,30 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_PATTERN_BINDING_TEST_MATCHERS_H_
-#define CARBON_TOOLCHAIN_SEMANTICS_NODES_PATTERN_BINDING_TEST_MATCHERS_H_
-
-#include <gtest/gtest.h>
-
-#include "llvm/ADT/StringExtras.h"
-#include "toolchain/semantics/nodes/declared_name_test_matchers.h"
-#include "toolchain/semantics/nodes/pattern_binding.h"
-#include "toolchain/semantics/semantics_ir_for_test.h"
-
-namespace Carbon::Testing {
-
-inline auto PatternBinding(
-    ::testing::Matcher<llvm::StringRef> name_matcher,
-    ::testing::Matcher<Semantics::Expression> type_matcher)
-    -> ::testing::Matcher<Semantics::PatternBinding> {
-  return ::testing::AllOf(
-      ::testing::Property("name", &Semantics::PatternBinding::name,
-                          DeclaredName(name_matcher)),
-      ::testing::Property("type", &Semantics::PatternBinding::type,
-                          type_matcher));
-}
-
-}  // namespace Carbon::Testing
-
-#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_PATTERN_BINDING_TEST_MATCHERS_H_

+ 21 - 6
toolchain/semantics/nodes/return.h

@@ -6,25 +6,40 @@
 #define CARBON_TOOLCHAIN_SEMANTICS_NODES_RETURN_H_
 
 #include "common/ostream.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
 #include "toolchain/parser/parse_tree.h"
-#include "toolchain/semantics/meta_node.h"
+#include "toolchain/semantics/node_kind.h"
+#include "toolchain/semantics/node_ref.h"
 
 namespace Carbon::Semantics {
 
 // Represents `return [expr];`
 class Return {
  public:
-  static constexpr StatementKind MetaNodeKind = StatementKind::Return;
+  static constexpr NodeKind Kind = NodeKind::Return;
 
-  Return(ParseTree::Node node, llvm::Optional<Expression> expr)
-      : node_(node), expr_(expr) {}
+  Return(ParseTree::Node node, llvm::Optional<int32_t> target_id)
+      : node_(node), target_id_(target_id) {}
+
+  void Print(llvm::raw_ostream& out) const {
+    out << "Return(";
+    if (target_id_) {
+      out << "%" << *target_id_;
+    } else {
+      out << "None";
+    }
+    out << ")";
+  }
 
   auto node() const -> ParseTree::Node { return node_; }
-  auto expression() const -> const llvm::Optional<Expression>& { return expr_; }
+  auto target_id() const -> const llvm::Optional<int32_t>& {
+    return target_id_;
+  }
 
  private:
   ParseTree::Node node_;
-  llvm::Optional<Expression> expr_;
+  llvm::Optional<int32_t> target_id_;
 };
 
 }  // namespace Carbon::Semantics

+ 10 - 10
toolchain/semantics/nodes/return_test_matchers.h

@@ -5,7 +5,7 @@
 #ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_RETURN_TEST_MATCHERS_H_
 #define CARBON_TOOLCHAIN_SEMANTICS_NODES_RETURN_TEST_MATCHERS_H_
 
-#include <gtest/gtest.h>
+#include <gmock/gmock.h>
 
 #include "llvm/ADT/StringExtras.h"
 #include "toolchain/semantics/nodes/return.h"
@@ -13,16 +13,16 @@
 
 namespace Carbon::Testing {
 
-MATCHER_P(Return, expr_matcher,
-          llvm::formatv(
-              "Return {0}",
-              ::testing::DescribeMatcher<llvm::Optional<Semantics::Expression>>(
-                  expr_matcher))) {
-  const Semantics::Statement& stmt = arg;
-  if (auto ret = SemanticsIRForTest::GetStatement<Semantics::Return>(stmt)) {
-    return ExplainMatchResult(expr_matcher, ret->expression(), result_listener);
+MATCHER_P(Return, target_id_matcher,
+          llvm::formatv("Return({0})",
+                        ::testing::DescribeMatcher<llvm::Optional<int32_t>>(
+                            target_id_matcher))) {
+  const Semantics::NodeRef& node_ref = arg;
+  if (auto ret = SemanticsIRForTest::GetNode<Semantics::Return>(node_ref)) {
+    return ExplainMatchResult(target_id_matcher, ret->target_id(),
+                              result_listener);
   } else {
-    *result_listener << "node is not a function";
+    *result_listener << "node is not a Return";
     return result_listener;
   }
 }

+ 44 - 0
toolchain/semantics/nodes/set_name.h

@@ -0,0 +1,44 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_SET_NAME_H_
+#define CARBON_TOOLCHAIN_SEMANTICS_NODES_SET_NAME_H_
+
+#include "common/ostream.h"
+#include "llvm/ADT/SmallVector.h"
+#include "toolchain/parser/parse_tree.h"
+#include "toolchain/semantics/node_kind.h"
+
+namespace Carbon::Semantics {
+
+// Represents `fn name(params...) [-> return_expr] body`.
+class SetName {
+ public:
+  static constexpr NodeKind Kind = NodeKind::SetName;
+
+  SetName(ParseTree::Node node, llvm::StringRef name, int32_t target_id)
+      : node_(node), name_(name), target_id_(target_id) {}
+
+  void Print(llvm::raw_ostream& out) const {
+    out << "SetName(`" << name_ << "`, %" << target_id_ << ")";
+  }
+
+  auto node() const -> ParseTree::Node { return node_; }
+  auto name() const -> llvm::StringRef { return name_; }
+  auto target_id() const -> int32_t { return target_id_; }
+
+ private:
+  // The name node.
+  ParseTree::Node node_;
+
+  // The name to assign.
+  llvm::StringRef name_;
+
+  // The ID being named.
+  int32_t target_id_;
+};
+
+}  // namespace Carbon::Semantics
+
+#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_SET_NAME_H_

+ 34 - 0
toolchain/semantics/nodes/set_name_test_matchers.h

@@ -0,0 +1,34 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_SET_NAME_TEST_MATCHERS_H_
+#define CARBON_TOOLCHAIN_SEMANTICS_NODES_SET_NAME_TEST_MATCHERS_H_
+
+#include <gmock/gmock.h>
+
+#include "llvm/ADT/StringExtras.h"
+#include "toolchain/semantics/nodes/set_name.h"
+#include "toolchain/semantics/semantics_ir_for_test.h"
+
+namespace Carbon::Testing {
+
+MATCHER_P2(
+    SetName, name_matcher, target_id_matcher,
+    llvm::formatv("SetName(`{0}`, %`{1}`)",
+                  ::testing::DescribeMatcher<llvm::StringRef>(name_matcher),
+                  ::testing::DescribeMatcher<int32_t>(target_id_matcher))) {
+  const Semantics::NodeRef& node_ref = arg;
+  if (auto node = SemanticsIRForTest::GetNode<Semantics::SetName>(node_ref)) {
+    return ExplainMatchResult(name_matcher, node->name(), result_listener) &&
+           ExplainMatchResult(target_id_matcher, node->target_id(),
+                              result_listener);
+  } else {
+    *result_listener << "node is not a SetName";
+    return result_listener;
+  }
+}
+
+}  // namespace Carbon::Testing
+
+#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_SET_NAME_TEST_MATCHERS_H_

+ 12 - 0
toolchain/semantics/nodes_test_matchers.h

@@ -0,0 +1,12 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_SEMANTICS_NODES_TEST_MATCHERS_H_
+#define CARBON_TOOLCHAIN_SEMANTICS_NODES_TEST_MATCHERS_H_
+
+// This is a wrapper header that only aggregates all nodes into a single, common
+// header so that the list is centralized.
+#include "toolchain/semantics/nodes/function_test_matchers.h"
+
+#endif  // CARBON_TOOLCHAIN_SEMANTICS_NODES_TEST_MATCHERS_H_

+ 15 - 104
toolchain/semantics/semantics_ir.cpp

@@ -7,120 +7,31 @@
 #include "common/check.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "toolchain/lexer/tokenized_buffer.h"
-#include "toolchain/semantics/nodes/expression_statement.h"
 
 namespace Carbon {
 
-void SemanticsIR::Print(llvm::raw_ostream& out, ParseTree::Node node) const {
-  out << parse_tree_->GetNodeText(node);
-}
-
 void SemanticsIR::Print(llvm::raw_ostream& out,
-                        Semantics::Declaration decl) const {
-  switch (decl.kind()) {
-    case Semantics::DeclarationKind::Function:
-      Print(out, declarations_.Get<Semantics::Function>(decl));
+                        Semantics::NodeRef node_ref) const {
+  switch (node_ref.kind()) {
+    case Semantics::NodeKind::BinaryOperator:
+      nodes_.Get<Semantics::BinaryOperator>(node_ref).Print(out);
       return;
-    case Semantics::DeclarationKind::Invalid:
-      CARBON_FATAL() << "Invalid declaration type";
-  }
-}
-
-void SemanticsIR::Print(llvm::raw_ostream& out,
-                        Semantics::Expression expr) const {
-  switch (expr.kind()) {
-    case Semantics::ExpressionKind::InfixOperator:
-      Print(out, expressions_.Get<Semantics::InfixOperator>(expr));
+    case Semantics::NodeKind::Function:
+      nodes_.Get<Semantics::Function>(node_ref).Print(
+          out, [&](Semantics::NodeRef other) { Print(out, other); });
       return;
-    case Semantics::ExpressionKind::Literal:
-      Print(out, expressions_.Get<Semantics::Literal>(expr));
+    case Semantics::NodeKind::IntegerLiteral:
+      nodes_.Get<Semantics::IntegerLiteral>(node_ref).Print(out);
       return;
-    case Semantics::ExpressionKind::Invalid:
-      CARBON_FATAL() << "Invalid expression type";
-  }
-}
-
-void SemanticsIR::Print(llvm::raw_ostream& out,
-                        Semantics::Statement stmt) const {
-  switch (stmt.kind()) {
-    case Semantics::StatementKind::ExpressionStatement:
-      Print(out, statements_.Get<Semantics::ExpressionStatement>(stmt));
+    case Semantics::NodeKind::Return:
+      nodes_.Get<Semantics::Return>(node_ref).Print(out);
       return;
-    case Semantics::StatementKind::Return:
-      Print(out, statements_.Get<Semantics::Return>(stmt));
+    case Semantics::NodeKind::SetName:
+      nodes_.Get<Semantics::SetName>(node_ref).Print(out);
       return;
-    case Semantics::StatementKind::Invalid:
-      CARBON_FATAL() << "Invalid expression type";
-  }
-  out << ";";
-}
-
-void SemanticsIR::Print(llvm::raw_ostream& out,
-                        const Semantics::DeclaredName& name) const {
-  Print(out, name.node());
-}
-
-void SemanticsIR::Print(llvm::raw_ostream& out,
-                        const Semantics::ExpressionStatement& expr) const {
-  Print(out, expr.expression());
-}
-
-void SemanticsIR::Print(llvm::raw_ostream& out,
-                        const Semantics::Function& function) const {
-  out << "fn ";
-  Print(out, function.name());
-  out << "(";
-  llvm::ListSeparator sep;
-  for (const auto& param : function.params()) {
-    out << sep;
-    Print(out, param);
-  }
-  out << ")";
-  if (function.return_expr()) {
-    out << " -> ";
-    Print(out, *function.return_expr());
-  }
-  Print(out, function.body());
-}
-
-void SemanticsIR::Print(llvm::raw_ostream& out,
-                        const Semantics::InfixOperator& op) const {
-  Print(out, op.lhs());
-  out << " ";
-  Print(out, op.node());
-  out << " ";
-  Print(out, op.rhs());
-}
-
-void SemanticsIR::Print(llvm::raw_ostream& out,
-                        const Semantics::Literal& literal) const {
-  Print(out, literal.node());
-}
-
-void SemanticsIR::Print(llvm::raw_ostream& out,
-                        const Semantics::PatternBinding& binding) const {
-  Print(out, binding.name());
-  out << ": ";
-  Print(out, binding.type());
-}
-
-void SemanticsIR::Print(llvm::raw_ostream& out,
-                        const Semantics::Return& ret) const {
-  out << "return";
-  if (ret.expression()) {
-    out << " ";
-    Print(out, *ret.expression());
-  }
-}
-
-void SemanticsIR::Print(llvm::raw_ostream& out,
-                        const Semantics::StatementBlock& block) const {
-  out << " { ";
-  for (const auto& statement : block.nodes()) {
-    Print(out, statement);
-    out << "; ";
+    case Semantics::NodeKind::Invalid:
+      CARBON_FATAL() << "Invalid NodeRef kind";
   }
-  out << "}";
 }
 
 }  // namespace Carbon

+ 7 - 35
toolchain/semantics/semantics_ir.h

@@ -7,13 +7,7 @@
 
 #include "llvm/ADT/SmallVector.h"
 #include "toolchain/parser/parse_tree.h"
-#include "toolchain/semantics/meta_node_block.h"
-#include "toolchain/semantics/nodes/expression_statement.h"
-#include "toolchain/semantics/nodes/function.h"
-#include "toolchain/semantics/nodes/infix_operator.h"
-#include "toolchain/semantics/nodes/literal.h"
-#include "toolchain/semantics/nodes/pattern_binding.h"
-#include "toolchain/semantics/nodes/return.h"
+#include "toolchain/semantics/node_store.h"
 
 namespace Carbon::Testing {
 class SemanticsIRForTest;
@@ -25,30 +19,12 @@ namespace Carbon {
 class SemanticsIR {
  public:
   // File-level declarations.
-  auto root_block() const -> const Semantics::DeclarationBlock& {
-    return *root_block_;
+  auto root_block() const -> llvm::ArrayRef<Semantics::NodeRef> {
+    return root_block_;
   }
 
-  // Debug printer for the parse tree.
-  void Print(llvm::raw_ostream& out, ParseTree::Node node) const;
-
-  // Debug printers for meta nodes.
-  void Print(llvm::raw_ostream& out, Semantics::Declaration decl) const;
-  void Print(llvm::raw_ostream& out, Semantics::Expression expr) const;
-  void Print(llvm::raw_ostream& out, Semantics::Statement stmt) const;
-
-  // Debug printers for other nodes.
-  void Print(llvm::raw_ostream& out, const Semantics::DeclaredName& name) const;
-  void Print(llvm::raw_ostream& out,
-             const Semantics::ExpressionStatement& expr) const;
-  void Print(llvm::raw_ostream& out, const Semantics::Function& function) const;
-  void Print(llvm::raw_ostream& out, const Semantics::InfixOperator& op) const;
-  void Print(llvm::raw_ostream& out, const Semantics::Literal& literal) const;
-  void Print(llvm::raw_ostream& out,
-             const Semantics::PatternBinding& binding) const;
-  void Print(llvm::raw_ostream& out, const Semantics::Return& ret) const;
-  void Print(llvm::raw_ostream& out,
-             const Semantics::StatementBlock& block) const;
+  // Prints the node information.
+  void Print(llvm::raw_ostream& out, Semantics::NodeRef node_ref) const;
 
  private:
   friend class SemanticsIRFactory;
@@ -57,12 +33,8 @@ class SemanticsIR {
   explicit SemanticsIR(const ParseTree& parse_tree)
       : parse_tree_(&parse_tree) {}
 
-  Semantics::DeclarationStore declarations_;
-  Semantics::ExpressionStore expressions_;
-  Semantics::StatementStore statements_;
-
-  // The file-level block. Only assigned after initialization is complete.
-  llvm::Optional<Semantics::DeclarationBlock> root_block_;
+  Semantics::NodeStore nodes_;
+  llvm::SmallVector<Semantics::NodeRef, 0> root_block_;
 
   const ParseTree* parse_tree_;
 };

+ 108 - 74
toolchain/semantics/semantics_ir_factory.cpp

@@ -9,10 +9,11 @@
 #include "common/check.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/Support/FormatVariadic.h"
+#include "toolchain/lexer/token_kind.h"
 #include "toolchain/lexer/tokenized_buffer.h"
 #include "toolchain/parser/parse_node_kind.h"
-#include "toolchain/semantics/meta_node_block.h"
-#include "toolchain/semantics/nodes/expression_statement.h"
+//#include "toolchain/semantics/meta_node_block.h"
+#include "toolchain/semantics/nodes/binary_operator.h"
 #include "toolchain/semantics/parse_subtree_consumer.h"
 
 namespace Carbon {
@@ -25,34 +26,17 @@ static void FixReverseOrdering(T& container) {
   std::reverse(container.begin(), container.end());
 }
 
-auto SemanticsIRFactory::Build(const ParseTree& parse_tree) -> SemanticsIR {
-  SemanticsIRFactory builder(parse_tree);
+auto SemanticsIRFactory::Build(const TokenizedBuffer& tokens,
+                               const ParseTree& parse_tree) -> SemanticsIR {
+  SemanticsIRFactory builder(tokens, parse_tree);
   builder.Build();
   return builder.semantics_;
 }
 
 void SemanticsIRFactory::Build() {
   auto subtree = ParseSubtreeConsumer::ForTree(parse_tree());
-  // FileEnd is a placeholder node which can be discarded.
-  RequireNodeEmpty(subtree.RequireConsume(ParseNodeKind::FileEnd()));
-  llvm::SmallVector<Semantics::Declaration, 0> nodes;
-  llvm::StringMap<Semantics::Declaration> name_lookup;
-  while (llvm::Optional<ParseTree::Node> node = subtree.TryConsume()) {
-    switch (auto node_kind = parse_tree().node_kind(*node)) {
-      case ParseNodeKind::FunctionDeclaration(): {
-        auto [name, decl] = TransformFunctionDeclaration(*node);
-        nodes.push_back(decl);
-        name_lookup[name] = decl;
-        break;
-      }
-      default:
-        CARBON_FATAL() << "At index " << node->index() << ", unexpected "
-                       << node_kind;
-    }
-  }
-  FixReverseOrdering(nodes);
   semantics_.root_block_ =
-      Semantics::DeclarationBlock(std::move(nodes), std::move(name_lookup));
+      TransformBlockSubtree(subtree, ParseNodeKind::FileEnd());
 }
 
 void SemanticsIRFactory::RequireNodeEmpty(ParseTree::Node node) {
@@ -63,58 +47,81 @@ void SemanticsIRFactory::RequireNodeEmpty(ParseTree::Node node) {
       << "would have subtree_size of 1, but was " << subtree_size;
 }
 
-auto SemanticsIRFactory::TransformCodeBlock(ParseTree::Node node)
-    -> Semantics::StatementBlock {
-  CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::CodeBlock());
-
-  auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
-  RequireNodeEmpty(subtree.RequireConsume(ParseNodeKind::CodeBlockEnd()));
+auto SemanticsIRFactory::TransformBlockSubtree(ParseSubtreeConsumer& subtree,
+                                               ParseNodeKind end_kind)
+    -> llvm::SmallVector<Semantics::NodeRef, 0> {
+  RequireNodeEmpty(subtree.RequireConsume(end_kind));
 
-  llvm::SmallVector<Semantics::Statement, 0> nodes;
+  llvm::SmallVector<Semantics::NodeRef, 0> nodes;
   while (llvm::Optional<ParseTree::Node> child = subtree.TryConsume()) {
     switch (auto child_kind = parse_tree().node_kind(*child)) {
-      case ParseNodeKind::ExpressionStatement():
-        nodes.push_back(TransformExpressionStatement(*child));
+      case ParseNodeKind::FunctionDeclaration(): {
+        TransformFunctionDeclaration(nodes, *child);
         break;
+      }
+      // case ParseNodeKind::ExpressionStatement():
+      //   nodes.push_back(TransformExpressionStatement(*child));
+      //   break;
       case ParseNodeKind::ReturnStatement():
-        nodes.push_back(TransformReturnStatement(*child));
-        break;
-      case ParseNodeKind::VariableDeclaration():
-        // TODO: Handle.
+        TransformReturnStatement(nodes, *child);
         break;
+      // case ParseNodeKind::VariableDeclaration():
+      //   // TODO: Handle.
+      //   break;
       default:
         CARBON_FATAL() << "At index " << child->index() << ", unexpected "
                        << child_kind;
     }
   }
   FixReverseOrdering(nodes);
-  return Semantics::StatementBlock(std::move(nodes),
-                                   /*name_lookup=*/{});
+  return nodes;
 }
 
-auto SemanticsIRFactory::TransformDeclaredName(ParseTree::Node node)
-    -> Semantics::DeclaredName {
+auto SemanticsIRFactory::TransformCodeBlock(ParseTree::Node node)
+    -> llvm::SmallVector<Semantics::NodeRef, 0> {
+  CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::CodeBlock());
+
+  auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
+  return TransformBlockSubtree(subtree, ParseNodeKind::CodeBlockEnd());
+}
+
+void SemanticsIRFactory::TransformDeclaredName(
+    llvm::SmallVector<Semantics::NodeRef, 0>& nodes, ParseTree::Node node,
+    int32_t target_id) {
   CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::DeclaredName());
   RequireNodeEmpty(node);
 
-  return Semantics::DeclaredName(node);
+  nodes.push_back(semantics_.nodes_.Store(
+      Semantics::SetName(node, parse_tree().GetNodeText(node), target_id)));
 }
 
-auto SemanticsIRFactory::TransformExpression(ParseTree::Node node)
-    -> Semantics::Expression {
+void SemanticsIRFactory::TransformExpression(
+    llvm::SmallVector<Semantics::NodeRef, 0>& nodes, ParseTree::Node node,
+    int32_t target_id) {
   switch (auto node_kind = parse_tree().node_kind(node)) {
-    case ParseNodeKind::Literal():
+    case ParseNodeKind::Literal(): {
       RequireNodeEmpty(node);
-      return semantics_.expressions_.Store(Semantics::Literal(node));
+      auto token = parse_tree().node_token(node);
+      switch (auto token_kind = tokens_->GetKind(token)) {
+        case TokenKind::IntegerLiteral(): {
+          nodes.push_back(semantics_.nodes_.Store(Semantics::IntegerLiteral(
+              node, target_id, tokens_->GetIntegerLiteral(token))));
+          break;
+        }
+        default:
+          CARBON_FATAL() << "Unhandled kind: " << token_kind.Name();
+      }
+      break;
+    }
     case ParseNodeKind::InfixOperator():
-      return semantics_.expressions_.Store(TransformInfixOperator(node));
+      return TransformInfixOperator(nodes, node, target_id);
     default:
       CARBON_FATAL() << "At index " << node.index() << ", unexpected "
                      << node_kind;
-      break;
   }
 }
 
+/*
 auto SemanticsIRFactory::TransformExpressionStatement(ParseTree::Node node)
     -> Semantics::Statement {
   CARBON_CHECK(parse_tree().node_kind(node) ==
@@ -122,44 +129,65 @@ auto SemanticsIRFactory::TransformExpressionStatement(ParseTree::Node node)
 
   auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
   RequireNodeEmpty(subtree.RequireConsume(ParseNodeKind::StatementEnd()));
-  return semantics_.statements_.Store(Semantics::ExpressionStatement(
-      TransformExpression(subtree.RequireConsume())));
+  return TransformExpression(subtree.RequireConsume());
 }
+*/
 
-auto SemanticsIRFactory::TransformFunctionDeclaration(ParseTree::Node node)
-    -> std::tuple<llvm::StringRef, Semantics::Declaration> {
+void SemanticsIRFactory::TransformFunctionDeclaration(
+    llvm::SmallVector<Semantics::NodeRef, 0>& nodes, ParseTree::Node node) {
   CARBON_CHECK(parse_tree().node_kind(node) ==
                ParseNodeKind::FunctionDeclaration());
 
+  auto id = next_id();
   auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
   auto body =
       TransformCodeBlock(subtree.RequireConsume(ParseNodeKind::CodeBlock()));
-  llvm::Optional<Semantics::Expression> return_type_expr;
-  if (auto return_type_node = subtree.TryConsume(ParseNodeKind::ReturnType())) {
-    return_type_expr = TransformReturnType(*return_type_node);
+  // llvm::Optional<Semantics::Statement> return_type_expr;
+  // if (auto return_type_node =
+  //   subtree.TryConsume(ParseNodeKind::ReturnType())) {
+  //   return_type_expr = TransformReturnType(*return_type_node);
+  // }
+  (void)subtree.RequireConsume(ParseNodeKind::ParameterList());
+  // auto params = TransformParameterList(
+  //   subtree.RequireConsume(ParseNodeKind::ParameterList()));
+  TransformDeclaredName(
+      nodes, subtree.RequireConsume(ParseNodeKind::DeclaredName()), id);
+  nodes.push_back(
+      semantics_.nodes_.Store(Semantics::Function(node, id, std::move(body))));
+}
+
+static auto GetBinaryOp(TokenKind kind) -> Semantics::BinaryOperator::Op {
+  switch (kind) {
+    case TokenKind::Plus():
+      return Semantics::BinaryOperator::Op::Add;
+    default:
+      CARBON_FATAL() << "Unrecognized token kind: " << kind.Name();
   }
-  auto params = TransformParameterList(
-      subtree.RequireConsume(ParseNodeKind::ParameterList()));
-  auto name = TransformDeclaredName(
-      subtree.RequireConsume(ParseNodeKind::DeclaredName()));
-  auto decl = semantics_.declarations_.Store(
-      Semantics::Function(node, name, params, return_type_expr, body));
-  return std::make_tuple(parse_tree().GetNodeText(name.node()), decl);
 }
 
-auto SemanticsIRFactory::TransformInfixOperator(ParseTree::Node node)
-    -> Semantics::InfixOperator {
+void SemanticsIRFactory::TransformInfixOperator(
+    llvm::SmallVector<Semantics::NodeRef, 0>& nodes, ParseTree::Node node,
+    int32_t target_id) {
   CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::InfixOperator());
 
+  auto token = parse_tree().node_token(node);
+  auto token_kind = tokens_->GetKind(token);
+  auto op = GetBinaryOp(token_kind);
+
+  auto rhs_id = next_id();
+  auto lhs_id = next_id();
+  nodes.push_back(semantics_.nodes_.Store(
+      Semantics::BinaryOperator(node, target_id, op, lhs_id, rhs_id)));
   auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
-  auto rhs = TransformExpression(subtree.RequireConsume());
-  auto lhs = TransformExpression(subtree.RequireConsume());
-  return Semantics::InfixOperator(node, lhs, rhs);
+  TransformExpression(nodes, subtree.RequireConsume(), rhs_id);
+  TransformExpression(nodes, subtree.RequireConsume(), lhs_id);
 }
 
+/*
 auto SemanticsIRFactory::TransformParameterList(ParseTree::Node node)
     -> llvm::SmallVector<Semantics::PatternBinding, 0> {
-  CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::ParameterList());
+  CARBON_CHECK(parse_tree().node_kind(node) ==
+ParseNodeKind::ParameterList());
 
   auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
   RequireNodeEmpty(subtree.RequireConsume(ParseNodeKind::ParameterListEnd()));
@@ -182,7 +210,8 @@ auto SemanticsIRFactory::TransformParameterList(ParseTree::Node node)
 
 auto SemanticsIRFactory::TransformPatternBinding(ParseTree::Node node)
     -> Semantics::PatternBinding {
-  CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::PatternBinding());
+  CARBON_CHECK(parse_tree().node_kind(node) ==
+ParseNodeKind::PatternBinding());
 
   auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
   auto type = TransformExpression(subtree.RequireConsume());
@@ -190,9 +219,10 @@ auto SemanticsIRFactory::TransformPatternBinding(ParseTree::Node node)
       subtree.RequireConsume(ParseNodeKind::DeclaredName()));
   return Semantics::PatternBinding(node, name, type);
 }
+*/
 
-auto SemanticsIRFactory::TransformReturnStatement(ParseTree::Node node)
-    -> Semantics::Statement {
+void SemanticsIRFactory::TransformReturnStatement(
+    llvm::SmallVector<Semantics::NodeRef, 0>& nodes, ParseTree::Node node) {
   CARBON_CHECK(parse_tree().node_kind(node) ==
                ParseNodeKind::ReturnStatement());
 
@@ -202,20 +232,24 @@ auto SemanticsIRFactory::TransformReturnStatement(ParseTree::Node node)
   auto expr = subtree.TryConsume();
   if (expr) {
     // return expr;
-    return semantics_.statements_.Store(
-        Semantics::Return(node, TransformExpression(*expr)));
+    auto id = next_id();
+    nodes.push_back(semantics_.nodes_.Store(Semantics::Return(node, id)));
+    TransformExpression(nodes, *expr, id);
   } else {
     // return;
-    return semantics_.statements_.Store(Semantics::Return(node, llvm::None));
+    nodes.push_back(
+        semantics_.nodes_.Store(Semantics::Return(node, llvm::None)));
   }
 }
 
+/*
 auto SemanticsIRFactory::TransformReturnType(ParseTree::Node node)
-    -> Semantics::Expression {
+    -> Semantics::Statement {
   CARBON_CHECK(parse_tree().node_kind(node) == ParseNodeKind::ReturnType());
 
   auto subtree = ParseSubtreeConsumer::ForParent(parse_tree(), node);
   return TransformExpression(subtree.RequireConsume());
 }
+*/
 
 }  // namespace Carbon

+ 41 - 17
toolchain/semantics/semantics_ir_factory.h

@@ -6,6 +6,7 @@
 #define CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_IR_FACTORY_H_
 
 #include "toolchain/parser/parse_tree.h"
+#include "toolchain/semantics/parse_subtree_consumer.h"
 #include "toolchain/semantics/semantics_ir.h"
 
 namespace Carbon {
@@ -14,11 +15,13 @@ namespace Carbon {
 class SemanticsIRFactory {
  public:
   // Builds the SemanticsIR without doing any substantial semantic analysis.
-  static auto Build(const ParseTree& parse_tree) -> SemanticsIR;
+  static auto Build(const TokenizedBuffer& tokens, const ParseTree& parse_tree)
+      -> SemanticsIR;
 
  private:
-  explicit SemanticsIRFactory(const ParseTree& parse_tree)
-      : semantics_(parse_tree) {}
+  explicit SemanticsIRFactory(const TokenizedBuffer& tokens,
+                              const ParseTree& parse_tree)
+      : tokens_(&tokens), semantics_(parse_tree) {}
 
   void Build();
 
@@ -26,27 +29,48 @@ class SemanticsIRFactory {
   // otherwise checked.
   void RequireNodeEmpty(ParseTree::Node node);
 
+  // Transforms a block subtree, such as a file or CodeBlock, into its semantic
+  // nodes.
+  auto TransformBlockSubtree(ParseSubtreeConsumer& subtree,
+                             ParseNodeKind end_kind)
+      -> llvm::SmallVector<Semantics::NodeRef, 0>;
+
   // Each of these takes a parse tree node and does a transformation based on
   // its type. These functions are per ParseNodeKind.
-  auto TransformCodeBlock(ParseTree::Node node) -> Semantics::StatementBlock;
-  auto TransformDeclaredName(ParseTree::Node node) -> Semantics::DeclaredName;
-  auto TransformExpression(ParseTree::Node node) -> Semantics::Expression;
-  auto TransformExpressionStatement(ParseTree::Node node)
-      -> Semantics::Statement;
-  auto TransformFunctionDeclaration(ParseTree::Node node)
-      -> std::tuple<llvm::StringRef, Semantics::Declaration>;
-  auto TransformInfixOperator(ParseTree::Node node) -> Semantics::InfixOperator;
-  auto TransformParameterList(ParseTree::Node node)
-      -> llvm::SmallVector<Semantics::PatternBinding, 0>;
-  auto TransformPatternBinding(ParseTree::Node node)
-      -> Semantics::PatternBinding;
-  auto TransformReturnType(ParseTree::Node node) -> Semantics::Expression;
-  auto TransformReturnStatement(ParseTree::Node node) -> Semantics::Statement;
+  auto TransformCodeBlock(ParseTree::Node node)
+      -> llvm::SmallVector<Semantics::NodeRef, 0>;
+  void TransformDeclaredName(llvm::SmallVector<Semantics::NodeRef, 0>& nodes,
+                             ParseTree::Node node, int32_t target_id);
+  void TransformExpression(llvm::SmallVector<Semantics::NodeRef, 0>& nodes,
+                           ParseTree::Node node, int32_t target_id);
+  // auto TransformExpressionStatement(ParseTree::Node node)
+  //   -> Semantics::Statement;
+  void TransformFunctionDeclaration(
+      llvm::SmallVector<Semantics::NodeRef, 0>& nodes, ParseTree::Node node);
+  void TransformInfixOperator(llvm::SmallVector<Semantics::NodeRef, 0>& nodes,
+                              ParseTree::Node node, int32_t target_id);
+  // auto TransformParameterList(ParseTree::Node node)
+  //   -> llvm::SmallVector<Semantics::PatternBinding, 0>
+  // auto TransformPatternBinding(ParseTree::Node node)
+  //   -> Semantics::PatternBinding;
+  // auto TransformReturnType(ParseTree::Node node) -> Semantics::Statement;
+  void TransformReturnStatement(llvm::SmallVector<Semantics::NodeRef, 0>& nodes,
+                                ParseTree::Node node);
+
+  // Returns a unique ID for the SemanticsIR.
+  auto next_id() -> int32_t { return id_counter_++; }
 
   // Convenience accessor.
   auto parse_tree() -> const ParseTree& { return *semantics_.parse_tree_; }
 
+  // Tokens for getting data on literals.
+  const TokenizedBuffer* tokens_;
+
+  // The SemanticsIR being constructed.
   SemanticsIR semantics_;
+
+  // A counter for unique IDs.
+  int32_t id_counter_ = 0;
 };
 
 }  // namespace Carbon

+ 43 - 58
toolchain/semantics/semantics_ir_factory_test.cpp

@@ -18,10 +18,9 @@ namespace {
 
 using ::testing::_;
 using ::testing::ElementsAre;
-using ::testing::Eq;
 using ::testing::IsEmpty;
 using ::testing::Optional;
-using ::testing::UnorderedElementsAre;
+using ::testing::StrEq;
 
 class SemanticsIRFactoryTest : public ::testing::Test {
  protected:
@@ -31,17 +30,14 @@ class SemanticsIRFactoryTest : public ::testing::Test {
     EXPECT_FALSE(tokenized_buffer->has_errors());
     parse_tree = ParseTree::Parse(*tokenized_buffer, consumer);
     EXPECT_FALSE(parse_tree->has_errors());
-    SemanticsIRForTest::set_semantics(SemanticsIRFactory::Build(*parse_tree));
+    SemanticsIRForTest::set_semantics(
+        SemanticsIRFactory::Build(*tokenized_buffer, *parse_tree));
   }
 
   ~SemanticsIRFactoryTest() override { SemanticsIRForTest::clear(); }
 
-  void ExpectRootBlock(
-      ::testing::Matcher<llvm::ArrayRef<Semantics::Declaration>> decls,
-      ::testing::Matcher<llvm::StringMap<Semantics::Declaration>> name_lookup) {
-    EXPECT_THAT(SemanticsIRForTest::semantics().root_block().nodes(), decls);
-    EXPECT_THAT(SemanticsIRForTest::semantics().root_block().name_lookup(),
-                name_lookup);
+  auto root_block() const -> llvm::ArrayRef<Semantics::NodeRef> {
+    return SemanticsIRForTest::semantics().root_block();
   }
 
   llvm::Optional<SourceBuffer> source_buffer;
@@ -65,33 +61,30 @@ TEST_F(SemanticsIRFactoryTest, SimpleProgram) {
              return x;
            }
           )");
-  ExpectRootBlock(
-      ElementsAre(
-          Function(
-              Eq("Add"),
-              ElementsAre(PatternBinding(Eq("x"), Literal("i32")),
-                          PatternBinding(Eq("y"), Literal("i32"))),
-              Optional(Literal("i32"))),
-          Function(Eq("Main"), IsEmpty(), Optional(Literal("i32")))),
-      UnorderedElementsAre(MappedNode("Add", FunctionName("Add")),
-                           MappedNode("Main", FunctionName("Main"))));
+  EXPECT_THAT(
+      SemanticsIRForTest::semantics().root_block(),
+      ElementsAre(Function(Eq("Add"),
+                           ElementsAre(PatternBinding(Eq("x"), Literal("i32")),
+                                       PatternBinding(Eq("y"), Literal("i32"))),
+                           Optional(Literal("i32"))),
+                  Function(Eq("Main"), IsEmpty(), Optional(Literal("i32")))));
 }
 */
 
 TEST_F(SemanticsIRFactoryTest, Empty) {
   EXPECT_CALL(consumer, HandleDiagnostic(_)).Times(0);
   Build("");
-  ExpectRootBlock(IsEmpty(), IsEmpty());
+  EXPECT_THAT(root_block(), IsEmpty());
 }
 
 TEST_F(SemanticsIRFactoryTest, FunctionBasic) {
   EXPECT_CALL(consumer, HandleDiagnostic(_)).Times(0);
   Build("fn Foo() {}");
-  ExpectRootBlock(ElementsAre(Function(Eq("Foo"), IsEmpty(), IsNone(),
-                                       StatementBlock(IsEmpty(), IsEmpty()))),
-                  UnorderedElementsAre(MappedNode("Foo", FunctionName("Foo"))));
+  EXPECT_THAT(root_block(),
+              ElementsAre(Function(0, IsEmpty()), SetName(StrEq("Foo"), 0)));
 }
 
+/*
 TEST_F(SemanticsIRFactoryTest, FunctionParams) {
   EXPECT_CALL(consumer, HandleDiagnostic(_)).Times(0);
   Build("fn Foo(x: i32, y: i64) {}");
@@ -102,33 +95,27 @@ TEST_F(SemanticsIRFactoryTest, FunctionParams) {
                            IsNone(), StatementBlock(IsEmpty(), IsEmpty()))),
       UnorderedElementsAre(MappedNode("Foo", FunctionName("Foo"))));
 }
+*/
 
+/*
 TEST_F(SemanticsIRFactoryTest, FunctionReturnType) {
   EXPECT_CALL(consumer, HandleDiagnostic(_)).Times(0);
   Build("fn Foo() -> i32 {}");
-  ExpectRootBlock(
-      ElementsAre(Function(Eq("Foo"), IsEmpty(), Optional(Literal("i32")),
-                           StatementBlock(IsEmpty(), IsEmpty()))),
-      UnorderedElementsAre(MappedNode("Foo", FunctionName("Foo"))));
-}
-
-TEST_F(SemanticsIRFactoryTest, FunctionDuplicate) {
-  EXPECT_CALL(consumer, HandleDiagnostic(_)).Times(0);
-  Build(R"(fn Foo() {}
-           fn Foo() {}
-          )");
-  ExpectRootBlock(ElementsAre(FunctionName("Foo"), FunctionName("Foo")),
-                  UnorderedElementsAre(MappedNode("Foo", FunctionName("Foo"))));
+  EXPECT_THAT(root_block(), ElementsAre(Function(0, IsEmpty()),
+                                        SetName(StrEq("Foo"), 0)));
 }
+*/
 
 TEST_F(SemanticsIRFactoryTest, FunctionOrder) {
   EXPECT_CALL(consumer, HandleDiagnostic(_)).Times(0);
   Build(R"(fn Foo() {}
            fn Bar() {}
+           fn Bar() {}
           )");
-  ExpectRootBlock(ElementsAre(FunctionName("Foo"), FunctionName("Bar")),
-                  UnorderedElementsAre(MappedNode("Bar", FunctionName("Bar")),
-                                       MappedNode("Foo", FunctionName("Foo"))));
+  EXPECT_THAT(root_block(),
+              ElementsAre(Function(2, IsEmpty()), SetName(StrEq("Foo"), 2),
+                          Function(1, IsEmpty()), SetName(StrEq("Bar"), 1),
+                          Function(0, IsEmpty()), SetName(StrEq("Bar"), 0)));
 }
 
 TEST_F(SemanticsIRFactoryTest, TrivialReturn) {
@@ -137,40 +124,38 @@ TEST_F(SemanticsIRFactoryTest, TrivialReturn) {
              return;
            }
           )");
-  ExpectRootBlock(
-      ElementsAre(
-          Function(Eq("Main"), IsEmpty(), IsNone(),
-                   StatementBlock(ElementsAre(Return(IsNone())), IsEmpty()))),
-      UnorderedElementsAre(MappedNode("Main", FunctionName("Main"))));
+  EXPECT_THAT(root_block(),
+              ElementsAre(Function(0, ElementsAre(Return(IsNone()))),
+                          SetName(StrEq("Main"), 0)));
 }
 
 TEST_F(SemanticsIRFactoryTest, ReturnLiteral) {
   EXPECT_CALL(consumer, HandleDiagnostic(_)).Times(0);
   Build(R"(fn Main() {
-             return 1;
+             return 12;
            }
           )");
-  ExpectRootBlock(
-      ElementsAre(
-          Function(Eq("Main"), IsEmpty(), IsNone(),
-                   StatementBlock(ElementsAre(Return(Optional(Literal("1")))),
-                                  IsEmpty()))),
-      UnorderedElementsAre(MappedNode("Main", FunctionName("Main"))));
+  EXPECT_THAT(root_block(),
+              ElementsAre(Function(0, ElementsAre(IntegerLiteral(1, 12),
+                                                  Return(Optional(1)))),
+                          SetName(StrEq("Main"), 0)));
 }
 
 TEST_F(SemanticsIRFactoryTest, ReturnArithmetic) {
   EXPECT_CALL(consumer, HandleDiagnostic(_)).Times(0);
   Build(R"(fn Main() {
-             return 1 + 2;
+             return 12 + 34;
            }
           )");
-  ExpectRootBlock(
+  EXPECT_THAT(
+      root_block(),
       ElementsAre(
-          Function(Eq("Main"), IsEmpty(), IsNone(),
-                   StatementBlock(ElementsAre(Return(Optional(InfixOperator(
-                                      Literal("1"), "+", Literal("2"))))),
-                                  IsEmpty()))),
-      UnorderedElementsAre(MappedNode("Main", FunctionName("Main"))));
+          Function(0,
+                   ElementsAre(IntegerLiteral(3, 12), IntegerLiteral(2, 34),
+                               BinaryOperator(
+                                   1, Semantics::BinaryOperator::Op::Add, 3, 2),
+                               Return(Optional(1)))),
+          SetName(StrEq("Main"), 0)));
 }
 
 }  // namespace

+ 7 - 89
toolchain/semantics/semantics_ir_for_test.h

@@ -12,7 +12,7 @@
 
 #include "common/check.h"
 #include "llvm/ADT/StringExtras.h"
-#include "toolchain/semantics/nodes/infix_operator.h"
+//#include "toolchain/semantics/nodes/infix_operator.h"
 #include "toolchain/semantics/semantics_ir.h"
 
 namespace Carbon::Testing {
@@ -24,39 +24,11 @@ namespace Carbon::Testing {
 class SemanticsIRForTest {
  public:
   template <typename NodeT>
-  static auto GetDeclaration(Semantics::Declaration decl)
-      -> llvm::Optional<NodeT> {
-    if (decl.kind() != NodeT::MetaNodeKind) {
+  static auto GetNode(Semantics::NodeRef node_ref) -> llvm::Optional<NodeT> {
+    if (node_ref.kind() != NodeT::Kind) {
       return llvm::None;
     }
-    return semantics().declarations_.Get<NodeT>(decl);
-  }
-
-  template <typename NodeT>
-  static auto GetExpression(Semantics::Expression expr)
-      -> llvm::Optional<NodeT> {
-    if (expr.kind() != NodeT::MetaNodeKind) {
-      return llvm::None;
-    }
-    return semantics().expressions_.Get<NodeT>(expr);
-  }
-
-  template <typename NodeT>
-  static auto GetStatement(Semantics::Statement expr) -> llvm::Optional<NodeT> {
-    if (expr.kind() != NodeT::MetaNodeKind) {
-      return llvm::None;
-    }
-    return semantics().statements_.Get<NodeT>(expr);
-  }
-
-  static auto GetNodeText(ParseTree::Node node) -> llvm::StringRef {
-    return semantics().parse_tree_->GetNodeText(node);
-  }
-
-  template <typename PrintableT>
-  static void PrintTo(const PrintableT& printable, std::ostream* out) {
-    llvm::raw_os_ostream wrapped_out(*out);
-    semantics().Print(wrapped_out, printable);
+    return semantics().nodes_.Get<NodeT>(node_ref);
   }
 
   static auto semantics() -> const SemanticsIR& {
@@ -80,65 +52,11 @@ class SemanticsIRForTest {
 
 namespace Carbon::Semantics {
 
-// Meta node printers.
-inline void PrintTo(const Declaration& node, std::ostream* out) {
-  Carbon::Testing::SemanticsIRForTest::PrintTo(node, out);
-}
-inline void PrintTo(const Expression& node, std::ostream* out) {
-  Carbon::Testing::SemanticsIRForTest::PrintTo(node, out);
-}
-inline void PrintTo(const Statement& node, std::ostream* out) {
-  Carbon::Testing::SemanticsIRForTest::PrintTo(node, out);
-}
-
-// Other node printers.
-inline void PrintTo(const DeclaredName& node, std::ostream* out) {
-  Carbon::Testing::SemanticsIRForTest::PrintTo(node, out);
-}
-inline void PrintTo(const ExpressionStatement& node, std::ostream* out) {
-  Carbon::Testing::SemanticsIRForTest::PrintTo(node, out);
-}
-inline void PrintTo(const Function& node, std::ostream* out) {
-  Carbon::Testing::SemanticsIRForTest::PrintTo(node, out);
-}
-inline void PrintTo(const InfixOperator& node, std::ostream* out) {
-  Carbon::Testing::SemanticsIRForTest::PrintTo(node, out);
-}
-inline void PrintTo(const Literal& node, std::ostream* out) {
-  Carbon::Testing::SemanticsIRForTest::PrintTo(node, out);
-}
-inline void PrintTo(const PatternBinding& node, std::ostream* out) {
-  Carbon::Testing::SemanticsIRForTest::PrintTo(node, out);
-}
-inline void PrintTo(const Return& node, std::ostream* out) {
-  Carbon::Testing::SemanticsIRForTest::PrintTo(node, out);
-}
-inline void PrintTo(const StatementBlock& node, std::ostream* out) {
-  Carbon::Testing::SemanticsIRForTest::PrintTo(node, out);
+inline void PrintTo(const NodeRef& node_ref, std::ostream* out) {
+  llvm::raw_os_ostream wrapped_out(*out);
+  Carbon::Testing::SemanticsIRForTest::semantics().Print(wrapped_out, node_ref);
 }
 
 }  // namespace Carbon::Semantics
 
-namespace llvm {
-
-// Prints a StringMapEntry for gmock.
-inline void PrintTo(
-    const llvm::StringMapEntry<Carbon::Semantics::Declaration>& entry,
-    std::ostream* out) {
-  *out << "StringMapEntry(" << entry.getKey() << ", ";
-  Carbon::Testing::SemanticsIRForTest::PrintTo(entry.getValue(), out);
-  *out << ")";
-}
-
-// Prints a StringMapEntry for gmock.
-inline void PrintTo(
-    const llvm::StringMapEntry<Carbon::Semantics::Statement>& entry,
-    std::ostream* out) {
-  *out << "StringMapEntry(" << entry.getKey() << ", ";
-  Carbon::Testing::SemanticsIRForTest::PrintTo(entry.getValue(), out);
-  *out << ")";
-}
-
-}  // namespace llvm
-
 #endif  // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_IR_FOR_TEST_H_

+ 3 - 29
toolchain/semantics/semantics_ir_test_helpers.h

@@ -11,44 +11,18 @@
 #include "common/check.h"
 #include "common/ostream.h"
 #include "llvm/ADT/StringExtras.h"
-#include "toolchain/semantics/nodes/declared_name_test_matchers.h"
+#include "toolchain/semantics/nodes/binary_operator_test_matchers.h"
 #include "toolchain/semantics/nodes/function_test_matchers.h"
-#include "toolchain/semantics/nodes/infix_operator_test_matchers.h"
-#include "toolchain/semantics/nodes/literal_test_matchers.h"
-#include "toolchain/semantics/nodes/pattern_binding_test_matchers.h"
+#include "toolchain/semantics/nodes/integer_literal_test_matchers.h"
 #include "toolchain/semantics/nodes/return_test_matchers.h"
+#include "toolchain/semantics/nodes/set_name_test_matchers.h"
 #include "toolchain/semantics/semantics_ir_for_test.h"
 
 namespace Carbon::Testing {
 
-// TODO: Relocate these matchers.
-
-inline auto MappedNode(::testing::Matcher<std::string> key,
-                       ::testing::Matcher<Semantics::Declaration> value)
-    -> ::testing::Matcher<llvm::StringMapEntry<Semantics::Declaration>> {
-  return ::testing::AllOf(
-      ::testing::Property(
-          "key", &llvm::StringMapEntry<Semantics::Declaration>::getKey, key),
-      ::testing::Property(
-          "value", &llvm::StringMapEntry<Semantics::Declaration>::getValue,
-          value));
-}
-
 // Avoids gtest confusion of how to print llvm::None.
 MATCHER(IsNone, "is llvm::None") { return arg == llvm::None; }
 
-inline auto StatementBlock(
-    ::testing::Matcher<llvm::ArrayRef<Semantics::Statement>> nodes_matcher,
-    ::testing::Matcher<llvm::StringMap<Semantics::Statement>>
-        name_lookup_matcher) -> ::testing::Matcher<Semantics::StatementBlock> {
-  return ::testing::AllOf(
-      ::testing::Property("nodes", &Semantics::StatementBlock::nodes,
-                          nodes_matcher),
-      ::testing::Property("name_lookup",
-                          &Semantics::StatementBlock::name_lookup,
-                          name_lookup_matcher));
-}
-
 }  // namespace Carbon::Testing
 
 #endif  // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_IR_TEST_HELPERS_H_