Skip to content

Commit

Permalink
Refactor state construction and change how the decl loop makes state. (
Browse files Browse the repository at this point in the history
…carbon-language#3467)

Building on carbon-language#3463. The PushState+PopState to construct a state feels
worth cleanup. The rest is just kind of making it easier to do without
adding another PushState overload.
  • Loading branch information
jonmeow committed Dec 8, 2023
1 parent 3b0923c commit 5007153
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 58 deletions.
39 changes: 14 additions & 25 deletions toolchain/parse/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,6 @@ class Context {

// Used to track state on state_stack_.
struct StateStackEntry : public Printable<StateStackEntry> {
explicit StateStackEntry(State state, PrecedenceGroup ambient_precedence,
PrecedenceGroup lhs_precedence,
Lex::TokenIndex token, int32_t subtree_start)
: state(state),
ambient_precedence(ambient_precedence),
lhs_precedence(lhs_precedence),
token(token),
subtree_start(subtree_start) {}

// Prints state information for verbose output.
auto Print(llvm::raw_ostream& output) const -> void {
output << state << " @" << token << " subtree_start=" << subtree_start
Expand All @@ -77,8 +68,8 @@ class Context {
// operator precedence. The ambient_precedence deals with how the expression
// should interact with outside context, while the lhs_precedence is
// specific to the lhs of an operator expression.
PrecedenceGroup ambient_precedence;
PrecedenceGroup lhs_precedence;
PrecedenceGroup ambient_precedence = PrecedenceGroup::ForTopLevelExpr();
PrecedenceGroup lhs_precedence = PrecedenceGroup::ForTopLevelExpr();

// A token providing context based on the subtree. This will typically be
// the first token in the subtree, but may sometimes be a token within. It
Expand Down Expand Up @@ -248,32 +239,30 @@ class Context {
}

// Pushes a new state with the current position for context.
auto PushState(State state) -> void {
PushState(StateStackEntry(state, PrecedenceGroup::ForTopLevelExpr(),
PrecedenceGroup::ForTopLevelExpr(), *position_,
tree_->size()));
}
auto PushState(State state) -> void { PushState(state, *position_); }

// Pushes a new state with a specific token for context. Used when forming a
// new subtree with a token that isn't the start of the subtree.
// new subtree when the current position isn't the start of the subtree.
auto PushState(State state, Lex::TokenIndex token) -> void {
PushState(StateStackEntry(state, PrecedenceGroup::ForTopLevelExpr(),
PrecedenceGroup::ForTopLevelExpr(), token,
tree_->size()));
PushState({.state = state, .token = token, .subtree_start = tree_->size()});
}

// Pushes a new expression state with specific precedence.
auto PushStateForExpr(PrecedenceGroup ambient_precedence) -> void {
PushState(StateStackEntry(State::Expr, ambient_precedence,
PrecedenceGroup::ForTopLevelExpr(), *position_,
tree_->size()));
PushState({.state = State::Expr,
.ambient_precedence = ambient_precedence,
.token = *position_,
.subtree_start = tree_->size()});
}

// Pushes a new state with detailed precedence for expression resume states.
auto PushStateForExprLoop(State state, PrecedenceGroup ambient_precedence,
PrecedenceGroup lhs_precedence) -> void {
PushState(StateStackEntry(state, ambient_precedence, lhs_precedence,
*position_, tree_->size()));
PushState({.state = state,
.ambient_precedence = ambient_precedence,
.lhs_precedence = lhs_precedence,
.token = *position_,
.subtree_start = tree_->size()});
}

// Pushes a constructed state onto the stack.
Expand Down
12 changes: 6 additions & 6 deletions toolchain/parse/handle_binding_pattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ auto HandleBindingPattern(Context& context) -> void {
// Parameters may have keywords prefixing the pattern. They become the parent
// for the full BindingPattern.
if (auto token = context.ConsumeIf(Lex::TokenKind::Template)) {
context.PushState(Context::StateStackEntry(
State::BindingPatternTemplate, PrecedenceGroup::ForTopLevelExpr(),
PrecedenceGroup::ForTopLevelExpr(), *token, state.subtree_start));
context.PushState({.state = State::BindingPatternTemplate,
.token = *token,
.subtree_start = state.subtree_start});
}

if (auto token = context.ConsumeIf(Lex::TokenKind::Addr)) {
context.PushState(Context::StateStackEntry(
State::BindingPatternAddress, PrecedenceGroup::ForTopLevelExpr(),
PrecedenceGroup::ForTopLevelExpr(), *token, state.subtree_start));
context.PushState({.state = State::BindingPatternAddress,
.token = *token,
.subtree_start = state.subtree_start});
}

// Handle an invalid pattern introducer for parameters and variables.
Expand Down
57 changes: 31 additions & 26 deletions toolchain/parse/handle_decl_scope_loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,26 @@ static auto HandleUnrecognizedDecl(Context& context, int32_t subtree_start)
FinishAndSkipInvalidDecl(context, subtree_start);
}

// Replaces the introducer placeholder node, and pushes the introducer state for
// processing.
static auto ApplyIntroducer(Context& context, Context::StateStackEntry state,
NodeKind introducer_kind, State next_state)
-> void {
context.ReplacePlaceholderNode(state.subtree_start, introducer_kind,
context.Consume());
// Reuse state here to retain its `subtree_start`.
state.state = next_state;
context.PushState(state);
}

// Handles `base` as a declaration.
static auto HandleBaseAsDecl(Context& context, Context::StateStackEntry state)
-> void {
// At this point, `base` has been ruled out as a modifier (`base class`). If
// it's followed by a colon, it's an introducer (`extend base: BaseType;`).
// Otherwise it's an error.
if (context.PositionIs(Lex::TokenKind::Colon, Lookahead::NextToken)) {
context.ReplacePlaceholderNode(state.subtree_start,
NodeKind::BaseIntroducer, context.Consume());
// Reuse state here to retain its `subtree_start`
state.state = State::BaseDecl;
context.PushState(state);
ApplyIntroducer(context, state, NodeKind::BaseIntroducer, State::BaseDecl);
context.PushState(State::Expr);
context.AddLeafNode(NodeKind::BaseColon, context.Consume());
} else {
Expand All @@ -109,26 +117,19 @@ static auto HandleBaseAsDecl(Context& context, Context::StateStackEntry state)
// to a state to parse the rest of the declaration.
static auto TryHandleAsDecl(Context& context, Context::StateStackEntry state,
bool saw_modifier) -> bool {
auto introducer = [&](NodeKind node_kind, State next_state) {
context.ReplacePlaceholderNode(state.subtree_start, node_kind,
context.Consume());
// Reuse state here to retain its `subtree_start`.
state.state = next_state;
context.PushState(state);
};

switch (context.PositionKind()) {
case Lex::TokenKind::Base: {
HandleBaseAsDecl(context, state);
return true;
}
case Lex::TokenKind::Class: {
introducer(NodeKind::ClassIntroducer, State::TypeAfterIntroducerAsClass);
ApplyIntroducer(context, state, NodeKind::ClassIntroducer,
State::TypeAfterIntroducerAsClass);
return true;
}
case Lex::TokenKind::Constraint: {
introducer(NodeKind::NamedConstraintIntroducer,
State::TypeAfterIntroducerAsNamedConstraint);
ApplyIntroducer(context, state, NodeKind::NamedConstraintIntroducer,
State::TypeAfterIntroducerAsNamedConstraint);
return true;
}
case Lex::TokenKind::Extend: {
Expand All @@ -137,7 +138,8 @@ static auto TryHandleAsDecl(Context& context, Context::StateStackEntry state,
return true;
}
case Lex::TokenKind::Fn: {
introducer(NodeKind::FunctionIntroducer, State::FunctionIntroducer);
ApplyIntroducer(context, state, NodeKind::FunctionIntroducer,
State::FunctionIntroducer);
return true;
}
case Lex::TokenKind::Impl: {
Expand All @@ -146,20 +148,22 @@ static auto TryHandleAsDecl(Context& context, Context::StateStackEntry state,
return true;
}
case Lex::TokenKind::Interface: {
introducer(NodeKind::InterfaceIntroducer,
State::TypeAfterIntroducerAsInterface);
ApplyIntroducer(context, state, NodeKind::InterfaceIntroducer,
State::TypeAfterIntroducerAsInterface);
return true;
}
case Lex::TokenKind::Namespace: {
introducer(NodeKind::NamespaceStart, State::Namespace);
ApplyIntroducer(context, state, NodeKind::NamespaceStart,
State::Namespace);
return true;
}
case Lex::TokenKind::Let: {
introducer(NodeKind::LetIntroducer, State::Let);
ApplyIntroducer(context, state, NodeKind::LetIntroducer, State::Let);
return true;
}
case Lex::TokenKind::Var: {
introducer(NodeKind::VariableIntroducer, State::VarAsDecl);
ApplyIntroducer(context, state, NodeKind::VariableIntroducer,
State::VarAsDecl);
return true;
}

Expand Down Expand Up @@ -243,10 +247,11 @@ auto HandleDeclScopeLoop(Context& context) -> void {
return;
}

// Create a state with the correct starting position, with a dummy kind until
// we see the declaration's introducer.
context.PushState(State::DeclScopeLoop);
auto state = context.PopState();
// Create a state with the correct starting position, with a dummy kind
// until we see the declaration's introducer.
Context::StateStackEntry state{.state = State::Invalid,
.token = *context.position(),
.subtree_start = context.tree().size()};

// Add a placeholder node, to be replaced by the declaration introducer once
// it is found.
Expand Down
7 changes: 6 additions & 1 deletion toolchain/parse/state.def
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
CARBON_PARSE_STATE_VARIANT(State, Variant1) \
CARBON_PARSE_STATE_VARIANTS3(State, Variant2, Variant3, Variant4)

// Used as a default for StateStackEntry initialization in some cases. Should
// not be put on the state stack.
CARBON_PARSE_STATE(Invalid)

// Handles an index expression:
//
// a[0]
Expand Down Expand Up @@ -1039,7 +1043,8 @@ CARBON_PARSE_STATE_VARIANTS3(TypeDefinitionFinish, Class, Interface,
// ^
// 1. DeclNameAndParamsAsOptional
// 2. TypeAfterParamsAs(Class|Interface|NamedConstraint)
CARBON_PARSE_STATE_VARIANTS3(TypeAfterIntroducer, Class, Interface, NamedConstraint)
CARBON_PARSE_STATE_VARIANTS3(TypeAfterIntroducer, Class, Interface,
NamedConstraint)

// Handles processing of a type after its optional parameters.
//
Expand Down
5 changes: 5 additions & 0 deletions toolchain/parse/tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@

namespace Carbon::Parse {

auto HandleInvalid(Context& context) -> void {
CARBON_FATAL() << "The Invalid state shouldn't be on the stack: "
<< context.PopState();
}

auto Tree::Parse(Lex::TokenizedBuffer& tokens, DiagnosticConsumer& consumer,
llvm::raw_ostream* vlog_stream) -> Tree {
Lex::TokenLocationTranslator translator(&tokens);
Expand Down

0 comments on commit 5007153

Please sign in to comment.