On Mon, Jul 01, 2024 at 08:51:45PM -0400, Jeff King wrote: > Hmm. The patch below seems to work on a simple test. > > The lexer stuffs the heredoc into a special variable. Which at first > glance feels like a hack versus returning it from the token stream, but > the contents really _aren't_ part of that stream. They're a separate > magic thing that is found on the stdin of whatever command the tokens > represent. > > And then ScriptParser::parse_cmd() just has to recognize that any "<<" > token isn't interesting, and that "-" means "read the here-doc". BTW, there's one non-obvious thing here about why this works. You'd think that: test_expect_success 'foo' <<\EOT cat <<-\EOF this is a here-doc EOF echo ok EOT wouldn't work, because the lexer only has a single here-doc store, and the inner one is going to overwrite the outer. But we don't lex the inner contents of the test snippet until we've processed the test_expect_success line, at which point we've copied it out. So I dunno. It feels a bit hacky, but I think it's how you have to do it anyway. > @@ -648,7 +654,7 @@ sub parse_cmd { > my @tokens = $self->SUPER::parse_cmd(); > return @tokens unless @tokens && $tokens[0]->[0] =~ /^test_expect_(?:success|failure)$/; > my $n = $#tokens; > - $n-- while $n >= 0 && $tokens[$n]->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/; > + $n-- while $n >= 0 && $tokens[$n]->[0] =~ /^(?:[;&\n|]|&&|\|\||<<[A-Za-z]+)$/; One curiosity I noted is that the backslash of my "<<\EOT" seems to be eaten by the lexer (I guess because it doesn't know the special meaning of backslash here, and just does the usual "take the next char literally"). I think that is OK for our purposes here, though we might in the long run want to raise a linting error if you accidentally used an interpolating here-doc (it's not strictly wrong to do so, but I think we generally frown on it as a style thing). -Peff