mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 07:21:04 +01:00
Factor out a Pattern sum type from Expression (#685)
`Pattern` is intended to pilot some changes I would like to apply to all our sum types: - The alternatives are expressed as derived classes rather than members of a `std::variant`. - The alternatives are classes in the [style guide sense](https://google.github.io/styleguide/cppguide.html#Structs_vs._Classes), meaning they can have invariants, but can't have public data members. - Creating an object is expressed using a constructor rather than a factory function. - Accessing an alternative is expressed as a cast (using LLVM's RTTI system) rather than `std::get` or a `Get` method. Co-authored-by: Jon Meow <46229924+jonmeow@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
Jon Meow
parent
b08f6bb0f1
commit
6ac3adfa53
@@ -16,6 +16,7 @@ cc_library(
|
||||
deps = [
|
||||
":function_definition",
|
||||
":member",
|
||||
":pattern",
|
||||
":struct_definition",
|
||||
"//common:ostream",
|
||||
"//executable_semantics/interpreter:address",
|
||||
@@ -33,10 +34,26 @@ cc_library(
|
||||
"//common:ostream",
|
||||
"//executable_semantics/common:arena",
|
||||
"//executable_semantics/common:error",
|
||||
"//executable_semantics/syntax:paren_contents",
|
||||
"@llvm-project//llvm:Support",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "expression_test",
|
||||
srcs = ["expression_test.cpp"],
|
||||
env = {
|
||||
# TODO(#580): Remove this when leaks are fixed.
|
||||
"ASAN_OPTIONS": "detect_leaks=0",
|
||||
},
|
||||
deps = [
|
||||
":expression",
|
||||
"//executable_semantics/syntax:paren_contents",
|
||||
"@llvm-project//llvm:gtest",
|
||||
"@llvm-project//llvm:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "function_definition",
|
||||
srcs = ["function_definition.cpp"],
|
||||
@@ -52,19 +69,47 @@ cc_library(
|
||||
name = "member",
|
||||
srcs = ["member.cpp"],
|
||||
hdrs = ["member.h"],
|
||||
deps = [
|
||||
":pattern",
|
||||
"//common:ostream",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "pattern",
|
||||
srcs = ["pattern.cpp"],
|
||||
hdrs = ["pattern.h"],
|
||||
deps = [
|
||||
":expression",
|
||||
"//common:ostream",
|
||||
"//executable_semantics/common:error",
|
||||
"@llvm-project//llvm:Support",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "pattern_test",
|
||||
srcs = ["pattern_test.cpp"],
|
||||
env = {
|
||||
# TODO(#580): Remove this when leaks are fixed.
|
||||
"ASAN_OPTIONS": "detect_leaks=0",
|
||||
},
|
||||
deps = [
|
||||
":pattern",
|
||||
"//executable_semantics/syntax:paren_contents",
|
||||
"@llvm-project//llvm:Support",
|
||||
"@llvm-project//llvm:gtest",
|
||||
"@llvm-project//llvm:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "statement",
|
||||
srcs = ["statement.cpp"],
|
||||
hdrs = ["statement.h"],
|
||||
deps = [
|
||||
":expression",
|
||||
":pattern",
|
||||
"//common:check",
|
||||
"//common:ostream",
|
||||
"@llvm-project//llvm:Support",
|
||||
|
||||
@@ -35,14 +35,13 @@ auto Declaration::MakeChoiceDeclaration(
|
||||
return d;
|
||||
}
|
||||
|
||||
auto Declaration::MakeVariableDeclaration(int source_location, std::string name,
|
||||
const Expression* type,
|
||||
auto Declaration::MakeVariableDeclaration(int source_location,
|
||||
const BindingPattern* binding,
|
||||
const Expression* initializer)
|
||||
-> const Declaration {
|
||||
Declaration d;
|
||||
d.value = VariableDeclaration({.source_location = source_location,
|
||||
.name = std::move(name),
|
||||
.type = type,
|
||||
.binding = binding,
|
||||
.initializer = initializer});
|
||||
return d;
|
||||
}
|
||||
@@ -91,8 +90,7 @@ void Declaration::Print(llvm::raw_ostream& out) const {
|
||||
|
||||
case DeclarationKind::VariableDeclaration: {
|
||||
const auto& var = GetVariableDeclaration();
|
||||
out << "var " << *var.type << " : " << var.name << " = "
|
||||
<< *var.initializer << "\n";
|
||||
out << "var " << *var.binding << " = " << *var.initializer << "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/ast/function_definition.h"
|
||||
#include "executable_semantics/ast/member.h"
|
||||
#include "executable_semantics/ast/pattern.h"
|
||||
#include "executable_semantics/ast/struct_definition.h"
|
||||
#include "executable_semantics/interpreter/address.h"
|
||||
#include "executable_semantics/interpreter/dictionary.h"
|
||||
@@ -58,8 +59,10 @@ struct ChoiceDeclaration {
|
||||
struct VariableDeclaration {
|
||||
static constexpr DeclarationKind Kind = DeclarationKind::VariableDeclaration;
|
||||
int source_location;
|
||||
std::string name;
|
||||
const Expression* type;
|
||||
// TODO: split this into a non-optional name and a type, initialized by
|
||||
// a constructor that takes a BindingPattern and handles errors like a
|
||||
// missing name.
|
||||
const BindingPattern* binding;
|
||||
const Expression* initializer;
|
||||
};
|
||||
|
||||
@@ -74,8 +77,8 @@ class Declaration {
|
||||
int line_num, std::string name,
|
||||
std::list<std::pair<std::string, const Expression*>> alternatives)
|
||||
-> const Declaration;
|
||||
static auto MakeVariableDeclaration(int source_location, std::string name,
|
||||
const Expression* type,
|
||||
static auto MakeVariableDeclaration(int source_location,
|
||||
const BindingPattern* binding,
|
||||
const Expression* initializer)
|
||||
-> const Declaration;
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "executable_semantics/ast/expression.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "executable_semantics/common/arena.h"
|
||||
#include "executable_semantics/common/error.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
@@ -11,6 +13,24 @@
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
auto ExpressionFromParenContents(
|
||||
int line_num, const ParenContents<Expression>& paren_contents)
|
||||
-> const Expression* {
|
||||
std::optional<const Expression*> single_term = paren_contents.SingleTerm();
|
||||
if (single_term.has_value()) {
|
||||
return *single_term;
|
||||
} else {
|
||||
return TupleExpressionFromParenContents(line_num, paren_contents);
|
||||
}
|
||||
}
|
||||
|
||||
auto TupleExpressionFromParenContents(
|
||||
int line_num, const ParenContents<Expression>& paren_contents)
|
||||
-> const Expression* {
|
||||
return Expression::MakeTupleLiteral(
|
||||
line_num, paren_contents.TupleElements<FieldInitializer>(line_num));
|
||||
}
|
||||
|
||||
auto Expression::GetIdentifierExpression() const
|
||||
-> const IdentifierExpression& {
|
||||
return std::get<IdentifierExpression>(value);
|
||||
@@ -25,10 +45,6 @@ auto Expression::GetIndexExpression() const -> const IndexExpression& {
|
||||
return std::get<IndexExpression>(value);
|
||||
}
|
||||
|
||||
auto Expression::GetBindingExpression() const -> const BindingExpression& {
|
||||
return std::get<BindingExpression>(value);
|
||||
}
|
||||
|
||||
auto Expression::GetIntLiteral() const -> int {
|
||||
return std::get<IntLiteral>(value).value;
|
||||
}
|
||||
@@ -75,13 +91,6 @@ auto Expression::MakeBoolTypeLiteral(int line_num) -> const Expression* {
|
||||
return t;
|
||||
}
|
||||
|
||||
auto Expression::MakeAutoTypeLiteral(int line_num) -> const Expression* {
|
||||
auto* t = global_arena->New<Expression>();
|
||||
t->line_num = line_num;
|
||||
t->value = AutoTypeLiteral();
|
||||
return t;
|
||||
}
|
||||
|
||||
// Returns a Continuation type AST node at the given source location.
|
||||
auto Expression::MakeContinuationTypeLiteral(int line_num)
|
||||
-> const Expression* {
|
||||
@@ -108,16 +117,6 @@ auto Expression::MakeIdentifierExpression(int line_num, std::string var)
|
||||
return v;
|
||||
}
|
||||
|
||||
auto Expression::MakeBindingExpression(int line_num,
|
||||
std::optional<std::string> var,
|
||||
const Expression* type)
|
||||
-> const Expression* {
|
||||
auto* v = global_arena->New<Expression>();
|
||||
v->line_num = line_num;
|
||||
v->value = BindingExpression({.name = std::move(var), .type = type});
|
||||
return v;
|
||||
}
|
||||
|
||||
auto Expression::MakeIntLiteral(int line_num, int i) -> const Expression* {
|
||||
auto* e = global_arena->New<Expression>();
|
||||
e->line_num = line_num;
|
||||
@@ -166,21 +165,7 @@ auto Expression::MakeTupleLiteral(int line_num,
|
||||
-> const Expression* {
|
||||
auto* e = global_arena->New<Expression>();
|
||||
e->line_num = line_num;
|
||||
int i = 0;
|
||||
bool seen_named_member = false;
|
||||
for (auto& arg : args) {
|
||||
if (arg.name == "") {
|
||||
if (seen_named_member) {
|
||||
FATAL_USER_ERROR(line_num)
|
||||
<< "positional members must come before named members";
|
||||
}
|
||||
arg.name = std::to_string(i);
|
||||
++i;
|
||||
} else {
|
||||
seen_named_member = true;
|
||||
}
|
||||
}
|
||||
e->value = TupleLiteral({.fields = args});
|
||||
e->value = TupleLiteral({.fields = std::move(args)});
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -269,16 +254,6 @@ void Expression::Print(llvm::raw_ostream& out) const {
|
||||
case ExpressionKind::IdentifierExpression:
|
||||
out << GetIdentifierExpression().name;
|
||||
break;
|
||||
case ExpressionKind::BindingExpression: {
|
||||
const BindingExpression& binding = GetBindingExpression();
|
||||
if (binding.name.has_value()) {
|
||||
out << *binding.name;
|
||||
} else {
|
||||
out << "_";
|
||||
}
|
||||
out << ": " << *binding.type;
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::CallExpression:
|
||||
out << *GetCallExpression().function;
|
||||
if (GetCallExpression().argument->tag() == ExpressionKind::TupleLiteral) {
|
||||
@@ -296,9 +271,6 @@ void Expression::Print(llvm::raw_ostream& out) const {
|
||||
case ExpressionKind::TypeTypeLiteral:
|
||||
out << "Type";
|
||||
break;
|
||||
case ExpressionKind::AutoTypeLiteral:
|
||||
out << "auto";
|
||||
break;
|
||||
case ExpressionKind::ContinuationTypeLiteral:
|
||||
out << "Continuation";
|
||||
break;
|
||||
|
||||
@@ -11,15 +11,33 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/syntax/paren_contents.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
struct Expression;
|
||||
class Pattern;
|
||||
|
||||
// Converts paren_contents to an Expression, interpreting the parentheses as
|
||||
// grouping if their contents permit that interpretation, or as forming a
|
||||
// tuple otherwise.
|
||||
auto ExpressionFromParenContents(
|
||||
int line_num, const ParenContents<Expression>& paren_contents)
|
||||
-> const Expression*;
|
||||
|
||||
// Converts paren_contents to an Expression, interpreting the parentheses as
|
||||
// forming a tuple.
|
||||
auto TupleExpressionFromParenContents(
|
||||
int line_num, const ParenContents<Expression>& paren_contents)
|
||||
-> const Expression*;
|
||||
|
||||
// A FieldInitializer represents the initialization of a single tuple field.
|
||||
struct FieldInitializer {
|
||||
// The field name. For a positional field, this may be empty.
|
||||
FieldInitializer(std::string name, const Expression* expression)
|
||||
: name(std::move(name)), expression(expression) {}
|
||||
|
||||
// The field name. Cannot be empty.
|
||||
std::string name;
|
||||
|
||||
// The expression that initializes the field.
|
||||
@@ -27,7 +45,6 @@ struct FieldInitializer {
|
||||
};
|
||||
|
||||
enum class ExpressionKind {
|
||||
AutoTypeLiteral,
|
||||
BoolTypeLiteral,
|
||||
BoolLiteral,
|
||||
CallExpression,
|
||||
@@ -37,7 +54,6 @@ enum class ExpressionKind {
|
||||
IntTypeLiteral,
|
||||
ContinuationTypeLiteral, // The type of a continuation value.
|
||||
IntLiteral,
|
||||
BindingExpression,
|
||||
PrimitiveOperatorExpression,
|
||||
TupleLiteral,
|
||||
TypeTypeLiteral,
|
||||
@@ -76,13 +92,6 @@ struct IndexExpression {
|
||||
const Expression* offset;
|
||||
};
|
||||
|
||||
struct BindingExpression {
|
||||
static constexpr ExpressionKind Kind = ExpressionKind::BindingExpression;
|
||||
// nullopt represents the `_` placeholder.
|
||||
std::optional<std::string> name;
|
||||
const Expression* type;
|
||||
};
|
||||
|
||||
struct IntLiteral {
|
||||
static constexpr ExpressionKind Kind = ExpressionKind::IntLiteral;
|
||||
int value;
|
||||
@@ -117,10 +126,6 @@ struct FunctionTypeLiteral {
|
||||
const Expression* return_type;
|
||||
};
|
||||
|
||||
struct AutoTypeLiteral {
|
||||
static constexpr ExpressionKind Kind = ExpressionKind::AutoTypeLiteral;
|
||||
};
|
||||
|
||||
struct BoolTypeLiteral {
|
||||
static constexpr ExpressionKind Kind = ExpressionKind::BoolTypeLiteral;
|
||||
};
|
||||
@@ -141,10 +146,6 @@ struct TypeTypeLiteral {
|
||||
struct Expression {
|
||||
static auto MakeIdentifierExpression(int line_num, std::string var)
|
||||
-> const Expression*;
|
||||
static auto MakeBindingExpression(int line_num,
|
||||
std::optional<std::string> var,
|
||||
const Expression* type)
|
||||
-> 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(
|
||||
@@ -164,13 +165,11 @@ struct Expression {
|
||||
static auto MakeFunctionTypeLiteral(int line_num, const Expression* param,
|
||||
const Expression* ret)
|
||||
-> const Expression*;
|
||||
static auto MakeAutoTypeLiteral(int line_num) -> 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 GetBindingExpression() const -> const BindingExpression&;
|
||||
auto GetIntLiteral() const -> int;
|
||||
auto GetBoolLiteral() const -> bool;
|
||||
auto GetTupleLiteral() const -> const TupleLiteral&;
|
||||
@@ -190,10 +189,10 @@ struct Expression {
|
||||
|
||||
private:
|
||||
std::variant<IdentifierExpression, FieldAccessExpression, IndexExpression,
|
||||
BindingExpression, IntLiteral, BoolLiteral, TupleLiteral,
|
||||
IntLiteral, BoolLiteral, TupleLiteral,
|
||||
PrimitiveOperatorExpression, CallExpression, FunctionTypeLiteral,
|
||||
AutoTypeLiteral, BoolTypeLiteral, IntTypeLiteral,
|
||||
ContinuationTypeLiteral, TypeTypeLiteral>
|
||||
BoolTypeLiteral, IntTypeLiteral, ContinuationTypeLiteral,
|
||||
TypeTypeLiteral>
|
||||
value;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
// 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 "executable_semantics/ast/expression.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "executable_semantics/syntax/paren_contents.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace {
|
||||
|
||||
using testing::ElementsAre;
|
||||
using testing::IsEmpty;
|
||||
|
||||
// Matches a FieldInitializer named `name` whose `expression` is an
|
||||
// `IntLiteral`
|
||||
MATCHER_P(IntFieldNamed, name, "") {
|
||||
return arg.name == std::string(name) &&
|
||||
arg.expression->tag() == ExpressionKind::IntLiteral;
|
||||
}
|
||||
|
||||
TEST(ExpressionTest, EmptyAsExpression) {
|
||||
ParenContents<Expression> contents = {.elements = {},
|
||||
.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());
|
||||
}
|
||||
|
||||
TEST(ExpressionTest, EmptyAsTuple) {
|
||||
ParenContents<Expression> contents = {.elements = {},
|
||||
.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());
|
||||
}
|
||||
|
||||
TEST(ExpressionTest, UnaryNoCommaAsExpression) {
|
||||
// Equivalent to a code fragment like
|
||||
// ```
|
||||
// (
|
||||
// 42
|
||||
// )
|
||||
// ```
|
||||
ParenContents<Expression> contents = {
|
||||
.elements = {{.name = std::nullopt,
|
||||
.term = Expression::MakeIntLiteral(/*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);
|
||||
}
|
||||
|
||||
TEST(ExpressionTest, UnaryNoCommaAsTuple) {
|
||||
ParenContents<Expression> contents = {
|
||||
.elements = {{.name = std::nullopt,
|
||||
.term = Expression::MakeIntLiteral(/*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")));
|
||||
}
|
||||
|
||||
TEST(ExpressionTest, UnaryWithCommaAsExpression) {
|
||||
ParenContents<Expression> contents = {
|
||||
.elements = {{.name = std::nullopt,
|
||||
.term = Expression::MakeIntLiteral(/*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,
|
||||
ElementsAre(IntFieldNamed("0")));
|
||||
}
|
||||
|
||||
TEST(ExpressionTest, UnaryWithCommaAsTuple) {
|
||||
ParenContents<Expression> contents = {
|
||||
.elements = {{.name = std::nullopt,
|
||||
.term = Expression::MakeIntLiteral(/*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")));
|
||||
}
|
||||
|
||||
TEST(ExpressionTest, BinaryAsExpression) {
|
||||
ParenContents<Expression> contents = {
|
||||
.elements = {{.name = std::nullopt,
|
||||
.term = Expression::MakeIntLiteral(/*line_num=*/2, 42)},
|
||||
{.name = std::nullopt,
|
||||
.term = Expression::MakeIntLiteral(/*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,
|
||||
ElementsAre(IntFieldNamed("0"), IntFieldNamed("1")));
|
||||
}
|
||||
|
||||
TEST(ExpressionTest, BinaryAsTuple) {
|
||||
ParenContents<Expression> contents = {
|
||||
.elements = {{.name = std::nullopt,
|
||||
.term = Expression::MakeIntLiteral(/*line_num=*/2, 42)},
|
||||
{.name = std::nullopt,
|
||||
.term = Expression::MakeIntLiteral(/*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,
|
||||
ElementsAre(IntFieldNamed("0"), IntFieldNamed("1")));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Carbon
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/ast/expression.h"
|
||||
#include "executable_semantics/ast/pattern.h"
|
||||
#include "executable_semantics/ast/statement.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
@@ -23,8 +24,8 @@ struct FunctionDefinition {
|
||||
FunctionDefinition() = default;
|
||||
FunctionDefinition(int line_num, std::string name,
|
||||
std::vector<GenericBinding> deduced_params,
|
||||
const Expression* param_pattern,
|
||||
const Expression* return_type, const Statement* body)
|
||||
const TuplePattern* param_pattern,
|
||||
const Pattern* return_type, const Statement* body)
|
||||
: line_num(line_num),
|
||||
name(std::move(name)),
|
||||
deduced_parameters(deduced_params),
|
||||
@@ -39,8 +40,8 @@ struct FunctionDefinition {
|
||||
int line_num;
|
||||
std::string name;
|
||||
std::vector<GenericBinding> deduced_parameters;
|
||||
const Expression* param_pattern;
|
||||
const Expression* return_type;
|
||||
const TuplePattern* param_pattern;
|
||||
const Pattern* return_type;
|
||||
const Statement* body;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
auto Member::MakeFieldMember(int line_num, std::string name,
|
||||
const Expression* type) -> Member* {
|
||||
auto Member::MakeFieldMember(int line_num, const BindingPattern* binding)
|
||||
-> Member* {
|
||||
auto m = new Member();
|
||||
m->line_num = line_num;
|
||||
m->value = FieldMember({.name = std::move(name), .type = type});
|
||||
m->value = FieldMember({.binding = binding});
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ void Member::Print(llvm::raw_ostream& out) const {
|
||||
switch (tag()) {
|
||||
case MemberKind::FieldMember:
|
||||
const auto& field = GetFieldMember();
|
||||
out << "var " << field.name << " : " << *field.type << ";\n";
|
||||
out << "var " << field.binding << ";\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/ast/expression.h"
|
||||
#include "executable_semantics/ast/pattern.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace Carbon {
|
||||
@@ -17,13 +18,15 @@ enum class MemberKind { FieldMember };
|
||||
|
||||
struct FieldMember {
|
||||
static constexpr MemberKind Kind = MemberKind::FieldMember;
|
||||
std::string name;
|
||||
const Expression* type;
|
||||
// TODO: split this into a non-optional name and a type, initialized by
|
||||
// a constructor that takes a BindingPattern and handles errors like a
|
||||
// missing name.
|
||||
const BindingPattern* binding;
|
||||
};
|
||||
|
||||
struct Member {
|
||||
static auto MakeFieldMember(int line_num, std::string name,
|
||||
const Expression* type) -> Member*;
|
||||
static auto MakeFieldMember(int line_num, const BindingPattern* binding)
|
||||
-> Member*;
|
||||
|
||||
auto GetFieldMember() const -> const FieldMember&;
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
// 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 "executable_semantics/ast/pattern.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/ast/expression.h"
|
||||
#include "executable_semantics/common/error.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
using llvm::cast;
|
||||
|
||||
void Pattern::Print(llvm::raw_ostream& out) const {
|
||||
switch (Tag()) {
|
||||
case Kind::AutoPattern:
|
||||
out << "auto";
|
||||
break;
|
||||
case Kind::BindingPattern: {
|
||||
const auto& binding = cast<BindingPattern>(*this);
|
||||
if (binding.Name().has_value()) {
|
||||
out << *binding.Name();
|
||||
} else {
|
||||
out << "_";
|
||||
}
|
||||
out << ": " << *binding.Type();
|
||||
break;
|
||||
}
|
||||
case Kind::TuplePattern: {
|
||||
const auto& tuple = cast<TuplePattern>(*this);
|
||||
out << "(";
|
||||
llvm::ListSeparator sep;
|
||||
for (const TuplePattern::Field& field : tuple.Fields()) {
|
||||
out << sep << field.name << " = " << field.pattern;
|
||||
}
|
||||
out << ")";
|
||||
break;
|
||||
}
|
||||
case Kind::AlternativePattern: {
|
||||
const auto& alternative = cast<AlternativePattern>(*this);
|
||||
out << alternative.ChoiceType() << "." << alternative.AlternativeName()
|
||||
<< alternative.Arguments();
|
||||
break;
|
||||
}
|
||||
case Kind::ExpressionPattern:
|
||||
out << cast<ExpressionPattern>(*this).Expression();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
fields.push_back(Field(init.name, new ExpressionPattern(init.expression)));
|
||||
}
|
||||
}
|
||||
|
||||
auto PatternFromParenContents(int line_num,
|
||||
const ParenContents<Pattern>& paren_contents)
|
||||
-> const Pattern* {
|
||||
std::optional<const Pattern*> single_term = paren_contents.SingleTerm();
|
||||
if (single_term.has_value()) {
|
||||
return *single_term;
|
||||
} else {
|
||||
return TuplePatternFromParenContents(line_num, paren_contents);
|
||||
}
|
||||
}
|
||||
|
||||
auto TuplePatternFromParenContents(int line_num,
|
||||
const ParenContents<Pattern>& paren_contents)
|
||||
-> const TuplePattern* {
|
||||
return new TuplePattern(
|
||||
line_num, paren_contents.TupleElements<TuplePattern::Field>(line_num));
|
||||
}
|
||||
|
||||
AlternativePattern::AlternativePattern(int line_num,
|
||||
const Expression* alternative,
|
||||
const TuplePattern* arguments)
|
||||
: Pattern(Kind::AlternativePattern, line_num), arguments(arguments) {
|
||||
if (alternative->tag() != ExpressionKind::FieldAccessExpression) {
|
||||
FATAL_USER_ERROR(alternative->line_num)
|
||||
<< "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;
|
||||
}
|
||||
|
||||
auto ParenExpressionToParenPattern(const ParenContents<Expression>& contents)
|
||||
-> ParenContents<Pattern> {
|
||||
ParenContents<Pattern> result = {
|
||||
.elements = {}, .has_trailing_comma = contents.has_trailing_comma};
|
||||
for (const auto& element : contents.elements) {
|
||||
result.elements.push_back(
|
||||
{.name = element.name, .term = new ExpressionPattern(element.term)});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
@@ -0,0 +1,199 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#ifndef EXECUTABLE_SEMANTICS_AST_PATTERN_H_
|
||||
#define EXECUTABLE_SEMANTICS_AST_PATTERN_H_
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/ast/expression.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
// Abstract base class of all AST nodes representing patterns.
|
||||
//
|
||||
// Pattern and its derived classes support LLVM-style RTTI, including
|
||||
// llvm::isa, llvm::cast, and llvm::dyn_cast. To support this, every
|
||||
// class derived from Pattern must provide a `classof` operation, and
|
||||
// every concrete derived class must have a corresponding enumerator
|
||||
// in `Kind`; see https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html for
|
||||
// details.
|
||||
class Pattern {
|
||||
public:
|
||||
enum class Kind {
|
||||
AutoPattern,
|
||||
BindingPattern,
|
||||
TuplePattern,
|
||||
AlternativePattern,
|
||||
ExpressionPattern,
|
||||
};
|
||||
|
||||
Pattern(const Pattern&) = delete;
|
||||
Pattern& operator=(const Pattern&) = delete;
|
||||
|
||||
// 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;
|
||||
|
||||
protected:
|
||||
// Constructs a Pattern representing syntax at the given line number.
|
||||
// `tag` must be the enumerator corresponding to the most-derived type being
|
||||
// constructed.
|
||||
Pattern(Kind tag, int line_num) : tag(tag), line_num(line_num) {}
|
||||
|
||||
private:
|
||||
const Kind tag;
|
||||
int line_num;
|
||||
};
|
||||
|
||||
// A pattern consisting of the `auto` keyword.
|
||||
class AutoPattern : public Pattern {
|
||||
public:
|
||||
explicit AutoPattern(int line_num) : Pattern(Kind::AutoPattern, line_num) {}
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
return pattern->Tag() == Kind::AutoPattern;
|
||||
}
|
||||
};
|
||||
|
||||
// A pattern that matches a value of a specified type, and optionally binds
|
||||
// a name to it.
|
||||
class BindingPattern : public Pattern {
|
||||
public:
|
||||
BindingPattern(int line_num, std::optional<std::string> name,
|
||||
const Pattern* type)
|
||||
: Pattern(Kind::BindingPattern, line_num),
|
||||
name(std::move(name)),
|
||||
type(type) {}
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
return pattern->Tag() == Kind::BindingPattern;
|
||||
}
|
||||
|
||||
// The name this pattern binds, if any.
|
||||
auto Name() const -> const std::optional<std::string>& { return name; }
|
||||
|
||||
// The pattern specifying the type of values that this pattern matches.
|
||||
auto Type() const -> const Pattern* { return type; }
|
||||
|
||||
private:
|
||||
std::optional<std::string> name;
|
||||
const Pattern* type;
|
||||
};
|
||||
|
||||
// A pattern that matches a tuple value field-wise.
|
||||
class TuplePattern : public Pattern {
|
||||
public:
|
||||
// Represents a portion of a tuple pattern corresponding to a single field.
|
||||
struct Field {
|
||||
Field(std::string name, const Pattern* pattern)
|
||||
: name(std::move(name)), pattern(pattern) {}
|
||||
|
||||
// The field name. Cannot be empty
|
||||
std::string name;
|
||||
|
||||
// The pattern the field must match.
|
||||
const Pattern* pattern;
|
||||
};
|
||||
|
||||
TuplePattern(int line_num, std::vector<Field> fields)
|
||||
: Pattern(Kind::TuplePattern, line_num), fields(std::move(fields)) {}
|
||||
|
||||
// Converts tuple_literal to a TuplePattern, by wrapping each field in an
|
||||
// ExpressionPattern.
|
||||
//
|
||||
// REQUIRES: tuple_literal->Tag() == ExpressionKind::TupleLiteral
|
||||
explicit TuplePattern(const Expression* tuple_literal);
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
return pattern->Tag() == Kind::TuplePattern;
|
||||
}
|
||||
|
||||
auto Fields() const -> const std::vector<Field>& { return fields; }
|
||||
|
||||
private:
|
||||
std::vector<Field> fields;
|
||||
};
|
||||
|
||||
// Converts paren_contents to a Pattern, interpreting the parentheses as
|
||||
// grouping if their contents permit that interpretation, or as forming a
|
||||
// tuple otherwise.
|
||||
auto PatternFromParenContents(int line_num,
|
||||
const ParenContents<Pattern>& paren_contents)
|
||||
-> const Pattern*;
|
||||
|
||||
// Converts paren_contents to a TuplePattern, interpreting the parentheses as
|
||||
// forming a tuple.
|
||||
auto TuplePatternFromParenContents(int line_num,
|
||||
const ParenContents<Pattern>& paren_contents)
|
||||
-> const TuplePattern*;
|
||||
|
||||
// Converts `contents` to ParenContents<Pattern> by replacing each Expression
|
||||
// with an ExpressionPattern.
|
||||
auto ParenExpressionToParenPattern(const ParenContents<Expression>& contents)
|
||||
-> ParenContents<Pattern>;
|
||||
|
||||
// A pattern that matches an alternative of a choice type.
|
||||
class AlternativePattern : public Pattern {
|
||||
public:
|
||||
// Constructs an AlternativePattern that matches a value of the type
|
||||
// specified by choice_type if it represents an alternative named
|
||||
// alternative_name, and its arguments match `arguments`.
|
||||
AlternativePattern(int line_num, const Expression* choice_type,
|
||||
std::string alternative_name,
|
||||
const TuplePattern* arguments)
|
||||
: Pattern(Kind::AlternativePattern, line_num),
|
||||
choice_type(choice_type),
|
||||
alternative_name(std::move(alternative_name)),
|
||||
arguments(arguments) {}
|
||||
|
||||
// Constructs an AlternativePattern that matches the alternative specified
|
||||
// by `alternative`, if its arguments match `arguments`.
|
||||
AlternativePattern(int line_num, const Expression* alternative,
|
||||
const TuplePattern* arguments);
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
return pattern->Tag() == Kind::AlternativePattern;
|
||||
}
|
||||
|
||||
auto ChoiceType() const -> const Expression* { return choice_type; }
|
||||
auto AlternativeName() const -> const std::string& {
|
||||
return alternative_name;
|
||||
}
|
||||
auto Arguments() const -> const TuplePattern* { return arguments; }
|
||||
|
||||
private:
|
||||
const Expression* choice_type;
|
||||
std::string alternative_name;
|
||||
const TuplePattern* arguments;
|
||||
};
|
||||
|
||||
// A pattern that matches a value if it is equal to the value of a given
|
||||
// expression.
|
||||
class ExpressionPattern : public Pattern {
|
||||
public:
|
||||
ExpressionPattern(const Expression* expression)
|
||||
: Pattern(Kind::ExpressionPattern, expression->line_num),
|
||||
expression(expression) {}
|
||||
|
||||
static auto classof(const Pattern* pattern) -> bool {
|
||||
return pattern->Tag() == Kind::ExpressionPattern;
|
||||
}
|
||||
|
||||
auto Expression() const -> const Expression* { return expression; }
|
||||
|
||||
private:
|
||||
const Carbon::Expression* expression;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
#endif // EXECUTABLE_SEMANTICS_AST_PATTERN_H_
|
||||
@@ -0,0 +1,130 @@
|
||||
// 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 "executable_semantics/ast/pattern.h"
|
||||
|
||||
#include "executable_semantics/ast/expression.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 llvm::isa;
|
||||
using testing::ElementsAre;
|
||||
using testing::IsEmpty;
|
||||
|
||||
// Matches a TuplePattern::Field named `name` whose `pattern` is an
|
||||
// `AutoPattern`.
|
||||
MATCHER_P(AutoFieldNamed, name, "") {
|
||||
return arg.name == std::string(name) && isa<AutoPattern>(arg.pattern);
|
||||
}
|
||||
|
||||
TEST(PatternTest, EmptyAsPattern) {
|
||||
ParenContents<Pattern> contents = {.elements = {},
|
||||
.has_trailing_comma = false};
|
||||
const Pattern* pattern = PatternFromParenContents(/*line_num=*/1, contents);
|
||||
EXPECT_EQ(pattern->LineNumber(), 1);
|
||||
ASSERT_TRUE(isa<TuplePattern>(pattern));
|
||||
EXPECT_THAT(cast<TuplePattern>(pattern)->Fields(), IsEmpty());
|
||||
}
|
||||
|
||||
TEST(PatternTest, EmptyAsTuplePattern) {
|
||||
ParenContents<Pattern> contents = {.elements = {},
|
||||
.has_trailing_comma = false};
|
||||
const TuplePattern* tuple =
|
||||
TuplePatternFromParenContents(/*line_num=*/1, contents);
|
||||
EXPECT_EQ(tuple->LineNumber(), 1);
|
||||
EXPECT_THAT(tuple->Fields(), IsEmpty());
|
||||
}
|
||||
|
||||
TEST(PatternTest, UnaryNoCommaAsPattern) {
|
||||
// Equivalent to a code fragment like
|
||||
// ```
|
||||
// (
|
||||
// auto
|
||||
// )
|
||||
// ```
|
||||
ParenContents<Pattern> contents = {
|
||||
.elements = {{.name = std::nullopt,
|
||||
.term = new AutoPattern(/*line_num=*/2)}},
|
||||
.has_trailing_comma = false};
|
||||
|
||||
const Pattern* pattern = PatternFromParenContents(/*line_num=*/1, contents);
|
||||
EXPECT_EQ(pattern->LineNumber(), 2);
|
||||
ASSERT_TRUE(isa<AutoPattern>(pattern));
|
||||
}
|
||||
|
||||
TEST(PatternTest, UnaryNoCommaAsTuplePattern) {
|
||||
ParenContents<Pattern> contents = {
|
||||
.elements = {{.name = std::nullopt,
|
||||
.term = new AutoPattern(/*line_num=*/2)}},
|
||||
.has_trailing_comma = false};
|
||||
|
||||
const TuplePattern* tuple =
|
||||
TuplePatternFromParenContents(/*line_num=*/1, contents);
|
||||
EXPECT_EQ(tuple->LineNumber(), 1);
|
||||
EXPECT_THAT(tuple->Fields(), ElementsAre(AutoFieldNamed("0")));
|
||||
}
|
||||
|
||||
TEST(PatternTest, UnaryWithCommaAsPattern) {
|
||||
ParenContents<Pattern> contents = {
|
||||
.elements = {{.name = std::nullopt,
|
||||
.term = new AutoPattern(/*line_num=*/2)}},
|
||||
.has_trailing_comma = true};
|
||||
|
||||
const Pattern* pattern = PatternFromParenContents(/*line_num=*/1, contents);
|
||||
EXPECT_EQ(pattern->LineNumber(), 1);
|
||||
ASSERT_TRUE(isa<TuplePattern>(pattern));
|
||||
EXPECT_THAT(cast<TuplePattern>(pattern)->Fields(),
|
||||
ElementsAre(AutoFieldNamed("0")));
|
||||
}
|
||||
|
||||
TEST(PatternTest, UnaryWithCommaAsTuplePattern) {
|
||||
ParenContents<Pattern> contents = {
|
||||
.elements = {{.name = std::nullopt,
|
||||
.term = new AutoPattern(/*line_num=*/2)}},
|
||||
.has_trailing_comma = true};
|
||||
|
||||
const TuplePattern* tuple =
|
||||
TuplePatternFromParenContents(/*line_num=*/1, contents);
|
||||
EXPECT_EQ(tuple->LineNumber(), 1);
|
||||
EXPECT_THAT(tuple->Fields(), ElementsAre(AutoFieldNamed("0")));
|
||||
}
|
||||
|
||||
TEST(PatternTest, BinaryAsPattern) {
|
||||
ParenContents<Pattern> contents = {
|
||||
.elements = {{.name = std::nullopt,
|
||||
.term = new AutoPattern(/*line_num=*/2)},
|
||||
{.name = std::nullopt,
|
||||
.term = new AutoPattern(/*line_num=*/3)}},
|
||||
.has_trailing_comma = true};
|
||||
|
||||
const Pattern* pattern = PatternFromParenContents(/*line_num=*/1, contents);
|
||||
EXPECT_EQ(pattern->LineNumber(), 1);
|
||||
ASSERT_TRUE(isa<TuplePattern>(pattern));
|
||||
EXPECT_THAT(cast<TuplePattern>(pattern)->Fields(),
|
||||
ElementsAre(AutoFieldNamed("0"), AutoFieldNamed("1")));
|
||||
}
|
||||
|
||||
TEST(PatternTest, BinaryAsTuplePattern) {
|
||||
ParenContents<Pattern> contents = {
|
||||
.elements = {{.name = std::nullopt,
|
||||
.term = new AutoPattern(/*line_num=*/2)},
|
||||
{.name = std::nullopt,
|
||||
.term = new AutoPattern(/*line_num=*/3)}},
|
||||
.has_trailing_comma = true};
|
||||
|
||||
const TuplePattern* tuple =
|
||||
TuplePatternFromParenContents(/*line_num=*/1, contents);
|
||||
EXPECT_EQ(tuple->LineNumber(), 1);
|
||||
EXPECT_THAT(tuple->Fields(),
|
||||
ElementsAre(AutoFieldNamed("0"), AutoFieldNamed("1")));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Carbon
|
||||
@@ -76,7 +76,7 @@ auto Statement::MakeAssign(int line_num, const Expression* lhs,
|
||||
return s;
|
||||
}
|
||||
|
||||
auto Statement::MakeVariableDefinition(int line_num, const Expression* pat,
|
||||
auto Statement::MakeVariableDefinition(int line_num, const Pattern* pat,
|
||||
const Expression* init)
|
||||
-> const Statement* {
|
||||
auto* s = new Statement();
|
||||
@@ -142,7 +142,7 @@ auto Statement::MakeBlock(int line_num, const Statement* stmt)
|
||||
|
||||
auto Statement::MakeMatch(
|
||||
int line_num, const Expression* exp,
|
||||
std::list<std::pair<const Expression*, const Statement*>>* clauses)
|
||||
std::list<std::pair<const Pattern*, const Statement*>>* clauses)
|
||||
-> const Statement* {
|
||||
auto* s = new Statement();
|
||||
s->line_num = line_num;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/ast/expression.h"
|
||||
#include "executable_semantics/ast/pattern.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace Carbon {
|
||||
@@ -45,7 +46,7 @@ struct Assign {
|
||||
|
||||
struct VariableDefinition {
|
||||
static constexpr StatementKind Kind = StatementKind::VariableDefinition;
|
||||
const Expression* pat;
|
||||
const Pattern* pat;
|
||||
const Expression* init;
|
||||
};
|
||||
|
||||
@@ -89,7 +90,7 @@ struct Continue {
|
||||
struct Match {
|
||||
static constexpr StatementKind Kind = StatementKind::Match;
|
||||
const Expression* exp;
|
||||
std::list<std::pair<const Expression*, const Statement*>>* clauses;
|
||||
std::list<std::pair<const Pattern*, const Statement*>>* clauses;
|
||||
};
|
||||
|
||||
struct Continuation {
|
||||
@@ -113,7 +114,7 @@ struct Statement {
|
||||
-> const Statement*;
|
||||
static auto MakeAssign(int line_num, const Expression* lhs,
|
||||
const Expression* rhs) -> const Statement*;
|
||||
static auto MakeVariableDefinition(int line_num, const Expression* pat,
|
||||
static auto MakeVariableDefinition(int line_num, const Pattern* pat,
|
||||
const Expression* init)
|
||||
-> const Statement*;
|
||||
static auto MakeIf(int line_num, const Expression* cond,
|
||||
@@ -129,7 +130,7 @@ struct Statement {
|
||||
static auto MakeContinue(int line_num) -> const Statement*;
|
||||
static auto MakeMatch(
|
||||
int line_num, const Expression* exp,
|
||||
std::list<std::pair<const Expression*, const Statement*>>* clauses)
|
||||
std::list<std::pair<const Pattern*, const Statement*>>* clauses)
|
||||
-> const Statement*;
|
||||
// Returns an AST node for a continuation statement give its line number and
|
||||
// contituent parts.
|
||||
|
||||
Reference in New Issue
Block a user