@@ -6,7 +6,7 @@ export const SQL_SPLIT_SYMBOL_TEXT = ';';
66
77abstract class SemanticContextCollector {
88 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.
1010 const tokenIndex = findCaretTokenIndex ( caretPosition , allTokens ) ;
1111
1212 if ( tokenIndex !== undefined ) {
@@ -17,14 +17,15 @@ abstract class SemanticContextCollector {
1717 if ( allTokens ?. length ) {
1818 let i = tokenIndex ? tokenIndex - 1 : allTokens . length - 1 ;
1919 /**
20- * Find the previous no-hidden token.
20+ * Link to @case4 and @case5
21+ * Find the previous unhidden token.
2122 * If can't find tokenIndex or current token is whiteSpace at caretPosition,
2223 * prevTokenIndex is useful to help us determine if it is new statement.
2324 */
2425 while ( i >= 0 ) {
2526 if (
2627 allTokens [ i ] . channel !== Token . HIDDEN_CHANNEL &&
27- ( allTokens [ i ] . line < caretPosition ? .lineNumber ||
28+ ( allTokens [ i ] . line < caretPosition . lineNumber ||
2829 ( allTokens [ i ] . line === caretPosition . lineNumber &&
2930 allTokens [ i ] . column < caretPosition . column ) )
3031 ) {
@@ -34,7 +35,10 @@ abstract class SemanticContextCollector {
3435 i -- ;
3536 }
3637
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+ */
3842 if (
3943 tokenIndex === 0 ||
4044 i === - 1 ||
@@ -48,10 +52,27 @@ abstract class SemanticContextCollector {
4852
4953 private _tokenIndex : number ;
5054 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+ */
5172 private _isNewStatement : boolean = false ;
5273
5374 /**
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
5576 */
5677 private _prevTokenIndex : number ;
5778
@@ -65,7 +86,7 @@ abstract class SemanticContextCollector {
6586
6687 abstract getStatementRuleType ( ) : number ;
6788
68- private previousStatementHasError ( node : TerminalNode | ErrorNode | ParserRuleContext ) {
89+ private prevStatementHasError ( node : TerminalNode | ErrorNode | ParserRuleContext ) {
6990 let parent = node . parent as ParserRuleContext ;
7091 if ( ! parent ) return false ;
7192
@@ -85,19 +106,17 @@ abstract class SemanticContextCollector {
85106 }
86107
87108 /**
88- * Most root rules is program.
109+ * Most root rule is ` program` .
89110 */
90- private getIsRootRuleNode ( node : TerminalNode | ErrorNode | ParserRuleContext ) {
111+ private isRootRule ( node : TerminalNode | ErrorNode | ParserRuleContext ) {
91112 return node instanceof ParserRuleContext && node ?. parent === null ;
92113 }
93114
94115 /**
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`.
99118 */
100- protected statementVisitor ( ctx : ParserRuleContext ) {
119+ protected visitStatement ( ctx : ParserRuleContext ) {
101120 const isWhiteSpaceToken =
102121 this . _tokenIndex === undefined ||
103122 this . _allTokens [ this . _tokenIndex ] ?. type === this . getWhiteSpaceRuleType ( ) ||
@@ -108,9 +127,7 @@ abstract class SemanticContextCollector {
108127 this . _prevTokenIndex && ctx . stop ?. tokenIndex === this . _prevTokenIndex ;
109128
110129 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 ;
114131 }
115132 }
116133
@@ -124,14 +141,16 @@ abstract class SemanticContextCollector {
124141 let currentNode : TerminalNode | ParserRuleContext = node ;
125142
126143 /**
144+ * Link to @case2
127145 * The error node is a direct child node of the program node
128146 */
129- if ( this . getIsRootRuleNode ( parent ) ) {
130- this . _isNewStatement = ! this . previousStatementHasError ( currentNode ) ;
147+ if ( this . isRootRule ( parent ) ) {
148+ this . _isNewStatement = ! this . prevStatementHasError ( currentNode ) ;
131149 return ;
132150 }
133151
134152 /**
153+ * Link to @case3
135154 * Error node must be the first leaf node of the statement parse tree.
136155 **/
137156 while ( parent !== null && parent . ruleIndex !== this . getStatementRuleType ( ) ) {
@@ -147,6 +166,7 @@ abstract class SemanticContextCollector {
147166 let isNewStatement = true ;
148167
149168 /**
169+ * Link to @case1
150170 * Previous statement must have no exception
151171 */
152172 if ( parent ?. ruleIndex === this . getStatementRuleType ( ) ) {
@@ -160,9 +180,7 @@ abstract class SemanticContextCollector {
160180 */
161181 const isStatementEOF = parent . exception ?. offendingToken ?. text === '<EOF>' ;
162182 isNewStatement =
163- this . previousStatementHasError ( parent ) && ! isStatementEOF
164- ? false
165- : isNewStatement ;
183+ this . prevStatementHasError ( parent ) && ! isStatementEOF ? false : isNewStatement ;
166184 }
167185 }
168186
@@ -176,6 +194,7 @@ abstract class SemanticContextCollector {
176194 let parent = node . parent as ParserRuleContext | null ;
177195
178196 /**
197+ * Link to @case3
179198 * Current terminal node must be the first leaf node of the statement parse tree.
180199 **/
181200 while ( parent !== null && parent . ruleIndex !== this . getStatementRuleType ( ) ) {
@@ -190,12 +209,16 @@ abstract class SemanticContextCollector {
190209
191210 let isNewStatement = true ;
192211
212+ /**
213+ * Link to @case1
214+ * Previous statement must have no exception
215+ */
193216 if ( parent ?. ruleIndex === this . getStatementRuleType ( ) ) {
194217 const programRule = parent . parent ;
195218 const currentStatementRuleIndex =
196219 programRule ?. children ?. findIndex ( ( node ) => node === parent ) || - 1 ;
197220 if ( currentStatementRuleIndex > 0 ) {
198- isNewStatement = this . previousStatementHasError ( parent ) ? false : isNewStatement ;
221+ isNewStatement = this . prevStatementHasError ( parent ) ? false : isNewStatement ;
199222 }
200223 }
201224
0 commit comments