// 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} %param {yyscan_t yyscanner} %param {ParseAndLexContext& context} // "out" parameter passed to the parser, where the AST is written. %parse-param {std::optional* 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 #include #include #include #include #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 #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/common/arena.h" #include "explorer/common/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 integer_literal %token identifier %token intrinsic_identifier %token sized_type_literal %token string_literal %type designator %type impl_kind_intro %type > impl_type %type > package_directive %type import_directive %type > import_directives %type optional_library_path %type api_or_impl %type fn_virtual_override_intro %type destructor_virtual_override_intro %type class_declaration_extensibility %type >> class_declaration_extends %type > declaration %type > declared_name %type > function_declaration %type > destructor_declaration %type > mix_declaration %type > alias_declaration %type > impl_declaration %type > match_first_declaration %type >> match_first_declaration_list %type >> declaration_list %type >> class_body %type >> mixin_body %type >> interface_body %type >> impl_body %type > statement %type > assign_statement %type assign_operator %type > if_statement %type >> optional_else %type , bool>> return_expression %type > block %type >> statement_list %type > primary_expression %type > postfix_expression %type > ref_deref_expression %type > type_expression %type > fn_type_expression %type > minus_expression %type > complement_expression %type > unary_expression %type > simple_binary_operand %type > multiplicative_lhs %type > multiplicative_expression %type > additive_operand %type > additive_lhs %type > additive_expression %type > modulo_expression %type > bitwise_and_lhs %type > bitwise_and_expression %type > bitwise_or_lhs %type > bitwise_or_expression %type > bitwise_xor_lhs %type > bitwise_xor_expression %type > bitwise_expression %type > bit_shift_expression %type > as_expression %type > unimpl_expression %type > value_expression %type > comparison_operand %type > comparison_expression %type > not_expression %type > predicate_expression %type > and_or_operand %type > and_lhs %type > and_expression %type > or_lhs %type > or_expression %type > where_clause %type >> where_clause_list %type > where_expression %type > type_or_where_expression %type > statement_expression %type > if_expression %type > expression %type > mixin_import %type > generic_binding %type > deduced_param %type >> deduced_params %type >> impl_deduced_params %type >> deduced_param_list %type > pattern %type > non_expression_pattern %type > return_term %type > paren_expression %type > struct_literal %type > struct_literal_contents %type > struct_type_literal %type > struct_type_literal_contents %type > tuple %type binding_lhs %type > variable_declaration %type > paren_expression_base %type > paren_expression_contents %type > paren_pattern %type > tuple_pattern %type > maybe_empty_tuple_pattern %type >> type_params %type > paren_pattern_base %type > paren_pattern_contents %type > alternative %type >> alternative_list %type >> alternative_list_contents %type > clause %type > clause_list %type 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 EXTENDS EXTERNAL 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 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 declaration_list { *ast = AST({.package = $[package_directive].first, .is_api = $[package_directive].second, .imports = std::move($[import_directives]), .declarations = std::move($[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(); } | 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(context.source_loc(), $[identifier]); } | designator { // `.Foo` is rewritten to `.Self.Foo`. $$ = arena->New( context.source_loc(), arena->New(context.source_loc()), $[designator]); } | PERIOD SELF { $$ = arena->New(context.source_loc()); } | integer_literal { $$ = arena->New(context.source_loc(), $[integer_literal]); } | string_literal { $$ = arena->New(context.source_loc(), $[string_literal]); } | TRUE { $$ = arena->New(context.source_loc(), true); } | FALSE { $$ = arena->New(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(context.source_loc()); } } | SELF // TODO: Should we create a new TypeLiteral for `Self`? { $$ = arena->New(context.source_loc(), "Self"); } | STRING { $$ = arena->New(context.source_loc()); } | BOOL { $$ = arena->New(context.source_loc()); } | TYPE { $$ = arena->New(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(context.source_loc(), $[type_expression], $[size_expression]); } ; postfix_expression: primary_expression | postfix_expression[child_postfix_expression] designator { $$ = arena->New( context.source_loc(), $[child_postfix_expression], $[designator]); } | postfix_expression[child_postfix_expression] ARROW identifier { auto deref = arena->New( context.source_loc(), Operator::Deref, std::vector>({$[child_postfix_expression]})); $$ = arena->New(context.source_loc(), deref, $[identifier]); } | postfix_expression[child_postfix_expression] PERIOD LEFT_PARENTHESIS expression RIGHT_PARENTHESIS { $$ = arena->New( context.source_loc(), $[child_postfix_expression], $[expression]); } | postfix_expression[child_postfix_expression] ARROW LEFT_PARENTHESIS expression RIGHT_PARENTHESIS { auto deref = arena->New( context.source_loc(), Operator::Deref, std::vector>({$[child_postfix_expression]})); $$ = arena->New(context.source_loc(), deref, $[expression]); } | postfix_expression[child_postfix_expression] LEFT_SQUARE_BRACKET expression RIGHT_SQUARE_BRACKET { $$ = arena->New( context.source_loc(), $[child_postfix_expression], $[expression]); } | intrinsic_identifier tuple { $$ = arena->New($[intrinsic_identifier], $[tuple], context.source_loc()); } | postfix_expression[child_postfix_expression] tuple { $$ = arena->New(context.source_loc(), $[child_postfix_expression], $[tuple]); } | postfix_expression[child_postfix_expression] POSTFIX_STAR { $$ = arena->New( context.source_loc(), Operator::Ptr, std::vector>({$[child_postfix_expression]})); } | postfix_expression[child_postfix_expression] UNARY_STAR { $$ = arena->New( context.source_loc(), Operator::Ptr, std::vector>({$[child_postfix_expression]})); } ; ref_deref_expression: postfix_expression | PREFIX_STAR ref_deref_expression[child_ref_deref_expression] { $$ = arena->New( context.source_loc(), Operator::Deref, std::vector>({$[child_ref_deref_expression]})); } | UNARY_STAR ref_deref_expression[child_ref_deref_expression] { $$ = arena->New( context.source_loc(), Operator::Deref, std::vector>({$[child_ref_deref_expression]})); } | AMPERSAND ref_deref_expression[child_ref_deref_expression] { $$ = arena->New( context.source_loc(), Operator::AddressOf, std::vector>({$[child_ref_deref_expression]})); } ; fn_type_expression: FN_TYPE tuple ARROW type_expression { $$ = arena->New(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( context.source_loc(), Operator::Neg, std::vector>({$[ref_deref_expression]})); } ; complement_expression: // ref_deref_expression excluded due to precedence diamond. CARET ref_deref_expression { $$ = arena->New( context.source_loc(), Operator::Complement, std::vector>({$[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( context.source_loc(), Operator::Mul, std::vector>( {$[multiplicative_lhs], $[simple_binary_operand]})); } | multiplicative_lhs SLASH simple_binary_operand { $$ = arena->New( context.source_loc(), Operator::Div, std::vector>( {$[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( context.source_loc(), Operator::Add, std::vector>( {$[additive_lhs], $[additive_operand]})); } | additive_lhs MINUS additive_operand { $$ = arena->New( context.source_loc(), Operator::Sub, std::vector>( {$[additive_lhs], $[additive_operand]})); } ; modulo_expression: simple_binary_operand[lhs_simple_binary_operand] PERCENT simple_binary_operand[rhs_simple_binary_operand] { $$ = arena->New( context.source_loc(), Operator::Mod, std::vector>( {$[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( context.source_loc(), Operator::BitwiseAnd, std::vector>( {$[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( context.source_loc(), Operator::BitwiseOr, std::vector>( {$[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( context.source_loc(), Operator::BitwiseXor, std::vector>( {$[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( context.source_loc(), Operator::BitShiftLeft, std::vector>( {$[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( context.source_loc(), Operator::BitShiftRight, std::vector>( {$[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( context.source_loc(), Operator::As, std::vector>{$[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( 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( context.source_loc(), $[comparison_operator], std::vector>( {$[lhs_simple_binary_operand], $[rhs_simple_binary_operand]})); } ; not_expression: NOT ref_deref_expression { $$ = arena->New( context.source_loc(), Operator::Not, std::vector>({$[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( context.source_loc(), Operator::And, std::vector>({$[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( context.source_loc(), Operator::Or, std::vector>({$[or_lhs], $[and_or_operand]})); } ; where_clause: comparison_operand[lhs_simple_binary_operand] IMPLS comparison_operand[rhs_simple_binary_operand] { $$ = arena->New(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(context.source_loc(), $[lhs_simple_binary_operand], $[rhs_simple_binary_operand]); } // TODO: .(expression) = expression | designator EQUAL comparison_operand { $$ = arena->New(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( context.source_loc(), ".Self", $[type_expression], GenericBinding::BindingKind::Checked); $$ = arena->New(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(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(context.source_loc()); } | LEFT_CURLY_BRACE struct_literal_contents RIGHT_CURLY_BRACE { $$ = arena->New(context.source_loc(), $[struct_literal_contents]); } | LEFT_CURLY_BRACE struct_literal_contents COMMA RIGHT_CURLY_BRACE { $$ = arena->New(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(context.source_loc(), $[struct_type_literal_contents]); } | LEFT_CURLY_BRACE struct_type_literal_contents COMMA RIGHT_CURLY_BRACE { $$ = arena->New(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($[expression]); } ; non_expression_pattern: AUTO { $$ = arena->New(context.source_loc()); } | binding_lhs COLON pattern { $$ = arena->New(context.source_loc(), $[binding_lhs], $[pattern], std::nullopt); } | binding_lhs COLON_BANG expression { $$ = arena->New(context.source_loc(), $[binding_lhs], $[expression], GenericBinding::BindingKind::Checked); } | TEMPLATE binding_lhs COLON_BANG expression { $$ = arena->New(context.source_loc(), $[binding_lhs], $[expression], GenericBinding::BindingKind::Template); } | paren_pattern { $$ = $[paren_pattern]; } | postfix_expression tuple_pattern { ErrorOr> 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(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($[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(context.source_loc(), std::vector>()); } | tuple_pattern { $$ = $[tuple_pattern]; } ; clause: CASE pattern DOUBLE_ARROW block { $$ = Match::Clause($[pattern], $[block]); } | DEFAULT DOUBLE_ARROW block { $$ = Match::Clause(arena->New( context.source_loc(), std::string(AnonymousName), arena->New(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( context.source_loc(), $[pattern], std::nullopt, ExpressionCategory::Reference, VariableDefinition::DefinitionType::Var); } | VAR pattern EQUAL expression SEMICOLON { $$ = arena->New( context.source_loc(), $[pattern], $[expression], ExpressionCategory::Reference, VariableDefinition::DefinitionType::Var); } | RETURNED VAR variable_declaration SEMICOLON { $$ = arena->New( context.source_loc(), $[variable_declaration], std::nullopt, ExpressionCategory::Reference, VariableDefinition::DefinitionType::Returned); } | RETURNED VAR variable_declaration EQUAL expression SEMICOLON { $$ = arena->New( context.source_loc(), $[variable_declaration], $[expression], ExpressionCategory::Reference, VariableDefinition::DefinitionType::Returned); } | LET pattern EQUAL expression SEMICOLON { $$ = arena->New( context.source_loc(), $[pattern], $[expression], ExpressionCategory::Value, VariableDefinition::DefinitionType::Var); } | statement_expression SEMICOLON { $$ = arena->New(context.source_loc(), $[statement_expression]); } | if_statement { $$ = $[if_statement]; } | WHILE LEFT_PARENTHESIS expression RIGHT_PARENTHESIS block { $$ = arena->New(context.source_loc(), $[expression], $[block]); } | BREAK SEMICOLON { $$ = arena->New(context.source_loc()); } | CONTINUE SEMICOLON { $$ = arena->New(context.source_loc()); } | RETURN return_expression SEMICOLON { auto [return_exp, is_omitted_exp] = $[return_expression]; $$ = arena->New(context.source_loc(), return_exp, is_omitted_exp); } | RETURN VAR SEMICOLON { $$ = arena->New(context.source_loc()); } | MATCH LEFT_PARENTHESIS expression RIGHT_PARENTHESIS LEFT_CURLY_BRACE clause_list RIGHT_CURLY_BRACE { $$ = arena->New(context.source_loc(), $[expression], $[clause_list]); } | FOR LEFT_PARENTHESIS variable_declaration IN type_expression RIGHT_PARENTHESIS block { $$ = arena->New(context.source_loc(), $[variable_declaration], $[type_expression], $[block]); } ; assign_statement: statement_expression assign_operator expression SEMICOLON { $$ = arena->New(context.source_loc(), $[statement_expression], $[assign_operator], $[expression]); } | PLUS_PLUS expression SEMICOLON { $$ = arena->New(context.source_loc(), $[expression], true); } | MINUS_MINUS expression SEMICOLON { $$ = arena->New(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(context.source_loc(), $[expression], $[block], $[optional_else]); } ; optional_else: // Empty { $$ = std::nullopt; } | ELSE if_statement { $$ = arena->New( context.source_loc(), std::vector>({$[if_statement]})); } | ELSE block { $$ = $[block]; } ; return_expression: // Empty { $$ = {arena->New(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(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(context.source_loc(), std::move($[identifier]), $[expression], GenericBinding::BindingKind::Checked); } | TEMPLATE identifier COLON_BANG expression { $$ = arena->New(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(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>(); } | LEFT_SQUARE_BRACKET deduced_param_list RIGHT_SQUARE_BRACKET { $$ = $[deduced_param_list]; } ; impl_deduced_params: // Empty { $$ = std::vector>(); } | 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 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 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(context.source_loc(), $1, $3, std::nullopt); } ; alias_declaration: ALIAS declared_name EQUAL expression SEMICOLON { $$ = arena->New(context.source_loc(), $[declared_name], $[expression]); } ; // EXPERIMENTAL MIXIN FEATURE mix_declaration: MIX expression SEMICOLON { $$ = arena->New(context.source_loc(), $[expression]); } ; alternative: identifier tuple { $$ = arena->New(context.source_loc(), $[identifier], $[tuple]); } | identifier { $$ = arena->New(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(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; } ; class_declaration_extends: // Empty { $$ = std::nullopt; } | EXTENDS expression { $$ = $[expression]; } ; declaration: NAMESPACE declared_name SEMICOLON { $$ = arena->New(context.source_loc(), std::move($[declared_name])); } | function_declaration { $$ = $[function_declaration]; } | destructor_declaration { $$ = $[destructor_declaration]; } | class_declaration_extensibility CLASS declared_name type_params class_declaration_extends LEFT_CURLY_BRACE class_body RIGHT_CURLY_BRACE { $$ = arena->New( context.source_loc(), std::move($[declared_name]), arena->New(context.source_loc()), $[class_declaration_extensibility], $[type_params], $[class_declaration_extends], $[class_body]); } | MIXIN declared_name type_params mixin_import LEFT_CURLY_BRACE mixin_body RIGHT_CURLY_BRACE { // EXPERIMENTAL MIXN FEATURE auto self = arena->New( context.source_loc(), "Self", $[mixin_import], GenericBinding::BindingKind::Checked); $$ = arena->New(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(context.source_loc(), $[declared_name], $[type_params], $[alternative_list]); } | VAR variable_declaration SEMICOLON { $$ = arena->New( context.source_loc(), $[variable_declaration], std::nullopt, ExpressionCategory::Reference); } | VAR variable_declaration EQUAL expression SEMICOLON { $$ = arena->New( context.source_loc(), $[variable_declaration], $[expression], ExpressionCategory::Reference); } | LET variable_declaration EQUAL expression SEMICOLON { $$ = arena->New( context.source_loc(), $[variable_declaration], $[expression], ExpressionCategory::Value); } | INTERFACE declared_name type_params LEFT_CURLY_BRACE interface_body RIGHT_CURLY_BRACE { $$ = arena->New(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(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_kind_intro impl_deduced_params impl_type AS type_or_where_expression LEFT_CURLY_BRACE impl_body RIGHT_CURLY_BRACE { ErrorOr impl = ImplDeclaration::Create( arena, context.source_loc(), $[impl_kind_intro], $[impl_type], $[type_or_where_expression], $[impl_deduced_params], $[impl_body]); if (impl.ok()) { $$ = *impl; } else { context.RecordSyntaxError(std::move(impl).error()); YYERROR; } } impl_kind_intro: IMPL // Internal { $$ = Carbon::ImplKind::InternalImpl; } | EXTERNAL IMPL { $$ = Carbon::ImplKind::ExternalImpl; } ; impl_type: // Self { $$ = arena->New(context.source_loc(), "Self"); } | type_expression ; match_first_declaration: MATCH_FIRST LEFT_CURLY_BRACE match_first_declaration_list RIGHT_CURLY_BRACE { $$ = arena->New( 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 fn = DestructorDeclaration::CreateDestructor( arena, context.source_loc(), $[deduced_params], arena->New(context.source_loc(), std::vector>()), ReturnTerm::Omitted(context.source_loc()), $[block], $[destructor_virtual_override_intro]); if (fn.ok()) { $$ = *fn; } else { context.RecordSyntaxError(std::move(fn).error()); YYERROR; } } ; declaration_list: // Empty { $$ = {}; } | declaration_list[accumulated_declaration_list] declaration { $$ = std::move($[accumulated_declaration_list]); $$.push_back(Nonnull($[declaration])); } ; class_body: // Empty { $$ = {}; } | class_body[accumulated_class_body] declaration { $$ = std::move($[accumulated_class_body]); $$.push_back(Nonnull($[declaration])); } | class_body[accumulated_class_body] mix_declaration { $$ = std::move($[accumulated_class_body]); $$.push_back(Nonnull($[mix_declaration])); } ; // EXPERIMENTAL MIXIN FEATURE mixin_body: // Empty { $$ = {}; } | mixin_body[accumulated_mixin_body] function_declaration { $$ = std::move($[accumulated_mixin_body]); $$.push_back(Nonnull($[function_declaration])); } | mixin_body[accumulated_mixin_body] mix_declaration { $$ = std::move($[accumulated_mixin_body]); $$.push_back(Nonnull($[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( context.source_loc(), $[generic_binding])); } | interface_body[accumulated_interface_body] EXTENDS expression SEMICOLON { $$ = std::move($[accumulated_interface_body]); $$.push_back(arena->New(context.source_loc(), $[expression])); } | interface_body[accumulated_interface_body] IMPL impl_type AS type_or_where_expression SEMICOLON { $$ = std::move($[accumulated_interface_body]); $$.push_back(arena->New( context.source_loc(), $[impl_type], $[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]); } ; %%