mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
1659 lines
52 KiB
Plaintext
1659 lines
52 KiB
Plaintext
// 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.
|
||
// See README.md#precedence-and-associativity for a description of how
|
||
// operator precedence is expressed.
|
||
%expect 0
|
||
|
||
// -----------------------------------------------------------------------------
|
||
|
||
%code top {
|
||
#include <algorithm>
|
||
#include <cstdarg>
|
||
#include <cstdio>
|
||
#include <cstdlib>
|
||
#include <vector>
|
||
|
||
#include "explorer/syntax/parse_and_lex_context.h"
|
||
#include "llvm/ADT/StringExtras.h"
|
||
#include "llvm/Support/FormatVariadic.h"
|
||
#include "llvm/Support/raw_ostream.h"
|
||
} // %code top
|
||
|
||
%code requires {
|
||
#include <optional>
|
||
|
||
#include "explorer/ast/ast.h"
|
||
#include "explorer/ast/declaration.h"
|
||
#include "explorer/ast/expression.h"
|
||
#include "explorer/ast/expression_category.h"
|
||
#include "explorer/ast/paren_contents.h"
|
||
#include "explorer/ast/pattern.h"
|
||
#include "explorer/base/arena.h"
|
||
#include "explorer/base/nonnull.h"
|
||
#include "explorer/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.RecordSyntaxError(message);
|
||
}
|
||
} // %code
|
||
|
||
%token <int> integer_literal
|
||
%token <std::string> identifier
|
||
%token <IntrinsicExpression::Intrinsic> intrinsic_identifier
|
||
%token <std::string> sized_type_literal
|
||
%token <std::string> string_literal
|
||
%type <std::string> designator
|
||
%type <Nonnull<Expression*>> impl_type
|
||
%type <Nonnull<Expression*>> no_impl_type
|
||
%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 <VirtualOverride> fn_virtual_override_intro
|
||
%type <VirtualOverride> destructor_virtual_override_intro
|
||
%type <ClassExtensibility> class_declaration_extensibility
|
||
%type <Nonnull<Declaration*>> declaration
|
||
%type <Nonnull<Declaration*>> namespace_declaration
|
||
%type <BisonWrap<DeclaredName>> declared_name
|
||
%type <Nonnull<FunctionDeclaration*>> function_declaration
|
||
%type <Nonnull<DestructorDeclaration*>> destructor_declaration
|
||
%type <Nonnull<ExtendBaseDeclaration*>> extend_base_declaration
|
||
%type <Nonnull<MixDeclaration*>> mix_declaration
|
||
%type <Nonnull<AliasDeclaration*>> alias_declaration
|
||
%type <Nonnull<ImplDeclaration*>> impl_declaration
|
||
%type <Nonnull<ImplDeclaration*>> extend_impl_declaration
|
||
%type <Nonnull<MatchFirstDeclaration*>> match_first_declaration
|
||
%type <std::vector<Nonnull<ImplDeclaration*>>> match_first_declaration_list
|
||
%type <std::vector<Nonnull<Declaration*>>> top_level_declaration_list
|
||
%type <std::vector<Nonnull<Declaration*>>> class_body
|
||
%type <std::vector<Nonnull<Declaration*>>> mixin_body
|
||
%type <std::vector<Nonnull<Declaration*>>> interface_body
|
||
%type <std::vector<Nonnull<Declaration*>>> impl_body
|
||
%type <Nonnull<Statement*>> statement
|
||
%type <Nonnull<Statement*>> assign_statement
|
||
%type <AssignOperator> assign_operator
|
||
%type <Nonnull<If*>> if_statement
|
||
%type <std::optional<Nonnull<Block*>>> optional_else
|
||
%type <std::pair<Nonnull<Expression*>, bool>> return_expression
|
||
%type <Nonnull<Block*>> block
|
||
%type <std::vector<Nonnull<Statement*>>> statement_list
|
||
%type <Nonnull<Expression*>> primary_expression
|
||
%type <Nonnull<Expression*>> postfix_expression
|
||
%type <Nonnull<Expression*>> ref_deref_expression
|
||
%type <Nonnull<Expression*>> type_expression
|
||
%type <Nonnull<Expression*>> fn_type_expression
|
||
%type <Nonnull<Expression*>> minus_expression
|
||
%type <Nonnull<Expression*>> complement_expression
|
||
%type <Nonnull<Expression*>> unary_expression
|
||
%type <Nonnull<Expression*>> simple_binary_operand
|
||
%type <Nonnull<Expression*>> multiplicative_lhs
|
||
%type <Nonnull<Expression*>> multiplicative_expression
|
||
%type <Nonnull<Expression*>> additive_operand
|
||
%type <Nonnull<Expression*>> additive_lhs
|
||
%type <Nonnull<Expression*>> additive_expression
|
||
%type <Nonnull<Expression*>> modulo_expression
|
||
%type <Nonnull<Expression*>> bitwise_and_lhs
|
||
%type <Nonnull<Expression*>> bitwise_and_expression
|
||
%type <Nonnull<Expression*>> bitwise_or_lhs
|
||
%type <Nonnull<Expression*>> bitwise_or_expression
|
||
%type <Nonnull<Expression*>> bitwise_xor_lhs
|
||
%type <Nonnull<Expression*>> bitwise_xor_expression
|
||
%type <Nonnull<Expression*>> bitwise_expression
|
||
%type <Nonnull<Expression*>> bit_shift_expression
|
||
%type <Nonnull<Expression*>> as_expression
|
||
%type <Nonnull<Expression*>> unimpl_expression
|
||
%type <Nonnull<Expression*>> value_expression
|
||
%type <Nonnull<Expression*>> comparison_operand
|
||
%type <Nonnull<Expression*>> comparison_expression
|
||
%type <Nonnull<Expression*>> not_expression
|
||
%type <Nonnull<Expression*>> predicate_expression
|
||
%type <Nonnull<Expression*>> and_or_operand
|
||
%type <Nonnull<Expression*>> and_lhs
|
||
%type <Nonnull<Expression*>> and_expression
|
||
%type <Nonnull<Expression*>> or_lhs
|
||
%type <Nonnull<Expression*>> or_expression
|
||
%type <Nonnull<WhereClause*>> where_clause
|
||
%type <std::vector<Nonnull<WhereClause*>>> where_clause_list
|
||
%type <Nonnull<Expression*>> where_expression
|
||
%type <Nonnull<Expression*>> type_or_where_expression
|
||
%type <Nonnull<Expression*>> statement_expression
|
||
%type <Nonnull<Expression*>> if_expression
|
||
%type <Nonnull<Expression*>> expression
|
||
%type <Nonnull<Expression*>> mixin_import
|
||
%type <Nonnull<GenericBinding*>> generic_binding
|
||
%type <Nonnull<Pattern*>> deduced_param
|
||
%type <std::vector<Nonnull<AstNode*>>> deduced_params
|
||
%type <std::vector<Nonnull<AstNode*>>> impl_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 <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 <std::optional<Nonnull<TuplePattern*>>> type_params
|
||
%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
|
||
%type <Operator> comparison_operator;
|
||
|
||
%token
|
||
// Most tokens have their spelling defined in lexer.lpp.
|
||
// table-begin
|
||
ABSTRACT
|
||
ADDR
|
||
ALIAS
|
||
AMPERSAND
|
||
AMPERSAND_EQUAL
|
||
AND
|
||
API
|
||
ARROW
|
||
AS
|
||
AUTO
|
||
BASE
|
||
BOOL
|
||
BREAK
|
||
CARET
|
||
CARET_EQUAL
|
||
CASE
|
||
CHOICE
|
||
CLASS
|
||
COLON
|
||
COLON_BANG
|
||
COMMA
|
||
CONSTRAINT
|
||
CONTINUE
|
||
DEFAULT
|
||
DESTRUCTOR
|
||
DOUBLE_ARROW
|
||
ELSE
|
||
EQUAL
|
||
EQUAL_EQUAL
|
||
EXTEND
|
||
FALSE
|
||
FN
|
||
FN_TYPE
|
||
FOR
|
||
FORALL
|
||
GREATER
|
||
GREATER_EQUAL
|
||
GREATER_GREATER
|
||
GREATER_GREATER_EQUAL
|
||
IF
|
||
IMPL
|
||
IMPLS
|
||
IMPORT
|
||
IN
|
||
INTERFACE
|
||
LEFT_CURLY_BRACE
|
||
LEFT_PARENTHESIS
|
||
LEFT_SQUARE_BRACKET
|
||
LESS
|
||
LESS_EQUAL
|
||
LESS_LESS
|
||
LESS_LESS_EQUAL
|
||
LET
|
||
LIBRARY
|
||
MATCH
|
||
MATCH_FIRST
|
||
MINUS
|
||
MINUS_EQUAL
|
||
MINUS_MINUS
|
||
MIX
|
||
MIXIN
|
||
NAMESPACE
|
||
NOT
|
||
NOT_EQUAL
|
||
OR
|
||
OR_EQUAL
|
||
PACKAGE
|
||
PERCENT
|
||
PERCENT_EQUAL
|
||
PERIOD
|
||
PIPE
|
||
PIPE_EQUAL
|
||
PLUS
|
||
PLUS_EQUAL
|
||
PLUS_PLUS
|
||
REQUIRE
|
||
RETURN
|
||
RETURNED
|
||
RIGHT_CURLY_BRACE
|
||
RIGHT_PARENTHESIS
|
||
RIGHT_SQUARE_BRACKET
|
||
SELF
|
||
SEMICOLON
|
||
SLASH
|
||
SLASH_EQUAL
|
||
STAR_EQUAL
|
||
STRING
|
||
TEMPLATE
|
||
THEN
|
||
TRUE
|
||
TYPE
|
||
UNDERSCORE
|
||
UNIMPL_EXAMPLE
|
||
VAR
|
||
VIRTUAL
|
||
WHERE
|
||
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 *"
|
||
;
|
||
|
||
%start input
|
||
%%
|
||
input: package_directive import_directives top_level_declaration_list
|
||
{
|
||
*ast = AST({.package = $[package_directive].first,
|
||
.is_api = $[package_directive].second,
|
||
.imports = std::move($[import_directives]),
|
||
.declarations = std::move($[top_level_declaration_list])});
|
||
}
|
||
;
|
||
package_directive:
|
||
PACKAGE identifier optional_library_path api_or_impl SEMICOLON
|
||
{
|
||
$$ = {LibraryName(
|
||
{.package = $[identifier], .path = $[optional_library_path]}),
|
||
$[api_or_impl]};
|
||
}
|
||
;
|
||
import_directive:
|
||
IMPORT identifier optional_library_path SEMICOLON
|
||
{
|
||
$$ = LibraryName(
|
||
{.package = $[identifier], .path = $[optional_library_path]});
|
||
}
|
||
;
|
||
import_directives:
|
||
// Empty
|
||
{ $$ = std::vector<LibraryName>(); }
|
||
| import_directives[accumulated_import_directives] import_directive
|
||
{
|
||
$$ = std::move($[accumulated_import_directives]);
|
||
$$.push_back($[import_directive]);
|
||
}
|
||
;
|
||
optional_library_path:
|
||
// Empty
|
||
{ $$ = ""; }
|
||
| LIBRARY string_literal
|
||
{ $$ = $[string_literal]; }
|
||
;
|
||
api_or_impl:
|
||
API
|
||
{ $$ = true; }
|
||
| IMPL
|
||
{ $$ = false; }
|
||
;
|
||
primary_expression:
|
||
identifier
|
||
{
|
||
$$ =
|
||
arena->New<IdentifierExpression>(context.source_loc(), $[identifier]);
|
||
}
|
||
| designator
|
||
{
|
||
// `.Foo` is rewritten to `.Self.Foo`.
|
||
$$ = arena->New<SimpleMemberAccessExpression>(
|
||
context.source_loc(),
|
||
arena->New<DotSelfExpression>(context.source_loc()), $[designator]);
|
||
}
|
||
| PERIOD SELF
|
||
{ $$ = arena->New<DotSelfExpression>(context.source_loc()); }
|
||
| integer_literal
|
||
{ $$ = arena->New<IntLiteral>(context.source_loc(), $[integer_literal]); }
|
||
| string_literal
|
||
{ $$ = arena->New<StringLiteral>(context.source_loc(), $[string_literal]); }
|
||
| TRUE
|
||
{ $$ = arena->New<BoolLiteral>(context.source_loc(), true); }
|
||
| FALSE
|
||
{ $$ = arena->New<BoolLiteral>(context.source_loc(), false); }
|
||
| sized_type_literal
|
||
{
|
||
int val = 0;
|
||
if (!llvm::to_integer(llvm::StringRef($[sized_type_literal]).substr(1),
|
||
val)) {
|
||
context.RecordSyntaxError(
|
||
llvm::formatv("Invalid type literal: {0}", $[sized_type_literal]));
|
||
YYERROR;
|
||
} else if ($[sized_type_literal][0] != 'i' || val != 32) {
|
||
context.RecordSyntaxError(llvm::formatv(
|
||
"Only i32 is supported for now: {0}", $[sized_type_literal]));
|
||
YYERROR;
|
||
} else {
|
||
$$ = arena->New<IntTypeLiteral>(context.source_loc());
|
||
}
|
||
}
|
||
| SELF
|
||
// TODO: Should we create a new TypeLiteral for `Self`?
|
||
{ $$ = arena->New<IdentifierExpression>(context.source_loc(), "Self"); }
|
||
| STRING
|
||
{ $$ = arena->New<StringTypeLiteral>(context.source_loc()); }
|
||
| BOOL
|
||
{ $$ = arena->New<BoolTypeLiteral>(context.source_loc()); }
|
||
| TYPE
|
||
{ $$ = arena->New<TypeTypeLiteral>(context.source_loc()); }
|
||
| paren_expression { $$ = $[paren_expression]; }
|
||
| struct_literal { $$ = $[struct_literal]; }
|
||
| struct_type_literal { $$ = $[struct_type_literal]; }
|
||
| LEFT_SQUARE_BRACKET expression[type_expression] SEMICOLON
|
||
expression[size_expression] RIGHT_SQUARE_BRACKET
|
||
{
|
||
$$ = arena->New<ArrayTypeLiteral>(context.source_loc(),
|
||
$[type_expression], $[size_expression]);
|
||
}
|
||
| LEFT_SQUARE_BRACKET expression[type_expression] SEMICOLON RIGHT_SQUARE_BRACKET
|
||
{
|
||
$$ = arena->New<ArrayTypeLiteral>(context.source_loc(),
|
||
$[type_expression]);
|
||
}
|
||
;
|
||
postfix_expression:
|
||
primary_expression
|
||
| postfix_expression[child_postfix_expression] designator
|
||
{
|
||
$$ = arena->New<SimpleMemberAccessExpression>(
|
||
context.source_loc(), $[child_postfix_expression], $[designator]);
|
||
}
|
||
| postfix_expression[child_postfix_expression] ARROW identifier
|
||
{
|
||
auto deref = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Deref,
|
||
std::vector<Nonnull<Expression*>>({$[child_postfix_expression]}));
|
||
$$ = arena->New<SimpleMemberAccessExpression>(context.source_loc(), deref,
|
||
$[identifier]);
|
||
}
|
||
| postfix_expression[child_postfix_expression] PERIOD LEFT_PARENTHESIS
|
||
expression RIGHT_PARENTHESIS
|
||
{
|
||
$$ = arena->New<CompoundMemberAccessExpression>(
|
||
context.source_loc(), $[child_postfix_expression], $[expression]);
|
||
}
|
||
| postfix_expression[child_postfix_expression] ARROW LEFT_PARENTHESIS expression
|
||
RIGHT_PARENTHESIS
|
||
{
|
||
auto deref = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Deref,
|
||
std::vector<Nonnull<Expression*>>({$[child_postfix_expression]}));
|
||
$$ = arena->New<CompoundMemberAccessExpression>(context.source_loc(),
|
||
deref, $[expression]);
|
||
}
|
||
| postfix_expression[child_postfix_expression] LEFT_SQUARE_BRACKET expression
|
||
RIGHT_SQUARE_BRACKET
|
||
{
|
||
$$ = arena->New<IndexExpression>(
|
||
context.source_loc(), $[child_postfix_expression], $[expression]);
|
||
}
|
||
| intrinsic_identifier tuple
|
||
{
|
||
$$ = arena->New<IntrinsicExpression>($[intrinsic_identifier], $[tuple],
|
||
context.source_loc());
|
||
}
|
||
| postfix_expression[child_postfix_expression] tuple
|
||
{
|
||
$$ = arena->New<CallExpression>(context.source_loc(),
|
||
$[child_postfix_expression], $[tuple]);
|
||
}
|
||
| postfix_expression[child_postfix_expression] POSTFIX_STAR
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Ptr,
|
||
std::vector<Nonnull<Expression*>>({$[child_postfix_expression]}));
|
||
}
|
||
| postfix_expression[child_postfix_expression] UNARY_STAR
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Ptr,
|
||
std::vector<Nonnull<Expression*>>({$[child_postfix_expression]}));
|
||
}
|
||
;
|
||
ref_deref_expression:
|
||
postfix_expression
|
||
| PREFIX_STAR ref_deref_expression[child_ref_deref_expression]
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Deref,
|
||
std::vector<Nonnull<Expression*>>({$[child_ref_deref_expression]}));
|
||
}
|
||
| UNARY_STAR ref_deref_expression[child_ref_deref_expression]
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Deref,
|
||
std::vector<Nonnull<Expression*>>({$[child_ref_deref_expression]}));
|
||
}
|
||
| AMPERSAND ref_deref_expression[child_ref_deref_expression]
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::AddressOf,
|
||
std::vector<Nonnull<Expression*>>({$[child_ref_deref_expression]}));
|
||
}
|
||
;
|
||
fn_type_expression:
|
||
FN_TYPE tuple ARROW type_expression
|
||
{
|
||
$$ = arena->New<FunctionTypeLiteral>(context.source_loc(), $[tuple],
|
||
$[type_expression]);
|
||
}
|
||
;
|
||
type_expression:
|
||
ref_deref_expression
|
||
| bitwise_and_expression
|
||
| fn_type_expression
|
||
;
|
||
minus_expression:
|
||
// ref_deref_expression excluded due to precedence diamond.
|
||
MINUS ref_deref_expression
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Neg,
|
||
std::vector<Nonnull<Expression*>>({$[ref_deref_expression]}));
|
||
}
|
||
;
|
||
complement_expression:
|
||
// ref_deref_expression excluded due to precedence diamond.
|
||
CARET ref_deref_expression
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Complement,
|
||
std::vector<Nonnull<Expression*>>({$[ref_deref_expression]}));
|
||
}
|
||
;
|
||
unary_expression:
|
||
// ref_deref_expression excluded due to precedence diamond.
|
||
minus_expression
|
||
| complement_expression
|
||
;
|
||
// A simple_binary_operand is an operand of a binary operator
|
||
// that is not itself a binary operator expression.
|
||
simple_binary_operand:
|
||
ref_deref_expression
|
||
| unary_expression
|
||
;
|
||
multiplicative_lhs:
|
||
simple_binary_operand
|
||
| multiplicative_expression
|
||
;
|
||
multiplicative_expression:
|
||
multiplicative_lhs BINARY_STAR simple_binary_operand
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Mul,
|
||
std::vector<Nonnull<Expression*>>(
|
||
{$[multiplicative_lhs], $[simple_binary_operand]}));
|
||
}
|
||
| multiplicative_lhs SLASH simple_binary_operand
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Div,
|
||
std::vector<Nonnull<Expression*>>(
|
||
{$[multiplicative_lhs], $[simple_binary_operand]}));
|
||
}
|
||
;
|
||
additive_operand:
|
||
simple_binary_operand
|
||
| multiplicative_expression
|
||
;
|
||
additive_lhs:
|
||
simple_binary_operand
|
||
| additive_expression
|
||
;
|
||
additive_expression:
|
||
multiplicative_expression
|
||
| additive_lhs PLUS additive_operand
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Add,
|
||
std::vector<Nonnull<Expression*>>(
|
||
{$[additive_lhs], $[additive_operand]}));
|
||
}
|
||
| additive_lhs MINUS additive_operand
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Sub,
|
||
std::vector<Nonnull<Expression*>>(
|
||
{$[additive_lhs], $[additive_operand]}));
|
||
}
|
||
;
|
||
modulo_expression:
|
||
simple_binary_operand[lhs_simple_binary_operand] PERCENT
|
||
simple_binary_operand[rhs_simple_binary_operand]
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Mod,
|
||
std::vector<Nonnull<Expression*>>(
|
||
{$[lhs_simple_binary_operand], $[rhs_simple_binary_operand]}));
|
||
}
|
||
;
|
||
bitwise_and_lhs:
|
||
simple_binary_operand
|
||
| bitwise_and_expression
|
||
;
|
||
bitwise_and_expression:
|
||
bitwise_and_lhs AMPERSAND simple_binary_operand
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::BitwiseAnd,
|
||
std::vector<Nonnull<Expression*>>(
|
||
{$[bitwise_and_lhs], $[simple_binary_operand]}));
|
||
}
|
||
;
|
||
bitwise_or_lhs:
|
||
simple_binary_operand
|
||
| bitwise_or_expression
|
||
;
|
||
bitwise_or_expression:
|
||
bitwise_or_lhs PIPE simple_binary_operand
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::BitwiseOr,
|
||
std::vector<Nonnull<Expression*>>(
|
||
{$[bitwise_or_lhs], $[simple_binary_operand]}));
|
||
}
|
||
;
|
||
bitwise_xor_lhs:
|
||
simple_binary_operand
|
||
| bitwise_xor_expression
|
||
;
|
||
bitwise_xor_expression:
|
||
bitwise_xor_lhs CARET simple_binary_operand
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::BitwiseXor,
|
||
std::vector<Nonnull<Expression*>>(
|
||
{$[bitwise_xor_lhs], $[simple_binary_operand]}));
|
||
}
|
||
;
|
||
bitwise_expression:
|
||
bitwise_and_expression
|
||
| bitwise_or_expression
|
||
| bitwise_xor_expression
|
||
;
|
||
bit_shift_expression:
|
||
simple_binary_operand[lhs_simple_binary_operand] LESS_LESS
|
||
simple_binary_operand[rhs_simple_binary_operand]
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::BitShiftLeft,
|
||
std::vector<Nonnull<Expression*>>(
|
||
{$[lhs_simple_binary_operand], $[rhs_simple_binary_operand]}));
|
||
}
|
||
| simple_binary_operand[lhs_simple_binary_operand] GREATER_GREATER
|
||
simple_binary_operand[rhs_simple_binary_operand]
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::BitShiftRight,
|
||
std::vector<Nonnull<Expression*>>(
|
||
{$[lhs_simple_binary_operand], $[rhs_simple_binary_operand]}));
|
||
}
|
||
;
|
||
as_expression:
|
||
simple_binary_operand[lhs_simple_binary_operand] AS
|
||
simple_binary_operand[rhs_simple_binary_operand]
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::As,
|
||
std::vector<Nonnull<Expression*>>{$[lhs_simple_binary_operand],
|
||
$[rhs_simple_binary_operand]});
|
||
}
|
||
;
|
||
unimpl_expression:
|
||
// ref_deref_expression excluded due to precedence diamond.
|
||
ref_deref_expression[lhs_ref_deref_expression] UNIMPL_EXAMPLE
|
||
ref_deref_expression[rhs_ref_deref_expression]
|
||
{
|
||
$$ = arena->New<UnimplementedExpression>(
|
||
context.source_loc(), "ExampleInfix", $[lhs_ref_deref_expression],
|
||
$[rhs_ref_deref_expression]);
|
||
}
|
||
;
|
||
value_expression:
|
||
// ref_deref_expression excluded due to precedence diamond.
|
||
additive_expression
|
||
| as_expression
|
||
| bitwise_expression
|
||
| bit_shift_expression
|
||
| fn_type_expression
|
||
| modulo_expression
|
||
| unary_expression
|
||
| unimpl_expression
|
||
;
|
||
comparison_operand:
|
||
ref_deref_expression
|
||
| value_expression
|
||
;
|
||
comparison_operator:
|
||
EQUAL_EQUAL
|
||
{ $$ = Operator::Eq; }
|
||
| LESS
|
||
{ $$ = Operator::Less; }
|
||
| LESS_EQUAL
|
||
{ $$ = Operator::LessEq; }
|
||
| GREATER
|
||
{ $$ = Operator::Greater; }
|
||
| GREATER_EQUAL
|
||
{ $$ = Operator::GreaterEq; }
|
||
| NOT_EQUAL
|
||
{ $$ = Operator::NotEq; }
|
||
;
|
||
comparison_expression:
|
||
value_expression
|
||
| comparison_operand[lhs_simple_binary_operand] comparison_operator
|
||
comparison_operand[rhs_simple_binary_operand]
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), $[comparison_operator],
|
||
std::vector<Nonnull<Expression*>>(
|
||
{$[lhs_simple_binary_operand], $[rhs_simple_binary_operand]}));
|
||
}
|
||
;
|
||
not_expression:
|
||
NOT ref_deref_expression
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Not,
|
||
std::vector<Nonnull<Expression*>>({$[ref_deref_expression]}));
|
||
}
|
||
;
|
||
predicate_expression:
|
||
// ref_deref_expression excluded due to precedence diamond.
|
||
not_expression
|
||
| comparison_expression
|
||
;
|
||
and_or_operand:
|
||
ref_deref_expression
|
||
| predicate_expression
|
||
;
|
||
and_lhs:
|
||
and_or_operand
|
||
| and_expression
|
||
;
|
||
and_expression:
|
||
// predicate_expression excluded due to precedence diamond.
|
||
and_lhs AND and_or_operand
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::And,
|
||
std::vector<Nonnull<Expression*>>({$[and_lhs], $[and_or_operand]}));
|
||
}
|
||
;
|
||
or_lhs:
|
||
and_or_operand
|
||
| or_expression
|
||
;
|
||
or_expression:
|
||
// predicate_expression excluded due to precedence diamond.
|
||
or_lhs OR and_or_operand
|
||
{
|
||
$$ = arena->New<OperatorExpression>(
|
||
context.source_loc(), Operator::Or,
|
||
std::vector<Nonnull<Expression*>>({$[or_lhs], $[and_or_operand]}));
|
||
}
|
||
;
|
||
where_clause:
|
||
comparison_operand[lhs_simple_binary_operand] IMPLS
|
||
comparison_operand[rhs_simple_binary_operand]
|
||
{
|
||
$$ = arena->New<ImplsWhereClause>(context.source_loc(),
|
||
$[lhs_simple_binary_operand],
|
||
$[rhs_simple_binary_operand]);
|
||
}
|
||
| comparison_operand[lhs_simple_binary_operand] EQUAL_EQUAL
|
||
comparison_operand[rhs_simple_binary_operand]
|
||
{
|
||
$$ = arena->New<EqualsWhereClause>(context.source_loc(),
|
||
$[lhs_simple_binary_operand],
|
||
$[rhs_simple_binary_operand]);
|
||
}
|
||
// TODO: .(expression) = expression
|
||
| designator EQUAL comparison_operand
|
||
{
|
||
$$ = arena->New<RewriteWhereClause>(context.source_loc(), $[designator],
|
||
$[comparison_operand]);
|
||
}
|
||
;
|
||
where_clause_list:
|
||
where_clause
|
||
{ $$ = {$[where_clause]}; }
|
||
| where_clause_list[accumulated_where_clause_list] AND where_clause
|
||
{
|
||
$$ = std::move($[accumulated_where_clause_list]);
|
||
$$.push_back($[where_clause]);
|
||
}
|
||
;
|
||
where_expression:
|
||
type_expression WHERE where_clause_list
|
||
{
|
||
auto* self = arena->New<GenericBinding>(
|
||
context.source_loc(), ".Self", $[type_expression],
|
||
GenericBinding::BindingKind::Checked);
|
||
$$ = arena->New<WhereExpression>(context.source_loc(), self,
|
||
$[where_clause_list]);
|
||
}
|
||
;
|
||
type_or_where_expression:
|
||
type_expression
|
||
| where_expression
|
||
;
|
||
statement_expression:
|
||
ref_deref_expression
|
||
| predicate_expression
|
||
| and_expression
|
||
| or_expression
|
||
| where_expression
|
||
;
|
||
if_expression:
|
||
statement_expression
|
||
| IF expression THEN if_expression[then_if_expression] ELSE
|
||
if_expression[else_if_expression]
|
||
{
|
||
$$ = arena->New<IfExpression>(context.source_loc(), $[expression],
|
||
$[then_if_expression],
|
||
$[else_if_expression]);
|
||
}
|
||
;
|
||
expression:
|
||
if_expression
|
||
;
|
||
designator:
|
||
PERIOD identifier { $$ = $[identifier]; }
|
||
| PERIOD BASE { $$ = "base"; }
|
||
;
|
||
paren_expression: paren_expression_base
|
||
{
|
||
$$ = ExpressionFromParenContents(arena, context.source_loc(),
|
||
$[paren_expression_base]);
|
||
}
|
||
;
|
||
tuple: paren_expression_base
|
||
{
|
||
$$ = TupleExpressionFromParenContents(arena, context.source_loc(),
|
||
$[paren_expression_base]);
|
||
}
|
||
;
|
||
paren_expression_base:
|
||
LEFT_PARENTHESIS RIGHT_PARENTHESIS
|
||
{ $$ = {.elements = {}, .has_trailing_comma = false}; }
|
||
| LEFT_PARENTHESIS paren_expression_contents RIGHT_PARENTHESIS
|
||
{ $$ = $[paren_expression_contents]; }
|
||
| LEFT_PARENTHESIS paren_expression_contents COMMA RIGHT_PARENTHESIS
|
||
{
|
||
$$ = $[paren_expression_contents];
|
||
$$.has_trailing_comma = true;
|
||
}
|
||
;
|
||
paren_expression_contents:
|
||
expression
|
||
{ $$ = {.elements = {$[expression]}, .has_trailing_comma = false}; }
|
||
| paren_expression_contents[accumulated_paren_expression_contents] COMMA
|
||
expression
|
||
{
|
||
$$ = std::move($[accumulated_paren_expression_contents]);
|
||
$$.elements.push_back($[expression]);
|
||
}
|
||
;
|
||
|
||
struct_literal:
|
||
LEFT_CURLY_BRACE RIGHT_CURLY_BRACE
|
||
{ $$ = arena->New<StructLiteral>(context.source_loc()); }
|
||
| LEFT_CURLY_BRACE struct_literal_contents RIGHT_CURLY_BRACE
|
||
{
|
||
$$ = arena->New<StructLiteral>(context.source_loc(),
|
||
$[struct_literal_contents]);
|
||
}
|
||
| LEFT_CURLY_BRACE struct_literal_contents COMMA RIGHT_CURLY_BRACE
|
||
{
|
||
$$ = arena->New<StructLiteral>(context.source_loc(),
|
||
$[struct_literal_contents]);
|
||
}
|
||
;
|
||
struct_literal_contents:
|
||
designator EQUAL expression
|
||
{ $$ = {FieldInitializer($[designator], $[expression])}; }
|
||
| struct_literal_contents[accumulated_struct_literal_contents] COMMA designator
|
||
EQUAL expression
|
||
{
|
||
$$ = std::move($[accumulated_struct_literal_contents]);
|
||
$$.push_back(FieldInitializer($[designator], $[expression]));
|
||
}
|
||
;
|
||
|
||
struct_type_literal:
|
||
LEFT_CURLY_BRACE struct_type_literal_contents RIGHT_CURLY_BRACE
|
||
{
|
||
$$ = arena->New<StructTypeLiteral>(context.source_loc(),
|
||
$[struct_type_literal_contents]);
|
||
}
|
||
| LEFT_CURLY_BRACE struct_type_literal_contents COMMA RIGHT_CURLY_BRACE
|
||
{
|
||
$$ = arena->New<StructTypeLiteral>(context.source_loc(),
|
||
$[struct_type_literal_contents]);
|
||
}
|
||
;
|
||
struct_type_literal_contents:
|
||
designator COLON expression
|
||
{ $$ = {FieldInitializer($[designator], $[expression])}; }
|
||
| struct_type_literal_contents[accumulated_struct_type_literal_contents] COMMA
|
||
designator COLON expression
|
||
{
|
||
$$ = std::move($[accumulated_struct_type_literal_contents]);
|
||
$$.push_back(FieldInitializer($[designator], $[expression]));
|
||
}
|
||
;
|
||
|
||
// 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
|
||
{ $$ = $[non_expression_pattern]; }
|
||
| expression
|
||
{ $$ = arena->New<ExpressionPattern>($[expression]); }
|
||
;
|
||
non_expression_pattern:
|
||
AUTO
|
||
{ $$ = arena->New<AutoPattern>(context.source_loc()); }
|
||
| binding_lhs COLON pattern
|
||
{
|
||
$$ = arena->New<BindingPattern>(context.source_loc(), $[binding_lhs],
|
||
$[pattern], std::nullopt);
|
||
}
|
||
| binding_lhs COLON_BANG expression
|
||
{
|
||
$$ = arena->New<GenericBinding>(context.source_loc(), $[binding_lhs],
|
||
$[expression],
|
||
GenericBinding::BindingKind::Checked);
|
||
}
|
||
| TEMPLATE binding_lhs COLON_BANG expression
|
||
{
|
||
$$ = arena->New<GenericBinding>(context.source_loc(), $[binding_lhs],
|
||
$[expression],
|
||
GenericBinding::BindingKind::Template);
|
||
}
|
||
| paren_pattern
|
||
{ $$ = $[paren_pattern]; }
|
||
| postfix_expression tuple_pattern
|
||
{
|
||
ErrorOr<Nonnull<AlternativePattern*>> alternative_pattern =
|
||
AlternativePattern::Create(arena, context.source_loc(),
|
||
$[postfix_expression], $[tuple_pattern]);
|
||
if (alternative_pattern.ok()) {
|
||
$$ = *alternative_pattern;
|
||
} else {
|
||
context.RecordSyntaxError(std::move(alternative_pattern).error());
|
||
YYERROR;
|
||
}
|
||
}
|
||
| VAR non_expression_pattern[child_non_expression_pattern]
|
||
{
|
||
$$ = arena->New<VarPattern>(context.source_loc(),
|
||
$[child_non_expression_pattern]);
|
||
}
|
||
;
|
||
binding_lhs:
|
||
identifier { $$ = $[identifier]; }
|
||
| UNDERSCORE { $$ = AnonymousName; }
|
||
;
|
||
paren_pattern: paren_pattern_base
|
||
{
|
||
$$ = PatternFromParenContents(arena, context.source_loc(),
|
||
$[paren_pattern_base]);
|
||
}
|
||
;
|
||
paren_pattern_base:
|
||
LEFT_PARENTHESIS paren_pattern_contents RIGHT_PARENTHESIS
|
||
{ $$ = $[paren_pattern_contents]; }
|
||
| LEFT_PARENTHESIS paren_pattern_contents COMMA RIGHT_PARENTHESIS
|
||
{
|
||
$$ = $[paren_pattern_contents];
|
||
$$.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 = {$[non_expression_pattern]},
|
||
.has_trailing_comma = false};
|
||
}
|
||
| paren_expression_contents[accumulated_paren_pattern_contents] COMMA
|
||
non_expression_pattern
|
||
{
|
||
$$ = ParenExpressionToParenPattern(arena,
|
||
$[accumulated_paren_pattern_contents]);
|
||
$$.elements.push_back($[non_expression_pattern]);
|
||
}
|
||
| paren_pattern_contents[accumulated_paren_pattern_contents] COMMA expression
|
||
{
|
||
$$ = std::move($[accumulated_paren_pattern_contents]);
|
||
$$.elements.push_back(arena->New<ExpressionPattern>($[expression]));
|
||
}
|
||
| paren_pattern_contents[accumulated_paren_pattern_contents] COMMA
|
||
non_expression_pattern
|
||
{
|
||
$$ = std::move($[accumulated_paren_pattern_contents]);
|
||
$$.elements.push_back($[non_expression_pattern]);
|
||
}
|
||
;
|
||
tuple_pattern: paren_pattern_base
|
||
{
|
||
$$ = TuplePatternFromParenContents(arena, context.source_loc(),
|
||
$[paren_pattern_base]);
|
||
}
|
||
;
|
||
// 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
|
||
{ $$ = $[tuple_pattern]; }
|
||
;
|
||
|
||
clause:
|
||
CASE pattern DOUBLE_ARROW block
|
||
{ $$ = Match::Clause($[pattern], $[block]); }
|
||
| DEFAULT DOUBLE_ARROW block
|
||
{
|
||
$$ = Match::Clause(arena->New<BindingPattern>(
|
||
context.source_loc(), std::string(AnonymousName),
|
||
arena->New<AutoPattern>(context.source_loc()),
|
||
ExpressionCategory::Value),
|
||
$[block]);
|
||
}
|
||
;
|
||
clause_list:
|
||
// Empty
|
||
{ $$ = {}; }
|
||
| clause_list[accumulated_clause_list] clause
|
||
{
|
||
$$ = std::move($[accumulated_clause_list]);
|
||
$$.push_back($[clause]);
|
||
}
|
||
;
|
||
statement:
|
||
assign_statement
|
||
| VAR pattern SEMICOLON
|
||
{
|
||
$$ = arena->New<VariableDefinition>(
|
||
context.source_loc(), $[pattern], std::nullopt,
|
||
ExpressionCategory::Reference,
|
||
VariableDefinition::DefinitionType::Var);
|
||
}
|
||
| VAR pattern EQUAL expression SEMICOLON
|
||
{
|
||
$$ = arena->New<VariableDefinition>(
|
||
context.source_loc(), $[pattern], $[expression],
|
||
ExpressionCategory::Reference,
|
||
VariableDefinition::DefinitionType::Var);
|
||
}
|
||
| RETURNED VAR variable_declaration SEMICOLON
|
||
{
|
||
$$ = arena->New<VariableDefinition>(
|
||
context.source_loc(), $[variable_declaration], std::nullopt,
|
||
ExpressionCategory::Reference,
|
||
VariableDefinition::DefinitionType::Returned);
|
||
}
|
||
| RETURNED VAR variable_declaration EQUAL expression SEMICOLON
|
||
{
|
||
$$ = arena->New<VariableDefinition>(
|
||
context.source_loc(), $[variable_declaration], $[expression],
|
||
ExpressionCategory::Reference,
|
||
VariableDefinition::DefinitionType::Returned);
|
||
}
|
||
| LET pattern EQUAL expression SEMICOLON
|
||
{
|
||
$$ = arena->New<VariableDefinition>(
|
||
context.source_loc(), $[pattern], $[expression],
|
||
ExpressionCategory::Value, VariableDefinition::DefinitionType::Var);
|
||
}
|
||
| statement_expression SEMICOLON
|
||
{
|
||
$$ = arena->New<ExpressionStatement>(context.source_loc(),
|
||
$[statement_expression]);
|
||
}
|
||
| if_statement
|
||
{ $$ = $[if_statement]; }
|
||
| WHILE LEFT_PARENTHESIS expression RIGHT_PARENTHESIS block
|
||
{ $$ = arena->New<While>(context.source_loc(), $[expression], $[block]); }
|
||
| 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] = $[return_expression];
|
||
$$ = arena->New<ReturnExpression>(context.source_loc(), return_exp,
|
||
is_omitted_exp);
|
||
}
|
||
| RETURN VAR SEMICOLON
|
||
{ $$ = arena->New<ReturnVar>(context.source_loc()); }
|
||
| MATCH LEFT_PARENTHESIS expression RIGHT_PARENTHESIS LEFT_CURLY_BRACE
|
||
clause_list RIGHT_CURLY_BRACE
|
||
{
|
||
$$ = arena->New<Match>(context.source_loc(), $[expression],
|
||
$[clause_list]);
|
||
}
|
||
| FOR LEFT_PARENTHESIS variable_declaration IN type_expression RIGHT_PARENTHESIS
|
||
block
|
||
{
|
||
$$ = arena->New<For>(context.source_loc(), $[variable_declaration],
|
||
$[type_expression], $[block]);
|
||
}
|
||
;
|
||
assign_statement:
|
||
statement_expression assign_operator expression SEMICOLON
|
||
{
|
||
$$ = arena->New<Assign>(context.source_loc(), $[statement_expression],
|
||
$[assign_operator], $[expression]);
|
||
}
|
||
| PLUS_PLUS expression SEMICOLON
|
||
{
|
||
$$ = arena->New<IncrementDecrement>(context.source_loc(), $[expression],
|
||
true);
|
||
}
|
||
| MINUS_MINUS expression SEMICOLON
|
||
{
|
||
$$ = arena->New<IncrementDecrement>(context.source_loc(), $[expression],
|
||
false);
|
||
}
|
||
;
|
||
assign_operator:
|
||
EQUAL
|
||
{ $$ = AssignOperator::Plain; }
|
||
| PLUS_EQUAL
|
||
{ $$ = AssignOperator::Add; }
|
||
| SLASH_EQUAL
|
||
{ $$ = AssignOperator::Div; }
|
||
| STAR_EQUAL
|
||
{ $$ = AssignOperator::Mul; }
|
||
| PERCENT_EQUAL
|
||
{ $$ = AssignOperator::Mod; }
|
||
| MINUS_EQUAL
|
||
{ $$ = AssignOperator::Sub; }
|
||
| AMPERSAND_EQUAL
|
||
{ $$ = AssignOperator::And; }
|
||
| PIPE_EQUAL
|
||
{ $$ = AssignOperator::Or; }
|
||
| CARET_EQUAL
|
||
{ $$ = AssignOperator::Xor; }
|
||
| LESS_LESS_EQUAL
|
||
{ $$ = AssignOperator::ShiftLeft; }
|
||
| GREATER_GREATER_EQUAL
|
||
{ $$ = AssignOperator::ShiftRight; }
|
||
;
|
||
if_statement:
|
||
IF LEFT_PARENTHESIS expression RIGHT_PARENTHESIS block optional_else
|
||
{
|
||
$$ = arena->New<If>(context.source_loc(), $[expression], $[block],
|
||
$[optional_else]);
|
||
}
|
||
;
|
||
optional_else:
|
||
// Empty
|
||
{ $$ = std::nullopt; }
|
||
| ELSE if_statement
|
||
{
|
||
$$ = arena->New<Block>(
|
||
context.source_loc(),
|
||
std::vector<Nonnull<Statement*>>({$[if_statement]}));
|
||
}
|
||
| ELSE block
|
||
{ $$ = $[block]; }
|
||
;
|
||
return_expression:
|
||
// Empty
|
||
{ $$ = {arena->New<TupleLiteral>(context.source_loc()), true}; }
|
||
| expression
|
||
{ $$ = {$[expression], false}; }
|
||
;
|
||
statement_list:
|
||
// Empty
|
||
{ $$ = {}; }
|
||
| statement_list[accumulated_statement_list] statement
|
||
{
|
||
$$ = std::move($[accumulated_statement_list]);
|
||
$$.push_back($[statement]);
|
||
}
|
||
;
|
||
block:
|
||
LEFT_CURLY_BRACE statement_list RIGHT_CURLY_BRACE
|
||
{
|
||
$$ =
|
||
arena->New<Block>(context.source_loc(), std::move($[statement_list]));
|
||
}
|
||
;
|
||
return_term:
|
||
// Empty
|
||
{ $$ = ReturnTerm::Omitted(context.source_loc()); }
|
||
| ARROW AUTO
|
||
{ $$ = ReturnTerm::Auto(context.source_loc()); }
|
||
| ARROW expression
|
||
{ $$ = ReturnTerm::Explicit($[expression]); }
|
||
;
|
||
generic_binding:
|
||
identifier COLON_BANG expression
|
||
{
|
||
$$ = arena->New<GenericBinding>(context.source_loc(),
|
||
std::move($[identifier]), $[expression],
|
||
GenericBinding::BindingKind::Checked);
|
||
}
|
||
| TEMPLATE identifier COLON_BANG expression
|
||
{
|
||
$$ = arena->New<GenericBinding>(context.source_loc(),
|
||
std::move($[identifier]), $[expression],
|
||
GenericBinding::BindingKind::Template);
|
||
}
|
||
;
|
||
deduced_param:
|
||
generic_binding
|
||
{ $$ = $[generic_binding]; }
|
||
| variable_declaration
|
||
{ $$ = $[variable_declaration]; }
|
||
| ADDR variable_declaration
|
||
{
|
||
$$ = arena->New<AddrPattern>(context.source_loc(),
|
||
$[variable_declaration]);
|
||
}
|
||
;
|
||
deduced_param_list:
|
||
// Empty
|
||
{ $$ = {}; }
|
||
| deduced_param
|
||
{ $$ = {$[deduced_param]}; }
|
||
| deduced_param_list[accumulated_deduced_param_list] COMMA deduced_param
|
||
{
|
||
$$ = std::move($[accumulated_deduced_param_list]);
|
||
$$.push_back($[deduced_param]);
|
||
}
|
||
;
|
||
deduced_params:
|
||
// Empty
|
||
{ $$ = std::vector<Nonnull<AstNode*>>(); }
|
||
| LEFT_SQUARE_BRACKET deduced_param_list RIGHT_SQUARE_BRACKET
|
||
{ $$ = $[deduced_param_list]; }
|
||
;
|
||
impl_deduced_params:
|
||
// Empty
|
||
{ $$ = std::vector<Nonnull<AstNode*>>(); }
|
||
| FORALL LEFT_SQUARE_BRACKET deduced_param_list RIGHT_SQUARE_BRACKET
|
||
{ $$ = $[deduced_param_list]; }
|
||
;
|
||
declared_name:
|
||
identifier
|
||
{ $$ = DeclaredName(context.source_loc(), $[identifier]); }
|
||
| declared_name[child_declared_name] PERIOD identifier
|
||
{
|
||
$$ = std::move($[child_declared_name]);
|
||
$$.Unwrap().Append(context.source_loc(), $[identifier]);
|
||
}
|
||
| LEFT_PARENTHESIS declared_name[child_declared_name] RIGHT_PARENTHESIS
|
||
{ $$ = $[child_declared_name]; }
|
||
;
|
||
// This includes the FN keyword to work around a shift-reduce conflict between
|
||
// virtual function's `IMPL FN` and interfaces `IMPL`.
|
||
fn_virtual_override_intro:
|
||
FN
|
||
{ $$ = VirtualOverride::None; }
|
||
| ABSTRACT FN
|
||
{ $$ = VirtualOverride::Abstract; }
|
||
| VIRTUAL FN
|
||
{ $$ = VirtualOverride::Virtual; }
|
||
| IMPL FN
|
||
{ $$ = VirtualOverride::Impl; }
|
||
;
|
||
function_declaration:
|
||
fn_virtual_override_intro declared_name deduced_params
|
||
maybe_empty_tuple_pattern return_term block
|
||
{
|
||
ErrorOr<FunctionDeclaration*> fn = FunctionDeclaration::Create(
|
||
arena, context.source_loc(), std::move($[declared_name]),
|
||
$[deduced_params], $[maybe_empty_tuple_pattern], $[return_term],
|
||
$[block], $[fn_virtual_override_intro]);
|
||
if (fn.ok()) {
|
||
$$ = *fn;
|
||
} else {
|
||
context.RecordSyntaxError(std::move(fn).error());
|
||
YYERROR;
|
||
}
|
||
}
|
||
| fn_virtual_override_intro declared_name deduced_params
|
||
maybe_empty_tuple_pattern return_term SEMICOLON
|
||
{
|
||
ErrorOr<FunctionDeclaration*> fn = FunctionDeclaration::Create(
|
||
arena, context.source_loc(), std::move($[declared_name]),
|
||
$[deduced_params], $[maybe_empty_tuple_pattern], $[return_term],
|
||
std::nullopt, $[fn_virtual_override_intro]);
|
||
if (fn.ok()) {
|
||
$$ = *fn;
|
||
} else {
|
||
context.RecordSyntaxError(std::move(fn).error());
|
||
YYERROR;
|
||
}
|
||
}
|
||
;
|
||
variable_declaration: identifier COLON pattern
|
||
{
|
||
$$ = arena->New<BindingPattern>(context.source_loc(), $[identifier],
|
||
$[pattern], std::nullopt);
|
||
}
|
||
;
|
||
alias_declaration: ALIAS declared_name EQUAL expression SEMICOLON
|
||
{
|
||
$$ = arena->New<AliasDeclaration>(context.source_loc(), $[declared_name],
|
||
$[expression]);
|
||
}
|
||
;
|
||
// EXPERIMENTAL MIXIN FEATURE
|
||
mix_declaration: MIX expression SEMICOLON
|
||
{ $$ = arena->New<MixDeclaration>(context.source_loc(), $[expression]); }
|
||
;
|
||
alternative:
|
||
identifier tuple
|
||
{
|
||
$$ = arena->New<AlternativeSignature>(context.source_loc(), $[identifier],
|
||
$[tuple]);
|
||
}
|
||
| identifier
|
||
{
|
||
$$ = arena->New<AlternativeSignature>(context.source_loc(), $[identifier],
|
||
std::nullopt);
|
||
}
|
||
;
|
||
alternative_list:
|
||
// Empty
|
||
{ $$ = {}; }
|
||
| alternative_list_contents[accumulated_alternative_list_contents]
|
||
| alternative_list_contents[accumulated_alternative_list_contents] COMMA
|
||
;
|
||
alternative_list_contents:
|
||
alternative
|
||
{ $$ = {std::move($[alternative])}; }
|
||
| alternative_list_contents[accumulated_alternative_list_contents] COMMA
|
||
alternative
|
||
{
|
||
$$ = std::move($[accumulated_alternative_list_contents]);
|
||
$$.push_back(std::move($[alternative]));
|
||
}
|
||
;
|
||
type_params:
|
||
// Empty
|
||
{ $$ = std::nullopt; }
|
||
| tuple_pattern
|
||
{ $$ = $[tuple_pattern]; }
|
||
;
|
||
// EXPERIMENTAL MIXIN FEATURE
|
||
mixin_import:
|
||
// Empty
|
||
{ $$ = arena->New<TypeTypeLiteral>(context.source_loc()); }
|
||
| FOR expression
|
||
{
|
||
context.RecordSyntaxError("'for' not supported currently");
|
||
YYERROR;
|
||
// $$ = $[expression];
|
||
}
|
||
;
|
||
class_declaration_extensibility:
|
||
// Empty
|
||
{ $$ = Carbon::ClassExtensibility::None; }
|
||
| ABSTRACT
|
||
{ $$ = Carbon::ClassExtensibility::Abstract; }
|
||
| BASE
|
||
{ $$ = Carbon::ClassExtensibility::Base; }
|
||
;
|
||
// Declarations which are valid in most contexts: top-level, classes, etc.
|
||
declaration:
|
||
function_declaration
|
||
{ $$ = $[function_declaration]; }
|
||
| destructor_declaration
|
||
{ $$ = $[destructor_declaration]; }
|
||
| class_declaration_extensibility CLASS declared_name type_params
|
||
LEFT_CURLY_BRACE class_body RIGHT_CURLY_BRACE
|
||
{
|
||
$$ = arena->New<ClassDeclaration>(
|
||
context.source_loc(), std::move($[declared_name]),
|
||
arena->New<SelfDeclaration>(context.source_loc()),
|
||
$[class_declaration_extensibility], $[type_params], $[class_body]);
|
||
}
|
||
| MIXIN declared_name type_params mixin_import LEFT_CURLY_BRACE mixin_body
|
||
RIGHT_CURLY_BRACE
|
||
{
|
||
// EXPERIMENTAL MIXN FEATURE
|
||
auto self = arena->New<GenericBinding>(
|
||
context.source_loc(), "Self", $[mixin_import],
|
||
GenericBinding::BindingKind::Checked);
|
||
$$ = arena->New<MixinDeclaration>(context.source_loc(),
|
||
std::move($[declared_name]),
|
||
$[type_params], self, $[mixin_body]);
|
||
}
|
||
| CHOICE declared_name type_params LEFT_CURLY_BRACE alternative_list
|
||
RIGHT_CURLY_BRACE
|
||
{
|
||
$$ = arena->New<ChoiceDeclaration>(context.source_loc(), $[declared_name],
|
||
$[type_params], $[alternative_list]);
|
||
}
|
||
| VAR variable_declaration SEMICOLON
|
||
{
|
||
$$ = arena->New<VariableDeclaration>(
|
||
context.source_loc(), $[variable_declaration], std::nullopt,
|
||
ExpressionCategory::Reference);
|
||
}
|
||
| VAR variable_declaration EQUAL expression SEMICOLON
|
||
{
|
||
$$ = arena->New<VariableDeclaration>(
|
||
context.source_loc(), $[variable_declaration], $[expression],
|
||
ExpressionCategory::Reference);
|
||
}
|
||
| LET variable_declaration EQUAL expression SEMICOLON
|
||
{
|
||
$$ = arena->New<VariableDeclaration>(
|
||
context.source_loc(), $[variable_declaration], $[expression],
|
||
ExpressionCategory::Value);
|
||
}
|
||
| INTERFACE declared_name type_params LEFT_CURLY_BRACE interface_body
|
||
RIGHT_CURLY_BRACE
|
||
{
|
||
$$ = arena->New<InterfaceDeclaration>(arena, context.source_loc(),
|
||
std::move($[declared_name]),
|
||
$[type_params], $[interface_body]);
|
||
}
|
||
| CONSTRAINT declared_name type_params LEFT_CURLY_BRACE interface_body
|
||
RIGHT_CURLY_BRACE
|
||
{
|
||
$$ = arena->New<ConstraintDeclaration>(arena, context.source_loc(),
|
||
std::move($[declared_name]),
|
||
$[type_params], $[interface_body]);
|
||
}
|
||
| impl_declaration
|
||
{ $$ = $[impl_declaration]; }
|
||
| match_first_declaration
|
||
{ $$ = $[match_first_declaration]; }
|
||
| alias_declaration
|
||
{ $$ = $[alias_declaration]; }
|
||
;
|
||
impl_declaration:
|
||
IMPL impl_deduced_params impl_type AS type_or_where_expression
|
||
LEFT_CURLY_BRACE impl_body RIGHT_CURLY_BRACE
|
||
{
|
||
ErrorOr<ImplDeclaration*> impl = ImplDeclaration::Create(
|
||
arena, context.source_loc(), Carbon::ImplKind::ExternalImpl,
|
||
$[impl_type], $[type_or_where_expression], $[impl_deduced_params],
|
||
$[impl_body]);
|
||
if (impl.ok()) {
|
||
$$ = *impl;
|
||
} else {
|
||
context.RecordSyntaxError(std::move(impl).error());
|
||
YYERROR;
|
||
}
|
||
}
|
||
;
|
||
extend_impl_declaration:
|
||
EXTEND IMPL no_impl_type AS type_or_where_expression
|
||
LEFT_CURLY_BRACE impl_body RIGHT_CURLY_BRACE
|
||
{
|
||
ErrorOr<ImplDeclaration*> impl = ImplDeclaration::Create(
|
||
arena, context.source_loc(), Carbon::ImplKind::InternalImpl,
|
||
$[no_impl_type], $[type_or_where_expression], {}, $[impl_body]);
|
||
if (impl.ok()) {
|
||
$$ = *impl;
|
||
} else {
|
||
context.RecordSyntaxError(std::move(impl).error());
|
||
YYERROR;
|
||
}
|
||
}
|
||
;
|
||
impl_type:
|
||
// Self
|
||
{ $$ = arena->New<IdentifierExpression>(context.source_loc(), "Self"); }
|
||
| type_expression
|
||
;
|
||
no_impl_type:
|
||
{ $$ = arena->New<IdentifierExpression>(context.source_loc(), "Self"); }
|
||
;
|
||
match_first_declaration:
|
||
MATCH_FIRST LEFT_CURLY_BRACE match_first_declaration_list RIGHT_CURLY_BRACE
|
||
{
|
||
$$ = arena->New<MatchFirstDeclaration>(
|
||
context.source_loc(), std::move($[match_first_declaration_list]));
|
||
}
|
||
;
|
||
match_first_declaration_list:
|
||
// Empty
|
||
{ $$ = {}; }
|
||
| match_first_declaration_list[accumulated_match_first_declaration_list]
|
||
impl_declaration
|
||
{
|
||
$$ = std::move($[accumulated_match_first_declaration_list]);
|
||
$$.push_back($[impl_declaration]);
|
||
}
|
||
destructor_virtual_override_intro:
|
||
DESTRUCTOR
|
||
{ $$ = VirtualOverride::None; }
|
||
| VIRTUAL DESTRUCTOR
|
||
{ $$ = VirtualOverride::Virtual; }
|
||
| IMPL DESTRUCTOR
|
||
{ $$ = VirtualOverride::Impl; }
|
||
;
|
||
destructor_declaration:
|
||
destructor_virtual_override_intro deduced_params block
|
||
{
|
||
ErrorOr<DestructorDeclaration*> fn =
|
||
DestructorDeclaration::CreateDestructor(
|
||
arena, context.source_loc(), $[deduced_params],
|
||
arena->New<TuplePattern>(context.source_loc(),
|
||
std::vector<Nonnull<Pattern*>>()),
|
||
ReturnTerm::Omitted(context.source_loc()), $[block],
|
||
$[destructor_virtual_override_intro]);
|
||
if (fn.ok()) {
|
||
$$ = *fn;
|
||
} else {
|
||
context.RecordSyntaxError(std::move(fn).error());
|
||
YYERROR;
|
||
}
|
||
}
|
||
;
|
||
namespace_declaration:
|
||
NAMESPACE declared_name SEMICOLON
|
||
{
|
||
$$ = arena->New<NamespaceDeclaration>(context.source_loc(),
|
||
std::move($[declared_name]));
|
||
}
|
||
;
|
||
top_level_declaration_list:
|
||
// Empty
|
||
{ $$ = {}; }
|
||
| top_level_declaration_list[accumulated_top_level_declaration_list]
|
||
declaration
|
||
{
|
||
$$ = std::move($[accumulated_top_level_declaration_list]);
|
||
$$.push_back(Nonnull<Declaration*>($[declaration]));
|
||
}
|
||
| top_level_declaration_list[accumulated_top_level_declaration_list]
|
||
namespace_declaration
|
||
{
|
||
$$ = std::move($[accumulated_top_level_declaration_list]);
|
||
$$.push_back(Nonnull<Declaration*>($[namespace_declaration]));
|
||
}
|
||
;
|
||
extend_base_declaration:
|
||
EXTEND BASE COLON expression SEMICOLON
|
||
{
|
||
$$ = arena->New<ExtendBaseDeclaration>(context.source_loc(),
|
||
$[expression]);
|
||
}
|
||
;
|
||
class_body:
|
||
// Empty
|
||
{ $$ = {}; }
|
||
| class_body[accumulated_class_body] declaration
|
||
{
|
||
$$ = std::move($[accumulated_class_body]);
|
||
$$.push_back(Nonnull<Declaration*>($[declaration]));
|
||
}
|
||
| class_body[accumulated_class_body] mix_declaration
|
||
{
|
||
$$ = std::move($[accumulated_class_body]);
|
||
$$.push_back(Nonnull<Declaration*>($[mix_declaration]));
|
||
}
|
||
| class_body[accumulated_class_body] extend_base_declaration
|
||
{
|
||
$$ = std::move($[accumulated_class_body]);
|
||
$$.push_back(Nonnull<Declaration*>($[extend_base_declaration]));
|
||
}
|
||
| class_body[accumulated_class_body] extend_impl_declaration
|
||
{
|
||
$$ = std::move($[accumulated_class_body]);
|
||
$$.push_back(Nonnull<Declaration*>($[extend_impl_declaration]));
|
||
}
|
||
;
|
||
// EXPERIMENTAL MIXIN FEATURE
|
||
mixin_body:
|
||
// Empty
|
||
{ $$ = {}; }
|
||
| mixin_body[accumulated_mixin_body] function_declaration
|
||
{
|
||
$$ = std::move($[accumulated_mixin_body]);
|
||
$$.push_back(Nonnull<Declaration*>($[function_declaration]));
|
||
}
|
||
| mixin_body[accumulated_mixin_body] mix_declaration
|
||
{
|
||
$$ = std::move($[accumulated_mixin_body]);
|
||
$$.push_back(Nonnull<Declaration*>($[mix_declaration]));
|
||
}
|
||
;
|
||
interface_body:
|
||
// Empty
|
||
{ $$ = {}; }
|
||
| interface_body[accumulated_interface_body] function_declaration
|
||
{
|
||
$$ = std::move($[accumulated_interface_body]);
|
||
$$.push_back($[function_declaration]);
|
||
}
|
||
| interface_body[accumulated_interface_body] LET generic_binding SEMICOLON
|
||
{
|
||
$$ = std::move($[accumulated_interface_body]);
|
||
$$.push_back(arena->New<AssociatedConstantDeclaration>(
|
||
context.source_loc(), $[generic_binding]));
|
||
}
|
||
| interface_body[accumulated_interface_body] EXTEND expression SEMICOLON
|
||
{
|
||
$$ = std::move($[accumulated_interface_body]);
|
||
$$.push_back(arena->New<InterfaceExtendDeclaration>(context.source_loc(),
|
||
$[expression]));
|
||
}
|
||
| interface_body[accumulated_interface_body] REQUIRE type_expression IMPLS
|
||
type_or_where_expression SEMICOLON
|
||
{
|
||
$$ = std::move($[accumulated_interface_body]);
|
||
$$.push_back(arena->New<InterfaceRequireDeclaration>(
|
||
context.source_loc(), $[type_expression],
|
||
$[type_or_where_expression]));
|
||
}
|
||
;
|
||
impl_body:
|
||
// Empty
|
||
{ $$ = {}; }
|
||
| impl_body[accumulated_impl_body] function_declaration
|
||
{
|
||
$$ = std::move($[accumulated_impl_body]);
|
||
$$.push_back($[function_declaration]);
|
||
}
|
||
| impl_body[accumulated_impl_body] alias_declaration
|
||
{
|
||
$$ = std::move($[accumulated_impl_body]);
|
||
$$.push_back($[alias_declaration]);
|
||
}
|
||
;
|
||
%%
|