@@ -8,10 +8,9 @@ package parser
88// SCOPE: this is a TOKEN-STREAM snapshot, not a complete parser/lexer
99// snapshot. It does NOT cover mid-token-content lexer state (literalbuf,
1010// dolqstart, utf16FirstPart, xcdepth, stateBeforeStrStop, warning flags)
11- // or completion-mode state (candidates, collecting). Those fields are
12- // either reset at token boundaries (lexer internals) or not used during
13- // speculative parses (completion mode), so they don't need to be saved
14- // here for token-stream rollback to be sound.
11+ // or completion-mode state (candidates, collecting). Lexer internals are
12+ // reset at token boundaries. Completion-mode speculative callers that can
13+ // scan past the cursor should use snapshotTokenStreamAndCompletion.
1514//
1615// If a future caller needs to roll back from INSIDE a token (e.g., from
1716// inside a string literal or dollar-quoted block), this struct is
@@ -42,6 +41,13 @@ type tokenStreamState struct {
4241 lexerState LexerState
4342}
4443
44+ type tokenStreamAndCompletionState struct {
45+ tokenStream tokenStreamState
46+ collecting bool
47+ collectDepth int
48+ candidates * CandidateSet
49+ }
50+
4551// snapshotTokenStream captures the current token-stream position for
4652// later restoration via restoreTokenStream. See tokenStreamState for
4753// scope and limitations.
@@ -58,16 +64,31 @@ func (p *Parser) snapshotTokenStream() tokenStreamState {
5864 }
5965}
6066
67+ // snapshotTokenStreamAndCompletion captures token-stream state plus the
68+ // completion state that advance() can mutate when a speculative walk crosses
69+ // the cursor. Use this for completion-mode lookahead that can scan arbitrary
70+ // user input before rolling back.
71+ func (p * Parser ) snapshotTokenStreamAndCompletion () tokenStreamAndCompletionState {
72+ s := tokenStreamAndCompletionState {
73+ tokenStream : p .snapshotTokenStream (),
74+ collecting : p .collecting ,
75+ collectDepth : p .collectDepth ,
76+ }
77+ if p .candidates != nil {
78+ s .candidates = p .candidates .snapshot ()
79+ }
80+ return s
81+ }
82+
6183// restoreTokenStream rewinds parser + lexer state to a previously
6284// captured snapshot. After restore, the next advance() will emit the
6385// same token as it would have at the moment snapshotTokenStream() was
6486// called.
6587//
6688// Caller responsibility: do not interleave restore with completion-mode
67- // queries or with any operation that mutates lexer state outside the
68- // token stream (string literal scanning, etc). The current speculative
69- // parse sites in parseFuncArg and parseFuncType only consume keyword
70- // tokens and punctuation, so they are safe.
89+ // queries or with any operation that mutates lexer state outside the token
90+ // stream. Use restoreTokenStreamAndCompletion for lookahead that may cross
91+ // the completion cursor.
7192func (p * Parser ) restoreTokenStream (s tokenStreamState ) {
7293 p .cur = s .cur
7394 p .prev = s .prev
@@ -78,3 +99,14 @@ func (p *Parser) restoreTokenStream(s tokenStreamState) {
7899 p .lexer .start = s .lexerStart
79100 p .lexer .state = s .lexerState
80101}
102+
103+ // restoreTokenStreamAndCompletion rewinds token-stream and completion state
104+ // captured by snapshotTokenStreamAndCompletion.
105+ func (p * Parser ) restoreTokenStreamAndCompletion (s tokenStreamAndCompletionState ) {
106+ p .restoreTokenStream (s .tokenStream )
107+ p .collecting = s .collecting
108+ p .collectDepth = s .collectDepth
109+ if p .candidates != nil && s .candidates != nil {
110+ p .candidates .restore (s .candidates )
111+ }
112+ }
0 commit comments