Skip to content

Commit

Permalink
Parsing impl...as (carbon-language#3473)
Browse files Browse the repository at this point in the history
Co-authored-by: Jon Ross-Perkins <[email protected]>
  • Loading branch information
josh11b and jonmeow committed Dec 9, 2023
1 parent c4864aa commit 5f439b8
Show file tree
Hide file tree
Showing 19 changed files with 650 additions and 116 deletions.
34 changes: 34 additions & 0 deletions toolchain/check/handle_impl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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"

namespace Carbon::Check {

auto HandleImplIntroducer(Context& context, Parse::NodeId parse_node) -> bool {
return context.TODO(parse_node, "HandleImplIntroducer");
}

auto HandleImplForall(Context& context, Parse::NodeId parse_node) -> bool {
return context.TODO(parse_node, "HandleImplForall");
}

auto HandleImplAs(Context& context, Parse::NodeId parse_node) -> bool {
return context.TODO(parse_node, "HandleImplAs");
}

auto HandleImplDecl(Context& context, Parse::NodeId parse_node) -> bool {
return context.TODO(parse_node, "HandleImplDecl");
}

auto HandleImplDefinitionStart(Context& context, Parse::NodeId parse_node)
-> bool {
return context.TODO(parse_node, "HandleImplDefinitionStart");
}

auto HandleImplDefinition(Context& context, Parse::NodeId parse_node) -> bool {
return context.TODO(parse_node, "HandleImplDefinition");
}

} // namespace Carbon::Check
12 changes: 11 additions & 1 deletion toolchain/check/handle_name.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,14 @@ static auto GetExprValueForLookupResult(Context& context,
return context.types().GetInstId(
context.classes().Get(class_decl->class_id).self_type_id);
}
if (auto interface_decl = lookup_result.TryAs<SemIR::InterfaceDecl>()) {
// TODO: unimplemented
return SemIR::InstId::Invalid;
}

// Anything else should be a typed value already.
CARBON_CHECK(lookup_result.kind().value_kind() == SemIR::InstValueKind::Typed)
<< "Unexpected kind for lookup result";
<< "Unexpected kind for lookup result, " << lookup_result;
return lookup_result_id;
}

Expand Down Expand Up @@ -81,6 +85,9 @@ auto HandleMemberAccessExpr(Context& context, Parse::NodeId parse_node)
? context.LookupQualifiedName(parse_node, name_id, *name_scope_id)
: SemIR::InstId::BuiltinError;
inst_id = GetExprValueForLookupResult(context, inst_id);
if (!inst_id.is_valid()) {
return context.TODO(parse_node, "Unimplemented use of interface");
}
auto inst = context.insts().Get(inst_id);
// TODO: Track that this instruction was named within `base_id`.
context.AddInstAndPush(
Expand Down Expand Up @@ -246,6 +253,9 @@ static auto HandleNameAsExpr(Context& context, Parse::NodeId parse_node,
SemIR::NameId name_id) -> bool {
auto value_id = context.LookupUnqualifiedName(parse_node, name_id);
value_id = GetExprValueForLookupResult(context, value_id);
if (!value_id.is_valid()) {
return context.TODO(parse_node, "Unimplemented use of interface");
}
auto value = context.insts().Get(value_id);
context.AddInstAndPush(parse_node, SemIR::NameRef{parse_node, value.type_id(),
name_id, value_id});
Expand Down
2 changes: 2 additions & 0 deletions toolchain/diagnostics/diagnostic_kind.def
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ CARBON_DIAGNOSTIC_KIND(ExpectedInitializerAfterLet)
CARBON_DIAGNOSTIC_KIND(ParamsRequiredAfterImplicit)
CARBON_DIAGNOSTIC_KIND(ParamsRequiredByIntroducer)
CARBON_DIAGNOSTIC_KIND(ExpectedAfterBase)
CARBON_DIAGNOSTIC_KIND(ImplExpectedAfterForall)
CARBON_DIAGNOSTIC_KIND(ImplExpectedAs)

// ============================================================================
// Semantics diagnostics
Expand Down
90 changes: 90 additions & 0 deletions toolchain/parse/handle_decl_definition.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// 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/parse/context.h"

namespace Carbon::Parse {

// Handles processing after params, deciding whether it's a declaration or
// definition.
static auto HandleDeclOrDefinition(Context& context, NodeKind decl_kind,
NodeKind definition_start_kind,
State definition_finish_state) -> void {
auto state = context.PopState();

if (state.has_error) {
context.RecoverFromDeclError(state, decl_kind,
/*skip_past_likely_end=*/true);
return;
}

if (auto semi = context.ConsumeIf(Lex::TokenKind::Semi)) {
context.AddNode(decl_kind, *semi, state.subtree_start, state.has_error);
return;
}

if (!context.PositionIs(Lex::TokenKind::OpenCurlyBrace)) {
context.EmitExpectedDeclSemiOrDefinition(
context.tokens().GetKind(state.token));
context.RecoverFromDeclError(state, decl_kind,
/*skip_past_likely_end=*/true);
return;
}

context.PushState(state, definition_finish_state);
context.PushState(State::DeclScopeLoop);
context.AddNode(definition_start_kind, context.Consume(), state.subtree_start,
state.has_error);
}

auto HandleDeclOrDefinitionAsClass(Context& context) -> void {
HandleDeclOrDefinition(context, NodeKind::ClassDecl,
NodeKind::ClassDefinitionStart,
State::DeclDefinitionFinishAsClass);
}

auto HandleDeclOrDefinitionAsImpl(Context& context) -> void {
HandleDeclOrDefinition(context, NodeKind::ImplDecl,
NodeKind::ImplDefinitionStart,
State::DeclDefinitionFinishAsImpl);
}

auto HandleDeclOrDefinitionAsInterface(Context& context) -> void {
HandleDeclOrDefinition(context, NodeKind::InterfaceDecl,
NodeKind::InterfaceDefinitionStart,
State::DeclDefinitionFinishAsInterface);
}

auto HandleDeclOrDefinitionAsNamedConstraint(Context& context) -> void {
HandleDeclOrDefinition(context, NodeKind::NamedConstraintDecl,
NodeKind::NamedConstraintDefinitionStart,
State::DeclDefinitionFinishAsNamedConstraint);
}

// Handles parsing after the declaration scope of a type.
static auto HandleDeclDefinitionFinish(Context& context,
NodeKind definition_kind) -> void {
auto state = context.PopState();

context.AddNode(definition_kind, context.Consume(), state.subtree_start,
state.has_error);
}

auto HandleDeclDefinitionFinishAsClass(Context& context) -> void {
HandleDeclDefinitionFinish(context, NodeKind::ClassDefinition);
}

auto HandleDeclDefinitionFinishAsImpl(Context& context) -> void {
HandleDeclDefinitionFinish(context, NodeKind::ImplDefinition);
}

auto HandleDeclDefinitionFinishAsInterface(Context& context) -> void {
HandleDeclDefinitionFinish(context, NodeKind::InterfaceDefinition);
}

auto HandleDeclDefinitionFinishAsNamedConstraint(Context& context) -> void {
HandleDeclDefinitionFinish(context, NodeKind::NamedConstraintDefinition);
}

} // namespace Carbon::Parse
4 changes: 2 additions & 2 deletions toolchain/parse/handle_decl_scope_loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ static auto TryHandleAsDecl(Context& context, Context::StateStackEntry state,
return true;
}
case Lex::TokenKind::Impl: {
// TODO: Treat this `impl` token as a declaration introducer
HandleUnrecognizedDecl(context, state.subtree_start);
ApplyIntroducer(context, state, NodeKind::ImplIntroducer,
State::ImplAfterIntroducer);
return true;
}
case Lex::TokenKind::Interface: {
Expand Down
79 changes: 79 additions & 0 deletions toolchain/parse/handle_impl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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/parse/context.h"

namespace Carbon::Parse {

static auto ExpectAsOrTypeExpression(Carbon::Parse::Context& context) -> void {
if (context.PositionIs(Lex::TokenKind::As)) {
// as <expression> ...
context.AddLeafNode(NodeKind::ImplAs, context.Consume());
context.PushState(State::Expr);
} else {
// <expression> as <expression>...
context.PushState(State::ImplBeforeAs);
context.PushStateForExpr(PrecedenceGroup::ForImplAs());
}
}

auto HandleImplAfterIntroducer(Carbon::Parse::Context& context) -> void {
auto state = context.PopState();
state.state = State::DeclOrDefinitionAsImpl;
context.PushState(state);

if (context.PositionIs(Lex::TokenKind::Forall)) {
// forall [<implicit parameter list>] ...
context.PushState(State::ImplAfterForall);
context.ConsumeAndDiscard();
if (context.PositionIs(Lex::TokenKind::OpenSquareBracket)) {
context.PushState(State::PatternListAsImplicit);
} else {
CARBON_DIAGNOSTIC(ImplExpectedAfterForall, Error,
"Expected `[` after `forall` in `impl` declaration.");
context.emitter().Emit(*context.position(), ImplExpectedAfterForall);
context.ReturnErrorOnState();
}
} else {
// One of:
// as <expression> ...
// <expression> as <expression>...
ExpectAsOrTypeExpression(context);
}
}

auto HandleImplAfterForall(Carbon::Parse::Context& context) -> void {
auto state = context.PopState();
if (state.has_error) {
context.AddLeafNode(NodeKind::InvalidParse, *context.position(),
/*has_error=*/true);
context.ReturnErrorOnState();
}
context.AddNode(NodeKind::ImplForall, state.token, state.subtree_start,
state.has_error);

// One of:
// as <expression> ...
// <expression> as <expression>...
ExpectAsOrTypeExpression(context);
}

auto HandleImplBeforeAs(Carbon::Parse::Context& context) -> void {
auto state = context.PopState();
if (state.has_error) {
context.ReturnErrorOnState();
return;
}
if (auto as = context.ConsumeIf(Lex::TokenKind::As)) {
context.AddLeafNode(NodeKind::ImplAs, *as);
context.PushState(State::Expr);
} else {
CARBON_DIAGNOSTIC(ImplExpectedAs, Error,
"Expected `as` in `impl` declaration.");
context.emitter().Emit(*context.position(), ImplExpectedAs);
context.ReturnErrorOnState();
}
}

} // namespace Carbon::Parse
77 changes: 3 additions & 74 deletions toolchain/parse/handle_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,86 +15,15 @@ static auto HandleTypeAfterIntroducer(Context& context,
}

auto HandleTypeAfterIntroducerAsClass(Context& context) -> void {
HandleTypeAfterIntroducer(context, State::TypeAfterParamsAsClass);
HandleTypeAfterIntroducer(context, State::DeclOrDefinitionAsClass);
}

auto HandleTypeAfterIntroducerAsInterface(Context& context) -> void {
HandleTypeAfterIntroducer(context, State::TypeAfterParamsAsInterface);
HandleTypeAfterIntroducer(context, State::DeclOrDefinitionAsInterface);
}

auto HandleTypeAfterIntroducerAsNamedConstraint(Context& context) -> void {
HandleTypeAfterIntroducer(context, State::TypeAfterParamsAsNamedConstraint);
}

// Handles processing after params, deciding whether it's a declaration or
// definition.
static auto HandleTypeAfterParams(Context& context, NodeKind decl_kind,
NodeKind definition_start_kind,
State definition_finish_state) -> void {
auto state = context.PopState();

if (state.has_error) {
context.RecoverFromDeclError(state, decl_kind,
/*skip_past_likely_end=*/true);
return;
}

if (auto semi = context.ConsumeIf(Lex::TokenKind::Semi)) {
context.AddNode(decl_kind, *semi, state.subtree_start, state.has_error);
return;
}

if (!context.PositionIs(Lex::TokenKind::OpenCurlyBrace)) {
context.EmitExpectedDeclSemiOrDefinition(
context.tokens().GetKind(state.token));
context.RecoverFromDeclError(state, decl_kind,
/*skip_past_likely_end=*/true);
return;
}

context.PushState(state, definition_finish_state);
context.PushState(State::DeclScopeLoop);
context.AddNode(definition_start_kind, context.Consume(), state.subtree_start,
state.has_error);
}

auto HandleTypeAfterParamsAsClass(Context& context) -> void {
HandleTypeAfterParams(context, NodeKind::ClassDecl,
NodeKind::ClassDefinitionStart,
State::TypeDefinitionFinishAsClass);
}

auto HandleTypeAfterParamsAsInterface(Context& context) -> void {
HandleTypeAfterParams(context, NodeKind::InterfaceDecl,
NodeKind::InterfaceDefinitionStart,
State::TypeDefinitionFinishAsInterface);
}

auto HandleTypeAfterParamsAsNamedConstraint(Context& context) -> void {
HandleTypeAfterParams(context, NodeKind::NamedConstraintDecl,
NodeKind::NamedConstraintDefinitionStart,
State::TypeDefinitionFinishAsNamedConstraint);
}

// Handles parsing after the declaration scope of a type.
static auto HandleTypeDefinitionFinish(Context& context,
NodeKind definition_kind) -> void {
auto state = context.PopState();

context.AddNode(definition_kind, context.Consume(), state.subtree_start,
state.has_error);
}

auto HandleTypeDefinitionFinishAsClass(Context& context) -> void {
HandleTypeDefinitionFinish(context, NodeKind::ClassDefinition);
}

auto HandleTypeDefinitionFinishAsInterface(Context& context) -> void {
HandleTypeDefinitionFinish(context, NodeKind::InterfaceDefinition);
}

auto HandleTypeDefinitionFinishAsNamedConstraint(Context& context) -> void {
HandleTypeDefinitionFinish(context, NodeKind::NamedConstraintDefinition);
HandleTypeAfterIntroducer(context, State::DeclOrDefinitionAsNamedConstraint);
}

} // namespace Carbon::Parse
29 changes: 29 additions & 0 deletions toolchain/parse/node_kind.def
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,35 @@ CARBON_PARSE_NODE_KIND_BRACKET(InterfaceDecl, InterfaceIntroducer,
CARBON_TOKEN(Semi)
CARBON_IF_ERROR(CARBON_TOKEN(Interface)))

// `impl ... as`:
// ImplIntroducer
// _repeated_ _external_: modifier
// _optional_ ImplForall (see below)
// _optional_ _external_: expression
// ImplAs
// _external_: expression
// ImplDefinitionStart
// _external_: declarations
// ImplDefinition
//
// The above is the structure for a definition; for a declaration,
// ImplDefinitionStart and later nodes are removed and replaced by
// ImplDecl.
CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplIntroducer, 0, CARBON_TOKEN(Impl))

// `forall ...`:
// _external_: ImplicitParamList
// ImplForall
CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplForall, 1, CARBON_TOKEN(Forall))
CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplAs, 0, CARBON_TOKEN(As))
CARBON_PARSE_NODE_KIND_BRACKET(ImplDefinitionStart, ImplIntroducer,
CARBON_TOKEN(OpenCurlyBrace))
CARBON_PARSE_NODE_KIND_BRACKET(ImplDefinition, ImplDefinitionStart,
CARBON_TOKEN(CloseCurlyBrace))
CARBON_PARSE_NODE_KIND_BRACKET(ImplDecl, ImplIntroducer,
CARBON_TOKEN(Semi)
CARBON_IF_ERROR(CARBON_ANY_TOKEN))

// `constraint`:
// NamedConstraintIntroducer
// _repeated_ _external_: modifier
Expand Down
4 changes: 4 additions & 0 deletions toolchain/parse/precedence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ auto PrecedenceGroup::ForExprStatement() -> PrecedenceGroup {

auto PrecedenceGroup::ForType() -> PrecedenceGroup { return ForTopLevelExpr(); }

auto PrecedenceGroup::ForImplAs() -> PrecedenceGroup {
return PrecedenceGroup(As);
}

auto PrecedenceGroup::ForLeading(Lex::TokenKind kind)
-> std::optional<PrecedenceGroup> {
switch (kind) {
Expand Down
Loading

0 comments on commit 5f439b8

Please sign in to comment.