tamer: asg::air::tpl: Refactor TplEndRef parsing

This removes the token of lookahead and just does what needs to be done in a
more clear manner.  There is no room for interpretation in what this is
doing now, and `TplEnd` delegates to `close` just as this does.

DEV-13163
main
Mike Gerwitz 2023-08-01 10:43:51 -04:00
parent 9f74c0fc92
commit d42c5584d0
2 changed files with 24 additions and 15 deletions

View File

@ -121,14 +121,18 @@ impl TplState {
/// This updates the span of the template to encompass the entire /// This updates the span of the template to encompass the entire
/// definition, /// definition,
/// even if an error occurs. /// even if an error occurs.
fn close(self, asg: &mut Asg, close_span: Span) -> Result<(), AsgError> { fn close(
self,
asg: &mut Asg,
close_span: Span,
) -> Result<ObjectIndex<Tpl>, AsgError> {
let oi = self.oi().close(asg, close_span); let oi = self.oi().close(asg, close_span);
match self { match self {
Self::Dangling(_) => { Self::Dangling(_) => {
Err(AsgError::DanglingTpl(oi.resolve(asg).span())) Err(AsgError::DanglingTpl(oi.resolve(asg).span()))
} }
Self::AnonymousReachable(..) | Self::Identified(..) => Ok(()), Self::AnonymousReachable(..) | Self::Identified(..) => Ok(oi),
} }
} }
} }
@ -218,25 +222,31 @@ impl ParseState for AirTplAggregate {
.transition(Toplevel(tpl)), .transition(Toplevel(tpl)),
(Toplevel(tpl), AirTpl(TplEnd(span))) => { (Toplevel(tpl), AirTpl(TplEnd(span))) => {
tpl.close(ctx.asg_mut(), span).transition(Done) tpl.close(ctx.asg_mut(), span).map(|_| ()).transition(Done)
} }
(Toplevel(tpl), AirTpl(TplEndRef(span))) => { (Toplevel(tpl), AirTpl(TplEndRef(span))) => {
// Note that we utilize lookahead in either case,
// but in the case of an error,
// we are effectively discarding the ref and translating
// into a `TplEnd`.
match ctx.expansion_oi() { match ctx.expansion_oi() {
// The template will be the equivalent of `TplEnd`'d
// before `IdentRef`'d,
// to ensure the definition has been completed.
Some(oi_target) => tpl Some(oi_target) => tpl
.oi() .anonymous_reachable()
.close(ctx.asg_mut(), span) .close(ctx.asg_mut(), span)
.expand_into(ctx.asg_mut(), oi_target) .and_then(|oi| oi.expand_into(ctx.asg_mut(), oi_target))
.map(|_| ()) .map(|_| ())
.transition(Toplevel(tpl.anonymous_reachable())), .transition(Done),
None => Transition(Toplevel(tpl))
.err(AsgError::InvalidExpansionContext(span)), // An invalid context will act as a `TplEnd`,
// effectively discarding the `Ref` part of the token.
None => tpl
.anonymous_reachable()
.close(ctx.asg_mut(), span)
.and(Err::<(), _>(AsgError::InvalidExpansionContext(
span,
)))
.transition(Done),
} }
.with_lookahead(AirTpl(TplEnd(span)))
} }
// If we just finished a template then this end may represent // If we just finished a template then this end may represent

View File

@ -357,8 +357,7 @@ fn tpl_inner_apply_expr_alongside_another_apply_expr() {
) )
)), )),
// RECOVERY: We ignore the template by not adding the edge. // RECOVERY: We ignore the template by not adding the edge.
Ok(Parsed::Incomplete), // TplEnd >LA Ok(Parsed::Incomplete), // TplEnd
Ok(Parsed::Incomplete), // TplEnd <LA
Ok(Parsed::Incomplete), // PkgEnd Ok(Parsed::Incomplete), // PkgEnd
], ],
sut.by_ref().collect::<Vec<_>>(), sut.by_ref().collect::<Vec<_>>(),