Lex and parse support for ... statements and expand. (#7832)

No support for `each` yet, but this should be enough that we can try out
an implementation approach supporting expanding a statement across
elements of a tuple without building "real" variadics.

Assisted-by: Claude via Antigravity
This commit is contained in:
Richard Smith authored and GitHub committed 2026-10-05 22:23:12 +00:00
1 parent ae5d1efd13
commit 2ec4bab59b
12 files changed
+958 -430

No files matched your search

+25
View File
@@ -0,0 +1,25 @@
// 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
#include "toolchain/check/context.h"
#include "toolchain/check/handle.h"
namespace Carbon::Check {
auto HandleParseNode(Context& context, Parse::PackExpansionStartId node_id)
-> bool {
return context.TODO(node_id, "HandlePackExpansionStart");
}
auto HandleParseNode(Context& context, Parse::PackExpansionStatementId node_id)
-> bool {
return context.TODO(node_id, "HandlePackExpansionStatement");
}
auto HandleParseNode(Context& context, Parse::PrefixOperatorExpandId node_id)
-> bool {
return context.TODO(node_id, "HandlePrefixOperatorExpand");
}
} // namespace Carbon::Check
+1
View File
@@ -468,6 +468,7 @@ class NodeStack {
case Parse::NodeKind::LetInitializer:
case Parse::NodeKind::LetIntroducer:
case Parse::NodeKind::NamedConstraintIntroducer:
case Parse::NodeKind::PackExpansionStart:
case Parse::NodeKind::RefBindingName:
case Parse::NodeKind::RuntimeBindingName:
case Parse::NodeKind::ReturnStatementStart:
@@ -0,0 +1,33 @@
// 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
//
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/variadics/pack_expansion.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/variadics/pack_expansion.carbon
// --- fail_todo_pack_expansion_statement.carbon
library "[[@TEST_NAME]]";
fn F() {
// CHECK:STDERR: fail_todo_pack_expansion_statement.carbon:[[@LINE+4]]:3: error: semantics TODO: `HandlePackExpansionStart` [SemanticsTodo]
// CHECK:STDERR: ... F();
// CHECK:STDERR: ^~~
// CHECK:STDERR:
... F();
}
// --- fail_todo_expand.carbon
library "[[@TEST_NAME]]";
fn F(x: (i32, i32)) {
// CHECK:STDERR: fail_todo_expand.carbon:[[@LINE+4]]:3: error: semantics TODO: `HandlePrefixOperatorExpand` [SemanticsTodo]
// CHECK:STDERR: expand x;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
expand x;
}
+23
View File
@@ -0,0 +1,23 @@
// 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
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lex/testdata/periods.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lex/testdata/periods.carbon
// CHECK:STDOUT: - filename: periods.carbon
// CHECK:STDOUT: tokens:
. .. ... .... ...... ...expand
// CHECK:STDOUT: - { index: 1, kind: "Period", line: {{ *}}[[@LINE-1]], column: 1, indent: 1, spelling: ".", has_leading_space: true }
// CHECK:STDOUT: - { index: 2, kind: "Period", line: {{ *}}[[@LINE-2]], column: 3, indent: 1, spelling: ".", has_leading_space: true }
// CHECK:STDOUT: - { index: 3, kind: "Period", line: {{ *}}[[@LINE-3]], column: 4, indent: 1, spelling: "." }
// CHECK:STDOUT: - { index: 4, kind: "PeriodPeriodPeriod", line: {{ *}}[[@LINE-4]], column: 6, indent: 1, spelling: "...", has_leading_space: true }
// CHECK:STDOUT: - { index: 5, kind: "PeriodPeriodPeriod", line: {{ *}}[[@LINE-5]], column: 10, indent: 1, spelling: "...", has_leading_space: true }
// CHECK:STDOUT: - { index: 6, kind: "Period", line: {{ *}}[[@LINE-6]], column: 13, indent: 1, spelling: "." }
// CHECK:STDOUT: - { index: 7, kind: "PeriodPeriodPeriod", line: {{ *}}[[@LINE-7]], column: 15, indent: 1, spelling: "...", has_leading_space: true }
// CHECK:STDOUT: - { index: 8, kind: "PeriodPeriodPeriod", line: {{ *}}[[@LINE-8]], column: 18, indent: 1, spelling: "..." }
// CHECK:STDOUT: - { index: 9, kind: "PeriodPeriodPeriod", line: {{ *}}[[@LINE-9]], column: 22, indent: 1, spelling: "...", has_leading_space: true }
// CHECK:STDOUT: - { index: 10, kind: "Expand", line: {{ *}}[[@LINE-10]], column: 25, indent: 1, spelling: "expand" }
+3
View File
@@ -60,6 +60,8 @@ CARBON_SYMBOL_TOKEN(GreaterGreaterEqual, ">>=")
CARBON_SYMBOL_TOKEN(LessEqualGreater, "<=>")
CARBON_SYMBOL_TOKEN(LessLessEqual, "<<=")
CARBON_SYMBOL_TOKEN(MinusGreaterQuestion,"->?")
CARBON_TOKEN_WITH_VIRTUAL_NODE(
CARBON_SYMBOL_TOKEN(PeriodPeriodPeriod, "..."))
CARBON_SYMBOL_TOKEN(AmpEqual, "&=")
CARBON_SYMBOL_TOKEN(CaretEqual, "^=")
@@ -189,6 +191,7 @@ CARBON_KEYWORD_TOKEN(Cpp, "Cpp")
CARBON_KEYWORD_TOKEN(Default, "default")
CARBON_KEYWORD_TOKEN(Else, "else")
CARBON_KEYWORD_TOKEN(Eval, "eval")
CARBON_KEYWORD_TOKEN(Expand, "expand")
CARBON_KEYWORD_TOKEN(Extend, "extend")
CARBON_KEYWORD_TOKEN(Extern, "extern")
CARBON_KEYWORD_TOKEN(False, "false")
+13
View File
@@ -51,6 +51,12 @@ auto HandleStatement(Context& context) -> void {
context.PushState(StateKind::MatchIntroducer);
break;
}
case Lex::TokenKind::PeriodPeriodPeriod: {
context.PushState(StateKind::StatementPackExpansionFinish);
context.AddLeafNode(NodeKind::PackExpansionStart, context.Consume());
context.PushState(StateKind::Statement);
break;
}
#define CARBON_PARSE_NODE_KIND(Name)
#define CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name) case Lex::TokenKind::Name:
#include "toolchain/parse/node_kind.def"
@@ -228,6 +234,13 @@ auto HandleStatementReturnFinish(Context& context) -> void {
HandleStatementKeywordFinish(context, NodeKind::ReturnStatement);
}
auto HandleStatementPackExpansionFinish(Context& context) -> void {
auto state = context.PopState();
context.AddNode(NodeKind::PackExpansionStatement, state.token,
state.has_error);
}
auto HandleStatementScopeLoop(Context& context) -> void {
// This maintains the current state until we're at the end of the scope.
+4
View File
@@ -286,6 +286,9 @@ CARBON_PARSE_NODE_KIND_STATEMENT(WhileConditionStart)
CARBON_PARSE_NODE_KIND_STATEMENT(WhileCondition)
CARBON_PARSE_NODE_KIND_STATEMENT(WhileStatement)
CARBON_PARSE_NODE_KIND_STATEMENT(PackExpansionStart)
CARBON_PARSE_NODE_KIND_STATEMENT(PackExpansionStatement)
CARBON_PARSE_NODE_KIND_EXPRESSION(IndexExprStart)
CARBON_PARSE_NODE_KIND_EXPRESSION(IndexExpr)
@@ -337,6 +340,7 @@ CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(UnsignedIntTypeLiteral,
CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR(Amp)
CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR(Caret)
CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR(Const)
CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR(Expand)
CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR(Not)
CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR(Minus)
CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR(MinusMinus)
+2
View File
@@ -149,6 +149,7 @@ auto PrecedenceGroup::ForLeading(Lex::TokenKind kind)
switch (kind) {
case Lex::TokenKind::Star:
case Lex::TokenKind::Amp:
case Lex::TokenKind::Expand:
return PrecedenceGroup(TermPrefix);
case Lex::TokenKind::Not:
@@ -249,6 +250,7 @@ auto PrecedenceGroup::ForTrailing(Lex::TokenKind kind, bool infix)
// Prefix-only operators.
case Lex::TokenKind::Const:
case Lex::TokenKind::Expand:
case Lex::TokenKind::MinusMinus:
case Lex::TokenKind::Not:
case Lex::TokenKind::Partial:
+442 -430
View File
File diff suppressed because it is too large. Load diff
+196
View File
@@ -0,0 +1,196 @@
// 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
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/variadics/expand.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/variadics/expand.carbon
// --- basic.carbon
var a: auto = expand x;
// --- precedence.carbon
// `expand` has the same precedence as prefix `*`.
var a: auto = expand x.y;
var b: auto = expand x.(0);
var c: auto = expand F();
var d: auto = expand x + 1;
var e: auto = expand x * 2;
var f: auto = expand *x;
var g: auto = *expand x;
var h: auto = expand expand x;
var i: auto = -expand x;
// --- fail_under_not.carbon
// Like prefix `*`, `expand` requires parentheses under `not`.
// CHECK:STDERR: fail_under_not.carbon:[[@LINE+4]]:19: error: parentheses are required around this unary `expand` operator [UnaryOperatorRequiresParentheses]
// CHECK:STDERR: var a: auto = not expand x;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
var a: auto = not expand x;
// --- fail_as_postfix.carbon
// CHECK:STDERR: fail_as_postfix.carbon:[[@LINE+4]]:17: error: `var` declarations must end with a `;` [ExpectedDeclSemi]
// CHECK:STDERR: var a: auto = x expand;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
var a: auto = x expand;
// CHECK:STDOUT: - filename: basic.carbon
// CHECK:STDOUT: ╭─FileStart ''
// CHECK:STDOUT: │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'a'
// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ ├─VariableInitializer '='
// CHECK:STDOUT: │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: ├─VariableDecl ';'
// CHECK:STDOUT: ├─FileEnd ''
// CHECK:STDOUT: (root)
// CHECK:STDOUT: - filename: precedence.carbon
// CHECK:STDOUT: ╭─FileStart ''
// CHECK:STDOUT: │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'a'
// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ ├─VariableInitializer '='
// CHECK:STDOUT: │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ ├─IdentifierNameNotBeforeSignature 'y'
// CHECK:STDOUT: │ │ ╭─MemberAccessExpr '.'
// CHECK:STDOUT: │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: ├─VariableDecl ';'
// CHECK:STDOUT: │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'b'
// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ ├─VariableInitializer '='
// CHECK:STDOUT: │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ │ ╭─ParenExprStart '('
// CHECK:STDOUT: │ │ │ ├─IntLiteral '0'
// CHECK:STDOUT: │ │ ├─ParenExpr ')'
// CHECK:STDOUT: │ │ ╭─MemberAccessExpr '.'
// CHECK:STDOUT: │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: ├─VariableDecl ';'
// CHECK:STDOUT: │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'c'
// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ ├─VariableInitializer '='
// CHECK:STDOUT: │ │ ╭─IdentifierNameExpr 'F'
// CHECK:STDOUT: │ │ ╭─CallExprStart '('
// CHECK:STDOUT: │ │ ╭─CallExpr ')'
// CHECK:STDOUT: │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: ├─VariableDecl ';'
// CHECK:STDOUT: │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'd'
// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ ├─VariableInitializer '='
// CHECK:STDOUT: │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ ╭─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ │ ├─IntLiteral '1'
// CHECK:STDOUT: │ ├─InfixOperatorPlus '+'
// CHECK:STDOUT: ├─VariableDecl ';'
// CHECK:STDOUT: │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'e'
// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ ├─VariableInitializer '='
// CHECK:STDOUT: │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ ╭─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ │ ├─IntLiteral '2'
// CHECK:STDOUT: │ ├─InfixOperatorStar '*'
// CHECK:STDOUT: ├─VariableDecl ';'
// CHECK:STDOUT: │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'f'
// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ ├─VariableInitializer '='
// CHECK:STDOUT: │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ ╭─PrefixOperatorStar '*'
// CHECK:STDOUT: │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: ├─VariableDecl ';'
// CHECK:STDOUT: │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'g'
// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ ├─VariableInitializer '='
// CHECK:STDOUT: │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ ╭─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ ├─PrefixOperatorStar '*'
// CHECK:STDOUT: ├─VariableDecl ';'
// CHECK:STDOUT: │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'h'
// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ ├─VariableInitializer '='
// CHECK:STDOUT: │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ ╭─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: ├─VariableDecl ';'
// CHECK:STDOUT: │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'i'
// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ ├─VariableInitializer '='
// CHECK:STDOUT: │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ ╭─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ ├─PrefixOperatorMinus '-'
// CHECK:STDOUT: ├─VariableDecl ';'
// CHECK:STDOUT: ├─FileEnd ''
// CHECK:STDOUT: (root)
// CHECK:STDOUT: - filename: fail_under_not.carbon
// CHECK:STDOUT: ╭─FileStart ''
// CHECK:STDOUT: │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'a'
// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ ├─VariableInitializer '='
// CHECK:STDOUT: │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ ╭─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ ├─PrefixOperatorNot 'not'
// CHECK:STDOUT: ├─VariableDecl ';'
// CHECK:STDOUT: ├─FileEnd ''
// CHECK:STDOUT: (root)
// CHECK:STDOUT: - filename: fail_as_postfix.carbon
// CHECK:STDOUT: ╭─FileStart ''
// CHECK:STDOUT: │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ ╭─IdentifierNameNotBeforeSignature 'a'
// CHECK:STDOUT: │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ ├─VariableInitializer '='
// CHECK:STDOUT: │ ├─IdentifierNameExpr 'x'
// CHECK:STDOUT: ├─VariableDecl ';' has_error
// CHECK:STDOUT: ├─FileEnd ''
// CHECK:STDOUT: (root)
@@ -0,0 +1,197 @@
// 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
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/variadics/pack_expansion_statement.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/variadics/pack_expansion_statement.carbon
// --- expr_statement.carbon
fn F() {
... G(expand x);
}
// --- var_statement.carbon
fn F() {
... var y: auto = expand x;
}
// --- compound_statements.carbon
fn F() {
... if (expand c) {
G(expand x);
} else {
H(expand y);
}
... while (expand c) {}
... return;
}
// --- nested.carbon
fn F() {
... ... G(expand x);
}
// --- fail_missing_statement.carbon
fn F() {
...
// CHECK:STDERR: fail_missing_statement.carbon:[[@LINE+4]]:1: error: expected expression [ExpectedExpr]
// CHECK:STDERR: }
// CHECK:STDERR: ^
// CHECK:STDERR:
}
// --- fail_missing_semi.carbon
fn F() {
... G()
// CHECK:STDERR: fail_missing_semi.carbon:[[@LINE+4]]:1: error: expected `;` after expression statement [ExpectedExprSemi]
// CHECK:STDERR: }
// CHECK:STDERR: ^
// CHECK:STDERR:
}
// CHECK:STDOUT: - filename: expr_statement.carbon
// CHECK:STDOUT: ╭─FileStart ''
// CHECK:STDOUT: │ ╭─FunctionIntroducer 'fn'
// CHECK:STDOUT: │ ├─IdentifierNameMaybeBeforeSignature 'F'
// CHECK:STDOUT: │ │ ╭─ExplicitParamListStart '('
// CHECK:STDOUT: │ ├─ExplicitParamList ')'
// CHECK:STDOUT: │ ╭─FunctionDefinitionStart '{'
// CHECK:STDOUT: │ │ ╭─PackExpansionStart '...'
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameExpr 'G'
// CHECK:STDOUT: │ │ │ ╭─CallExprStart '('
// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ │ │ ╭─CallExpr ')'
// CHECK:STDOUT: │ │ ├─ExprStatement ';'
// CHECK:STDOUT: │ ├─PackExpansionStatement '...'
// CHECK:STDOUT: ├─FunctionDefinition '}'
// CHECK:STDOUT: ├─FileEnd ''
// CHECK:STDOUT: (root)
// CHECK:STDOUT: - filename: var_statement.carbon
// CHECK:STDOUT: ╭─FileStart ''
// CHECK:STDOUT: │ ╭─FunctionIntroducer 'fn'
// CHECK:STDOUT: │ ├─IdentifierNameMaybeBeforeSignature 'F'
// CHECK:STDOUT: │ │ ╭─ExplicitParamListStart '('
// CHECK:STDOUT: │ ├─ExplicitParamList ')'
// CHECK:STDOUT: │ ╭─FunctionDefinitionStart '{'
// CHECK:STDOUT: │ │ ╭─PackExpansionStart '...'
// CHECK:STDOUT: │ │ │ ╭─VariableIntroducer 'var'
// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':'
// CHECK:STDOUT: │ │ │ │ ├─AutoTypeLiteral 'auto'
// CHECK:STDOUT: │ │ │ │ ╭─VarBindingPattern ':'
// CHECK:STDOUT: │ │ │ ├─VariablePattern 'var'
// CHECK:STDOUT: │ │ │ ├─VariableInitializer '='
// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ │ ├─VariableDecl ';'
// CHECK:STDOUT: │ ├─PackExpansionStatement '...'
// CHECK:STDOUT: ├─FunctionDefinition '}'
// CHECK:STDOUT: ├─FileEnd ''
// CHECK:STDOUT: (root)
// CHECK:STDOUT: - filename: compound_statements.carbon
// CHECK:STDOUT: ╭─FileStart ''
// CHECK:STDOUT: │ ╭─FunctionIntroducer 'fn'
// CHECK:STDOUT: │ ├─IdentifierNameMaybeBeforeSignature 'F'
// CHECK:STDOUT: │ │ ╭─ExplicitParamListStart '('
// CHECK:STDOUT: │ ├─ExplicitParamList ')'
// CHECK:STDOUT: │ ╭─FunctionDefinitionStart '{'
// CHECK:STDOUT: │ │ ╭─PackExpansionStart '...'
// CHECK:STDOUT: │ │ │ ╭─IfConditionStart '('
// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameExpr 'c'
// CHECK:STDOUT: │ │ │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ │ │ ╭─IfCondition ')'
// CHECK:STDOUT: │ │ │ │ ╭─CodeBlockStart '{'
// CHECK:STDOUT: │ │ │ │ │ ╭─IdentifierNameExpr 'G'
// CHECK:STDOUT: │ │ │ │ │ ╭─CallExprStart '('
// CHECK:STDOUT: │ │ │ │ │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ │ │ │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ │ │ │ │ ╭─CallExpr ')'
// CHECK:STDOUT: │ │ │ │ ├─ExprStatement ';'
// CHECK:STDOUT: │ │ │ ├─CodeBlock '}'
// CHECK:STDOUT: │ │ │ ├─IfStatementElse 'else'
// CHECK:STDOUT: │ │ │ │ ╭─CodeBlockStart '{'
// CHECK:STDOUT: │ │ │ │ │ ╭─IdentifierNameExpr 'H'
// CHECK:STDOUT: │ │ │ │ │ ╭─CallExprStart '('
// CHECK:STDOUT: │ │ │ │ │ │ ╭─IdentifierNameExpr 'y'
// CHECK:STDOUT: │ │ │ │ │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ │ │ │ │ ╭─CallExpr ')'
// CHECK:STDOUT: │ │ │ │ ├─ExprStatement ';'
// CHECK:STDOUT: │ │ │ ├─CodeBlock '}'
// CHECK:STDOUT: │ │ ├─IfStatement 'if'
// CHECK:STDOUT: │ ├─PackExpansionStatement '...'
// CHECK:STDOUT: │ │ ╭─PackExpansionStart '...'
// CHECK:STDOUT: │ │ │ ╭─WhileConditionStart '('
// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameExpr 'c'
// CHECK:STDOUT: │ │ │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ │ │ ╭─WhileCondition ')'
// CHECK:STDOUT: │ │ │ │ ╭─CodeBlockStart '{'
// CHECK:STDOUT: │ │ │ ├─CodeBlock '}'
// CHECK:STDOUT: │ │ ├─WhileStatement 'while'
// CHECK:STDOUT: │ ├─PackExpansionStatement '...'
// CHECK:STDOUT: │ │ ╭─PackExpansionStart '...'
// CHECK:STDOUT: │ │ │ ╭─ReturnStatementStart 'return'
// CHECK:STDOUT: │ │ ├─ReturnStatement ';'
// CHECK:STDOUT: │ ├─PackExpansionStatement '...'
// CHECK:STDOUT: ├─FunctionDefinition '}'
// CHECK:STDOUT: ├─FileEnd ''
// CHECK:STDOUT: (root)
// CHECK:STDOUT: - filename: nested.carbon
// CHECK:STDOUT: ╭─FileStart ''
// CHECK:STDOUT: │ ╭─FunctionIntroducer 'fn'
// CHECK:STDOUT: │ ├─IdentifierNameMaybeBeforeSignature 'F'
// CHECK:STDOUT: │ │ ╭─ExplicitParamListStart '('
// CHECK:STDOUT: │ ├─ExplicitParamList ')'
// CHECK:STDOUT: │ ╭─FunctionDefinitionStart '{'
// CHECK:STDOUT: │ │ ╭─PackExpansionStart '...'
// CHECK:STDOUT: │ │ │ ╭─PackExpansionStart '...'
// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameExpr 'G'
// CHECK:STDOUT: │ │ │ │ ╭─CallExprStart '('
// CHECK:STDOUT: │ │ │ │ │ ╭─IdentifierNameExpr 'x'
// CHECK:STDOUT: │ │ │ │ ├─PrefixOperatorExpand 'expand'
// CHECK:STDOUT: │ │ │ │ ╭─CallExpr ')'
// CHECK:STDOUT: │ │ │ ├─ExprStatement ';'
// CHECK:STDOUT: │ │ ├─PackExpansionStatement '...'
// CHECK:STDOUT: │ ├─PackExpansionStatement '...'
// CHECK:STDOUT: ├─FunctionDefinition '}'
// CHECK:STDOUT: ├─FileEnd ''
// CHECK:STDOUT: (root)
// CHECK:STDOUT: - filename: fail_missing_statement.carbon
// CHECK:STDOUT: ╭─FileStart ''
// CHECK:STDOUT: │ ╭─FunctionIntroducer 'fn'
// CHECK:STDOUT: │ ├─IdentifierNameMaybeBeforeSignature 'F'
// CHECK:STDOUT: │ │ ╭─ExplicitParamListStart '('
// CHECK:STDOUT: │ ├─ExplicitParamList ')'
// CHECK:STDOUT: │ ╭─FunctionDefinitionStart '{'
// CHECK:STDOUT: │ │ ╭─PackExpansionStart '...'
// CHECK:STDOUT: │ │ │ ╭─InvalidParse '}' has_error
// CHECK:STDOUT: │ │ ├─ExprStatement '...' has_error
// CHECK:STDOUT: │ ├─PackExpansionStatement '...'
// CHECK:STDOUT: ├─FunctionDefinition '}'
// CHECK:STDOUT: ├─FileEnd ''
// CHECK:STDOUT: (root)
// CHECK:STDOUT: - filename: fail_missing_semi.carbon
// CHECK:STDOUT: ╭─FileStart ''
// CHECK:STDOUT: │ ╭─FunctionIntroducer 'fn'
// CHECK:STDOUT: │ ├─IdentifierNameMaybeBeforeSignature 'F'
// CHECK:STDOUT: │ │ ╭─ExplicitParamListStart '('
// CHECK:STDOUT: │ ├─ExplicitParamList ')'
// CHECK:STDOUT: │ ╭─FunctionDefinitionStart '{'
// CHECK:STDOUT: │ │ ╭─PackExpansionStart '...'
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameExpr 'G'
// CHECK:STDOUT: │ │ │ ╭─CallExprStart '('
// CHECK:STDOUT: │ │ │ ╭─CallExpr ')'
// CHECK:STDOUT: │ │ ├─ExprStatement ')' has_error
// CHECK:STDOUT: │ ├─PackExpansionStatement '...'
// CHECK:STDOUT: ├─FunctionDefinition '}'
// CHECK:STDOUT: ├─FileEnd ''
// CHECK:STDOUT: (root)
+19
View File
@@ -954,6 +954,25 @@ struct WhileStatement {
CodeBlockId body;
};
// The start of a pack expansion: `...`. This marks the beginning of the
// expanded region.
using PackExpansionStart =
LeafNode<NodeKind::PackExpansionStart, Lex::PeriodPeriodPeriodTokenIndex>;
// A statement pack expansion: `... statement`.
struct PackExpansionStatement {
static constexpr auto Kind = NodeKind::PackExpansionStatement.Define(
{.category = NodeCategory::Statement,
.bracketed_by = PackExpansionStart::Kind,
.child_count = 2});
PackExpansionStartId start;
AnyStatementId body;
// This is a virtual token. The `...` token is owned by the
// PackExpansionStart node.
Lex::PeriodPeriodPeriodTokenIndex token;
};
using MatchConditionStart =
LeafNode<NodeKind::MatchConditionStart, Lex::OpenParenTokenIndex>;