Files
carbon-lang/executable_semantics/syntax/parser.ypp
T
7cce1bd124 interfaces, impls, and constrained generics (basics) (#1073)
* interfaces, impls, and constrained generics (basics)

* separate type checking into declare vs. type check, removing redundancy

* external impls

* added impl scopes to handle generics calling generics

* cleanup

* more cleanup

* Update executable_semantics/testdata/interface/external_impl_point_vector.carbon

Co-authored-by: josh11b <josh11b@users.noreply.github.com>

* Update executable_semantics/testdata/interface/generic_call_generic.carbon

Co-authored-by: josh11b <josh11b@users.noreply.github.com>

* Update executable_semantics/testdata/interface/tuple_vector_add_scale.carbon

Co-authored-by: josh11b <josh11b@users.noreply.github.com>

* Update executable_semantics/testdata/interface/vector_point_add_scale.carbon

Co-authored-by: josh11b <josh11b@users.noreply.github.com>

* change ImplementationDeclaration to ImplDeclaration

* remove impl_type_value

* split NamedEntity into two

* changed GetName to be a free function

* adding comments

* more edits to respond to review

* introduce ImplBinding, remove punning on GenericBinding

* new test case and some minor edits

* refactor GetMember and GetField to move impl logic to interpreter

* remove commennt

* change EntityView to ImplBinding in FieldAccess...

* move ImplBinding

* review response

* added example to impl_scope.h

* minor edits

* Update executable_semantics/interpreter/field_path.h

Co-authored-by: Geoff Romer <gromer@google.com>

* Update executable_semantics/interpreter/value.cpp

Co-authored-by: Geoff Romer <gromer@google.com>

* Update executable_semantics/interpreter/interpreter.cpp

Co-authored-by: Geoff Romer <gromer@google.com>

* Update executable_semantics/ast/expression.h

Co-authored-by: Geoff Romer <gromer@google.com>

* Update executable_semantics/ast/expression.h

Co-authored-by: Geoff Romer <gromer@google.com>

* Update executable_semantics/ast/generic_binding.h

Co-authored-by: Geoff Romer <gromer@google.com>

* more edits from review

* review response

* Update executable_semantics/ast/static_scope.h

Co-authored-by: Geoff Romer <gromer@google.com>

* remove ImplType, renamed node_view to value_node

Co-authored-by: josh11b <josh11b@users.noreply.github.com>
Co-authored-by: Geoff Romer <gromer@google.com>
2022-03-02 15:58:45 -05:00

775 lines
23 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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
// -----------------------------------------------------------------------------
// Bison Configuration
// -----------------------------------------------------------------------------
%require "3.2"
%language "c++"
// We don't need a separate header for Bison locations.
%define api.location.file none
// Use a type-safe C++ variant for semantic values
%define api.value.type variant
// Have Bison generate the functions ‘make_TEXT’ and ‘make_NUMBER’, but also
// ‘make_YYEOF’, for the end of input.
%define api.token.constructor
// Generate the parser as `::Carbon::Parser`.
%define api.namespace { Carbon }
%define api.parser.class { Parser }
// Make parse error messages more detailed
%define parse.error verbose
// Enable support for parser debugging
%define parse.trace true
// Generate location structs.
%locations
// Parameters to the parser and lexer.
//
// Parameters to the parser are stored therein as protected data members, and
// thus available to its methods.
// "inout" parameters passed to both the parser and the lexer.
%param {Nonnull<Arena*> arena}
%param {yyscan_t yyscanner}
%param {ParseAndLexContext& context}
// "out" parameter passed to the parser, where the AST is written.
%parse-param {std::optional<AST>* ast}
// No shift-reduce conflicts are expected.
%expect 0
// -----------------------------------------------------------------------------
%code top {
#include <algorithm>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include "common/check.h"
#include "executable_semantics/syntax/parse_and_lex_context.h"
#include "llvm/ADT/StringExtras.h"
} // %code top
%code requires {
#include <optional>
#include "executable_semantics/ast/ast.h"
#include "executable_semantics/ast/declaration.h"
#include "executable_semantics/ast/expression.h"
#include "executable_semantics/ast/paren_contents.h"
#include "executable_semantics/ast/pattern.h"
#include "executable_semantics/common/arena.h"
#include "executable_semantics/common/nonnull.h"
#include "executable_semantics/syntax/bison_wrap.h"
namespace Carbon {
class ParseAndLexContext;
} // namespace Carbon
typedef void* yyscan_t;
} // %code requires
%code {
void Carbon::Parser::error(const location_type&, const std::string& message) {
context.PrintDiagnostic(message);
}
} // %code
%token <int> integer_literal
%token <std::string> identifier
%token <std::string> intrinsic_identifier
%token <std::string> sized_type_literal
%token <std::string> string_literal
%type <std::string> designator
%type <ImplKind> impl_kind
%type <std::pair<LibraryName, bool>> package_directive
%type <LibraryName> import_directive
%type <std::vector<LibraryName>> import_directives
%type <std::string> optional_library_path
%type <bool> api_or_impl
%type <Nonnull<Declaration*>> declaration
%type <Nonnull<FunctionDeclaration*>> function_declaration
%type <std::vector<Nonnull<Declaration*>>> declaration_list
%type <Nonnull<Statement*>> statement
%type <Nonnull<If*>> if_statement
%type <std::optional<Nonnull<Block*>>> optional_else
%type <std::pair<Nonnull<Expression*>, bool>> return_expression
%type <Nonnull<Block*>> nonempty_block
%type <Nonnull<Block*>> block
%type <std::vector<Nonnull<Statement*>>> statement_list
%type <Nonnull<Expression*>> expression
%type <Nonnull<GenericBinding*>> generic_binding
%type <std::vector<Nonnull<AstNode*>>> deduced_params
%type <std::vector<Nonnull<AstNode*>>> deduced_param_list
%type <Nonnull<Pattern*>> pattern
%type <Nonnull<Pattern*>> non_expression_pattern
%type <BisonWrap<ReturnTerm>> return_term
%type <Nonnull<Expression*>> paren_expression
%type <Nonnull<StructLiteral*>> struct_literal
%type <std::vector<FieldInitializer>> struct_literal_contents
%type <Nonnull<StructTypeLiteral*>> struct_type_literal
%type <std::vector<FieldInitializer>> struct_type_literal_contents
%type <Nonnull<TupleLiteral*>> tuple
%type <std::string> binding_lhs
%type <std::optional<Nonnull<BindingPattern*>>> receiver
%type <Nonnull<BindingPattern*>> variable_declaration
%type <ParenContents<Expression>> paren_expression_base
%type <ParenContents<Expression>> paren_expression_contents
%type <Nonnull<Pattern*>> paren_pattern
%type <Nonnull<TuplePattern*>> tuple_pattern
%type <Nonnull<TuplePattern*>> maybe_empty_tuple_pattern
%type <ParenContents<Pattern>> paren_pattern_base
%type <ParenContents<Pattern>> paren_pattern_contents
%type <Nonnull<AlternativeSignature*>> alternative
%type <std::vector<Nonnull<AlternativeSignature*>>> alternative_list
%type <std::vector<Nonnull<AlternativeSignature*>>> alternative_list_contents
%type <BisonWrap<Match::Clause>> clause
%type <std::vector<Match::Clause>> clause_list
%token
// Most tokens have their spelling defined in lexer.lpp.
// table-begin
AMPERSAND
AND
API
ARROW
AS
AUTO
AWAIT
BOOL
BREAK
CASE
CHOICE
CLASS
COLON
COLON_BANG
COMMA
CONTINUATION
CONTINUATION_TYPE
CONTINUE
DEFAULT
DOUBLE_ARROW
ELSE
EQUAL
EQUAL_EQUAL
EXTERNAL
FALSE
FN
FN_TYPE
IF
IMPL
IMPORT
INTERFACE
LEFT_CURLY_BRACE
LEFT_PARENTHESIS
LEFT_SQUARE_BRACKET
LIBRARY
MATCH
MINUS
NOT
OR
PACKAGE
PERIOD
PLUS
RETURN
RIGHT_CURLY_BRACE
RIGHT_PARENTHESIS
RIGHT_SQUARE_BRACKET
RUN
SEMICOLON
SLASH
STRING
TRUE
TYPE
UNDERSCORE
UNIMPL_EXAMPLE
VAR
WHILE
// table-end
// Used to track EOF.
END_OF_FILE 0
// Only used for precedence.
FNARROW "-> in return type"
// The lexer determines the arity and fixity of each `*` based on whitespace
// and adjacent tokens. UNARY_STAR indicates that the operator is unary but
// could be either prefix or postfix.
UNARY_STAR "unary *"
PREFIX_STAR "prefix *"
POSTFIX_STAR "postfix *"
BINARY_STAR "binary *"
;
%precedence FNARROW
%precedence LEFT_CURLY_BRACE RIGHT_CURLY_BRACE
%precedence COLON_BANG COLON COMMA DOUBLE_ARROW
%left OR AND
%nonassoc EQUAL_EQUAL
%left PLUS MINUS
%left BINARY_STAR
%precedence NOT UNARY_MINUS PREFIX_STAR AMPERSAND
// We need to give the `UNARY_STAR` token a precedence, rather than overriding
// the precedence of the `expression UNARY_STAR` rule below, because bison
// compares the precedence of the final token (for a shift) to the precedence
// of the other rule (for a reduce) when attempting to resolve a shift-reduce
// conflict. See https://stackoverflow.com/a/26188429/1041090. When UNARY_STAR
// is the final token of a rule, it must be a postfix usage, so we give it the
// same precedence as POSTFIX_STAR.
%precedence POSTFIX_STAR UNARY_STAR
%left PERIOD ARROW
%nonassoc UNIMPL_EXAMPLE
%precedence
LEFT_PARENTHESIS
RIGHT_PARENTHESIS
LEFT_SQUARE_BRACKET
RIGHT_SQUARE_BRACKET
;
%start input
%%
input: package_directive import_directives declaration_list
{
*ast = AST({.package = $1.first,
.is_api = $1.second,
.imports = std::move($2),
.declarations = std::move($3)});
}
;
package_directive:
PACKAGE identifier optional_library_path api_or_impl SEMICOLON
{ $$ = {LibraryName({.package = $2, .path = $3}), $4}; }
;
import_directive:
IMPORT identifier optional_library_path SEMICOLON
{ $$ = LibraryName({.package = $2, .path = $3}); }
;
import_directives:
// Empty
{ $$ = std::vector<LibraryName>(); }
| import_directives import_directive
{
$$ = std::move($1);
$$.push_back($2);
}
;
optional_library_path:
// Empty
{ $$ = ""; }
| LIBRARY string_literal
{ $$ = $2; }
;
api_or_impl:
API
{ $$ = true; }
| IMPL
{ $$ = false; }
;
expression:
identifier
{ $$ = arena->New<IdentifierExpression>(context.source_loc(), $1); }
| expression designator
{ $$ = arena->New<FieldAccessExpression>(context.source_loc(), $1, $2); }
| expression LEFT_SQUARE_BRACKET expression RIGHT_SQUARE_BRACKET
{ $$ = arena->New<IndexExpression>(context.source_loc(), $1, $3); }
| integer_literal
{ $$ = arena->New<IntLiteral>(context.source_loc(), $1); }
| string_literal
{ $$ = arena->New<StringLiteral>(context.source_loc(), $1); }
| TRUE
{ $$ = arena->New<BoolLiteral>(context.source_loc(), true); }
| FALSE
{ $$ = arena->New<BoolLiteral>(context.source_loc(), 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;
$$ = arena->New<IntTypeLiteral>(context.source_loc());
}
| STRING
{ $$ = arena->New<StringTypeLiteral>(context.source_loc()); }
| BOOL
{ $$ = arena->New<BoolTypeLiteral>(context.source_loc()); }
| TYPE
{ $$ = arena->New<TypeTypeLiteral>(context.source_loc()); }
| CONTINUATION_TYPE
{ $$ = arena->New<ContinuationTypeLiteral>(context.source_loc()); }
| paren_expression { $$ = $1; }
| struct_literal { $$ = $1; }
| struct_type_literal { $$ = $1; }
| intrinsic_identifier tuple
{ $$ = arena->New<IntrinsicExpression>($1, $2, context.source_loc()); }
| expression EQUAL_EQUAL expression
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::Eq,
std::vector<Nonnull<Expression*>>({$1, $3}));
}
| expression PLUS expression
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::Add,
std::vector<Nonnull<Expression*>>({$1, $3}));
}
| expression MINUS expression
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::Sub,
std::vector<Nonnull<Expression*>>({$1, $3}));
}
| expression BINARY_STAR expression
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::Mul,
std::vector<Nonnull<Expression*>>({$1, $3}));
}
| expression AND expression
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::And,
std::vector<Nonnull<Expression*>>({$1, $3}));
}
| expression OR expression
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::Or,
std::vector<Nonnull<Expression*>>({$1, $3}));
}
| NOT expression
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::Not,
std::vector<Nonnull<Expression*>>({$2}));
}
| MINUS expression %prec UNARY_MINUS
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::Neg,
std::vector<Nonnull<Expression*>>({$2}));
}
| PREFIX_STAR expression
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::Deref,
std::vector<Nonnull<Expression*>>({$2}));
}
| UNARY_STAR expression %prec PREFIX_STAR
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::Deref,
std::vector<Nonnull<Expression*>>({$2}));
}
| AMPERSAND expression
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::AddressOf,
std::vector<Nonnull<Expression*>>({$2}));
}
| expression tuple
{ $$ = arena->New<CallExpression>(context.source_loc(), $1, $2); }
| expression POSTFIX_STAR
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::Ptr,
std::vector<Nonnull<Expression*>>({$1}));
}
| expression UNARY_STAR
{
$$ = arena->New<PrimitiveOperatorExpression>(
context.source_loc(), Operator::Ptr,
std::vector<Nonnull<Expression*>>({$1}));
}
| FN_TYPE tuple ARROW expression
{ $$ = arena->New<FunctionTypeLiteral>(context.source_loc(), $2, $4); }
| expression UNIMPL_EXAMPLE expression
{
$$ = arena->New<UnimplementedExpression>(context.source_loc(),
"ExampleInfix", $1, $3);
}
;
designator: PERIOD identifier { $$ = $2; }
;
paren_expression: paren_expression_base
{ $$ = ExpressionFromParenContents(arena, context.source_loc(), $1); }
;
tuple: paren_expression_base
{ $$ = TupleExpressionFromParenContents(arena, context.source_loc(), $1); }
;
paren_expression_base:
LEFT_PARENTHESIS RIGHT_PARENTHESIS
{ $$ = {.elements = {}, .has_trailing_comma = false}; }
| LEFT_PARENTHESIS paren_expression_contents RIGHT_PARENTHESIS
{ $$ = $2; }
| LEFT_PARENTHESIS paren_expression_contents COMMA RIGHT_PARENTHESIS
{
$$ = $2;
$$.has_trailing_comma = true;
}
;
paren_expression_contents:
expression
{ $$ = {.elements = {$1}, .has_trailing_comma = false}; }
| paren_expression_contents COMMA expression
{
$$ = $1;
$$.elements.push_back($3);
}
;
struct_literal:
LEFT_CURLY_BRACE struct_literal_contents RIGHT_CURLY_BRACE
{ $$ = arena->New<StructLiteral>(context.source_loc(), $2); }
| LEFT_CURLY_BRACE struct_literal_contents COMMA RIGHT_CURLY_BRACE
{ $$ = arena->New<StructLiteral>(context.source_loc(), $2); }
;
struct_literal_contents:
designator EQUAL expression
{ $$ = {FieldInitializer($1, $3)}; }
| struct_literal_contents COMMA designator EQUAL expression
{
$$ = $1;
$$.push_back(FieldInitializer($3, $5));
}
;
struct_type_literal:
LEFT_CURLY_BRACE RIGHT_CURLY_BRACE
{ $$ = arena->New<StructTypeLiteral>(context.source_loc()); }
| LEFT_CURLY_BRACE struct_type_literal_contents RIGHT_CURLY_BRACE
{ $$ = arena->New<StructTypeLiteral>(context.source_loc(), $2); }
| LEFT_CURLY_BRACE struct_type_literal_contents COMMA RIGHT_CURLY_BRACE
{ $$ = arena->New<StructTypeLiteral>(context.source_loc(), $2); }
;
struct_type_literal_contents:
designator COLON expression
{ $$ = {FieldInitializer($1, $3)}; }
| struct_type_literal_contents COMMA designator COLON expression
{
$$ = $1;
$$.push_back(FieldInitializer($3, $5));
}
;
// 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
{ $$ = arena->New<ExpressionPattern>($1); }
;
non_expression_pattern:
AUTO
{ $$ = arena->New<AutoPattern>(context.source_loc()); }
| binding_lhs COLON pattern
{ $$ = arena->New<BindingPattern>(context.source_loc(), $1, $3); }
| paren_pattern
{ $$ = $1; }
| expression tuple_pattern
{ $$ = arena->New<AlternativePattern>(context.source_loc(), $1, $2); }
;
binding_lhs:
identifier { $$ = $1; }
| UNDERSCORE { $$ = AnonymousName; }
;
paren_pattern: paren_pattern_base
{ $$ = PatternFromParenContents(arena, context.source_loc(), $1); }
;
paren_pattern_base:
LEFT_PARENTHESIS paren_pattern_contents RIGHT_PARENTHESIS
{ $$ = $2; }
| LEFT_PARENTHESIS paren_pattern_contents COMMA RIGHT_PARENTHESIS
{
$$ = $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:
non_expression_pattern
{ $$ = {.elements = {$1}, .has_trailing_comma = false}; }
| paren_expression_contents COMMA non_expression_pattern
{
$$ = ParenExpressionToParenPattern(arena, $1);
$$.elements.push_back($3);
}
| paren_pattern_contents COMMA expression
{
$$ = $1;
$$.elements.push_back(arena->New<ExpressionPattern>($3));
}
| paren_pattern_contents COMMA non_expression_pattern
{
$$ = $1;
$$.elements.push_back($3);
}
;
tuple_pattern: paren_pattern_base
{ $$ = TuplePatternFromParenContents(arena, context.source_loc(), $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:
LEFT_PARENTHESIS RIGHT_PARENTHESIS
{
$$ = arena->New<TuplePattern>(context.source_loc(),
std::vector<Nonnull<Pattern*>>());
}
| tuple_pattern
{ $$ = $1; }
;
clause:
CASE pattern DOUBLE_ARROW statement
{ $$ = Match::Clause($2, $4); }
| DEFAULT DOUBLE_ARROW statement
{
$$ = Match::Clause(arena->New<BindingPattern>(
context.source_loc(), std::string(AnonymousName),
arena->New<AutoPattern>(context.source_loc())),
$3);
}
;
clause_list:
// Empty
{ $$ = {}; }
| clause_list clause
{
$$ = $1;
$$.push_back($2);
}
;
statement:
expression EQUAL expression SEMICOLON
{ $$ = arena->New<Assign>(context.source_loc(), $1, $3); }
| VAR pattern EQUAL expression SEMICOLON
{ $$ = arena->New<VariableDefinition>(context.source_loc(), $2, $4); }
| expression SEMICOLON
{ $$ = arena->New<ExpressionStatement>(context.source_loc(), $1); }
| if_statement
{ $$ = $1; }
| WHILE LEFT_PARENTHESIS expression RIGHT_PARENTHESIS block
{ $$ = arena->New<While>(context.source_loc(), $3, $5); }
| BREAK SEMICOLON
{ $$ = arena->New<Break>(context.source_loc()); }
| CONTINUE SEMICOLON
{ $$ = arena->New<Continue>(context.source_loc()); }
| RETURN return_expression SEMICOLON
{
auto [return_exp, is_omitted_exp] = $2;
$$ = arena->New<Return>(context.source_loc(), return_exp, is_omitted_exp);
}
// We disallow empty blocks in places where an arbitrary statement can occur
// in order to avoid ambiguity with the empty struct literal `{}`. We can
// allow non-empty blocks because a non-empty struct literal always starts with
// a designator, and a block never does, so one token of lookahead suffices
// to disambiguate. As of this writing, the "official" resolution of this
// ambiguity is an open question (see
// https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/classes.md#literals)
| nonempty_block
{ $$ = $1; }
| MATCH LEFT_PARENTHESIS expression RIGHT_PARENTHESIS LEFT_CURLY_BRACE
clause_list RIGHT_CURLY_BRACE
{ $$ = arena->New<Match>(context.source_loc(), $3, $6); }
| CONTINUATION identifier block
{ $$ = arena->New<Continuation>(context.source_loc(), $2, $3); }
| RUN expression SEMICOLON
{ $$ = arena->New<Run>(context.source_loc(), $2); }
| AWAIT SEMICOLON
{ $$ = arena->New<Await>(context.source_loc()); }
;
if_statement:
IF LEFT_PARENTHESIS expression RIGHT_PARENTHESIS block optional_else
{ $$ = arena->New<If>(context.source_loc(), $3, $5, $6); }
;
optional_else:
// Empty
{ $$ = std::nullopt; }
| ELSE if_statement
{
$$ = arena->New<Block>(context.source_loc(),
std::vector<Nonnull<Statement*>>({$2}));
}
| ELSE block
{ $$ = $2; }
;
return_expression:
// Empty
{ $$ = {arena->New<TupleLiteral>(context.source_loc()), true}; }
| expression
{ $$ = {$1, false}; }
;
statement_list:
// Empty
{ $$ = {}; }
| statement_list statement
{
$$ = std::move($1);
$$.push_back($2);
}
;
block:
LEFT_CURLY_BRACE statement_list RIGHT_CURLY_BRACE
{ $$ = arena->New<Block>(context.source_loc(), std::move($2)); }
;
nonempty_block:
LEFT_CURLY_BRACE statement_list statement RIGHT_CURLY_BRACE
{
$2.push_back($3);
$$ = arena->New<Block>(context.source_loc(), std::move($2));
}
;
return_term:
// Empty
{ $$ = ReturnTerm::Omitted(context.source_loc()); }
| ARROW AUTO %prec FNARROW
{ $$ = ReturnTerm::Auto(context.source_loc()); }
| ARROW expression %prec FNARROW
{ $$ = ReturnTerm::Explicit($2); }
;
generic_binding:
identifier COLON_BANG expression
{
$$ = arena->New<GenericBinding>(context.source_loc(), std::move($1), $3);
}
;
deduced_param_list:
// Empty
{ $$ = std::vector<Nonnull<AstNode*>>(); }
| generic_binding
{
$$ = std::vector<Nonnull<AstNode*>>();
$$.push_back($1);
}
| generic_binding COMMA deduced_param_list
{
$$ = $3;
$$.push_back($1);
}
| variable_declaration
{
$$ = std::vector<Nonnull<AstNode*>>();
$$.push_back($1);
}
| variable_declaration COMMA deduced_param_list
{
$$ = $3;
$$.push_back($1);
}
;
deduced_params:
// Empty
{ $$ = std::vector<Nonnull<AstNode*>>(); }
| LEFT_SQUARE_BRACKET deduced_param_list RIGHT_SQUARE_BRACKET
{ $$ = $2; }
;
receiver:
// Empty
{ $$ = std::nullopt; }
| LEFT_CURLY_BRACE variable_declaration RIGHT_CURLY_BRACE
{ $$ = $2; }
;
function_declaration:
FN identifier deduced_params receiver maybe_empty_tuple_pattern return_term block
{
$$ = arena->New<FunctionDeclaration>(context.source_loc(), $2, $3, $4, $5,
$6, $7);
}
| FN identifier deduced_params receiver maybe_empty_tuple_pattern return_term SEMICOLON
{
$$ = arena->New<FunctionDeclaration>(context.source_loc(), $2, $3, $4, $5,
$6, std::nullopt);
}
;
variable_declaration: identifier COLON pattern
{ $$ = arena->New<BindingPattern>(context.source_loc(), $1, $3); }
;
alternative:
identifier tuple
{ $$ = arena->New<AlternativeSignature>(context.source_loc(), $1, $2); }
| identifier
{
$$ = arena->New<AlternativeSignature>(
context.source_loc(), $1,
arena->New<TupleLiteral>(context.source_loc()));
}
;
alternative_list:
// Empty
{ $$ = {}; }
| alternative_list_contents
{ $$ = $1; }
| alternative_list_contents COMMA
{ $$ = $1; }
;
alternative_list_contents:
alternative
{ $$ = {std::move($1)}; }
| alternative_list_contents COMMA alternative
{
$$ = $1;
$$.push_back(std::move($3));
}
;
declaration:
function_declaration
{ $$ = $1; }
| CLASS identifier LEFT_CURLY_BRACE declaration_list RIGHT_CURLY_BRACE
{ $$ = arena->New<ClassDeclaration>(context.source_loc(), $2, $4); }
| CHOICE identifier LEFT_CURLY_BRACE alternative_list RIGHT_CURLY_BRACE
{ $$ = arena->New<ChoiceDeclaration>(context.source_loc(), $2, $4); }
| VAR variable_declaration SEMICOLON
{
$$ = arena->New<VariableDeclaration>(context.source_loc(), $2,
std::nullopt);
}
| VAR variable_declaration EQUAL expression SEMICOLON
{ $$ = arena->New<VariableDeclaration>(context.source_loc(), $2, $4); }
| INTERFACE identifier LEFT_CURLY_BRACE declaration_list RIGHT_CURLY_BRACE
{
auto ty_ty = arena -> New<TypeTypeLiteral>(context.source_loc());
auto self =
arena -> New<GenericBinding>(context.source_loc(), "Self", ty_ty);
$$ = arena->New<InterfaceDeclaration>(context.source_loc(), $2, self, $4);
}
| impl_kind IMPL expression AS expression LEFT_CURLY_BRACE declaration_list RIGHT_CURLY_BRACE
{ $$ = arena->New<ImplDeclaration>(context.source_loc(), $1, $3, $5, $7); }
;
impl_kind:
// Internal
{ $$ = Carbon::ImplKind::InternalImpl; }
| EXTERNAL
{ $$ = Carbon::ImplKind::ExternalImpl; }
;
declaration_list:
// Empty
{ $$ = {}; }
| declaration_list declaration
{
$$ = $1;
$$.push_back(Nonnull<Declaration*>($2));
}
;
%%