Files
carbon-lang/toolchain/semantics/semantics_ir_factory_test.cpp
T
Jon Ross-Perkins a23f15e901 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.
2022-07-06 11:08:47 -07:00

163 lines
5.2 KiB
C++

// 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
#include "toolchain/semantics/semantics_ir_factory.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "toolchain/diagnostics/mocks.h"
#include "toolchain/lexer/tokenized_buffer.h"
#include "toolchain/parser/parse_tree.h"
#include "toolchain/semantics/semantics_ir_test_helpers.h"
#include "toolchain/source/source_buffer.h"
namespace Carbon::Testing {
namespace {
using ::testing::_;
using ::testing::ElementsAre;
using ::testing::IsEmpty;
using ::testing::Optional;
using ::testing::StrEq;
class SemanticsIRFactoryTest : public ::testing::Test {
protected:
void Build(llvm::Twine t) {
source_buffer.emplace(std::move(*SourceBuffer::CreateFromText(t)));
tokenized_buffer = TokenizedBuffer::Lex(*source_buffer, consumer);
EXPECT_FALSE(tokenized_buffer->has_errors());
parse_tree = ParseTree::Parse(*tokenized_buffer, consumer);
EXPECT_FALSE(parse_tree->has_errors());
SemanticsIRForTest::set_semantics(
SemanticsIRFactory::Build(*tokenized_buffer, *parse_tree));
}
~SemanticsIRFactoryTest() override { SemanticsIRForTest::clear(); }
auto root_block() const -> llvm::ArrayRef<Semantics::NodeRef> {
return SemanticsIRForTest::semantics().root_block();
}
llvm::Optional<SourceBuffer> source_buffer;
llvm::Optional<TokenizedBuffer> tokenized_buffer;
llvm::Optional<ParseTree> parse_tree;
MockDiagnosticConsumer consumer;
};
/*
TEST_F(SemanticsIRFactoryTest, SimpleProgram) {
EXPECT_CALL(consumer, HandleDiagnostic(_)).Times(0);
Build(R"(// package FactoryTest api;
fn Add(x: i32, y: i32) -> i32 {
return x + y;
}
fn Main() -> i32 {
var x: i32 = Add(3, 10);
x *= 5;
return x;
}
)");
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("");
EXPECT_THAT(root_block(), IsEmpty());
}
TEST_F(SemanticsIRFactoryTest, FunctionBasic) {
EXPECT_CALL(consumer, HandleDiagnostic(_)).Times(0);
Build("fn 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) {}");
ExpectRootBlock(
ElementsAre(Function(Eq("Foo"),
ElementsAre(PatternBinding(Eq("x"), Literal("i32")),
PatternBinding(Eq("y"), Literal("i64"))),
IsNone(), StatementBlock(IsEmpty(), IsEmpty()))),
UnorderedElementsAre(MappedNode("Foo", FunctionName("Foo"))));
}
*/
/*
TEST_F(SemanticsIRFactoryTest, FunctionReturnType) {
EXPECT_CALL(consumer, HandleDiagnostic(_)).Times(0);
Build("fn Foo() -> i32 {}");
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() {}
)");
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) {
EXPECT_CALL(consumer, HandleDiagnostic(_)).Times(0);
Build(R"(fn Main() {
return;
}
)");
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 12;
}
)");
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 12 + 34;
}
)");
EXPECT_THAT(
root_block(),
ElementsAre(
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
} // namespace Carbon::Testing