We were not correctly detecting EOF while parsing template expressions. Explicit EOF checking was based only on Lexer exhaustion, but that didn't account for the "current" token or the "push back" token. To complicate matters, when using the matching/peeking parsing helper methods, the parser will add a fake token (a closing curly brace) when EOF is encountered, so that deeply nested parsing code doesn't have to have to handle the repercussions of EOF until it comes back out from its deep recursion. Once we corrected the explicit EOF check to account for the current and push-back tokens, the pseudo token then obscured the EOF state, so we had to account for that as well. As a side-effect of fixing this, we uncovered an ancient syntax error (cut & pasted a half dozen times) in one of our tests. All fixed now.
We were not correctly detecting EOF while parsing template expressions. Explicit EOF checking was based only on Lexer exhaustion, but that didn't account for the "current" token or the "push back" token. To complicate matters, when using the matching/peeking parsing helper methods, the parser will add a fake token (a closing curly brace) when EOF is encountered, so that deeply nested parsing code doesn't have to have to handle the repercussions of EOF until it comes back out from its deep recursion. Once we corrected the explicit EOF check to account for the current and push-back tokens, the pseudo token then obscured the EOF state, so we had to account for that as well. As a side-effect of fixing this, we uncovered an ancient syntax error (cut & pasted a half dozen times) in one of our tests. All fixed now.