mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Implement the current set of rules for precedence partial ordering (#1096)
In the process, switch to an unambiguous grammar, using the precedence-climbing method for operator precedence (suitably modified to handle a partial precedence order) rather than Bison %precedence / %prec.
This commit is contained in:
@@ -46,6 +46,8 @@
|
||||
%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
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -109,6 +111,29 @@
|
||||
%type <Nonnull<Block*>> nonempty_block
|
||||
%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*>> multiplicative_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*>> 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<Expression*>> expression
|
||||
%type <Nonnull<GenericBinding*>> generic_binding
|
||||
%type <std::vector<Nonnull<AstNode*>>> deduced_params
|
||||
@@ -211,31 +236,6 @@
|
||||
BINARY_STAR "binary *"
|
||||
;
|
||||
|
||||
%precedence FNARROW
|
||||
%precedence LEFT_CURLY_BRACE RIGHT_CURLY_BRACE
|
||||
%precedence COLON_BANG COLON COMMA DOUBLE_ARROW
|
||||
%left OR AND
|
||||
%nonassoc EQUAL_EQUAL
|
||||
%left PLUS MINUS
|
||||
%left BINARY_STAR
|
||||
%precedence NOT UNARY_MINUS PREFIX_STAR AMPERSAND
|
||||
// We need to give the `UNARY_STAR` token a precedence, rather than overriding
|
||||
// the precedence of the `expression UNARY_STAR` rule below, because bison
|
||||
// compares the precedence of the final token (for a shift) to the precedence
|
||||
// of the other rule (for a reduce) when attempting to resolve a shift-reduce
|
||||
// conflict. See https://stackoverflow.com/a/26188429/1041090. When UNARY_STAR
|
||||
// is the final token of a rule, it must be a postfix usage, so we give it the
|
||||
// same precedence as POSTFIX_STAR.
|
||||
%precedence POSTFIX_STAR UNARY_STAR
|
||||
%left PERIOD ARROW
|
||||
%nonassoc UNIMPL_EXAMPLE
|
||||
%precedence
|
||||
LEFT_PARENTHESIS
|
||||
RIGHT_PARENTHESIS
|
||||
LEFT_SQUARE_BRACKET
|
||||
RIGHT_SQUARE_BRACKET
|
||||
;
|
||||
|
||||
%start input
|
||||
%%
|
||||
input: package_directive import_directives declaration_list
|
||||
@@ -275,13 +275,9 @@ api_or_impl:
|
||||
| IMPL
|
||||
{ $$ = false; }
|
||||
;
|
||||
expression:
|
||||
primary_expression:
|
||||
identifier
|
||||
{ $$ = arena->New<IdentifierExpression>(context.source_loc(), $1); }
|
||||
| expression designator
|
||||
{ $$ = arena->New<FieldAccessExpression>(context.source_loc(), $1, $2); }
|
||||
| expression LEFT_SQUARE_BRACKET expression RIGHT_SQUARE_BRACKET
|
||||
{ $$ = arena->New<IndexExpression>(context.source_loc(), $1, $3); }
|
||||
| integer_literal
|
||||
{ $$ = arena->New<IntLiteral>(context.source_loc(), $1); }
|
||||
| string_literal
|
||||
@@ -309,96 +305,184 @@ expression:
|
||||
| paren_expression { $$ = $1; }
|
||||
| struct_literal { $$ = $1; }
|
||||
| struct_type_literal { $$ = $1; }
|
||||
;
|
||||
postfix_expression:
|
||||
primary_expression
|
||||
| postfix_expression designator
|
||||
{ $$ = arena->New<FieldAccessExpression>(context.source_loc(), $1, $2); }
|
||||
| postfix_expression LEFT_SQUARE_BRACKET expression RIGHT_SQUARE_BRACKET
|
||||
{ $$ = arena->New<IndexExpression>(context.source_loc(), $1, $3); }
|
||||
| intrinsic_identifier tuple
|
||||
{ $$ = arena->New<IntrinsicExpression>($1, $2, context.source_loc()); }
|
||||
| expression EQUAL_EQUAL expression
|
||||
| postfix_expression tuple
|
||||
{ $$ = arena->New<CallExpression>(context.source_loc(), $1, $2); }
|
||||
| postfix_expression POSTFIX_STAR
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Eq,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
context.source_loc(), Operator::Ptr,
|
||||
std::vector<Nonnull<Expression*>>({$1}));
|
||||
}
|
||||
| expression PLUS expression
|
||||
| postfix_expression UNARY_STAR
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Add,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
context.source_loc(), Operator::Ptr,
|
||||
std::vector<Nonnull<Expression*>>({$1}));
|
||||
}
|
||||
| expression MINUS expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Sub,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
| expression BINARY_STAR expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Mul,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
| expression AND expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::And,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
| expression OR expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Or,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
| NOT expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Not,
|
||||
std::vector<Nonnull<Expression*>>({$2}));
|
||||
}
|
||||
| MINUS expression %prec UNARY_MINUS
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Neg,
|
||||
std::vector<Nonnull<Expression*>>({$2}));
|
||||
}
|
||||
| PREFIX_STAR expression
|
||||
;
|
||||
ref_deref_expression:
|
||||
postfix_expression
|
||||
| PREFIX_STAR ref_deref_expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Deref,
|
||||
std::vector<Nonnull<Expression*>>({$2}));
|
||||
}
|
||||
| UNARY_STAR expression %prec PREFIX_STAR
|
||||
| UNARY_STAR ref_deref_expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Deref,
|
||||
std::vector<Nonnull<Expression*>>({$2}));
|
||||
}
|
||||
| AMPERSAND expression
|
||||
| AMPERSAND ref_deref_expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::AddressOf,
|
||||
std::vector<Nonnull<Expression*>>({$2}));
|
||||
}
|
||||
| expression tuple
|
||||
{ $$ = arena->New<CallExpression>(context.source_loc(), $1, $2); }
|
||||
| expression POSTFIX_STAR
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Ptr,
|
||||
std::vector<Nonnull<Expression*>>({$1}));
|
||||
}
|
||||
| expression UNARY_STAR
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Ptr,
|
||||
std::vector<Nonnull<Expression*>>({$1}));
|
||||
}
|
||||
| FN_TYPE tuple ARROW expression
|
||||
;
|
||||
fn_type_expression:
|
||||
FN_TYPE tuple ARROW type_expression
|
||||
{ $$ = arena->New<FunctionTypeLiteral>(context.source_loc(), $2, $4); }
|
||||
| expression UNIMPL_EXAMPLE expression
|
||||
;
|
||||
type_expression:
|
||||
ref_deref_expression
|
||||
| fn_type_expression
|
||||
;
|
||||
minus_expression:
|
||||
// ref_deref_expression excluded due to precedence diamond.
|
||||
MINUS ref_deref_expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Neg,
|
||||
std::vector<Nonnull<Expression*>>({$2}));
|
||||
}
|
||||
;
|
||||
multiplicative_operand:
|
||||
ref_deref_expression
|
||||
| minus_expression
|
||||
;
|
||||
multiplicative_lhs:
|
||||
ref_deref_expression
|
||||
| multiplicative_expression
|
||||
;
|
||||
multiplicative_expression:
|
||||
minus_expression
|
||||
| multiplicative_lhs BINARY_STAR multiplicative_operand
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Mul,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
;
|
||||
additive_operand:
|
||||
ref_deref_expression
|
||||
| multiplicative_expression
|
||||
;
|
||||
additive_lhs:
|
||||
ref_deref_expression
|
||||
| additive_expression
|
||||
;
|
||||
additive_expression:
|
||||
multiplicative_expression
|
||||
| additive_lhs PLUS additive_operand
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Add,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
| additive_lhs MINUS additive_operand
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Sub,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
;
|
||||
unimpl_expression:
|
||||
// ref_deref_expression excluded due to precedence diamond.
|
||||
ref_deref_expression UNIMPL_EXAMPLE ref_deref_expression
|
||||
{
|
||||
$$ = arena->New<UnimplementedExpression>(context.source_loc(),
|
||||
"ExampleInfix", $1, $3);
|
||||
}
|
||||
;
|
||||
value_expression:
|
||||
// ref_deref_expression excluded due to precedence diamond.
|
||||
additive_expression
|
||||
| fn_type_expression
|
||||
| unimpl_expression
|
||||
;
|
||||
comparison_operand:
|
||||
ref_deref_expression
|
||||
| value_expression
|
||||
;
|
||||
comparison_expression:
|
||||
value_expression
|
||||
| comparison_operand EQUAL_EQUAL comparison_operand
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Eq,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
;
|
||||
not_expression:
|
||||
NOT ref_deref_expression
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Not,
|
||||
std::vector<Nonnull<Expression*>>({$2}));
|
||||
}
|
||||
;
|
||||
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<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::And,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
;
|
||||
or_lhs:
|
||||
and_or_operand
|
||||
| or_expression
|
||||
;
|
||||
or_expression:
|
||||
// predicate_expression excluded due to precedence diamond.
|
||||
or_lhs OR and_or_operand
|
||||
{
|
||||
$$ = arena->New<PrimitiveOperatorExpression>(
|
||||
context.source_loc(), Operator::Or,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
;
|
||||
expression:
|
||||
ref_deref_expression
|
||||
| predicate_expression
|
||||
| and_expression
|
||||
| or_expression
|
||||
;
|
||||
designator: PERIOD identifier { $$ = $2; }
|
||||
;
|
||||
paren_expression: paren_expression_base
|
||||
@@ -481,7 +565,7 @@ non_expression_pattern:
|
||||
{ $$ = arena->New<BindingPattern>(context.source_loc(), $1, $3); }
|
||||
| paren_pattern
|
||||
{ $$ = $1; }
|
||||
| expression tuple_pattern
|
||||
| postfix_expression tuple_pattern
|
||||
{ $$ = arena->New<AlternativePattern>(context.source_loc(), $1, $2); }
|
||||
;
|
||||
binding_lhs:
|
||||
@@ -643,9 +727,9 @@ nonempty_block:
|
||||
return_term:
|
||||
// Empty
|
||||
{ $$ = ReturnTerm::Omitted(context.source_loc()); }
|
||||
| ARROW AUTO %prec FNARROW
|
||||
| ARROW AUTO
|
||||
{ $$ = ReturnTerm::Auto(context.source_loc()); }
|
||||
| ARROW expression %prec FNARROW
|
||||
| ARROW expression
|
||||
{ $$ = ReturnTerm::Explicit($2); }
|
||||
;
|
||||
generic_binding:
|
||||
|
||||
Reference in New Issue
Block a user