@@ -6,7 +6,7 @@ export const SQL_SPLIT_SYMBOL_TEXT = ';';
6
6
7
7
abstract class SemanticContextCollector {
8
8
constructor ( _input : string , caretPosition : CaretPosition , allTokens : Token [ ] ) {
9
- // If caretPosition is whiteSpace, tokenIndex may be undefined.
9
+ // If caretPosition token is whiteSpace, tokenIndex may be undefined.
10
10
const tokenIndex = findCaretTokenIndex ( caretPosition , allTokens ) ;
11
11
12
12
if ( tokenIndex !== undefined ) {
@@ -17,14 +17,15 @@ abstract class SemanticContextCollector {
17
17
if ( allTokens ?. length ) {
18
18
let i = tokenIndex ? tokenIndex - 1 : allTokens . length - 1 ;
19
19
/**
20
- * Find the previous no-hidden token.
20
+ * Link to @case4 and @case5
21
+ * Find the previous unhidden token.
21
22
* If can't find tokenIndex or current token is whiteSpace at caretPosition,
22
23
* prevTokenIndex is useful to help us determine if it is new statement.
23
24
*/
24
25
while ( i >= 0 ) {
25
26
if (
26
27
allTokens [ i ] . channel !== Token . HIDDEN_CHANNEL &&
27
- ( allTokens [ i ] . line < caretPosition ? .lineNumber ||
28
+ ( allTokens [ i ] . line < caretPosition . lineNumber ||
28
29
( allTokens [ i ] . line === caretPosition . lineNumber &&
29
30
allTokens [ i ] . column < caretPosition . column ) )
30
31
) {
@@ -34,7 +35,10 @@ abstract class SemanticContextCollector {
34
35
i -- ;
35
36
}
36
37
37
- // Current token is the first token of tokenStream or the previous token is semicolon
38
+ /**
39
+ * We can directly conclude newStatement semantics when current token is
40
+ * the first token of tokenStream or the previous token is semicolon
41
+ */
38
42
if (
39
43
tokenIndex === 0 ||
40
44
i === - 1 ||
@@ -48,10 +52,27 @@ abstract class SemanticContextCollector {
48
52
49
53
private _tokenIndex : number ;
50
54
private _allTokens : Token [ ] = [ ] ;
55
+
56
+ /**
57
+ * If current caret position is in a newStatement semantics, it needs to follow some cases:
58
+ * @case 1 there is no statement node with an error before the current statement in the parse tree;
59
+ *
60
+ * @case 2 if it is an uncomplete keyword, it will be parsed as an `ErrorNode`
61
+ * and need be a direct child node of `program`;
62
+ *
63
+ * @case 3 if it is a complete keyword, the parsed TerminalNode or ErrorNode should be
64
+ * the first leaf node of current statement rule;
65
+ *
66
+ * @case 4 if it is whiteSpace in caret position, we can't visit it in antlr4 listener,
67
+ * so we find the first unhidden token before the whiteSpace token, and the unhidden token
68
+ * should be the last leaf node of statement its belongs to;
69
+ *
70
+ * @case 5 if the previous token is split symbol like `;`, ignore case1 and forcefully judged as newStatement.
71
+ */
51
72
private _isNewStatement : boolean = false ;
52
73
53
74
/**
54
- * Prev tokenIndex that not white space before current tokenIndex or cart position
75
+ * Prev tokenIndex that not white space before current tokenIndex or caret position
55
76
*/
56
77
private _prevTokenIndex : number ;
57
78
@@ -65,7 +86,7 @@ abstract class SemanticContextCollector {
65
86
66
87
abstract getStatementRuleType ( ) : number ;
67
88
68
- private previousStatementHasError ( node : TerminalNode | ErrorNode | ParserRuleContext ) {
89
+ private prevStatementHasError ( node : TerminalNode | ErrorNode | ParserRuleContext ) {
69
90
let parent = node . parent as ParserRuleContext ;
70
91
if ( ! parent ) return false ;
71
92
@@ -85,19 +106,17 @@ abstract class SemanticContextCollector {
85
106
}
86
107
87
108
/**
88
- * Most root rules is program.
109
+ * Most root rule is ` program` .
89
110
*/
90
- private getIsRootRuleNode ( node : TerminalNode | ErrorNode | ParserRuleContext ) {
111
+ private isRootRule ( node : TerminalNode | ErrorNode | ParserRuleContext ) {
91
112
return node instanceof ParserRuleContext && node ?. parent === null ;
92
113
}
93
114
94
115
/**
95
- * Caret position is white space, so it will not visited as terminal node or error node.
96
- * We can find the first previous no-white-space token,
97
- * and if previous token is the last leaf node of the statement,
98
- * it can be considered as being in the context of new statement
116
+ * link to @case4
117
+ * It should be called in each language's own `enterStatement`.
99
118
*/
100
- protected statementVisitor ( ctx : ParserRuleContext ) {
119
+ protected visitStatement ( ctx : ParserRuleContext ) {
101
120
const isWhiteSpaceToken =
102
121
this . _tokenIndex === undefined ||
103
122
this . _allTokens [ this . _tokenIndex ] ?. type === this . getWhiteSpaceRuleType ( ) ||
@@ -108,9 +127,7 @@ abstract class SemanticContextCollector {
108
127
this . _prevTokenIndex && ctx . stop ?. tokenIndex === this . _prevTokenIndex ;
109
128
110
129
if ( isWhiteSpaceToken && isPrevTokenEndOfStatement && ctx . exception === null ) {
111
- this . _isNewStatement = ! this . previousStatementHasError ( ctx )
112
- ? true
113
- : this . _isNewStatement ;
130
+ this . _isNewStatement = ! this . prevStatementHasError ( ctx ) ? true : this . _isNewStatement ;
114
131
}
115
132
}
116
133
@@ -124,14 +141,16 @@ abstract class SemanticContextCollector {
124
141
let currentNode : TerminalNode | ParserRuleContext = node ;
125
142
126
143
/**
144
+ * Link to @case2
127
145
* The error node is a direct child node of the program node
128
146
*/
129
- if ( this . getIsRootRuleNode ( parent ) ) {
130
- this . _isNewStatement = ! this . previousStatementHasError ( currentNode ) ;
147
+ if ( this . isRootRule ( parent ) ) {
148
+ this . _isNewStatement = ! this . prevStatementHasError ( currentNode ) ;
131
149
return ;
132
150
}
133
151
134
152
/**
153
+ * Link to @case3
135
154
* Error node must be the first leaf node of the statement parse tree.
136
155
**/
137
156
while ( parent !== null && parent . ruleIndex !== this . getStatementRuleType ( ) ) {
@@ -147,6 +166,7 @@ abstract class SemanticContextCollector {
147
166
let isNewStatement = true ;
148
167
149
168
/**
169
+ * Link to @case1
150
170
* Previous statement must have no exception
151
171
*/
152
172
if ( parent ?. ruleIndex === this . getStatementRuleType ( ) ) {
@@ -160,9 +180,7 @@ abstract class SemanticContextCollector {
160
180
*/
161
181
const isStatementEOF = parent . exception ?. offendingToken ?. text === '<EOF>' ;
162
182
isNewStatement =
163
- this . previousStatementHasError ( parent ) && ! isStatementEOF
164
- ? false
165
- : isNewStatement ;
183
+ this . prevStatementHasError ( parent ) && ! isStatementEOF ? false : isNewStatement ;
166
184
}
167
185
}
168
186
@@ -176,6 +194,7 @@ abstract class SemanticContextCollector {
176
194
let parent = node . parent as ParserRuleContext | null ;
177
195
178
196
/**
197
+ * Link to @case3
179
198
* Current terminal node must be the first leaf node of the statement parse tree.
180
199
**/
181
200
while ( parent !== null && parent . ruleIndex !== this . getStatementRuleType ( ) ) {
@@ -190,12 +209,16 @@ abstract class SemanticContextCollector {
190
209
191
210
let isNewStatement = true ;
192
211
212
+ /**
213
+ * Link to @case1
214
+ * Previous statement must have no exception
215
+ */
193
216
if ( parent ?. ruleIndex === this . getStatementRuleType ( ) ) {
194
217
const programRule = parent . parent ;
195
218
const currentStatementRuleIndex =
196
219
programRule ?. children ?. findIndex ( ( node ) => node === parent ) || - 1 ;
197
220
if ( currentStatementRuleIndex > 0 ) {
198
- isNewStatement = this . previousStatementHasError ( parent ) ? false : isNewStatement ;
221
+ isNewStatement = this . prevStatementHasError ( parent ) ? false : isNewStatement ;
199
222
}
200
223
}
201
224
0 commit comments