mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 19:01: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
@@ -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