diff --git a/executable_semantics/ast/expression.cpp b/executable_semantics/ast/expression.cpp index 07a728cdea26..fb6dafb6b68e 100644 --- a/executable_semantics/ast/expression.cpp +++ b/executable_semantics/ast/expression.cpp @@ -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& paren_contents) -> const Expression* { @@ -27,161 +30,10 @@ auto ExpressionFromParenContents( auto TupleExpressionFromParenContents( int line_num, const ParenContents& paren_contents) -> const Expression* { - return Expression::MakeTupleLiteral( + return global_arena->New( line_num, paren_contents.TupleElements(line_num)); } -auto Expression::GetIdentifierExpression() const - -> const IdentifierExpression& { - return std::get(value); -} - -auto Expression::GetFieldAccessExpression() const - -> const FieldAccessExpression& { - return std::get(value); -} - -auto Expression::GetIndexExpression() const -> const IndexExpression& { - return std::get(value); -} - -auto Expression::GetIntLiteral() const -> int { - return std::get(value).value; -} - -auto Expression::GetBoolLiteral() const -> bool { - return std::get(value).value; -} - -auto Expression::GetTupleLiteral() const -> const TupleLiteral& { - return std::get(value); -} - -auto Expression::GetPrimitiveOperatorExpression() const - -> const PrimitiveOperatorExpression& { - return std::get(value); -} - -auto Expression::GetCallExpression() const -> const CallExpression& { - return std::get(value); -} - -auto Expression::GetFunctionTypeLiteral() const -> const FunctionTypeLiteral& { - return std::get(value); -} - -auto Expression::MakeTypeTypeLiteral(int line_num) -> const Expression* { - auto* t = global_arena->New(); - t->line_num = line_num; - t->value = TypeTypeLiteral(); - return t; -} - -auto Expression::MakeIntTypeLiteral(int line_num) -> const Expression* { - auto* t = global_arena->New(); - t->line_num = line_num; - t->value = IntTypeLiteral(); - return t; -} - -auto Expression::MakeBoolTypeLiteral(int line_num) -> const Expression* { - auto* t = global_arena->New(); - 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(); - 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(); - 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(); - 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(); - 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(); - e->line_num = line_num; - e->value = BoolLiteral({.value = b}); - return e; -} - -auto Expression::MakePrimitiveOperatorExpression( - int line_num, enum Operator op, std::vector args) - -> const Expression* { - auto* e = global_arena->New(); - 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(); - 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(); - e->line_num = line_num; - e->value = - FieldAccessExpression({.aggregate = exp, .field = std::move(field)}); - return e; -} - -auto Expression::MakeTupleLiteral(int line_num, - std::vector args) - -> const Expression* { - auto* e = global_arena->New(); - 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(); - 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(*this); + out << *index.Aggregate() << "[" << *index.Offset() << "]"; break; - case ExpressionKind::FieldAccessExpression: - out << *GetFieldAccessExpression().aggregate << "." - << GetFieldAccessExpression().field; + } + case Expression::Kind::FieldAccessExpression: { + const auto& access = cast(*this); + out << *access.Aggregate() << "." << access.Field(); break; - case ExpressionKind::TupleLiteral: + } + case Expression::Kind::TupleLiteral: out << "("; - PrintFields(out, GetTupleLiteral().fields); + PrintFields(out, cast(*this).Fields()); out << ")"; break; - case ExpressionKind::IntLiteral: - out << GetIntLiteral(); + case Expression::Kind::IntLiteral: + out << cast(*this).Val(); break; - case ExpressionKind::BoolLiteral: - out << (GetBoolLiteral() ? "true" : "false"); + case Expression::Kind::BoolLiteral: + out << (cast(*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(*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(*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(*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(*this); + out << "fn " << *fn.Parameter() << " -> " << *fn.ReturnType(); break; + } } } diff --git a/executable_semantics/ast/expression.h b/executable_semantics/ast/expression.h index 178a21ca4d15..e562265ad758 100644 --- a/executable_semantics/ast/expression.h +++ b/executable_semantics/ast/expression.h @@ -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 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& { return fields; } + + private: std::vector fields; }; -struct PrimitiveOperatorExpression { - static constexpr ExpressionKind Kind = - ExpressionKind::PrimitiveOperatorExpression; +class PrimitiveOperatorExpression : public Expression { + public: + explicit PrimitiveOperatorExpression(int line_num, Operator op, + std::vector 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& { + return arguments; + } + + private: Operator op; std::vector 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 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 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 - 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 diff --git a/executable_semantics/ast/expression_test.cpp b/executable_semantics/ast/expression_test.cpp index 2c7733881de5..e5845782f4b2 100644 --- a/executable_semantics/ast/expression_test.cpp +++ b/executable_semantics/ast/expression_test.cpp @@ -6,13 +6,16 @@ #include +#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(*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(*tuple).Fields(), IsEmpty()); } TEST(ExpressionTest, UnaryNoCommaAsExpression) { @@ -52,84 +55,86 @@ TEST(ExpressionTest, UnaryNoCommaAsExpression) { // ``` ParenContents contents = { .elements = {{.name = std::nullopt, - .term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}}, + .term = global_arena->New(/*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 contents = { .elements = {{.name = std::nullopt, - .term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}}, + .term = global_arena->New(/*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(*tuple).Fields(), + ElementsAre(IntFieldNamed("0"))); } TEST(ExpressionTest, UnaryWithCommaAsExpression) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}}, + .term = global_arena->New(/*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(*expression).Fields(), ElementsAre(IntFieldNamed("0"))); } TEST(ExpressionTest, UnaryWithCommaAsTuple) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}}, + .term = global_arena->New(/*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(*tuple).Fields(), + ElementsAre(IntFieldNamed("0"))); } TEST(ExpressionTest, BinaryAsExpression) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}, + .term = global_arena->New(/*line_num=*/2, 42)}, {.name = std::nullopt, - .term = Expression::MakeIntLiteral(/*line_num=*/3, 42)}}, + .term = global_arena->New(/*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(*expression).Fields(), ElementsAre(IntFieldNamed("0"), IntFieldNamed("1"))); } TEST(ExpressionTest, BinaryAsTuple) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}, + .term = global_arena->New(/*line_num=*/2, 42)}, {.name = std::nullopt, - .term = Expression::MakeIntLiteral(/*line_num=*/3, 42)}}, + .term = global_arena->New(/*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(*tuple).Fields(), ElementsAre(IntFieldNamed("0"), IntFieldNamed("1"))); } diff --git a/executable_semantics/ast/pattern.cpp b/executable_semantics/ast/pattern.cpp index fb5c5d214d99..8ebdae1df7da 100644 --- a/executable_semantics/ast/pattern.cpp +++ b/executable_semantics/ast/pattern.cpp @@ -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(*tuple_literal); + for (const FieldInitializer& init : tuple.Fields()) { fields.push_back(Field( init.name, global_arena->New(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(*alternative); + choice_type = field_access.Aggregate(); + alternative_name = field_access.Field(); } auto ParenExpressionToParenPattern(const ParenContents& contents) diff --git a/executable_semantics/ast/pattern.h b/executable_semantics/ast/pattern.h index aa12a4566123..d1e0807b24f9 100644 --- a/executable_semantics/ast/pattern.h +++ b/executable_semantics/ast/pattern.h @@ -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 { diff --git a/executable_semantics/ast/statement.cpp b/executable_semantics/ast/statement.cpp index 754d715b0f9a..01bd749e4c46 100644 --- a/executable_semantics/ast/statement.cpp +++ b/executable_semantics/ast/statement.cpp @@ -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(line_num); } s->value = Return({.exp = exp, .is_omitted_exp = is_omitted_exp}); return s; diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index 5ecd9ce8983b..989c27f94caa 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -243,12 +243,12 @@ void DeallocateLocals(int line_num, Frame* frame) { void CreateTuple(Frame* frame, Action* act, const Expression* exp) { // { { (v1,...,vn) :: C, E, F} :: S, H} // -> { { `(v1,...,vn) :: C, E, F} :: S, H} - const auto& tup_lit = exp->GetTupleLiteral(); - CHECK(act->Results().size() == tup_lit.fields.size()); + const auto& tup_lit = cast(*exp); + CHECK(act->Results().size() == tup_lit.Fields().size()); std::vector elements; for (size_t i = 0; i < act->Results().size(); ++i) { elements.push_back( - {.name = tup_lit.fields[i].name, .value = act->Results()[i]}); + {.name = tup_lit.Fields()[i].name, .value = act->Results()[i]}); } const Value* tv = global_arena->New(std::move(elements)); @@ -407,50 +407,51 @@ void StepLvalue() { if (tracing_output) { llvm::outs() << "--- step lvalue " << *exp << " --->\n"; } - switch (exp->tag()) { - case ExpressionKind::IdentifierExpression: { + switch (exp->Tag()) { + case Expression::Kind::IdentifierExpression: { // { {x :: C, E, F} :: S, H} // -> { {E(x) :: C, E, F} :: S, H} std::optional
pointer = - CurrentEnv(state).Get(exp->GetIdentifierExpression().name); + CurrentEnv(state).Get(cast(*exp).Name()); if (!pointer) { - FATAL_RUNTIME_ERROR(exp->line_num) - << "could not find `" << exp->GetIdentifierExpression().name << "`"; + FATAL_RUNTIME_ERROR(exp->LineNumber()) + << "could not find `" << cast(*exp).Name() + << "`"; } const Value* v = global_arena->New(*pointer); frame->todo.Pop(); frame->todo.Push(global_arena->New(v)); break; } - case ExpressionKind::FieldAccessExpression: { + case Expression::Kind::FieldAccessExpression: { if (act->Pos() == 0) { // { {e.f :: C, E, F} :: S, H} // -> { e :: [].f :: C, E, F} :: S, H} frame->todo.Push(global_arena->New( - exp->GetFieldAccessExpression().aggregate)); + cast(*exp).Aggregate())); act->IncrementPos(); } else { // { v :: [].f :: C, E, F} :: S, H} // -> { { &v.f :: C, E, F} :: S, H } Address aggregate = cast(*act->Results()[0]).Val(); - Address field = - aggregate.SubobjectAddress(exp->GetFieldAccessExpression().field); + Address field = aggregate.SubobjectAddress( + cast(*exp).Field()); frame->todo.Pop(1); frame->todo.Push(global_arena->New( global_arena->New(field))); } break; } - case ExpressionKind::IndexExpression: { + case Expression::Kind::IndexExpression: { if (act->Pos() == 0) { // { {e[i] :: C, E, F} :: S, H} // -> { e :: [][i] :: C, E, F} :: S, H} - frame->todo.Push( - global_arena->New(exp->GetIndexExpression().aggregate)); + frame->todo.Push(global_arena->New( + cast(*exp).Aggregate())); act->IncrementPos(); } else if (act->Pos() == 1) { frame->todo.Push(global_arena->New( - exp->GetIndexExpression().offset)); + cast(*exp).Offset())); act->IncrementPos(); } else if (act->Pos() == 2) { // { v :: [][i] :: C, E, F} :: S, H} @@ -465,21 +466,21 @@ void StepLvalue() { } break; } - case ExpressionKind::TupleLiteral: { + case Expression::Kind::TupleLiteral: { if (act->Pos() == 0) { // { {(f1=e1,...) :: C, E, F} :: S, H} // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H} - const Expression* e1 = exp->GetTupleLiteral().fields[0].expression; + const Expression* e1 = cast(*exp).Fields()[0].expression; frame->todo.Push(global_arena->New(e1)); act->IncrementPos(); } else if (act->Pos() != - static_cast(exp->GetTupleLiteral().fields.size())) { + static_cast(cast(*exp).Fields().size())) { // { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S, // H} // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S, // H} const Expression* elt = - exp->GetTupleLiteral().fields[act->Pos()].expression; + cast(*exp).Fields()[act->Pos()].expression; frame->todo.Push(global_arena->New(elt)); act->IncrementPos(); } else { @@ -487,15 +488,15 @@ void StepLvalue() { } break; } - case ExpressionKind::IntLiteral: - case ExpressionKind::BoolLiteral: - case ExpressionKind::CallExpression: - case ExpressionKind::PrimitiveOperatorExpression: - case ExpressionKind::IntTypeLiteral: - case ExpressionKind::BoolTypeLiteral: - case ExpressionKind::TypeTypeLiteral: - case ExpressionKind::FunctionTypeLiteral: - case ExpressionKind::ContinuationTypeLiteral: { + case Expression::Kind::IntLiteral: + case Expression::Kind::BoolLiteral: + case Expression::Kind::CallExpression: + case Expression::Kind::PrimitiveOperatorExpression: + case Expression::Kind::IntTypeLiteral: + case Expression::Kind::BoolTypeLiteral: + case Expression::Kind::TypeTypeLiteral: + case Expression::Kind::FunctionTypeLiteral: + case Expression::Kind::ContinuationTypeLiteral: { FATAL_RUNTIME_ERROR_NO_LINE() << "Can't treat expression as lvalue: " << *exp; } @@ -511,17 +512,17 @@ void StepExp() { if (tracing_output) { llvm::outs() << "--- step exp " << *exp << " --->\n"; } - switch (exp->tag()) { - case ExpressionKind::IndexExpression: { + switch (exp->Tag()) { + case Expression::Kind::IndexExpression: { if (act->Pos() == 0) { // { { e[i] :: C, E, F} :: S, H} // -> { { e :: [][i] :: C, E, F} :: S, H} frame->todo.Push(global_arena->New( - exp->GetIndexExpression().aggregate)); + cast(*exp).Aggregate())); act->IncrementPos(); } else if (act->Pos() == 1) { frame->todo.Push(global_arena->New( - exp->GetIndexExpression().offset)); + cast(*exp).Offset())); act->IncrementPos(); } else if (act->Pos() == 2) { auto tuple = act->Results()[0]; @@ -547,25 +548,26 @@ void StepExp() { } break; } - case ExpressionKind::TupleLiteral: { + case Expression::Kind::TupleLiteral: { if (act->Pos() == 0) { - if (exp->GetTupleLiteral().fields.size() > 0) { + if (cast(*exp).Fields().size() > 0) { // { {(f1=e1,...) :: C, E, F} :: S, H} // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H} - const Expression* e1 = exp->GetTupleLiteral().fields[0].expression; + const Expression* e1 = + cast(*exp).Fields()[0].expression; frame->todo.Push(global_arena->New(e1)); act->IncrementPos(); } else { CreateTuple(frame, act, exp); } } else if (act->Pos() != - static_cast(exp->GetTupleLiteral().fields.size())) { + static_cast(cast(*exp).Fields().size())) { // { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S, // H} // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S, // H} const Expression* elt = - exp->GetTupleLiteral().fields[act->Pos()].expression; + cast(*exp).Fields()[act->Pos()].expression; frame->todo.Push(global_arena->New(elt)); act->IncrementPos(); } else { @@ -573,123 +575,122 @@ void StepExp() { } break; } - case ExpressionKind::FieldAccessExpression: { + case Expression::Kind::FieldAccessExpression: { + const auto& access = cast(*exp); if (act->Pos() == 0) { // { { e.f :: C, E, F} :: S, H} // -> { { e :: [].f :: C, E, F} :: S, H} - frame->todo.Push(global_arena->New( - exp->GetFieldAccessExpression().aggregate)); + frame->todo.Push( + global_arena->New(access.Aggregate())); act->IncrementPos(); } else { // { { v :: [].f :: C, E, F} :: S, H} // -> { { v_f :: C, E, F} : S, H} const Value* element = act->Results()[0]->GetField( - FieldPath(exp->GetFieldAccessExpression().field), exp->line_num); + FieldPath(access.Field()), exp->LineNumber()); frame->todo.Pop(1); frame->todo.Push(global_arena->New(element)); } break; } - case ExpressionKind::IdentifierExpression: { + case Expression::Kind::IdentifierExpression: { CHECK(act->Pos() == 0); + const auto& ident = cast(*exp); // { {x :: C, E, F} :: S, H} -> { {H(E(x)) :: C, E, F} :: S, H} - std::optional
pointer = - CurrentEnv(state).Get(exp->GetIdentifierExpression().name); + std::optional
pointer = CurrentEnv(state).Get(ident.Name()); if (!pointer) { - FATAL_RUNTIME_ERROR(exp->line_num) - << "could not find `" << exp->GetIdentifierExpression().name << "`"; + FATAL_RUNTIME_ERROR(exp->LineNumber()) + << "could not find `" << ident.Name() << "`"; } - const Value* pointee = state->heap.Read(*pointer, exp->line_num); + const Value* pointee = state->heap.Read(*pointer, exp->LineNumber()); frame->todo.Pop(1); frame->todo.Push(global_arena->New(pointee)); break; } - case ExpressionKind::IntLiteral: + case Expression::Kind::IntLiteral: CHECK(act->Pos() == 0); // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} frame->todo.Pop(1); frame->todo.Push(global_arena->New( - global_arena->New(exp->GetIntLiteral()))); + global_arena->New(cast(*exp).Val()))); break; - case ExpressionKind::BoolLiteral: + case Expression::Kind::BoolLiteral: CHECK(act->Pos() == 0); // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} frame->todo.Pop(1); frame->todo.Push(global_arena->New( - global_arena->New(exp->GetBoolLiteral()))); + global_arena->New(cast(*exp).Val()))); break; - case ExpressionKind::PrimitiveOperatorExpression: - if (act->Pos() != - static_cast( - exp->GetPrimitiveOperatorExpression().arguments.size())) { + case Expression::Kind::PrimitiveOperatorExpression: { + const auto& op = cast(*exp); + if (act->Pos() != static_cast(op.Arguments().size())) { // { {v :: op(vs,[],e,es) :: C, E, F} :: S, H} // -> { {e :: op(vs,v,[],es) :: C, E, F} :: S, H} - const Expression* arg = - exp->GetPrimitiveOperatorExpression().arguments[act->Pos()]; + const Expression* arg = op.Arguments()[act->Pos()]; frame->todo.Push(global_arena->New(arg)); act->IncrementPos(); } else { // { {v :: op(vs,[]) :: C, E, F} :: S, H} // -> { {eval_prim(op, (vs,v)) :: C, E, F} :: S, H} - const Value* v = EvalPrim(exp->GetPrimitiveOperatorExpression().op, - act->Results(), exp->line_num); + const Value* v = EvalPrim(op.Op(), act->Results(), exp->LineNumber()); frame->todo.Pop(1); frame->todo.Push(global_arena->New(v)); } break; - case ExpressionKind::CallExpression: + } + case Expression::Kind::CallExpression: if (act->Pos() == 0) { // { {e1(e2) :: C, E, F} :: S, H} // -> { {e1 :: [](e2) :: C, E, F} :: S, H} frame->todo.Push(global_arena->New( - exp->GetCallExpression().function)); + cast(*exp).Function())); act->IncrementPos(); } else if (act->Pos() == 1) { // { { v :: [](e) :: C, E, F} :: S, H} // -> { { e :: v([]) :: C, E, F} :: S, H} frame->todo.Push(global_arena->New( - exp->GetCallExpression().argument)); + cast(*exp).Argument())); act->IncrementPos(); } else if (act->Pos() == 2) { // { { v2 :: v1([]) :: C, E, F} :: S, H} // -> { {C',E',F'} :: {C, E, F} :: S, H} frame->todo.Pop(1); - CallFunction(exp->line_num, act->Results(), state); + CallFunction(exp->LineNumber(), act->Results(), state); } else { FATAL() << "in handle_value with Call pos " << act->Pos(); } break; - case ExpressionKind::IntTypeLiteral: { + case Expression::Kind::IntTypeLiteral: { CHECK(act->Pos() == 0); const Value* v = global_arena->New(); frame->todo.Pop(1); frame->todo.Push(global_arena->New(v)); break; } - case ExpressionKind::BoolTypeLiteral: { + case Expression::Kind::BoolTypeLiteral: { CHECK(act->Pos() == 0); const Value* v = global_arena->New(); frame->todo.Pop(1); frame->todo.Push(global_arena->New(v)); break; } - case ExpressionKind::TypeTypeLiteral: { + case Expression::Kind::TypeTypeLiteral: { CHECK(act->Pos() == 0); const Value* v = global_arena->New(); frame->todo.Pop(1); frame->todo.Push(global_arena->New(v)); break; } - case ExpressionKind::FunctionTypeLiteral: { + case Expression::Kind::FunctionTypeLiteral: { if (act->Pos() == 0) { frame->todo.Push(global_arena->New( - exp->GetFunctionTypeLiteral().parameter)); + cast(*exp).Parameter())); act->IncrementPos(); } else if (act->Pos() == 1) { // { { pt :: fn [] -> e :: C, E, F} :: S, H} // -> { { e :: fn pt -> []) :: C, E, F} :: S, H} frame->todo.Push(global_arena->New( - exp->GetFunctionTypeLiteral().return_type)); + cast(*exp).ReturnType())); act->IncrementPos(); } else if (act->Pos() == 2) { // { { rt :: fn pt -> [] :: C, E, F} :: S, H} @@ -702,14 +703,14 @@ void StepExp() { } break; } - case ExpressionKind::ContinuationTypeLiteral: { + case Expression::Kind::ContinuationTypeLiteral: { CHECK(act->Pos() == 0); const Value* v = global_arena->New(); frame->todo.Pop(1); frame->todo.Push(global_arena->New(v)); break; } - } // switch (exp->tag) + } // switch (exp->Tag) } void StepPattern() { @@ -1124,7 +1125,7 @@ void StepStmt() { Action* ignore_result = global_arena->New( Statement::MakeExpressionStatement( stmt->line_num, - Expression::MakeTupleLiteral(stmt->line_num, {}))); + global_arena->New(stmt->line_num))); frame->todo.Push(ignore_result); // Push the continuation onto the current stack. const std::vector& continuation_vector = @@ -1190,9 +1191,9 @@ auto InterpProgram(const std::list& fs) -> int { } InitGlobals(fs); - const Expression* arg = Expression::MakeTupleLiteral(0, {}); - const Expression* call_main = Expression::MakeCallExpression( - 0, Expression::MakeIdentifierExpression(0, "main"), arg); + const Expression* arg = global_arena->New(0); + const Expression* call_main = global_arena->New( + 0, global_arena->New(0, "main"), arg); auto todo = Stack(global_arena->New(call_main)); auto* scope = global_arena->New(globals, std::list()); auto* frame = global_arena->New("top", Stack(scope), todo); diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp index 355f8ef99dc4..8d6d85aa8fe4 100644 --- a/executable_semantics/interpreter/typecheck.cpp +++ b/executable_semantics/interpreter/typecheck.cpp @@ -46,16 +46,16 @@ static void ExpectPointerType(int line_num, const std::string& context, static auto ReifyType(const Value* t, int line_num) -> const Expression* { switch (t->Tag()) { case Value::Kind::IntType: - return Expression::MakeIntTypeLiteral(0); + return global_arena->New(0); case Value::Kind::BoolType: - return Expression::MakeBoolTypeLiteral(0); + return global_arena->New(0); case Value::Kind::TypeType: - return Expression::MakeTypeTypeLiteral(0); + return global_arena->New(0); case Value::Kind::ContinuationType: - return Expression::MakeContinuationTypeLiteral(0); + return global_arena->New(0); case Value::Kind::FunctionType: { const auto& fn_type = cast(*t); - return Expression::MakeFunctionTypeLiteral( + return global_arena->New( 0, ReifyType(fn_type.Param(), line_num), ReifyType(fn_type.Ret(), line_num), /*is_omitted_return_type=*/false); @@ -66,20 +66,21 @@ static auto ReifyType(const Value* t, int line_num) -> const Expression* { args.push_back( FieldInitializer(field.name, ReifyType(field.value, line_num))); } - return Expression::MakeTupleLiteral(0, args); + return global_arena->New(0, args); } case Value::Kind::StructType: - return Expression::MakeIdentifierExpression(0, - cast(*t).Name()); + return global_arena->New( + 0, cast(*t).Name()); case Value::Kind::ChoiceType: - return Expression::MakeIdentifierExpression(0, - cast(*t).Name()); + return global_arena->New( + 0, cast(*t).Name()); case Value::Kind::PointerType: - return Expression::MakePrimitiveOperatorExpression( + return global_arena->New( 0, Operator::Ptr, - {ReifyType(cast(*t).Type(), line_num)}); + std::vector( + {ReifyType(cast(*t).Type(), line_num)})); case Value::Kind::VariableType: - return Expression::MakeIdentifierExpression( + return global_arena->New( 0, cast(*t).Name()); default: FATAL() << "expected a type, not " << *t; @@ -245,202 +246,204 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) if (tracing_output) { llvm::outs() << "checking expression " << *e << "\n"; } - switch (e->tag()) { - case ExpressionKind::IndexExpression: { - auto res = TypeCheckExp(e->GetIndexExpression().aggregate, types, values); + switch (e->Tag()) { + case Expression::Kind::IndexExpression: { + const auto& index = cast(*e); + auto res = TypeCheckExp(index.Aggregate(), types, values); auto t = res.type; switch (t->Tag()) { case Value::Kind::TupleValue: { - auto i = - cast(*InterpExp(values, e->GetIndexExpression().offset)) - .Val(); + auto i = cast(*InterpExp(values, index.Offset())).Val(); std::string f = std::to_string(i); const Value* field_t = cast(*t).FindField(f); if (field_t == nullptr) { - FATAL_COMPILATION_ERROR(e->line_num) + FATAL_COMPILATION_ERROR(e->LineNumber()) << "field " << f << " is not in the tuple " << *t; } - auto new_e = Expression::MakeIndexExpression( - e->line_num, res.exp, Expression::MakeIntLiteral(e->line_num, i)); + auto new_e = global_arena->New( + e->LineNumber(), res.exp, + global_arena->New(e->LineNumber(), i)); return TCExpression(new_e, field_t, res.types); } default: - FATAL_COMPILATION_ERROR(e->line_num) << "expected a tuple"; + FATAL_COMPILATION_ERROR(e->LineNumber()) << "expected a tuple"; } } - case ExpressionKind::TupleLiteral: { + case Expression::Kind::TupleLiteral: { std::vector new_args; std::vector arg_types; auto new_types = types; - int i = 0; - for (auto arg = e->GetTupleLiteral().fields.begin(); - arg != e->GetTupleLiteral().fields.end(); ++arg, ++i) { - auto arg_res = TypeCheckExp(arg->expression, new_types, values); + for (const auto& arg : cast(*e).Fields()) { + auto arg_res = TypeCheckExp(arg.expression, new_types, values); new_types = arg_res.types; - new_args.push_back(FieldInitializer(arg->name, arg_res.exp)); - arg_types.push_back({.name = arg->name, .value = arg_res.type}); + new_args.push_back(FieldInitializer(arg.name, arg_res.exp)); + arg_types.push_back({.name = arg.name, .value = arg_res.type}); } - auto tuple_e = Expression::MakeTupleLiteral(e->line_num, new_args); + auto tuple_e = global_arena->New(e->LineNumber(), new_args); auto tuple_t = global_arena->New(std::move(arg_types)); return TCExpression(tuple_e, tuple_t, new_types); } - case ExpressionKind::FieldAccessExpression: { - auto res = - TypeCheckExp(e->GetFieldAccessExpression().aggregate, types, values); + case Expression::Kind::FieldAccessExpression: { + const auto& access = cast(*e); + auto res = TypeCheckExp(access.Aggregate(), types, values); auto t = res.type; switch (t->Tag()) { case Value::Kind::StructType: { const auto& t_struct = cast(*t); // Search for a field for (auto& field : t_struct.Fields()) { - if (e->GetFieldAccessExpression().field == field.first) { - const Expression* new_e = Expression::MakeFieldAccessExpression( - e->line_num, res.exp, e->GetFieldAccessExpression().field); + if (access.Field() == field.first) { + const Expression* new_e = + global_arena->New( + e->LineNumber(), res.exp, access.Field()); return TCExpression(new_e, field.second, res.types); } } // Search for a method for (auto& method : t_struct.Methods()) { - if (e->GetFieldAccessExpression().field == method.first) { - const Expression* new_e = Expression::MakeFieldAccessExpression( - e->line_num, res.exp, e->GetFieldAccessExpression().field); + if (access.Field() == method.first) { + const Expression* new_e = + global_arena->New( + e->LineNumber(), res.exp, access.Field()); return TCExpression(new_e, method.second, res.types); } } - FATAL_COMPILATION_ERROR(e->line_num) + FATAL_COMPILATION_ERROR(e->LineNumber()) << "struct " << t_struct.Name() << " does not have a field named " - << e->GetFieldAccessExpression().field; + << access.Field(); } case Value::Kind::TupleValue: { const auto& tup = cast(*t); for (const TupleElement& field : tup.Elements()) { - if (e->GetFieldAccessExpression().field == field.name) { - auto new_e = Expression::MakeFieldAccessExpression( - e->line_num, res.exp, e->GetFieldAccessExpression().field); + if (access.Field() == field.name) { + auto new_e = global_arena->New( + e->LineNumber(), res.exp, access.Field()); return TCExpression(new_e, field.value, res.types); } } - FATAL_COMPILATION_ERROR(e->line_num) + FATAL_COMPILATION_ERROR(e->LineNumber()) << "tuple " << tup << " does not have a field named " - << e->GetFieldAccessExpression().field; + << access.Field(); } case Value::Kind::ChoiceType: { const auto& choice = cast(*t); for (const auto& vt : choice.Alternatives()) { - if (e->GetFieldAccessExpression().field == vt.first) { - const Expression* new_e = Expression::MakeFieldAccessExpression( - e->line_num, res.exp, e->GetFieldAccessExpression().field); + if (access.Field() == vt.first) { + const Expression* new_e = + global_arena->New( + e->LineNumber(), res.exp, access.Field()); auto fun_ty = global_arena->New( std::vector(), vt.second, t); return TCExpression(new_e, fun_ty, res.types); } } - FATAL_COMPILATION_ERROR(e->line_num) + FATAL_COMPILATION_ERROR(e->LineNumber()) << "choice " << choice.Name() << " does not have a field named " - << e->GetFieldAccessExpression().field; + << access.Field(); } default: - FATAL_COMPILATION_ERROR(e->line_num) + FATAL_COMPILATION_ERROR(e->LineNumber()) << "field access, expected a struct\n" << *e; } } - case ExpressionKind::IdentifierExpression: { - std::optional type = - types.Get(e->GetIdentifierExpression().name); + case Expression::Kind::IdentifierExpression: { + const auto& ident = cast(*e); + std::optional type = types.Get(ident.Name()); if (type) { return TCExpression(e, *type, types); } else { - FATAL_COMPILATION_ERROR(e->line_num) - << "could not find `" << e->GetIdentifierExpression().name << "`"; + FATAL_COMPILATION_ERROR(e->LineNumber()) + << "could not find `" << ident.Name() << "`"; } } - case ExpressionKind::IntLiteral: + case Expression::Kind::IntLiteral: return TCExpression(e, global_arena->New(), types); - case ExpressionKind::BoolLiteral: + case Expression::Kind::BoolLiteral: return TCExpression(e, global_arena->New(), types); - case ExpressionKind::PrimitiveOperatorExpression: { + case Expression::Kind::PrimitiveOperatorExpression: { + const auto& op = cast(*e); std::vector es; std::vector ts; auto new_types = types; - for (const Expression* argument : - e->GetPrimitiveOperatorExpression().arguments) { + for (const Expression* argument : op.Arguments()) { auto res = TypeCheckExp(argument, types, values); new_types = res.types; es.push_back(res.exp); ts.push_back(res.type); } - auto new_e = Expression::MakePrimitiveOperatorExpression( - e->line_num, e->GetPrimitiveOperatorExpression().op, es); - switch (e->GetPrimitiveOperatorExpression().op) { + auto new_e = global_arena->New( + e->LineNumber(), op.Op(), es); + switch (op.Op()) { case Operator::Neg: - ExpectType(e->line_num, "negation", global_arena->New(), + ExpectType(e->LineNumber(), "negation", global_arena->New(), ts[0]); return TCExpression(new_e, global_arena->New(), new_types); case Operator::Add: - ExpectType(e->line_num, "addition(1)", global_arena->New(), - ts[0]); - ExpectType(e->line_num, "addition(2)", global_arena->New(), - ts[1]); + ExpectType(e->LineNumber(), "addition(1)", + global_arena->New(), ts[0]); + ExpectType(e->LineNumber(), "addition(2)", + global_arena->New(), ts[1]); return TCExpression(new_e, global_arena->New(), new_types); case Operator::Sub: - ExpectType(e->line_num, "subtraction(1)", + ExpectType(e->LineNumber(), "subtraction(1)", global_arena->New(), ts[0]); - ExpectType(e->line_num, "subtraction(2)", + ExpectType(e->LineNumber(), "subtraction(2)", global_arena->New(), ts[1]); return TCExpression(new_e, global_arena->New(), new_types); case Operator::Mul: - ExpectType(e->line_num, "multiplication(1)", + ExpectType(e->LineNumber(), "multiplication(1)", global_arena->New(), ts[0]); - ExpectType(e->line_num, "multiplication(2)", + ExpectType(e->LineNumber(), "multiplication(2)", global_arena->New(), ts[1]); return TCExpression(new_e, global_arena->New(), new_types); case Operator::And: - ExpectType(e->line_num, "&&(1)", global_arena->New(), + ExpectType(e->LineNumber(), "&&(1)", global_arena->New(), ts[0]); - ExpectType(e->line_num, "&&(2)", global_arena->New(), + ExpectType(e->LineNumber(), "&&(2)", global_arena->New(), ts[1]); return TCExpression(new_e, global_arena->New(), new_types); case Operator::Or: - ExpectType(e->line_num, "||(1)", global_arena->New(), + ExpectType(e->LineNumber(), "||(1)", global_arena->New(), ts[0]); - ExpectType(e->line_num, "||(2)", global_arena->New(), + ExpectType(e->LineNumber(), "||(2)", global_arena->New(), ts[1]); return TCExpression(new_e, global_arena->New(), new_types); case Operator::Not: - ExpectType(e->line_num, "!", global_arena->New(), ts[0]); + ExpectType(e->LineNumber(), "!", global_arena->New(), + ts[0]); return TCExpression(new_e, global_arena->New(), new_types); case Operator::Eq: - ExpectType(e->line_num, "==", ts[0], ts[1]); + ExpectType(e->LineNumber(), "==", ts[0], ts[1]); return TCExpression(new_e, global_arena->New(), new_types); case Operator::Deref: - ExpectPointerType(e->line_num, "*", ts[0]); + ExpectPointerType(e->LineNumber(), "*", ts[0]); return TCExpression(new_e, cast(*ts[0]).Type(), new_types); case Operator::Ptr: - ExpectType(e->line_num, "*", global_arena->New(), ts[0]); + ExpectType(e->LineNumber(), "*", global_arena->New(), + ts[0]); return TCExpression(new_e, global_arena->New(), new_types); } break; } - case ExpressionKind::CallExpression: { - auto fun_res = - TypeCheckExp(e->GetCallExpression().function, types, values); + case Expression::Kind::CallExpression: { + const auto& call = cast(*e); + auto fun_res = TypeCheckExp(call.Function(), types, values); switch (fun_res.type->Tag()) { case Value::Kind::FunctionType: { const auto& fun_t = cast(*fun_res.type); - auto arg_res = TypeCheckExp(e->GetCallExpression().argument, - fun_res.types, values); + auto arg_res = TypeCheckExp(call.Argument(), fun_res.types, values); auto parameter_type = fun_t.Param(); auto return_type = fun_t.Ret(); if (!fun_t.Deduced().empty()) { - auto deduced_args = ArgumentDeduction(e->line_num, TypeEnv(), + auto deduced_args = ArgumentDeduction(e->LineNumber(), TypeEnv(), parameter_type, arg_res.type); for (auto& deduced_param : fun_t.Deduced()) { // TODO: change the following to a CHECK once the real checking // has been added to the type checking of function signatures. if (!deduced_args.Get(deduced_param.name)) { - FATAL_COMPILATION_ERROR(e->line_num) + FATAL_COMPILATION_ERROR(e->LineNumber()) << "could not deduce type argument for type parameter " << deduced_param.name; } @@ -448,35 +451,37 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values) parameter_type = Substitute(deduced_args, parameter_type); return_type = Substitute(deduced_args, return_type); } else { - ExpectType(e->line_num, "call", parameter_type, arg_res.type); + ExpectType(e->LineNumber(), "call", parameter_type, arg_res.type); } - auto new_e = Expression::MakeCallExpression(e->line_num, fun_res.exp, - arg_res.exp); + auto new_e = global_arena->New( + e->LineNumber(), fun_res.exp, arg_res.exp); return TCExpression(new_e, return_type, arg_res.types); } default: { - FATAL_COMPILATION_ERROR(e->line_num) + FATAL_COMPILATION_ERROR(e->LineNumber()) << "in call, expected a function\n" << *e; } } break; } - case ExpressionKind::FunctionTypeLiteral: { - auto pt = InterpExp(values, e->GetFunctionTypeLiteral().parameter); - auto rt = InterpExp(values, e->GetFunctionTypeLiteral().return_type); - auto new_e = Expression::MakeFunctionTypeLiteral( - e->line_num, ReifyType(pt, e->line_num), ReifyType(rt, e->line_num), + case Expression::Kind::FunctionTypeLiteral: { + const auto& fn = cast(*e); + auto pt = InterpExp(values, fn.Parameter()); + auto rt = InterpExp(values, fn.ReturnType()); + auto new_e = global_arena->New( + e->LineNumber(), ReifyType(pt, e->LineNumber()), + ReifyType(rt, e->LineNumber()), /*is_omitted_return_type=*/false); return TCExpression(new_e, global_arena->New(), types); } - case ExpressionKind::IntTypeLiteral: + case Expression::Kind::IntTypeLiteral: return TCExpression(e, global_arena->New(), types); - case ExpressionKind::BoolTypeLiteral: + case Expression::Kind::BoolTypeLiteral: return TCExpression(e, global_arena->New(), types); - case ExpressionKind::TypeTypeLiteral: + case Expression::Kind::TypeTypeLiteral: return TCExpression(e, global_arena->New(), types); - case ExpressionKind::ContinuationTypeLiteral: + case Expression::Kind::ContinuationTypeLiteral: return TCExpression(e, global_arena->New(), types); } } diff --git a/executable_semantics/syntax/parser.ypp b/executable_semantics/syntax/parser.ypp index ad5cf86297a8..7109d3325958 100644 --- a/executable_semantics/syntax/parser.ypp +++ b/executable_semantics/syntax/parser.ypp @@ -211,71 +211,71 @@ input: declaration_list ; expression: identifier - { $$ = Expression::MakeIdentifierExpression(yylineno, $1); } + { $$ = global_arena->New(yylineno, $1); } | expression designator - { $$ = Expression::MakeFieldAccessExpression(yylineno, $1, $2); } + { $$ = global_arena->New(yylineno, $1, $2); } | expression "[" expression "]" - { $$ = Expression::MakeIndexExpression(yylineno, $1, $3); } + { $$ = global_arena->New(yylineno, $1, $3); } | integer_literal - { $$ = Expression::MakeIntLiteral(yylineno, $1); } + { $$ = global_arena->New(yylineno, $1); } | TRUE - { $$ = Expression::MakeBoolLiteral(yylineno, true); } + { $$ = global_arena->New(yylineno, true); } | FALSE - { $$ = Expression::MakeBoolLiteral(yylineno, false); } + { $$ = global_arena->New(yylineno, false); } | sized_type_literal { int val; CHECK(llvm::to_integer(llvm::StringRef($1).substr(1), val)); CHECK($1[0] == 'i' && val == 32) << "Only i32 is supported for now: " << $1; - $$ = Expression::MakeIntTypeLiteral(yylineno); + $$ = global_arena->New(yylineno); } | BOOL - { $$ = Expression::MakeBoolTypeLiteral(yylineno); } + { $$ = global_arena->New(yylineno); } | TYPE - { $$ = Expression::MakeTypeTypeLiteral(yylineno); } + { $$ = global_arena->New(yylineno); } | CONTINUATION_TYPE - { $$ = Expression::MakeContinuationTypeLiteral(yylineno); } + { $$ = global_arena->New(yylineno); } | paren_expression { $$ = $1; } | expression EQUAL_EQUAL expression - { $$ = Expression::MakePrimitiveOperatorExpression( - yylineno, Operator::Eq, {$1, $3}); } + { $$ = global_arena->New( + yylineno, Operator::Eq, std::vector({$1, $3})); } | expression "+" expression - { $$ = Expression::MakePrimitiveOperatorExpression( - yylineno, Operator::Add, {$1, $3}); } + { $$ = global_arena->New( + yylineno, Operator::Add, std::vector({$1, $3})); } | expression "-" expression - { $$ = Expression::MakePrimitiveOperatorExpression( - yylineno, Operator::Sub, {$1, $3}); } + { $$ = global_arena->New( + yylineno, Operator::Sub, std::vector({$1, $3})); } | expression BINARY_STAR expression - { $$ = Expression::MakePrimitiveOperatorExpression( - yylineno, Operator::Mul, {$1, $3}); } + { $$ = global_arena->New( + yylineno, Operator::Mul, std::vector({$1, $3})); } | expression AND expression - { $$ = Expression::MakePrimitiveOperatorExpression( - yylineno, Operator::And, {$1, $3}); } + { $$ = global_arena->New( + yylineno, Operator::And, std::vector({$1, $3})); } | expression OR expression - { $$ = Expression::MakePrimitiveOperatorExpression( - yylineno, Operator::Or, {$1, $3}); } + { $$ = global_arena->New( + yylineno, Operator::Or, std::vector({$1, $3})); } | NOT expression - { $$ = Expression::MakePrimitiveOperatorExpression( - yylineno, Operator::Not, {$2}); } + { $$ = global_arena->New( + yylineno, Operator::Not, std::vector({$2})); } | "-" expression %prec UNARY_MINUS - { $$ = Expression::MakePrimitiveOperatorExpression( - yylineno, Operator::Neg, {$2}); } + { $$ = global_arena->New( + yylineno, Operator::Neg, std::vector({$2})); } | PREFIX_STAR expression - { $$ = Expression::MakePrimitiveOperatorExpression( - yylineno, Operator::Deref, {$2}); } + { $$ = global_arena->New( + yylineno, Operator::Deref, std::vector({$2})); } | UNARY_STAR expression %prec PREFIX_STAR - { $$ = Expression::MakePrimitiveOperatorExpression( - yylineno, Operator::Deref, {$2}); } + { $$ = global_arena->New( + yylineno, Operator::Deref, std::vector({$2})); } | expression tuple - { $$ = Expression::MakeCallExpression(yylineno, $1, $2); } + { $$ = global_arena->New(yylineno, $1, $2); } | expression POSTFIX_STAR - { $$ = Expression::MakePrimitiveOperatorExpression( - yylineno, Operator::Ptr, {$1}); } + { $$ = global_arena->New( + yylineno, Operator::Ptr, std::vector({$1})); } | expression UNARY_STAR - { $$ = Expression::MakePrimitiveOperatorExpression( - yylineno, Operator::Ptr, {$1}); } + { $$ = global_arena->New( + yylineno, Operator::Ptr, std::vector({$1})); } | FNTY tuple return_type - { $$ = Expression::MakeFunctionTypeLiteral( + { $$ = global_arena->New( yylineno, $2, $3.first, $3.second); } ; designator: "." identifier { $$ = $2; } @@ -454,7 +454,7 @@ optional_else: ; return_expression: // Empty - { $$ = {Expression::MakeTupleLiteral(yylineno, {}), true}; } + { $$ = {global_arena->New(yylineno), true}; } | expression { $$ = {$1, false}; } ; @@ -470,7 +470,7 @@ block: ; return_type: // Empty - { $$ = {Expression::MakeTupleLiteral(yylineno, {}), true}; } + { $$ = {global_arena->New(yylineno), true}; } | ARROW expression %prec FNARROW { $$ = {$2, false}; } ; @@ -544,7 +544,7 @@ alternative: | identifier { $$ = std::pair( - $1, Expression::MakeTupleLiteral(yylineno, {})); + $1, global_arena->New(yylineno)); } ; alternative_list: