Switch Expression to use inheritance+cast (#712)

Co-authored-by: Geoff Romer <gromer@google.com>
This commit is contained in:
Jon Meow
2021-08-06 15:43:25 -07:00
committed by GitHub
co-authored by Geoff Romer
parent 4e0307efbc
commit dbcd6ad20d
9 changed files with 527 additions and 556 deletions
+47 -190
View File
@@ -9,10 +9,13 @@
#include "executable_semantics/common/arena.h"
#include "executable_semantics/common/error.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
namespace Carbon {
using llvm::cast;
auto ExpressionFromParenContents(
int line_num, const ParenContents<Expression>& paren_contents)
-> const Expression* {
@@ -27,161 +30,10 @@ auto ExpressionFromParenContents(
auto TupleExpressionFromParenContents(
int line_num, const ParenContents<Expression>& paren_contents)
-> const Expression* {
return Expression::MakeTupleLiteral(
return global_arena->New<TupleLiteral>(
line_num, paren_contents.TupleElements<FieldInitializer>(line_num));
}
auto Expression::GetIdentifierExpression() const
-> const IdentifierExpression& {
return std::get<IdentifierExpression>(value);
}
auto Expression::GetFieldAccessExpression() const
-> const FieldAccessExpression& {
return std::get<FieldAccessExpression>(value);
}
auto Expression::GetIndexExpression() const -> const IndexExpression& {
return std::get<IndexExpression>(value);
}
auto Expression::GetIntLiteral() const -> int {
return std::get<IntLiteral>(value).value;
}
auto Expression::GetBoolLiteral() const -> bool {
return std::get<BoolLiteral>(value).value;
}
auto Expression::GetTupleLiteral() const -> const TupleLiteral& {
return std::get<TupleLiteral>(value);
}
auto Expression::GetPrimitiveOperatorExpression() const
-> const PrimitiveOperatorExpression& {
return std::get<PrimitiveOperatorExpression>(value);
}
auto Expression::GetCallExpression() const -> const CallExpression& {
return std::get<CallExpression>(value);
}
auto Expression::GetFunctionTypeLiteral() const -> const FunctionTypeLiteral& {
return std::get<FunctionTypeLiteral>(value);
}
auto Expression::MakeTypeTypeLiteral(int line_num) -> const Expression* {
auto* t = global_arena->New<Expression>();
t->line_num = line_num;
t->value = TypeTypeLiteral();
return t;
}
auto Expression::MakeIntTypeLiteral(int line_num) -> const Expression* {
auto* t = global_arena->New<Expression>();
t->line_num = line_num;
t->value = IntTypeLiteral();
return t;
}
auto Expression::MakeBoolTypeLiteral(int line_num) -> const Expression* {
auto* t = global_arena->New<Expression>();
t->line_num = line_num;
t->value = BoolTypeLiteral();
return t;
}
// Returns a Continuation type AST node at the given source location.
auto Expression::MakeContinuationTypeLiteral(int line_num)
-> const Expression* {
auto* type = global_arena->New<Expression>();
type->line_num = line_num;
type->value = ContinuationTypeLiteral();
return type;
}
auto Expression::MakeFunctionTypeLiteral(int line_num,
const Expression* parameter,
const Expression* return_type,
bool is_omitted_return_type)
-> const Expression* {
auto* t = global_arena->New<Expression>();
t->line_num = line_num;
t->value =
FunctionTypeLiteral({.parameter = parameter,
.return_type = return_type,
.is_omitted_return_type = is_omitted_return_type});
return t;
}
auto Expression::MakeIdentifierExpression(int line_num, std::string var)
-> const Expression* {
auto* v = global_arena->New<Expression>();
v->line_num = line_num;
v->value = IdentifierExpression({.name = std::move(var)});
return v;
}
auto Expression::MakeIntLiteral(int line_num, int i) -> const Expression* {
auto* e = global_arena->New<Expression>();
e->line_num = line_num;
e->value = IntLiteral({.value = i});
return e;
}
auto Expression::MakeBoolLiteral(int line_num, bool b) -> const Expression* {
auto* e = global_arena->New<Expression>();
e->line_num = line_num;
e->value = BoolLiteral({.value = b});
return e;
}
auto Expression::MakePrimitiveOperatorExpression(
int line_num, enum Operator op, std::vector<const Expression*> args)
-> const Expression* {
auto* e = global_arena->New<Expression>();
e->line_num = line_num;
e->value =
PrimitiveOperatorExpression({.op = op, .arguments = std::move(args)});
return e;
}
auto Expression::MakeCallExpression(int line_num, const Expression* fun,
const Expression* arg)
-> const Expression* {
auto* e = global_arena->New<Expression>();
e->line_num = line_num;
e->value = CallExpression({.function = fun, .argument = arg});
return e;
}
auto Expression::MakeFieldAccessExpression(int line_num, const Expression* exp,
std::string field)
-> const Expression* {
auto* e = global_arena->New<Expression>();
e->line_num = line_num;
e->value =
FieldAccessExpression({.aggregate = exp, .field = std::move(field)});
return e;
}
auto Expression::MakeTupleLiteral(int line_num,
std::vector<FieldInitializer> args)
-> const Expression* {
auto* e = global_arena->New<Expression>();
e->line_num = line_num;
e->value = TupleLiteral({.fields = std::move(args)});
return e;
}
auto Expression::MakeIndexExpression(int line_num, const Expression* exp,
const Expression* i) -> const Expression* {
auto* e = global_arena->New<Expression>();
e->line_num = line_num;
e->value = IndexExpression({.aggregate = exp, .offset = i});
return e;
}
static void PrintOp(llvm::raw_ostream& out, Operator op) {
switch (op) {
case Operator::Add:
@@ -220,69 +72,74 @@ static void PrintFields(llvm::raw_ostream& out,
}
void Expression::Print(llvm::raw_ostream& out) const {
switch (tag()) {
case ExpressionKind::IndexExpression:
out << *GetIndexExpression().aggregate << "["
<< *GetIndexExpression().offset << "]";
switch (Tag()) {
case Expression::Kind::IndexExpression: {
const auto& index = cast<IndexExpression>(*this);
out << *index.Aggregate() << "[" << *index.Offset() << "]";
break;
case ExpressionKind::FieldAccessExpression:
out << *GetFieldAccessExpression().aggregate << "."
<< GetFieldAccessExpression().field;
}
case Expression::Kind::FieldAccessExpression: {
const auto& access = cast<FieldAccessExpression>(*this);
out << *access.Aggregate() << "." << access.Field();
break;
case ExpressionKind::TupleLiteral:
}
case Expression::Kind::TupleLiteral:
out << "(";
PrintFields(out, GetTupleLiteral().fields);
PrintFields(out, cast<TupleLiteral>(*this).Fields());
out << ")";
break;
case ExpressionKind::IntLiteral:
out << GetIntLiteral();
case Expression::Kind::IntLiteral:
out << cast<IntLiteral>(*this).Val();
break;
case ExpressionKind::BoolLiteral:
out << (GetBoolLiteral() ? "true" : "false");
case Expression::Kind::BoolLiteral:
out << (cast<BoolLiteral>(*this).Val() ? "true" : "false");
break;
case ExpressionKind::PrimitiveOperatorExpression: {
case Expression::Kind::PrimitiveOperatorExpression: {
out << "(";
PrimitiveOperatorExpression op = GetPrimitiveOperatorExpression();
if (op.arguments.size() == 0) {
PrintOp(out, op.op);
} else if (op.arguments.size() == 1) {
PrintOp(out, op.op);
out << " " << *op.arguments[0];
} else if (op.arguments.size() == 2) {
out << *op.arguments[0] << " ";
PrintOp(out, op.op);
out << " " << *op.arguments[1];
PrimitiveOperatorExpression op = cast<PrimitiveOperatorExpression>(*this);
if (op.Arguments().size() == 0) {
PrintOp(out, op.Op());
} else if (op.Arguments().size() == 1) {
PrintOp(out, op.Op());
out << " " << *op.Arguments()[0];
} else if (op.Arguments().size() == 2) {
out << *op.Arguments()[0] << " ";
PrintOp(out, op.Op());
out << " " << *op.Arguments()[1];
}
out << ")";
break;
}
case ExpressionKind::IdentifierExpression:
out << GetIdentifierExpression().name;
case Expression::Kind::IdentifierExpression:
out << cast<IdentifierExpression>(*this).Name();
break;
case ExpressionKind::CallExpression:
out << *GetCallExpression().function;
if (GetCallExpression().argument->tag() == ExpressionKind::TupleLiteral) {
out << *GetCallExpression().argument;
case Expression::Kind::CallExpression: {
const auto& call = cast<CallExpression>(*this);
out << *call.Function();
if (call.Argument()->Tag() == Expression::Kind::TupleLiteral) {
out << *call.Argument();
} else {
out << "(" << *GetCallExpression().argument << ")";
out << "(" << *call.Argument() << ")";
}
break;
case ExpressionKind::BoolTypeLiteral:
}
case Expression::Kind::BoolTypeLiteral:
out << "Bool";
break;
case ExpressionKind::IntTypeLiteral:
case Expression::Kind::IntTypeLiteral:
out << "i32";
break;
case ExpressionKind::TypeTypeLiteral:
case Expression::Kind::TypeTypeLiteral:
out << "Type";
break;
case ExpressionKind::ContinuationTypeLiteral:
case Expression::Kind::ContinuationTypeLiteral:
out << "Continuation";
break;
case ExpressionKind::FunctionTypeLiteral:
out << "fn " << *GetFunctionTypeLiteral().parameter << " -> "
<< *GetFunctionTypeLiteral().return_type;
case Expression::Kind::FunctionTypeLiteral: {
const auto& fn = cast<FunctionTypeLiteral>(*this);
out << "fn " << *fn.Parameter() << " -> " << *fn.ReturnType();
break;
}
}
}
+208 -105
View File
@@ -16,8 +16,43 @@
namespace Carbon {
struct Expression;
class Pattern;
class Expression {
public:
enum class Kind {
BoolTypeLiteral,
BoolLiteral,
CallExpression,
FunctionTypeLiteral,
FieldAccessExpression,
IndexExpression,
IntTypeLiteral,
ContinuationTypeLiteral, // The type of a continuation value.
IntLiteral,
PrimitiveOperatorExpression,
TupleLiteral,
TypeTypeLiteral,
IdentifierExpression,
};
// Returns the enumerator corresponding to the most-derived type of this
// object.
auto Tag() const -> Kind { return tag; }
auto LineNumber() const -> int { return line_num; }
void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
protected:
// Constructs an Expression representing syntax at the given line number.
// `tag` must be the enumerator corresponding to the most-derived type being
// constructed.
Expression(Kind tag, int line_num) : tag(tag), line_num(line_num) {}
private:
const Kind tag;
int line_num;
};
// Converts paren_contents to an Expression, interpreting the parentheses as
// grouping if their contents permit that interpretation, or as forming a
@@ -44,22 +79,6 @@ struct FieldInitializer {
const Expression* expression;
};
enum class ExpressionKind {
BoolTypeLiteral,
BoolLiteral,
CallExpression,
FunctionTypeLiteral,
FieldAccessExpression,
IndexExpression,
IntTypeLiteral,
ContinuationTypeLiteral, // The type of a continuation value.
IntLiteral,
PrimitiveOperatorExpression,
TupleLiteral,
TypeTypeLiteral,
IdentifierExpression,
};
enum class Operator {
Add,
And,
@@ -73,129 +92,213 @@ enum class Operator {
Ptr,
};
struct Expression;
class IdentifierExpression : public Expression {
public:
explicit IdentifierExpression(int line_num, std::string name)
: Expression(Kind::IdentifierExpression, line_num),
name(std::move(name)) {}
struct IdentifierExpression {
static constexpr ExpressionKind Kind = ExpressionKind::IdentifierExpression;
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::IdentifierExpression;
}
auto Name() const -> const std::string& { return name; }
private:
std::string name;
};
struct FieldAccessExpression {
static constexpr ExpressionKind Kind = ExpressionKind::FieldAccessExpression;
class FieldAccessExpression : public Expression {
public:
explicit FieldAccessExpression(int line_num, const Expression* aggregate,
std::string field)
: Expression(Kind::FieldAccessExpression, line_num),
aggregate(aggregate),
field(std::move(field)) {}
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::FieldAccessExpression;
}
auto Aggregate() const -> const Expression* { return aggregate; }
auto Field() const -> const std::string& { return field; }
private:
const Expression* aggregate;
std::string field;
};
struct IndexExpression {
static constexpr ExpressionKind Kind = ExpressionKind::IndexExpression;
class IndexExpression : public Expression {
public:
explicit IndexExpression(int line_num, const Expression* aggregate,
const Expression* offset)
: Expression(Kind::IndexExpression, line_num),
aggregate(aggregate),
offset(offset) {}
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::IndexExpression;
}
auto Aggregate() const -> const Expression* { return aggregate; }
auto Offset() const -> const Expression* { return offset; }
private:
const Expression* aggregate;
const Expression* offset;
};
struct IntLiteral {
static constexpr ExpressionKind Kind = ExpressionKind::IntLiteral;
int value;
class IntLiteral : public Expression {
public:
explicit IntLiteral(int line_num, int val)
: Expression(Kind::IntLiteral, line_num), val(val) {}
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::IntLiteral;
}
auto Val() const -> int { return val; }
private:
int val;
};
struct BoolLiteral {
static constexpr ExpressionKind Kind = ExpressionKind::BoolLiteral;
bool value;
class BoolLiteral : public Expression {
public:
explicit BoolLiteral(int line_num, bool val)
: Expression(Kind::BoolLiteral, line_num), val(val) {}
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::BoolLiteral;
}
auto Val() const -> bool { return val; }
private:
bool val;
};
struct TupleLiteral {
static constexpr ExpressionKind Kind = ExpressionKind::TupleLiteral;
class TupleLiteral : public Expression {
public:
explicit TupleLiteral(int line_num) : TupleLiteral(line_num, {}) {}
explicit TupleLiteral(int line_num, std::vector<FieldInitializer> fields)
: Expression(Kind::TupleLiteral, line_num), fields(std::move(fields)) {}
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::TupleLiteral;
}
auto Fields() const -> const std::vector<FieldInitializer>& { return fields; }
private:
std::vector<FieldInitializer> fields;
};
struct PrimitiveOperatorExpression {
static constexpr ExpressionKind Kind =
ExpressionKind::PrimitiveOperatorExpression;
class PrimitiveOperatorExpression : public Expression {
public:
explicit PrimitiveOperatorExpression(int line_num, Operator op,
std::vector<const Expression*> arguments)
: Expression(Kind::PrimitiveOperatorExpression, line_num),
op(op),
arguments(std::move(arguments)) {}
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::PrimitiveOperatorExpression;
}
auto Op() const -> Operator { return op; }
auto Arguments() const -> const std::vector<const Expression*>& {
return arguments;
}
private:
Operator op;
std::vector<const Expression*> arguments;
};
struct CallExpression {
static constexpr ExpressionKind Kind = ExpressionKind::CallExpression;
class CallExpression : public Expression {
public:
explicit CallExpression(int line_num, const Expression* function,
const Expression* argument)
: Expression(Kind::CallExpression, line_num),
function(function),
argument(argument) {}
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::CallExpression;
}
auto Function() const -> const Expression* { return function; }
auto Argument() const -> const Expression* { return argument; }
private:
const Expression* function;
const Expression* argument;
};
struct FunctionTypeLiteral {
static constexpr ExpressionKind Kind = ExpressionKind::FunctionTypeLiteral;
class FunctionTypeLiteral : public Expression {
public:
explicit FunctionTypeLiteral(int line_num, const Expression* parameter,
const Expression* return_type,
bool is_omitted_return_type)
: Expression(Kind::FunctionTypeLiteral, line_num),
parameter(parameter),
return_type(return_type),
is_omitted_return_type(is_omitted_return_type) {}
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::FunctionTypeLiteral;
}
auto Parameter() const -> const Expression* { return parameter; }
auto ReturnType() const -> const Expression* { return return_type; }
auto IsOmittedReturnType() const -> bool { return is_omitted_return_type; }
private:
const Expression* parameter;
const Expression* return_type;
bool is_omitted_return_type;
};
struct BoolTypeLiteral {
static constexpr ExpressionKind Kind = ExpressionKind::BoolTypeLiteral;
};
class BoolTypeLiteral : public Expression {
public:
explicit BoolTypeLiteral(int line_num)
: Expression(Kind::BoolTypeLiteral, line_num) {}
struct IntTypeLiteral {
static constexpr ExpressionKind Kind = ExpressionKind::IntTypeLiteral;
};
struct ContinuationTypeLiteral {
static constexpr ExpressionKind Kind =
ExpressionKind::ContinuationTypeLiteral;
};
struct TypeTypeLiteral {
static constexpr ExpressionKind Kind = ExpressionKind::TypeTypeLiteral;
};
struct Expression {
static auto MakeIdentifierExpression(int line_num, std::string var)
-> const Expression*;
static auto MakeIntLiteral(int line_num, int i) -> const Expression*;
static auto MakeBoolLiteral(int line_num, bool b) -> const Expression*;
static auto MakePrimitiveOperatorExpression(
int line_num, Operator op, std::vector<const Expression*> args)
-> const Expression*;
static auto MakeCallExpression(int line_num, const Expression* fun,
const Expression* arg) -> const Expression*;
static auto MakeFieldAccessExpression(int line_num, const Expression* exp,
std::string field) -> const Expression*;
static auto MakeTupleLiteral(int line_num, std::vector<FieldInitializer> args)
-> const Expression*;
static auto MakeIndexExpression(int line_num, const Expression* exp,
const Expression* i) -> const Expression*;
static auto MakeTypeTypeLiteral(int line_num) -> const Expression*;
static auto MakeIntTypeLiteral(int line_num) -> const Expression*;
static auto MakeBoolTypeLiteral(int line_num) -> const Expression*;
static auto MakeFunctionTypeLiteral(int line_num, const Expression* parameter,
const Expression* return_type,
bool is_omitted_return_type)
-> const Expression*;
static auto MakeContinuationTypeLiteral(int line_num) -> const Expression*;
auto GetIdentifierExpression() const -> const IdentifierExpression&;
auto GetFieldAccessExpression() const -> const FieldAccessExpression&;
auto GetIndexExpression() const -> const IndexExpression&;
auto GetIntLiteral() const -> int;
auto GetBoolLiteral() const -> bool;
auto GetTupleLiteral() const -> const TupleLiteral&;
auto GetPrimitiveOperatorExpression() const
-> const PrimitiveOperatorExpression&;
auto GetCallExpression() const -> const CallExpression&;
auto GetFunctionTypeLiteral() const -> const FunctionTypeLiteral&;
void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
inline auto tag() const -> ExpressionKind {
return std::visit([](const auto& t) { return t.Kind; }, value);
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::BoolTypeLiteral;
}
};
int line_num;
class IntTypeLiteral : public Expression {
public:
explicit IntTypeLiteral(int line_num)
: Expression(Kind::IntTypeLiteral, line_num) {}
private:
std::variant<IdentifierExpression, FieldAccessExpression, IndexExpression,
IntLiteral, BoolLiteral, TupleLiteral,
PrimitiveOperatorExpression, CallExpression, FunctionTypeLiteral,
BoolTypeLiteral, IntTypeLiteral, ContinuationTypeLiteral,
TypeTypeLiteral>
value;
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::IntTypeLiteral;
}
};
class ContinuationTypeLiteral : public Expression {
public:
explicit ContinuationTypeLiteral(int line_num)
: Expression(Kind::ContinuationTypeLiteral, line_num) {}
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::ContinuationTypeLiteral;
}
};
class TypeTypeLiteral : public Expression {
public:
explicit TypeTypeLiteral(int line_num)
: Expression(Kind::TypeTypeLiteral, line_num) {}
static auto classof(const Expression* exp) -> bool {
return exp->Tag() == Kind::TypeTypeLiteral;
}
};
} // namespace Carbon
+37 -32
View File
@@ -6,13 +6,16 @@
#include <string>
#include "executable_semantics/common/arena.h"
#include "executable_semantics/syntax/paren_contents.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "llvm/Support/Casting.h"
namespace Carbon {
namespace {
using llvm::cast;
using testing::ElementsAre;
using testing::IsEmpty;
@@ -20,7 +23,7 @@ using testing::IsEmpty;
// `IntLiteral`
MATCHER_P(IntFieldNamed, name, "") {
return arg.name == std::string(name) &&
arg.expression->tag() == ExpressionKind::IntLiteral;
arg.expression->Tag() == Expression::Kind::IntLiteral;
}
TEST(ExpressionTest, EmptyAsExpression) {
@@ -28,9 +31,9 @@ TEST(ExpressionTest, EmptyAsExpression) {
.has_trailing_comma = false};
const Expression* expression =
ExpressionFromParenContents(/*line_num=*/1, contents);
EXPECT_EQ(expression->line_num, 1);
ASSERT_EQ(expression->tag(), ExpressionKind::TupleLiteral);
EXPECT_THAT(expression->GetTupleLiteral().fields, IsEmpty());
EXPECT_EQ(expression->LineNumber(), 1);
ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral);
EXPECT_THAT(cast<TupleLiteral>(*expression).Fields(), IsEmpty());
}
TEST(ExpressionTest, EmptyAsTuple) {
@@ -38,9 +41,9 @@ TEST(ExpressionTest, EmptyAsTuple) {
.has_trailing_comma = false};
const Expression* tuple =
TupleExpressionFromParenContents(/*line_num=*/1, contents);
EXPECT_EQ(tuple->line_num, 1);
ASSERT_EQ(tuple->tag(), ExpressionKind::TupleLiteral);
EXPECT_THAT(tuple->GetTupleLiteral().fields, IsEmpty());
EXPECT_EQ(tuple->LineNumber(), 1);
ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral);
EXPECT_THAT(cast<TupleLiteral>(*tuple).Fields(), IsEmpty());
}
TEST(ExpressionTest, UnaryNoCommaAsExpression) {
@@ -52,84 +55,86 @@ TEST(ExpressionTest, UnaryNoCommaAsExpression) {
// ```
ParenContents<Expression> contents = {
.elements = {{.name = std::nullopt,
.term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}},
.term = global_arena->New<IntLiteral>(/*line_num=*/2, 42)}},
.has_trailing_comma = false};
const Expression* expression =
ExpressionFromParenContents(/*line_num=*/1, contents);
EXPECT_EQ(expression->line_num, 2);
ASSERT_EQ(expression->tag(), ExpressionKind::IntLiteral);
EXPECT_EQ(expression->LineNumber(), 2);
ASSERT_EQ(expression->Tag(), Expression::Kind::IntLiteral);
}
TEST(ExpressionTest, UnaryNoCommaAsTuple) {
ParenContents<Expression> contents = {
.elements = {{.name = std::nullopt,
.term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}},
.term = global_arena->New<IntLiteral>(/*line_num=*/2, 42)}},
.has_trailing_comma = false};
const Expression* tuple =
TupleExpressionFromParenContents(/*line_num=*/1, contents);
EXPECT_EQ(tuple->line_num, 1);
ASSERT_EQ(tuple->tag(), ExpressionKind::TupleLiteral);
EXPECT_THAT(tuple->GetTupleLiteral().fields, ElementsAre(IntFieldNamed("0")));
EXPECT_EQ(tuple->LineNumber(), 1);
ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral);
EXPECT_THAT(cast<TupleLiteral>(*tuple).Fields(),
ElementsAre(IntFieldNamed("0")));
}
TEST(ExpressionTest, UnaryWithCommaAsExpression) {
ParenContents<Expression> contents = {
.elements = {{.name = std::nullopt,
.term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}},
.term = global_arena->New<IntLiteral>(/*line_num=*/2, 42)}},
.has_trailing_comma = true};
const Expression* expression =
ExpressionFromParenContents(/*line_num=*/1, contents);
EXPECT_EQ(expression->line_num, 1);
ASSERT_EQ(expression->tag(), ExpressionKind::TupleLiteral);
EXPECT_THAT(expression->GetTupleLiteral().fields,
EXPECT_EQ(expression->LineNumber(), 1);
ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral);
EXPECT_THAT(cast<TupleLiteral>(*expression).Fields(),
ElementsAre(IntFieldNamed("0")));
}
TEST(ExpressionTest, UnaryWithCommaAsTuple) {
ParenContents<Expression> contents = {
.elements = {{.name = std::nullopt,
.term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}},
.term = global_arena->New<IntLiteral>(/*line_num=*/2, 42)}},
.has_trailing_comma = true};
const Expression* tuple =
TupleExpressionFromParenContents(/*line_num=*/1, contents);
EXPECT_EQ(tuple->line_num, 1);
ASSERT_EQ(tuple->tag(), ExpressionKind::TupleLiteral);
EXPECT_THAT(tuple->GetTupleLiteral().fields, ElementsAre(IntFieldNamed("0")));
EXPECT_EQ(tuple->LineNumber(), 1);
ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral);
EXPECT_THAT(cast<TupleLiteral>(*tuple).Fields(),
ElementsAre(IntFieldNamed("0")));
}
TEST(ExpressionTest, BinaryAsExpression) {
ParenContents<Expression> contents = {
.elements = {{.name = std::nullopt,
.term = Expression::MakeIntLiteral(/*line_num=*/2, 42)},
.term = global_arena->New<IntLiteral>(/*line_num=*/2, 42)},
{.name = std::nullopt,
.term = Expression::MakeIntLiteral(/*line_num=*/3, 42)}},
.term = global_arena->New<IntLiteral>(/*line_num=*/3, 42)}},
.has_trailing_comma = true};
const Expression* expression =
ExpressionFromParenContents(/*line_num=*/1, contents);
EXPECT_EQ(expression->line_num, 1);
ASSERT_EQ(expression->tag(), ExpressionKind::TupleLiteral);
EXPECT_THAT(expression->GetTupleLiteral().fields,
EXPECT_EQ(expression->LineNumber(), 1);
ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral);
EXPECT_THAT(cast<TupleLiteral>(*expression).Fields(),
ElementsAre(IntFieldNamed("0"), IntFieldNamed("1")));
}
TEST(ExpressionTest, BinaryAsTuple) {
ParenContents<Expression> contents = {
.elements = {{.name = std::nullopt,
.term = Expression::MakeIntLiteral(/*line_num=*/2, 42)},
.term = global_arena->New<IntLiteral>(/*line_num=*/2, 42)},
{.name = std::nullopt,
.term = Expression::MakeIntLiteral(/*line_num=*/3, 42)}},
.term = global_arena->New<IntLiteral>(/*line_num=*/3, 42)}},
.has_trailing_comma = true};
const Expression* tuple =
TupleExpressionFromParenContents(/*line_num=*/1, contents);
EXPECT_EQ(tuple->line_num, 1);
ASSERT_EQ(tuple->tag(), ExpressionKind::TupleLiteral);
EXPECT_THAT(tuple->GetTupleLiteral().fields,
EXPECT_EQ(tuple->LineNumber(), 1);
ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral);
EXPECT_THAT(cast<TupleLiteral>(*tuple).Fields(),
ElementsAre(IntFieldNamed("0"), IntFieldNamed("1")));
}
+8 -8
View File
@@ -55,9 +55,9 @@ void Pattern::Print(llvm::raw_ostream& out) const {
}
TuplePattern::TuplePattern(const Expression* tuple_literal)
: Pattern(Kind::TuplePattern, tuple_literal->line_num) {
const auto& tuple = tuple_literal->GetTupleLiteral();
for (const FieldInitializer& init : tuple.fields) {
: Pattern(Kind::TuplePattern, tuple_literal->LineNumber()) {
const auto& tuple = cast<TupleLiteral>(*tuple_literal);
for (const FieldInitializer& init : tuple.Fields()) {
fields.push_back(Field(
init.name, global_arena->New<ExpressionPattern>(init.expression)));
}
@@ -85,13 +85,13 @@ AlternativePattern::AlternativePattern(int line_num,
const Expression* alternative,
const TuplePattern* arguments)
: Pattern(Kind::AlternativePattern, line_num), arguments(arguments) {
if (alternative->tag() != ExpressionKind::FieldAccessExpression) {
FATAL_PROGRAM_ERROR(alternative->line_num)
if (alternative->Tag() != Expression::Kind::FieldAccessExpression) {
FATAL_PROGRAM_ERROR(alternative->LineNumber())
<< "Alternative pattern must have the form of a field access.";
}
const auto& field_access = alternative->GetFieldAccessExpression();
choice_type = field_access.aggregate;
alternative_name = field_access.field;
const auto& field_access = cast<FieldAccessExpression>(*alternative);
choice_type = field_access.Aggregate();
alternative_name = field_access.Field();
}
auto ParenExpressionToParenPattern(const ParenContents<Expression>& contents)
+2 -2
View File
@@ -111,7 +111,7 @@ class TuplePattern : public Pattern {
// Converts tuple_literal to a TuplePattern, by wrapping each field in an
// ExpressionPattern.
//
// REQUIRES: tuple_literal->Tag() == ExpressionKind::TupleLiteral
// REQUIRES: tuple_literal->Tag() == Expression::Kind::TupleLiteral
explicit TuplePattern(const Expression* tuple_literal);
static auto classof(const Pattern* pattern) -> bool {
@@ -182,7 +182,7 @@ class AlternativePattern : public Pattern {
class ExpressionPattern : public Pattern {
public:
ExpressionPattern(const Expression* expression)
: Pattern(Kind::ExpressionPattern, expression->line_num),
: Pattern(Kind::ExpressionPattern, expression->LineNumber()),
expression(expression) {}
static auto classof(const Pattern* pattern) -> bool {
+1 -1
View File
@@ -123,7 +123,7 @@ auto Statement::MakeReturn(int line_num, const Expression* exp,
s->line_num = line_num;
if (exp == nullptr) {
CHECK(is_omitted_exp);
exp = Expression::MakeTupleLiteral(line_num, {});
exp = global_arena->New<TupleLiteral>(line_num);
}
s->value = Return({.exp = exp, .is_omitted_exp = is_omitted_exp});
return s;