Add parsing for 'fn destroy' (#5045)

Syntax is proposed in #5017, but has already been discussed with leads.
Semantics is left as a TODO.

---------

Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
This commit is contained in:
Jon Ross-Perkins
2025-03-03 17:37:10 +00:00
committed by GitHub
co-authored by josh11b
parent 437d3b9af6
commit c44e688e5d
19 changed files with 362 additions and 64 deletions
+18 -1
View File
@@ -152,6 +152,16 @@ auto HandleParseNode(Context& context, Parse::IdentifierNameExprId node_id)
return true;
}
auto HandleParseNode(Context& context,
Parse::KeywordNameNotBeforeParamsId node_id) -> bool {
return context.TODO(node_id, "KeywordNameNotBeforeParamsId");
}
auto HandleParseNode(Context& context, Parse::KeywordNameBeforeParamsId node_id)
-> bool {
return context.TODO(node_id, "KeywordNameBeforeParamsId");
}
auto HandleParseNode(Context& context, Parse::BaseNameId node_id) -> bool {
context.node_stack().Push(node_id, SemIR::NameId::Base);
return true;
@@ -188,7 +198,8 @@ auto HandleParseNode(Context& context,
}
auto HandleParseNode(Context& context,
Parse::NameQualifierWithoutParamsId /*node_id*/) -> bool {
Parse::IdentifierNameQualifierWithoutParamsId /*node_id*/)
-> bool {
context.decl_name_stack().ApplyNameQualifier(PopNameComponent(context));
return true;
}
@@ -229,6 +240,12 @@ auto HandleParseNode(Context& context, Parse::DesignatorExprId node_id)
return true;
}
auto HandleParseNode(Context& context,
Parse::KeywordNameQualifierWithoutParamsId node_id)
-> bool {
return context.TODO(node_id, "KeywordNameQualifierWithoutParamsId");
}
auto HandleParseNode(Context& context, Parse::PackageExprId node_id) -> bool {
AddInstAndPush<SemIR::NameRef>(
context, node_id,
+1 -2
View File
@@ -57,8 +57,7 @@ auto PopNameComponent(Context& context, SemIR::InstId return_slot_pattern_id)
}
auto [name_loc_id, name_id] =
context.node_stack()
.PopWithNodeId<Parse::NodeCategory::NonExprIdentifierName>();
context.node_stack().PopWithNodeId<Parse::NodeCategory::NonExprName>();
return {
.name_loc_id = name_loc_id,
+5 -4
View File
@@ -377,9 +377,9 @@ class NodeStack {
Id::KindFor<SemIR::InstId>());
set_id_if_category_is(Parse::NodeCategory::Expr,
Id::KindFor<SemIR::InstId>());
set_id_if_category_is(Parse::NodeCategory::MemberName |
Parse::NodeCategory::NonExprIdentifierName,
Id::KindFor<SemIR::NameId>());
set_id_if_category_is(
Parse::NodeCategory::MemberName | Parse::NodeCategory::NonExprName,
Id::KindFor<SemIR::NameId>());
set_id_if_category_is(Parse::NodeCategory::ImplAs,
Id::KindFor<SemIR::InstId>());
set_id_if_category_is(Parse::NodeCategory::Decl |
@@ -469,11 +469,13 @@ class NodeStack {
case Parse::NodeKind::ForHeader:
case Parse::NodeKind::ForHeaderStart:
case Parse::NodeKind::ForIn:
case Parse::NodeKind::IdentifierNameQualifierWithoutParams:
case Parse::NodeKind::IdentifierPackageName:
case Parse::NodeKind::IfConditionStart:
case Parse::NodeKind::ImportIntroducer:
case Parse::NodeKind::IndexExprStart:
case Parse::NodeKind::InvalidParseStart:
case Parse::NodeKind::KeywordNameQualifierWithoutParams:
case Parse::NodeKind::LibraryIntroducer:
case Parse::NodeKind::LibrarySpecifier:
case Parse::NodeKind::MatchCase:
@@ -494,7 +496,6 @@ class NodeStack {
case Parse::NodeKind::NamedConstraintDefinitionStart:
case Parse::NodeKind::NamedConstraintIntroducer:
case Parse::NodeKind::NameQualifierWithParams:
case Parse::NodeKind::NameQualifierWithoutParams:
case Parse::NodeKind::NamespaceStart:
case Parse::NodeKind::PackageIntroducer:
case Parse::NodeKind::ParenExprStart:
+179
View File
@@ -0,0 +1,179 @@
// 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/check/testdata/class/no_prelude/destroy.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/no_prelude/destroy.carbon
// --- fail_todo_basic.carbon
library "[[@TEST_NAME]]";
class C {
// CHECK:STDERR: fail_todo_basic.carbon:[[@LINE+4]]:6: error: semantics TODO: `KeywordNameBeforeParamsId` [SemanticsTodo]
// CHECK:STDERR: fn destroy[self: Self]();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
fn destroy[self: Self]();
}
// --- fail_todo_addr.carbon
library "[[@TEST_NAME]]";
class C {
// CHECK:STDERR: fail_todo_addr.carbon:[[@LINE+4]]:6: error: semantics TODO: `KeywordNameBeforeParamsId` [SemanticsTodo]
// CHECK:STDERR: fn destroy[addr self: Self*]();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
fn destroy[addr self: Self*]();
}
// --- fail_todo_class_function.carbon
library "[[@TEST_NAME]]";
class C {
// CHECK:STDERR: fail_todo_class_function.carbon:[[@LINE+4]]:6: error: semantics TODO: `KeywordNameBeforeParamsId` [SemanticsTodo]
// CHECK:STDERR: fn destroy();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
fn destroy();
}
// --- fail_todo_destroy_in_namespace.carbon
library "[[@TEST_NAME]]";
namespace NS;
// CHECK:STDERR: fail_todo_destroy_in_namespace.carbon:[[@LINE+4]]:7: error: semantics TODO: `KeywordNameBeforeParamsId` [SemanticsTodo]
// CHECK:STDERR: fn NS.destroy();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
fn NS.destroy();
// --- fail_todo_missing_params.carbon
library "[[@TEST_NAME]]";
class C {
// CHECK:STDERR: fail_todo_missing_params.carbon:[[@LINE+4]]:6: error: semantics TODO: `KeywordNameNotBeforeParamsId` [SemanticsTodo]
// CHECK:STDERR: fn destroy;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
fn destroy;
}
fn C.destroy {}
// --- fail_todo_wrong_scope.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_todo_wrong_scope.carbon:[[@LINE+4]]:4: error: semantics TODO: `KeywordNameBeforeParamsId` [SemanticsTodo]
// CHECK:STDERR: fn destroy();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
fn destroy();
// --- fail_invalid_qualifier.carbon
class C {
// CHECK:STDERR: fail_invalid_qualifier.carbon:[[@LINE+4]]:6: error: semantics TODO: `KeywordNameBeforeParamsId` [SemanticsTodo]
// CHECK:STDERR: fn destroy();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
fn destroy();
}
fn C.destroy.destroy() {}
// CHECK:STDOUT: --- fail_todo_basic.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: complete_type_witness = invalid
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_addr.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: complete_type_witness = invalid
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_class_function.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: complete_type_witness = invalid
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_destroy_in_namespace.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_missing_params.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: complete_type_witness = invalid
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_wrong_scope.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_invalid_qualifier.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: complete_type_witness = invalid
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: }
// CHECK:STDOUT:
+1 -1
View File
@@ -179,7 +179,7 @@ CARBON_KEYWORD_TOKEN(Const, "const")
CARBON_KEYWORD_TOKEN(Continue, "continue")
CARBON_KEYWORD_TOKEN(Core, "Core")
CARBON_KEYWORD_TOKEN(Default, "default")
CARBON_KEYWORD_TOKEN(Destructor, "destructor")
CARBON_KEYWORD_TOKEN(Destroy, "destroy")
CARBON_KEYWORD_TOKEN(Else, "else")
CARBON_KEYWORD_TOKEN(Extend, "extend")
CARBON_KEYWORD_TOKEN(Extern, "extern")
+1
View File
@@ -110,6 +110,7 @@ cc_library(
"//toolchain/base:shared_value_stores",
"//toolchain/diagnostics:diagnostic_emitter",
"//toolchain/diagnostics:format_providers",
"//toolchain/lex:token_index",
"//toolchain/lex:token_kind",
"//toolchain/lex:tokenized_buffer",
],
+52 -32
View File
@@ -2,67 +2,87 @@
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/lex/token_index.h"
#include "toolchain/parse/context.h"
#include "toolchain/parse/handle.h"
namespace Carbon::Parse {
auto HandleDeclNameAndParams(Context& context) -> void {
auto state = context.PopState();
auto identifier = context.ConsumeIf(Lex::TokenKind::Identifier);
if (!identifier) {
Lex::TokenIndex token = *context.position();
if (context.tokens().GetKind(token) == Lex::TokenKind::FileEnd) {
// The end of file is an unhelpful diagnostic location. Instead, use the
// introducer token.
token = state.token;
}
if (state.token == *context.position()) {
CARBON_DIAGNOSTIC(ExpectedDeclNameAfterPeriod, Error,
"`.` should be followed by a name");
context.emitter().Emit(token, ExpectedDeclNameAfterPeriod);
} else {
CARBON_DIAGNOSTIC(ExpectedDeclName, Error,
"`{0}` introducer should be followed by a name",
Lex::TokenKind);
context.emitter().Emit(token, ExpectedDeclName,
context.tokens().GetKind(state.token));
}
context.ReturnErrorOnState();
context.AddInvalidParse(*context.position());
return;
}
// Adds a leaf node for the name, and updates the state stack for parameter
// handling.
static auto HandleName(Context& context, Context::StateStackEntry state,
Lex::TokenIndex name_token,
NodeKind not_before_params_kind,
NodeKind not_before_params_qualifier_kind,
NodeKind before_params_kind) -> void {
switch (context.PositionKind()) {
case Lex::TokenKind::Period:
context.AddLeafNode(NodeKind::IdentifierNameNotBeforeParams, *identifier);
context.AddNode(NodeKind::NameQualifierWithoutParams,
context.AddLeafNode(not_before_params_kind, name_token);
context.AddNode(not_before_params_qualifier_kind,
context.ConsumeChecked(Lex::TokenKind::Period),
state.has_error);
context.PushState(State::DeclNameAndParams);
break;
case Lex::TokenKind::OpenSquareBracket:
context.AddLeafNode(NodeKind::IdentifierNameBeforeParams, *identifier);
context.AddLeafNode(before_params_kind, name_token);
state.state = State::DeclNameAndParamsAfterImplicit;
context.PushState(state);
context.PushState(State::PatternListAsImplicit);
break;
case Lex::TokenKind::OpenParen:
context.AddLeafNode(NodeKind::IdentifierNameBeforeParams, *identifier);
context.AddLeafNode(before_params_kind, name_token);
state.state = State::DeclNameAndParamsAfterParams;
context.PushState(state);
context.PushState(State::PatternListAsExplicit);
break;
default:
context.AddLeafNode(NodeKind::IdentifierNameNotBeforeParams, *identifier);
context.AddLeafNode(not_before_params_kind, name_token);
break;
}
}
auto HandleDeclNameAndParams(Context& context) -> void {
auto state = context.PopState();
if (auto identifier = context.ConsumeIf(Lex::TokenKind::Identifier)) {
HandleName(context, state, *identifier,
NodeKind::IdentifierNameNotBeforeParams,
NodeKind::IdentifierNameQualifierWithoutParams,
NodeKind::IdentifierNameBeforeParams);
return;
}
if (auto keyword = context.ConsumeIf(Lex::TokenKind::Destroy)) {
HandleName(context, state, *keyword, NodeKind::KeywordNameNotBeforeParams,
NodeKind::KeywordNameQualifierWithoutParams,
NodeKind::KeywordNameBeforeParams);
return;
}
Lex::TokenIndex token = *context.position();
if (context.tokens().GetKind(token) == Lex::TokenKind::FileEnd) {
// The end of file is an unhelpful diagnostic location. Instead, use the
// introducer token.
token = state.token;
}
if (state.token == *context.position()) {
CARBON_DIAGNOSTIC(ExpectedDeclNameAfterPeriod, Error,
"`.` should be followed by a name");
context.emitter().Emit(token, ExpectedDeclNameAfterPeriod);
} else {
CARBON_DIAGNOSTIC(ExpectedDeclName, Error,
"`{0}` introducer should be followed by a name",
Lex::TokenKind);
context.emitter().Emit(token, ExpectedDeclName,
context.tokens().GetKind(state.token));
}
context.ReturnErrorOnState();
context.AddInvalidParse(*context.position());
}
auto HandleDeclNameAndParamsAfterImplicit(Context& context) -> void {
auto state = context.PopState();
+1 -1
View File
@@ -25,7 +25,7 @@ LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
X(MemberExpr) \
X(MemberName) \
X(Modifier) \
X(NonExprIdentifierName) \
X(NonExprName) \
X(PackageName) \
X(Pattern) \
X(Requirement) \
+1 -2
View File
@@ -79,8 +79,7 @@ using AnyPatternId = NodeIdInCategory<NodeCategory::Pattern>;
using AnyStatementId =
NodeIdInCategory<NodeCategory::Statement | NodeCategory::Decl>;
using AnyRequirementId = NodeIdInCategory<NodeCategory::Requirement>;
using AnyNonExprIdentifierNameId =
NodeIdInCategory<NodeCategory::NonExprIdentifierName>;
using AnyNonExprNameId = NodeIdInCategory<NodeCategory::NonExprName>;
using AnyPackageNameId = NodeIdInCategory<NodeCategory::PackageName>;
// NodeId with kind that matches one of the `T::Kind`s.
+5 -1
View File
@@ -98,6 +98,9 @@ CARBON_PARSE_NODE_KIND(EmptyDecl)
CARBON_PARSE_NODE_KIND(IdentifierNameNotBeforeParams)
CARBON_PARSE_NODE_KIND(IdentifierNameBeforeParams)
CARBON_PARSE_NODE_KIND(KeywordNameNotBeforeParams)
CARBON_PARSE_NODE_KIND(KeywordNameBeforeParams)
CARBON_PARSE_NODE_KIND(IdentifierNameExpr)
CARBON_PARSE_NODE_KIND(SelfValueName)
@@ -124,7 +127,8 @@ CARBON_PARSE_NODE_KIND(LibraryDecl)
CARBON_PARSE_NODE_KIND(LibrarySpecifier)
CARBON_PARSE_NODE_KIND(NameQualifierWithParams)
CARBON_PARSE_NODE_KIND(NameQualifierWithoutParams)
CARBON_PARSE_NODE_KIND(IdentifierNameQualifierWithoutParams)
CARBON_PARSE_NODE_KIND(KeywordNameQualifierWithoutParams)
CARBON_PARSE_NODE_KIND(ExportIntroducer)
CARBON_PARSE_NODE_KIND(ExportDecl)
+1 -1
View File
@@ -44,7 +44,7 @@ fn F() {
// CHECK:STDOUT: {kind: 'Alias', text: ';', subtree_size: 7},
// CHECK:STDOUT: {kind: 'AliasIntroducer', text: 'alias'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'NS'},
// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'ns'},
// CHECK:STDOUT: {kind: 'AliasInitializer', text: '='},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'foo'},
+1 -1
View File
@@ -41,7 +41,7 @@ fn F() {
// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 15},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'C'},
// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'H'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
+62
View File
@@ -36,6 +36,22 @@ fn foo(a: i32, b: i32);
fn foo() -> u32;
// --- keyword.carbon
fn destroy() {}
// --- keyword_no_params.carbon
fn destroy {}
// --- keyword_in_qualified.carbon
fn MyClass.destroy() {}
// --- keyword_decl.carbon
fn destroy.destroy() {}
// --- impl_fn.carbon
impl fn F();
@@ -256,6 +272,52 @@ fn (a tokens c d e f g h i j k l m n o p q r s t u v w x y z);
// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 7},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: keyword.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'KeywordNameBeforeParams', text: 'destroy'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 6},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: keyword_no_params.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'KeywordNameNotBeforeParams', text: 'destroy'},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 3},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 4},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: keyword_in_qualified.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'MyClass'},
// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'KeywordNameBeforeParams', text: 'destroy'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 7},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 8},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: keyword_decl.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'KeywordNameNotBeforeParams', text: 'destroy'},
// CHECK:STDOUT: {kind: 'KeywordNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'KeywordNameBeforeParams', text: 'destroy'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 7},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 8},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: impl_fn.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
@@ -79,7 +79,7 @@ fn C.(Self as Interface).F() {}
// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 15},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'C'},
// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InvalidParse', text: '(', has_error: yes},
// CHECK:STDOUT: {kind: 'FunctionDecl', text: '}', has_error: yes, subtree_size: 5},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
@@ -19,7 +19,7 @@ namespace Foo.;
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Foo'},
// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'Namespace', text: ';', has_error: yes, subtree_size: 5},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
+3 -3
View File
@@ -23,14 +23,14 @@ fn Foo.Bar.Baz() {
// CHECK:STDOUT: {kind: 'Namespace', text: ';', subtree_size: 3},
// CHECK:STDOUT: {kind: 'NamespaceStart', text: 'namespace'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Foo'},
// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Bar'},
// CHECK:STDOUT: {kind: 'Namespace', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Foo'},
// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Bar'},
// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Baz'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
+2 -2
View File
@@ -162,7 +162,7 @@ export Foo;
// CHECK:STDOUT: {kind: 'PackageDecl', text: ';', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ExportIntroducer', text: 'export'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Foo'},
// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Bar'},
// CHECK:STDOUT: {kind: 'ExportDecl', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
@@ -230,7 +230,7 @@ export Foo;
// CHECK:STDOUT: {kind: 'PackageDecl', text: ';', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ExportIntroducer', text: 'export'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'Foo'},
// CHECK:STDOUT: {kind: 'NameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithoutParams', text: '.', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes},
// CHECK:STDOUT: {kind: 'ExportDecl', text: ';', has_error: yes, subtree_size: 5},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
+24 -8
View File
@@ -131,13 +131,19 @@ using EmptyDecl =
// to be followed by parameters.
using IdentifierNameBeforeParams =
LeafNode<NodeKind::IdentifierNameBeforeParams, Lex::IdentifierTokenIndex,
NodeCategory::MemberName | NodeCategory::NonExprIdentifierName>;
NodeCategory::MemberName | NodeCategory::NonExprName>;
using KeywordNameBeforeParams =
LeafNode<NodeKind::KeywordNameBeforeParams, Lex::TokenIndex,
NodeCategory::MemberName | NodeCategory::NonExprName>;
// A name in a non-expression context, such as a declaration, that is known
// to not be followed by parameters.
using IdentifierNameNotBeforeParams =
LeafNode<NodeKind::IdentifierNameNotBeforeParams, Lex::IdentifierTokenIndex,
NodeCategory::MemberName | NodeCategory::NonExprIdentifierName>;
NodeCategory::MemberName | NodeCategory::NonExprName>;
using KeywordNameNotBeforeParams =
LeafNode<NodeKind::KeywordNameNotBeforeParams, Lex::TokenIndex,
NodeCategory::MemberName | NodeCategory::NonExprName>;
// A name in an expression context.
using IdentifierNameExpr =
@@ -174,21 +180,31 @@ struct NameQualifierWithParams {
};
// A name qualifier without parameters, such as `A.`.
struct NameQualifierWithoutParams {
static constexpr auto Kind = NodeKind::NameQualifierWithoutParams.Define(
{.bracketed_by = IdentifierNameNotBeforeParams::Kind});
struct IdentifierNameQualifierWithoutParams {
static constexpr auto Kind =
NodeKind::IdentifierNameQualifierWithoutParams.Define(
{.bracketed_by = IdentifierNameNotBeforeParams::Kind});
IdentifierNameNotBeforeParamsId name;
Lex::PeriodTokenIndex token;
};
struct KeywordNameQualifierWithoutParams {
static constexpr auto Kind =
NodeKind::KeywordNameQualifierWithoutParams.Define(
{.bracketed_by = KeywordNameNotBeforeParams::Kind});
KeywordNameNotBeforeParamsId name;
Lex::PeriodTokenIndex token;
};
// A complete name in a declaration: `A.C(T:! type).F(n: i32)`.
// Note that this includes the parameters of the entity itself.
struct DeclName {
llvm::SmallVector<
NodeIdOneOf<NameQualifierWithParams, NameQualifierWithoutParams>>
NodeIdOneOf<NameQualifierWithParams, IdentifierNameQualifierWithoutParams,
KeywordNameQualifierWithoutParams>>
qualifiers;
AnyNonExprIdentifierNameId name;
AnyNonExprNameId name;
std::optional<ImplicitParamListId> implicit_params;
std::optional<ExplicitParamListId> params;
};
@@ -1157,7 +1173,7 @@ struct ChoiceDefinition {
ChoiceDefinitionStartId signature;
struct Alternative {
AnyNonExprIdentifierNameId name;
AnyNonExprNameId name;
std::optional<ExplicitParamListId> parameters;
};
CommaSeparatedList<Alternative, ChoiceAlternativeListCommaId> alternatives;
+3 -3
View File
@@ -290,10 +290,10 @@ Optional [^:]*: found
Optional [^:]*: begin
NodeIdForKind error: wrong kind IdentifierNameBeforeParams, expected ImplicitParamList
Optional [^:]*: missing
NodeIdInCategory NonExprIdentifierName: kind IdentifierNameBeforeParams consumed
NodeIdInCategory NonExprName: kind IdentifierNameBeforeParams consumed
Vector: begin
NodeIdOneOf NameQualifierWithParams or NameQualifierWithoutParams: NameQualifierWithoutParams consumed
NodeIdOneOf error: wrong kind AbstractModifier, expected NameQualifierWithParams or NameQualifierWithoutParams
NodeIdOneOf NameQualifierWithParams or IdentifierNameQualifierWithoutParams or KeywordNameQualifierWithoutParams: IdentifierNameQualifierWithoutParams consumed
NodeIdOneOf error: wrong kind AbstractModifier, expected NameQualifierWithParams or IdentifierNameQualifierWithoutParams or KeywordNameQualifierWithoutParams
Vector: end
Aggregate [^:]*: success
Vector: begin