mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-03 16:26:05 +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
@@ -42,23 +42,7 @@ cc_library(
|
||||
|
||||
cc_library(
|
||||
name = "paren_contents",
|
||||
srcs = ["paren_contents.cpp"],
|
||||
hdrs = ["paren_contents.h"],
|
||||
deps = ["//executable_semantics/ast:expression"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "paren_contents_test",
|
||||
srcs = ["paren_contents_test.cpp"],
|
||||
env = {
|
||||
# TODO(#580): Remove this when leaks are fixed.
|
||||
"ASAN_OPTIONS": "detect_leaks=0",
|
||||
},
|
||||
deps = [
|
||||
":paren_contents",
|
||||
"@llvm-project//llvm:gtest",
|
||||
"@llvm-project//llvm:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
genrule(
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "executable_semantics/syntax/paren_contents.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
const Expression* ParenContents::AsExpression(int line_number) const {
|
||||
if (fields_.size() == 1 && fields_.front().name == "" &&
|
||||
has_trailing_comma_ == HasTrailingComma::No) {
|
||||
return new Expression(*fields_.front().expression);
|
||||
} else {
|
||||
return AsTuple(line_number);
|
||||
}
|
||||
}
|
||||
|
||||
const Expression* ParenContents::AsTuple(int line_number) const {
|
||||
return Expression::MakeTupleLiteral(line_number, fields_);
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
@@ -5,47 +5,82 @@
|
||||
#ifndef EXECUTABLE_SEMANTICS_SYNTAX_PAREN_CONTENTS_H_
|
||||
#define EXECUTABLE_SEMANTICS_SYNTAX_PAREN_CONTENTS_H_
|
||||
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "executable_semantics/ast/expression.h"
|
||||
#include "executable_semantics/common/error.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
// Represents the syntactic contents of an expression delimited by
|
||||
// parentheses. Such expressions can be interpreted as either tuples or
|
||||
// arbitrary expressions, depending on their context and the syntax of their
|
||||
// Represents the syntactic contents of an expression or pattern delimited by
|
||||
// parentheses. In those syntaxes, parentheses can be used either for grouping
|
||||
// or for forming a tuple, depending on their context and the syntax of their
|
||||
// contents; this class helps calling code resolve that ambiguity. Since that
|
||||
// ambiguity is purely syntactic, this class should only be needed during
|
||||
// parsing.
|
||||
class ParenContents {
|
||||
public:
|
||||
// Indicates whether the paren expression's contents end with a comma.
|
||||
enum class HasTrailingComma { Yes, No };
|
||||
//
|
||||
// `Term` is the type of the syntactic grouping being built, and the type of
|
||||
// the individual syntactic units it's built from; typically it should be
|
||||
// either `Expression` or `Pattern`.
|
||||
template <typename Term>
|
||||
struct ParenContents {
|
||||
struct Element {
|
||||
std::optional<std::string> name;
|
||||
const Term* term;
|
||||
};
|
||||
|
||||
// Constructs a ParenContents representing the contents of "()".
|
||||
ParenContents() : fields_({}), has_trailing_comma_(HasTrailingComma::No) {}
|
||||
// If this object represents a single term, with no name and no trailing
|
||||
// comma, this method returns that term. This typically means the parentheses
|
||||
// can be interpreted as grouping.
|
||||
auto SingleTerm() const -> std::optional<const Term*>;
|
||||
|
||||
// Constructs a ParenContents representing the given list of fields,
|
||||
// with or without a trailing comma.
|
||||
ParenContents(std::vector<FieldInitializer> fields,
|
||||
HasTrailingComma has_trailing_comma)
|
||||
: fields_(fields), has_trailing_comma_(has_trailing_comma) {}
|
||||
// Converts `elements` to std::vector<TupleElement>. TupleElement must
|
||||
// have a constructor that takes a std::string and a const Term*.
|
||||
//
|
||||
// TODO: Find a way to deduce TupleElement from Term.
|
||||
template <typename TupleElement>
|
||||
auto TupleElements(int line_num) const -> std::vector<TupleElement>;
|
||||
|
||||
ParenContents(const ParenContents&) = default;
|
||||
ParenContents& operator=(const ParenContents&) = default;
|
||||
|
||||
// Returns the paren expression, interpreted as a tuple.
|
||||
const Expression* AsTuple(int line_number) const;
|
||||
|
||||
// Returns the paren expression, with no external constraints on what kind
|
||||
// of expression it represents.
|
||||
const Expression* AsExpression(int line_number) const;
|
||||
|
||||
private:
|
||||
std::vector<FieldInitializer> fields_;
|
||||
HasTrailingComma has_trailing_comma_;
|
||||
std::vector<Element> elements;
|
||||
bool has_trailing_comma;
|
||||
};
|
||||
|
||||
// Implementation details only below here.
|
||||
|
||||
template <typename Term>
|
||||
auto ParenContents<Term>::SingleTerm() const -> std::optional<const Term*> {
|
||||
if (elements.size() == 1 && !elements.front().name.has_value() &&
|
||||
!has_trailing_comma) {
|
||||
return elements.front().term;
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Term>
|
||||
template <typename TupleElement>
|
||||
auto ParenContents<Term>::TupleElements(int line_num) const
|
||||
-> std::vector<TupleElement> {
|
||||
std::vector<TupleElement> result;
|
||||
int i = 0;
|
||||
bool seen_named_member = false;
|
||||
for (auto element : elements) {
|
||||
if (element.name.has_value()) {
|
||||
seen_named_member = true;
|
||||
result.push_back(TupleElement(*element.name, element.term));
|
||||
} else {
|
||||
if (seen_named_member) {
|
||||
FATAL_USER_ERROR(line_num)
|
||||
<< "positional members must come before named members";
|
||||
}
|
||||
result.push_back(TupleElement(std::to_string(i), element.term));
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
#endif // EXECUTABLE_SEMANTICS_SYNTAX_PAREN_CONTENTS_H_
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "executable_semantics/syntax/paren_contents.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace {
|
||||
|
||||
TEST(ParenContentsTest, EmptyAsExpression) {
|
||||
ParenContents contents;
|
||||
const Expression* expression = contents.AsExpression(/*line_num=*/1);
|
||||
EXPECT_EQ(expression->line_num, 1);
|
||||
ASSERT_EQ(expression->tag(), ExpressionKind::TupleLiteral);
|
||||
EXPECT_EQ(expression->GetTupleLiteral().fields.size(), 0);
|
||||
}
|
||||
|
||||
TEST(ParenContentsTest, EmptyAsTuple) {
|
||||
ParenContents contents;
|
||||
const Expression* tuple = contents.AsTuple(/*line_num=*/1);
|
||||
EXPECT_EQ(tuple->line_num, 1);
|
||||
ASSERT_EQ(tuple->tag(), ExpressionKind::TupleLiteral);
|
||||
EXPECT_EQ(tuple->GetTupleLiteral().fields.size(), 0);
|
||||
}
|
||||
|
||||
TEST(ParenContentsTest, UnaryNoCommaAsExpression) {
|
||||
// Equivalent to a code fragment like
|
||||
// ```
|
||||
// (
|
||||
// 42
|
||||
// )
|
||||
// ```
|
||||
ParenContents contents(
|
||||
{{.expression = Expression::MakeIntLiteral(/*line_num=*/2, 42)}},
|
||||
ParenContents::HasTrailingComma::No);
|
||||
|
||||
const Expression* expression = contents.AsExpression(/*line_num=*/1);
|
||||
EXPECT_EQ(expression->line_num, 2);
|
||||
ASSERT_EQ(expression->tag(), ExpressionKind::IntLiteral);
|
||||
}
|
||||
|
||||
TEST(ParenContentsTest, UnaryNoCommaAsTuple) {
|
||||
ParenContents contents(
|
||||
{{.expression = Expression::MakeIntLiteral(/*line_num=*/2, 42)}},
|
||||
ParenContents::HasTrailingComma::No);
|
||||
|
||||
const Expression* tuple = contents.AsTuple(/*line_num=*/1);
|
||||
EXPECT_EQ(tuple->line_num, 1);
|
||||
ASSERT_EQ(tuple->tag(), ExpressionKind::TupleLiteral);
|
||||
std::vector<FieldInitializer> fields = tuple->GetTupleLiteral().fields;
|
||||
ASSERT_EQ(fields.size(), 1);
|
||||
EXPECT_EQ(fields[0].expression->tag(), ExpressionKind::IntLiteral);
|
||||
}
|
||||
|
||||
TEST(ParenContentsTest, UnaryWithCommaAsExpression) {
|
||||
ParenContents contents(
|
||||
{{.expression = Expression::MakeIntLiteral(/*line_num=*/2, 42)}},
|
||||
ParenContents::HasTrailingComma::Yes);
|
||||
|
||||
const Expression* expression = contents.AsExpression(/*line_num=*/1);
|
||||
EXPECT_EQ(expression->line_num, 1);
|
||||
ASSERT_EQ(expression->tag(), ExpressionKind::TupleLiteral);
|
||||
std::vector<FieldInitializer> fields = expression->GetTupleLiteral().fields;
|
||||
ASSERT_EQ(fields.size(), 1);
|
||||
EXPECT_EQ(fields[0].expression->tag(), ExpressionKind::IntLiteral);
|
||||
}
|
||||
|
||||
TEST(ParenContentsTest, UnaryWithCommaAsTuple) {
|
||||
ParenContents contents(
|
||||
{{.expression = Expression::MakeIntLiteral(/*line_num=*/2, 42)}},
|
||||
ParenContents::HasTrailingComma::Yes);
|
||||
|
||||
const Expression* tuple = contents.AsTuple(/*line_num=*/1);
|
||||
EXPECT_EQ(tuple->line_num, 1);
|
||||
ASSERT_EQ(tuple->tag(), ExpressionKind::TupleLiteral);
|
||||
std::vector<FieldInitializer> fields = tuple->GetTupleLiteral().fields;
|
||||
ASSERT_EQ(fields.size(), 1);
|
||||
EXPECT_EQ(fields[0].expression->tag(), ExpressionKind::IntLiteral);
|
||||
}
|
||||
|
||||
TEST(ParenContentsTest, BinaryAsExpression) {
|
||||
ParenContents contents(
|
||||
{{.expression = Expression::MakeIntLiteral(/*line_num=*/2, 42)},
|
||||
{.expression = Expression::MakeIntLiteral(/*line_num=*/3, 42)}},
|
||||
ParenContents::HasTrailingComma::Yes);
|
||||
|
||||
const Expression* expression = contents.AsExpression(/*line_num=*/1);
|
||||
EXPECT_EQ(expression->line_num, 1);
|
||||
ASSERT_EQ(expression->tag(), ExpressionKind::TupleLiteral);
|
||||
std::vector<FieldInitializer> fields = expression->GetTupleLiteral().fields;
|
||||
ASSERT_EQ(fields.size(), 2);
|
||||
EXPECT_EQ(fields[0].expression->tag(), ExpressionKind::IntLiteral);
|
||||
EXPECT_EQ(fields[1].expression->tag(), ExpressionKind::IntLiteral);
|
||||
}
|
||||
|
||||
TEST(ParenContentsTest, BinaryAsTuple) {
|
||||
ParenContents contents(
|
||||
{{.expression = Expression::MakeIntLiteral(/*line_num=*/2, 42)},
|
||||
{.expression = Expression::MakeIntLiteral(/*line_num=*/3, 42)}},
|
||||
ParenContents::HasTrailingComma::Yes);
|
||||
|
||||
const Expression* tuple = contents.AsTuple(/*line_num=*/1);
|
||||
EXPECT_EQ(tuple->line_num, 1);
|
||||
ASSERT_EQ(tuple->tag(), ExpressionKind::TupleLiteral);
|
||||
std::vector<FieldInitializer> fields = tuple->GetTupleLiteral().fields;
|
||||
ASSERT_EQ(fields.size(), 2);
|
||||
EXPECT_EQ(fields[0].expression->tag(), ExpressionKind::IntLiteral);
|
||||
EXPECT_EQ(fields[1].expression->tag(), ExpressionKind::IntLiteral);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Carbon
|
||||
@@ -49,6 +49,7 @@
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "executable_semantics/syntax/syntax_helpers.h"
|
||||
#include "executable_semantics/syntax/parse_and_lex_context.h"
|
||||
@@ -59,7 +60,9 @@
|
||||
|
||||
#include "executable_semantics/ast/abstract_syntax_tree.h"
|
||||
#include "executable_semantics/ast/declaration.h"
|
||||
#include "executable_semantics/ast/expression.h"
|
||||
#include "executable_semantics/ast/function_definition.h"
|
||||
#include "executable_semantics/ast/pattern.h"
|
||||
#include "executable_semantics/syntax/paren_contents.h"
|
||||
|
||||
namespace Carbon {
|
||||
@@ -94,21 +97,28 @@ void yy::parser::error(const location_type&, const std::string& message) {
|
||||
%type <Carbon::GenericBinding> generic_binding
|
||||
%type <std::vector<Carbon::GenericBinding>> deduced_params
|
||||
%type <std::vector<Carbon::GenericBinding>> deduced_param_list
|
||||
%type <const Carbon::Expression*> pattern
|
||||
%type <const Carbon::Pattern*> pattern
|
||||
%type <const Carbon::Pattern*> non_expression_pattern
|
||||
%type <const Carbon::Expression*> return_type
|
||||
%type <const Carbon::Expression*> paren_expression
|
||||
%type <const Carbon::Expression*> tuple
|
||||
%type <std::optional<std::string>> binding_lhs
|
||||
%type <Carbon::Member*> variable_declaration
|
||||
%type <const Carbon::BindingPattern*> variable_declaration
|
||||
%type <Carbon::Member*> member
|
||||
%type <std::list<Carbon::Member*>> member_list
|
||||
%type <Carbon::FieldInitializer> field_initializer
|
||||
%type <Carbon::ParenContents> paren_contents
|
||||
%type <std::vector<Carbon::FieldInitializer>> paren_contents_without_trailing_comma
|
||||
%type <Carbon::ParenContents<Carbon::Expression>::Element> paren_expression_element
|
||||
%type <Carbon::ParenContents<Carbon::Expression>> paren_expression_base
|
||||
%type <Carbon::ParenContents<Carbon::Expression>> paren_expression_contents
|
||||
%type <const Carbon::Pattern*> paren_pattern
|
||||
%type <const Carbon::TuplePattern*> tuple_pattern
|
||||
%type <const Carbon::TuplePattern*> maybe_empty_tuple_pattern
|
||||
%type <Carbon::ParenContents<Carbon::Pattern>> paren_pattern_base
|
||||
%type <Carbon::ParenContents<Carbon::Pattern>::Element> paren_pattern_element
|
||||
%type <Carbon::ParenContents<Carbon::Pattern>> paren_pattern_contents
|
||||
%type <std::pair<std::string, const Carbon::Expression*>> alternative
|
||||
%type <std::list<std::pair<std::string, const Carbon::Expression*>>> alternative_list
|
||||
%type <std::pair<const Carbon::Expression*, const Carbon::Statement*>*> clause
|
||||
%type <std::list<std::pair<const Carbon::Expression*, const Carbon::Statement*>>*> clause_list
|
||||
%type <std::pair<const Carbon::Pattern*, const Carbon::Statement*>*> clause
|
||||
%type <std::list<std::pair<const Carbon::Pattern*, const Carbon::Statement*>>*> clause_list
|
||||
%token END_OF_FILE 0
|
||||
%token AND
|
||||
%token OR
|
||||
@@ -192,14 +202,6 @@ void yy::parser::error(const location_type&, const std::string& message) {
|
||||
input: declaration_list
|
||||
{ parsed_program = $1; }
|
||||
;
|
||||
pattern:
|
||||
expression
|
||||
{ $$ = $1; }
|
||||
;
|
||||
binding_lhs:
|
||||
identifier { $$ = $1; }
|
||||
| UNDERSCORE { $$ = std::nullopt; }
|
||||
;
|
||||
expression:
|
||||
identifier
|
||||
{ $$ = Carbon::Expression::MakeIdentifierExpression(yylineno, $1); }
|
||||
@@ -207,10 +209,6 @@ expression:
|
||||
{ $$ = Carbon::Expression::MakeFieldAccessExpression(yylineno, $1, $2); }
|
||||
| expression "[" expression "]"
|
||||
{ $$ = Carbon::Expression::MakeIndexExpression(yylineno, $1, $3); }
|
||||
| binding_lhs ":" expression
|
||||
{
|
||||
$$ = Carbon::Expression::MakeBindingExpression(yylineno, $1, $3);
|
||||
}
|
||||
| integer_literal
|
||||
{ $$ = Carbon::Expression::MakeIntLiteral(yylineno, $1); }
|
||||
| TRUE
|
||||
@@ -223,8 +221,6 @@ expression:
|
||||
{ $$ = Carbon::Expression::MakeBoolTypeLiteral(yylineno); }
|
||||
| TYPE
|
||||
{ $$ = Carbon::Expression::MakeTypeTypeLiteral(yylineno); }
|
||||
| AUTO
|
||||
{ $$ = Carbon::Expression::MakeAutoTypeLiteral(yylineno); }
|
||||
| CONTINUATION_TYPE
|
||||
{ $$ = Carbon::Expression::MakeContinuationTypeLiteral(yylineno); }
|
||||
| paren_expression { $$ = $1; }
|
||||
@@ -271,55 +267,133 @@ expression:
|
||||
;
|
||||
designator: "." identifier { $$ = $2; }
|
||||
;
|
||||
paren_expression: "(" paren_contents ")"
|
||||
{ $$ = $2.AsExpression(yylineno); }
|
||||
paren_expression: paren_expression_base
|
||||
{ $$ = Carbon::ExpressionFromParenContents(yylineno, $1); }
|
||||
;
|
||||
tuple: "(" paren_contents ")"
|
||||
{ $$ = $2.AsTuple(yylineno); }
|
||||
tuple: paren_expression_base
|
||||
{ $$ = Carbon::TupleExpressionFromParenContents(yylineno, $1); }
|
||||
;
|
||||
field_initializer:
|
||||
pattern
|
||||
{ $$ = Carbon::FieldInitializer({"", $1}); }
|
||||
| designator "=" pattern
|
||||
{ $$ = Carbon::FieldInitializer({$1, $3}); }
|
||||
paren_expression_element:
|
||||
expression
|
||||
{ $$ = {.name = std::nullopt, .term = $1}; }
|
||||
| designator "=" expression
|
||||
{ $$ = {.name = $1, .term = $3}; }
|
||||
;
|
||||
paren_contents:
|
||||
// Empty
|
||||
{ $$ = Carbon::ParenContents(); }
|
||||
| paren_contents_without_trailing_comma
|
||||
paren_expression_base:
|
||||
"(" ")"
|
||||
{ $$ = {.elements = {}, .has_trailing_comma = false}; }
|
||||
| "(" paren_expression_contents ")"
|
||||
{ $$ = $2; }
|
||||
| "(" paren_expression_contents "," ")"
|
||||
{
|
||||
$$ = Carbon::ParenContents($1,
|
||||
Carbon::ParenContents::HasTrailingComma::No);
|
||||
}
|
||||
| paren_contents_without_trailing_comma ","
|
||||
{
|
||||
$$ = Carbon::ParenContents($1,
|
||||
Carbon::ParenContents::HasTrailingComma::Yes);
|
||||
$$ = $2;
|
||||
$$.has_trailing_comma = true;
|
||||
}
|
||||
;
|
||||
paren_contents_without_trailing_comma:
|
||||
field_initializer
|
||||
{ $$ = {$1}; }
|
||||
| paren_contents_without_trailing_comma "," field_initializer
|
||||
paren_expression_contents:
|
||||
paren_expression_element
|
||||
{ $$ = {.elements = {$1}, .has_trailing_comma = false}; }
|
||||
| paren_expression_contents "," paren_expression_element
|
||||
{
|
||||
$$ = $1;
|
||||
$$.push_back($3);
|
||||
$$.elements.push_back($3);
|
||||
}
|
||||
;
|
||||
|
||||
// In many cases, using `pattern` recursively will result in ambiguities.
|
||||
// When that happens, it's necessary to factor out two separate productions,
|
||||
// one for when the sub-pattern is an expression, and one for when it is not.
|
||||
// To facilitate this, non-terminals besides `pattern` whose names contain
|
||||
// `pattern` are structured to be disjoint from `expression`, unless otherwise
|
||||
// specified.
|
||||
pattern:
|
||||
non_expression_pattern
|
||||
{ $$ = $1; }
|
||||
| expression
|
||||
{ $$ = new Carbon::ExpressionPattern($1); }
|
||||
;
|
||||
non_expression_pattern:
|
||||
AUTO
|
||||
{ $$ = new Carbon::AutoPattern(yylineno); }
|
||||
| binding_lhs ":" pattern
|
||||
{ $$ = new Carbon::BindingPattern(yylineno, $1, $3); }
|
||||
| paren_pattern
|
||||
{ $$ = $1; }
|
||||
| expression tuple_pattern
|
||||
{ $$ = new Carbon::AlternativePattern(yylineno, $1, $2); }
|
||||
;
|
||||
binding_lhs:
|
||||
identifier { $$ = $1; }
|
||||
| UNDERSCORE { $$ = std::nullopt; }
|
||||
;
|
||||
paren_pattern: paren_pattern_base
|
||||
{ $$ = Carbon::PatternFromParenContents(yylineno, $1); }
|
||||
;
|
||||
paren_pattern_base:
|
||||
"(" paren_pattern_contents ")"
|
||||
{ $$ = $2; }
|
||||
| "(" paren_pattern_contents "," ")"
|
||||
{
|
||||
$$ = $2;
|
||||
$$.has_trailing_comma = true;
|
||||
}
|
||||
;
|
||||
// paren_pattern is analogous to paren_expression, but in order to avoid
|
||||
// ambiguities, it must be disjoint from paren_expression, meaning it must
|
||||
// contain at least one non_expression_pattern. The structure of this rule
|
||||
// is very different from the corresponding expression rule because is has to
|
||||
// enforce that requirement.
|
||||
paren_pattern_contents:
|
||||
paren_pattern_element
|
||||
{ $$ = {.elements = {$1}, .has_trailing_comma = false }; }
|
||||
| paren_expression_contents "," paren_pattern_element
|
||||
{
|
||||
$$ = Carbon::ParenExpressionToParenPattern($1);
|
||||
$$.elements.push_back($3);
|
||||
}
|
||||
| paren_pattern_contents "," paren_expression_element
|
||||
{
|
||||
$$ = $1;
|
||||
$$.elements.push_back({.name = $3.name, .term = new Carbon::ExpressionPattern($3.term)});
|
||||
}
|
||||
| paren_pattern_contents "," paren_pattern_element
|
||||
{
|
||||
$$ = $1;
|
||||
$$.elements.push_back($3);
|
||||
}
|
||||
;
|
||||
paren_pattern_element:
|
||||
non_expression_pattern
|
||||
{ $$ = {.name = std::nullopt, .term = $1}; }
|
||||
| designator "=" non_expression_pattern
|
||||
{ $$ = {.name = $1, .term = $3}; }
|
||||
;
|
||||
tuple_pattern: paren_pattern_base
|
||||
{ $$ = Carbon::TuplePatternFromParenContents(yylineno, $1); }
|
||||
;
|
||||
// Unlike most `pattern` nonterminals, this one overlaps with `expression`,
|
||||
// so it should be used only when prior context (such as an introducer)
|
||||
// rules out the possibility of an `expression` at this point.
|
||||
maybe_empty_tuple_pattern:
|
||||
"(" ")"
|
||||
{ $$ = new Carbon::TuplePattern(yylineno, {}); }
|
||||
| tuple_pattern
|
||||
{ $$ = $1; }
|
||||
;
|
||||
clause:
|
||||
CASE pattern DBLARROW statement
|
||||
{ $$ = new std::pair<const Carbon::Expression*, const Carbon::Statement*>($2, $4); }
|
||||
{ $$ = new std::pair<const Carbon::Pattern*, const Carbon::Statement*>($2, $4); }
|
||||
| DEFAULT DBLARROW statement
|
||||
{
|
||||
auto vp = Carbon::Expression::MakeBindingExpression(
|
||||
yylineno, "_", Carbon::Expression::MakeAutoTypeLiteral(yylineno));
|
||||
$$ = new std::pair<const Carbon::Expression*, const Carbon::Statement*>(vp, $3);
|
||||
auto vp = new Carbon::BindingPattern(
|
||||
yylineno, std::nullopt, new Carbon::AutoPattern(yylineno));
|
||||
$$ = new std::pair<const Carbon::Pattern*, const Carbon::Statement*>(vp, $3);
|
||||
}
|
||||
;
|
||||
clause_list:
|
||||
// Empty
|
||||
{
|
||||
$$ = new std::list<std::pair<const Carbon::Expression*, const Carbon::Statement*>>();
|
||||
$$ = new std::list<std::pair<const Carbon::Pattern*, const Carbon::Statement*>>();
|
||||
}
|
||||
| clause clause_list
|
||||
{ $$ = $2; $$->push_front(*$1); }
|
||||
@@ -407,25 +481,30 @@ deduced_params:
|
||||
{ $$ = $2; }
|
||||
;
|
||||
function_definition:
|
||||
FN identifier deduced_params tuple return_type block
|
||||
{ $$ = Carbon::FunctionDefinition(yylineno, $2, $3, $4, $5, $6); }
|
||||
| FN identifier deduced_params tuple DBLARROW expression ";"
|
||||
FN identifier deduced_params maybe_empty_tuple_pattern return_type block
|
||||
{
|
||||
$$ = Carbon::FunctionDefinition(
|
||||
yylineno, $2, $3, $4, new Carbon::ExpressionPattern($5), $6);
|
||||
}
|
||||
| FN identifier deduced_params maybe_empty_tuple_pattern DBLARROW expression ";"
|
||||
{
|
||||
$$ = Carbon::FunctionDefinition(
|
||||
yylineno, $2, $3, $4,
|
||||
Carbon::Expression::MakeAutoTypeLiteral(yylineno),
|
||||
new Carbon::AutoPattern(yylineno),
|
||||
Carbon::Statement::MakeReturn(yylineno, $6));
|
||||
}
|
||||
;
|
||||
function_declaration:
|
||||
FN identifier deduced_params tuple return_type ";"
|
||||
{ $$ = Carbon::FunctionDefinition(yylineno, $2, $3, $4, $5, 0); }
|
||||
FN identifier deduced_params maybe_empty_tuple_pattern return_type ";"
|
||||
{
|
||||
$$ = Carbon::FunctionDefinition(
|
||||
yylineno, $2, $3, $4, new Carbon::ExpressionPattern($5), 0); }
|
||||
;
|
||||
variable_declaration: identifier ":" expression
|
||||
{ $$ = Carbon::Member::MakeFieldMember(yylineno, $1, $3); }
|
||||
variable_declaration: identifier ":" pattern
|
||||
{ $$ = new Carbon::BindingPattern(yylineno, $1, $3); }
|
||||
;
|
||||
member: VAR variable_declaration ";"
|
||||
{ $$ = $2; }
|
||||
{ $$ = Carbon::Member::MakeFieldMember(yylineno, $2); }
|
||||
;
|
||||
member_list:
|
||||
// Empty
|
||||
@@ -468,8 +547,7 @@ declaration:
|
||||
}
|
||||
| VAR variable_declaration "=" expression ";"
|
||||
{
|
||||
$$ = Carbon::Declaration::MakeVariableDeclaration(
|
||||
yylineno, $2->GetFieldMember().name, $2->GetFieldMember().type, $4);
|
||||
$$ = Carbon::Declaration::MakeVariableDeclaration(yylineno, $2, $4);
|
||||
}
|
||||
;
|
||||
declaration_list:
|
||||
|
||||
Reference in New Issue
Block a user